blob: 4fd6cacfae54d208cbeaea512d46186d01f370ce [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "memory-pressure.h"
#include <fidl/fuchsia.sysmem/cpp/fidl.h>
#include <fidl/fuchsia.sysmem2/cpp/fidl.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/sysmem-version/sysmem-version.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "src/lib/fsl/handles/object_info.h"
#include "src/lib/fxl/command_line.h"
void PrintHelp() {
Log(""
"Usage: sysmem-memory-pressure [--contiguous] [--help] [--heap=heap] [--usage=[cpu|vulkan]] "
"size_bytes\n");
Log("Options:\n");
Log(" --help Show this message.\n");
Log(" --contiguous Request physically-contiguous memory\n");
Log(" --heap Specifies the numeric value of the sysmem heap to request memory from. By "
"default system ram is used.\n");
Log(" --usage Specifies what usage should be requested from sysmem. Vulkan is the "
"default\n");
Log(" size_bytes The size of the memory in bytes.\n");
}
int MemoryPressureCommand(const fxl::CommandLine& command_line, bool sleep) {
if (command_line.HasOption("help")) {
PrintHelp();
return 0;
}
if (command_line.positional_args().size() != 1) {
LogError("Missing size to allocate\n");
PrintHelp();
return 1;
}
std::string size_string = command_line.positional_args()[0];
char* endptr;
uint64_t size = strtoull(size_string.c_str(), &endptr, 0);
if (endptr != size_string.c_str() + size_string.size()) {
LogError("Invalid size %s\n", size_string.c_str());
PrintHelp();
return 1;
}
fuchsia_sysmem::HeapType heap = fuchsia_sysmem::HeapType::kSystemRam;
std::string heap_string;
if (command_line.GetOptionValue("heap", &heap_string)) {
char* endptr;
heap = static_cast<fuchsia_sysmem::HeapType>(strtoull(heap_string.c_str(), &endptr, 0));
if (endptr != heap_string.c_str() + heap_string.size()) {
LogError("Invalid heap string: %s\n", heap_string.c_str());
return 1;
}
}
auto heap_type_result = sysmem::V2CopyFromV1HeapType(heap);
ZX_ASSERT(heap_type_result.is_ok());
auto heap_type = std::move(heap_type_result.value());
bool physically_contiguous = command_line.HasOption("contiguous");
fuchsia_sysmem2::BufferCollectionConstraints constraints;
std::string usage;
constraints.usage().emplace();
if (command_line.GetOptionValue("usage", &usage)) {
if (usage == "vulkan") {
constraints.usage()->vulkan() = fuchsia_sysmem2::kVulkanImageUsageTransferDst;
} else if (usage == "cpu") {
constraints.usage()->cpu() = fuchsia_sysmem2::kCpuUsageRead;
} else {
LogError("Invalid usage %s\n", usage.c_str());
PrintHelp();
return 1;
}
} else {
constraints.usage()->vulkan() = fuchsia_sysmem2::kVulkanImageUsageTransferDst;
}
constraints.min_buffer_count_for_camping() = 1;
auto& mem_constraints = constraints.buffer_memory_constraints().emplace();
mem_constraints.physically_contiguous_required() = physically_contiguous;
mem_constraints.min_size_bytes() = static_cast<uint32_t>(size);
mem_constraints.cpu_domain_supported() = true;
mem_constraints.ram_domain_supported() = true;
mem_constraints.inaccessible_domain_supported() = true;
mem_constraints.permitted_heaps().emplace().emplace_back(sysmem::MakeHeap(heap_type, 0));
zx::result client_end = component::Connect<fuchsia_sysmem2::Allocator>();
if (client_end.is_error()) {
LogError("Failed to connect to sysmem services, error %d\n", client_end.status_value());
return 1;
}
fidl::SyncClient sysmem_allocator{std::move(client_end.value())};
fuchsia_sysmem2::AllocatorSetDebugClientInfoRequest set_debug_request;
set_debug_request.name() = fsl::GetCurrentProcessName();
set_debug_request.id() = fsl::GetCurrentProcessKoid();
if (const auto set_debug_result =
sysmem_allocator->SetDebugClientInfo(std::move(set_debug_request));
!set_debug_result.is_ok()) {
LogError("Failed to set debug client info - error: %s\n",
set_debug_result.error_value().status_string());
return 1;
};
auto [client_collection_channel, server_collection] =
fidl::Endpoints<fuchsia_sysmem2::BufferCollection>::Create();
fuchsia_sysmem2::AllocatorAllocateNonSharedCollectionRequest allocate_non_shared_request;
allocate_non_shared_request.collection_request(std::move(server_collection));
if (const auto allocate_non_shared_result =
sysmem_allocator->AllocateNonSharedCollection(std::move(allocate_non_shared_request));
!allocate_non_shared_result.is_ok()) {
LogError("Failed to allocate collection - error: %s\n",
allocate_non_shared_result.error_value().status_string());
return 1;
}
fidl::SyncClient collection(std::move(client_collection_channel));
fuchsia_sysmem2::NodeSetNameRequest set_name_request;
set_name_request.priority() = 1000000;
set_name_request.name() = "sysmem-memory-pressure";
if (const auto set_name_result = collection->SetName(std::move(set_name_request));
!set_name_result.is_ok()) {
LogError("Failed to set collection name - error: %s\n",
set_name_result.error_value().status_string());
return 1;
}
fuchsia_sysmem2::BufferCollectionSetConstraintsRequest set_constraints_request;
set_constraints_request.constraints() = std::move(constraints);
if (const auto set_constraits_result =
collection->SetConstraints(std::move(set_constraints_request));
!set_constraits_result.is_ok()) {
LogError("Failed to set collection constraints - error: %s\n",
set_constraits_result.error_value().status_string());
return 1;
}
auto wait_result = collection->WaitForAllBuffersAllocated();
if (!wait_result.is_ok()) {
if (wait_result.error_value().is_framework_error()) {
LogError("Lost connection to sysmem services - framework_error: %s\n",
wait_result.error_value().framework_error().status_string());
} else {
LogError("Allocation error %u\n",
static_cast<uint32_t>(wait_result.error_value().domain_error()));
}
return 1;
}
Log("Allocated %ld bytes. Sleeping forever\n", size);
if (sleep) {
zx::nanosleep(zx::time::infinite());
}
return 0;
}