Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class ProfilerMetricsIOS {
private:
std::optional<CpuUsageInfo> CpuUsage();

std::optional<MemoryUsageInfo> MemoryUsage();

FML_DISALLOW_COPY_AND_ASSIGN(ProfilerMetricsIOS);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
namespace flutter {

ProfileSample ProfilerMetricsIOS::GenerateSample() {
return {.cpu_usage = CpuUsage()};
return {.cpu_usage = CpuUsage(), .memory_usage = MemoryUsage()};
}

std::optional<CpuUsageInfo> ProfilerMetricsIOS::CpuUsage() {
Expand Down Expand Up @@ -76,4 +76,33 @@
return cpu_usage_info;
}

std::optional<MemoryUsageInfo> ProfilerMetricsIOS::MemoryUsage() {
kern_return_t kernel_return_code;
task_vm_info_data_t task_memory_info;
mach_msg_type_number_t task_memory_info_count = TASK_VM_INFO_COUNT;

kernel_return_code =
task_info(mach_task_self(), TASK_VM_INFO, reinterpret_cast<task_info_t>(&task_memory_info),
&task_memory_info_count);
if (kernel_return_code != KERN_SUCCESS) {
FML_LOG(ERROR) << " Error retrieving task memory information: "
<< mach_error_string(kernel_return_code);
return std::nullopt;
}

// `phys_footprint` is Apple's recommended way to measure app's memory usage. It provides the
// best approximate to xcode memory gauge. According to its source code explanation, the physical
// footprint mainly consists of app's internal memory data and IOKit mappings. `resident_size`
// is the total physical memory used by the app, so we simply do `resident_size - phys_footprint`
// to obtain the shared memory usage.
const double dirty_memory_usage =
static_cast<double>(task_memory_info.phys_footprint) / 1024.0 / 1024.0;
const double owned_shared_memory_usage =
static_cast<double>(task_memory_info.resident_size) / 1024.0 / 1024.0 - dirty_memory_usage;
flutter::MemoryUsageInfo memory_usage_info = {
.dirty_memory_usage = dirty_memory_usage,
.owned_shared_memory_usage = owned_shared_memory_usage};
return memory_usage_info;
}

} // namespace flutter
14 changes: 12 additions & 2 deletions shell/profiling/sampling_profiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,28 @@ void SamplingProfiler::Start() const {
void SamplingProfiler::SampleRepeatedly(fml::TimeDelta task_delay) const {
profiler_task_runner_->PostDelayedTask(
[profiler = this, task_delay = task_delay, sampler = sampler_]() {
// TODO(kaushikiska): consider buffering these every n seconds to
// avoid spamming the trace buffer.
const ProfileSample usage = sampler();
if (usage.cpu_usage) {
const auto& cpu_usage = usage.cpu_usage;
// TODO(kaushikiska): consider buffering these every n seconds to
// avoid spamming the trace buffer.
std::string total_cpu_usage =
std::to_string(cpu_usage->total_cpu_usage);
std::string num_threads = std::to_string(cpu_usage->num_threads);
TRACE_EVENT_INSTANT2("flutter::profiling", "CpuUsage",
"total_cpu_usage", total_cpu_usage.c_str(),
"num_threads", num_threads.c_str());
}
if (usage.memory_usage) {
std::string dirty_memory_usage =
std::to_string(usage.memory_usage->dirty_memory_usage);
std::string owned_shared_memory_usage =
std::to_string(usage.memory_usage->owned_shared_memory_usage);
TRACE_EVENT_INSTANT2("flutter::profiling", "MemoryUsage",
"dirty_memory_usage", dirty_memory_usage.c_str(),
"owned_shared_memory_usage",
owned_shared_memory_usage.c_str());
}
profiler->SampleRepeatedly(task_delay);
},
task_delay);
Expand Down
18 changes: 16 additions & 2 deletions shell/profiling/sampling_profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,29 @@ struct CpuUsageInfo {
double total_cpu_usage;
};

/**
* @brief Memory usage stats. `dirty_memory_usage` is the the memory usage (in
* MB) such that the app uses its physical memory for dirty memory. Dirty memory
* is the memory data that cannot be paged to disk. `owned_shared_memory_usage`
* is the memory usage (in MB) such that the app uses its physicaal memory for
* shared memory, including loaded frameworks and executables. On iOS, it's
* `physical memory - dirty memory`.
*/
struct MemoryUsageInfo {
double dirty_memory_usage;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document what unit it uses (e.g., MB, KB, or something else)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I missed the "mega bytes" in the struct documentation... Maybe also put a capitalized MB there, or add a document for each field so they're more prominent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rephrased the docstring a bit so that "MB" should be more obvious than "mega bytes". I will keep the docstring as is so it is consistent with the CPU part.

As another way, we can also rename them to dirty_memory_usage_mb and owned_shared_memory_usage_mb, WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MB docstring as it is now looks good!

double owned_shared_memory_usage;
};

/**
* @brief Container for the metrics we collect during each run of `Sampler`.
* This currently holds `CpuUsageInfo` but the intent is to expand it to other
* metrics.
* This currently holds `CpuUsageInfo` and `MemoryUsageInfo` but the intent
* is to expand it to other metrics.
*
* @see flutter::Sampler
*/
struct ProfileSample {
std::optional<CpuUsageInfo> cpu_usage;
std::optional<MemoryUsageInfo> memory_usage;
};

/**
Expand Down