7 #import <Foundation/Foundation.h>
9 #import "flutter/fml/platform/darwin/cf_utils.h"
21 thread_array_t threads = NULL;
22 mach_msg_type_number_t thread_count = 0;
27 [[maybe_unused]] kern_return_t kernel_return_code = vm_deallocate(
28 mach_task_self(),
reinterpret_cast<vm_offset_t
>(threads), thread_count *
sizeof(thread_t));
29 FML_DCHECK(kernel_return_code == KERN_SUCCESS) <<
"Failed to deallocate thread infos.";
38 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG || \
39 FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE
45 struct CFRefTraits<io_object_t> {
46 static constexpr io_object_t kNullValue = 0;
58 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG || \
59 FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE
61 std::optional<GpuUsageInfo> FindGpuUsageInfo(
io_iterator_t iterator) {
62 for (fml::CFRef<io_registry_entry_t> reg_entry(
IOIteratorNext(iterator)); reg_entry.Get();
64 CFMutableDictionaryRef cf_service_dictionary;
70 NSDictionary* service_dictionary = (__bridge_transfer NSDictionary*)cf_service_dictionary;
71 cf_service_dictionary =
nullptr;
72 NSDictionary* performanceStatistics = service_dictionary[
@"PerformanceStatistics"];
73 NSNumber* utilization = performanceStatistics[
@"Device Utilization %"];
75 return (GpuUsageInfo){.percent_usage = [utilization doubleValue]};
81 [[maybe_unused]] std::optional<GpuUsageInfo> FindSimulatorGpuUsageInfo() {
85 fml::CFRef<io_iterator_t> iterator(io_iterator);
86 return FindGpuUsageInfo(iterator.Get());
91 [[maybe_unused]] std::optional<GpuUsageInfo> FindDeviceGpuUsageInfo() {
95 fml::CFRef<io_iterator_t> iterator(io_iterator);
96 for (fml::CFRef<io_registry_entry_t> reg_entry(
IOIteratorNext(iterator.Get())); reg_entry.Get();
101 fml::CFRef<io_iterator_t> inner_iterator(io_inner_iterator);
102 std::optional<GpuUsageInfo> result = FindGpuUsageInfo(inner_iterator.Get());
103 if (result.has_value()) {
112 #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG ||
115 std::optional<GpuUsageInfo> PollGpuUsage() {
116 #if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE || \
117 FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_JIT_RELEASE)
119 #elif TARGET_IPHONE_SIMULATOR
120 return FindSimulatorGpuUsageInfo();
122 return FindDeviceGpuUsageInfo();
123 #endif // TARGET_IPHONE_SIMULATOR
128 return {.cpu_usage = CpuUsage(), .memory_usage = MemoryUsage(), .gpu_usage = PollGpuUsage()};
131 std::optional<CpuUsageInfo> ProfilerMetricsIOS::CpuUsage() {
132 kern_return_t kernel_return_code;
133 MachThreads mach_threads = MachThreads();
137 task_threads(mach_task_self(), &mach_threads.threads, &mach_threads.thread_count);
138 if (kernel_return_code != KERN_SUCCESS) {
142 double total_cpu_usage = 0.0;
143 uint32_t num_threads = mach_threads.thread_count;
152 for (mach_msg_type_number_t i = 0; i < mach_threads.thread_count; i++) {
153 thread_basic_info_data_t basic_thread_info;
154 mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
156 thread_info(mach_threads.threads[i], THREAD_BASIC_INFO,
157 reinterpret_cast<thread_info_t
>(&basic_thread_info), &thread_info_count);
158 switch (kernel_return_code) {
160 const double current_thread_cpu_usage =
161 basic_thread_info.cpu_usage /
static_cast<float>(TH_USAGE_SCALE);
162 total_cpu_usage += current_thread_cpu_usage;
165 case MACH_SEND_TIMEOUT:
166 case MACH_SEND_TIMED_OUT:
167 case MACH_SEND_INVALID_DEST:
179 flutter::CpuUsageInfo cpu_usage_info = {.num_threads = num_threads,
180 .total_cpu_usage = total_cpu_usage * 100.0};
181 return cpu_usage_info;
184 std::optional<MemoryUsageInfo> ProfilerMetricsIOS::MemoryUsage() {
185 kern_return_t kernel_return_code;
186 task_vm_info_data_t task_memory_info;
187 mach_msg_type_number_t task_memory_info_count = TASK_VM_INFO_COUNT;
190 task_info(mach_task_self(), TASK_VM_INFO,
reinterpret_cast<task_info_t
>(&task_memory_info),
191 &task_memory_info_count);
192 if (kernel_return_code != KERN_SUCCESS) {
201 const double dirty_memory_usage =
202 static_cast<double>(task_memory_info.phys_footprint) / 1024.0 / 1024.0;
203 const double owned_shared_memory_usage =
204 static_cast<double>(task_memory_info.resident_size) / 1024.0 / 1024.0 - dirty_memory_usage;
205 flutter::MemoryUsageInfo memory_usage_info = {
206 .dirty_memory_usage = dirty_memory_usage,
207 .owned_shared_memory_usage = owned_shared_memory_usage};
208 return memory_usage_info;