7 #import <Foundation/Foundation.h>
20 thread_array_t threads = NULL;
21 mach_msg_type_number_t thread_count = 0;
26 [[maybe_unused]] kern_return_t kernel_return_code = vm_deallocate(
27 mach_task_self(),
reinterpret_cast<vm_offset_t
>(threads), thread_count *
sizeof(thread_t));
28 FML_DCHECK(kernel_return_code == KERN_SUCCESS) <<
"Failed to deallocate thread infos.";
40 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG || \
41 FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE
49 io_object_t ClearValue<io_object_t>() {
57 typedef void (*Deleter)(T);
58 explicit Scoped(Deleter deleter) : object_(ClearValue<T>()), deleter_(deleter) {}
59 Scoped(T
object, Deleter deleter) : object_(object), deleter_(deleter) {}
68 object_ = ClearValue<T>();
72 T get() {
return object_; }
73 void reset(T new_value) {
81 FML_DISALLOW_COPY_ASSIGN_AND_MOVE(Scoped);
86 void DeleteCF(CFMutableDictionaryRef value) {
90 void DeleteIO(io_object_t value) {
94 std::optional<GpuUsageInfo> FindGpuUsageInfo(
io_iterator_t iterator) {
95 for (Scoped<io_registry_entry_t> regEntry(
IOIteratorNext(iterator), DeleteIO); regEntry.get();
97 Scoped<CFMutableDictionaryRef> serviceDictionary(DeleteCF);
103 NSDictionary* dictionary =
104 ((__bridge NSDictionary*)serviceDictionary.get())[
@"PerformanceStatistics"];
105 NSNumber* utilization = dictionary[
@"Device Utilization %"];
107 return (GpuUsageInfo){.percent_usage = [utilization doubleValue]};
113 [[maybe_unused]] std::optional<GpuUsageInfo> FindSimulatorGpuUsageInfo() {
114 Scoped<io_iterator_t> iterator(DeleteIO);
117 return FindGpuUsageInfo(iterator.get());
122 [[maybe_unused]] std::optional<GpuUsageInfo> FindDeviceGpuUsageInfo() {
123 Scoped<io_iterator_t> iterator(DeleteIO);
126 for (Scoped<io_registry_entry_t> regEntry(
IOIteratorNext(iterator.get()), DeleteIO);
128 Scoped<io_iterator_t> innerIterator(DeleteIO);
131 std::optional<GpuUsageInfo> result = FindGpuUsageInfo(innerIterator.get());
132 if (result.has_value()) {
141 #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG ||
144 std::optional<GpuUsageInfo> PollGpuUsage() {
145 #if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE || \
146 FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_JIT_RELEASE)
148 #elif TARGET_IPHONE_SIMULATOR
149 return FindSimulatorGpuUsageInfo();
151 return FindDeviceGpuUsageInfo();
152 #endif // TARGET_IPHONE_SIMULATOR
157 return {.cpu_usage = CpuUsage(), .memory_usage = MemoryUsage(), .gpu_usage = PollGpuUsage()};
160 std::optional<CpuUsageInfo> ProfilerMetricsIOS::CpuUsage() {
161 kern_return_t kernel_return_code;
162 MachThreads mach_threads = MachThreads();
166 task_threads(mach_task_self(), &mach_threads.threads, &mach_threads.thread_count);
167 if (kernel_return_code != KERN_SUCCESS) {
171 double total_cpu_usage = 0.0;
172 uint32_t num_threads = mach_threads.thread_count;
181 for (mach_msg_type_number_t i = 0; i < mach_threads.thread_count; i++) {
182 thread_basic_info_data_t basic_thread_info;
183 mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
185 thread_info(mach_threads.threads[i], THREAD_BASIC_INFO,
186 reinterpret_cast<thread_info_t
>(&basic_thread_info), &thread_info_count);
187 switch (kernel_return_code) {
189 const double current_thread_cpu_usage =
190 basic_thread_info.cpu_usage /
static_cast<float>(TH_USAGE_SCALE);
191 total_cpu_usage += current_thread_cpu_usage;
194 case MACH_SEND_TIMEOUT:
195 case MACH_SEND_TIMED_OUT:
196 case MACH_SEND_INVALID_DEST:
208 flutter::CpuUsageInfo cpu_usage_info = {.num_threads = num_threads,
209 .total_cpu_usage = total_cpu_usage * 100.0};
210 return cpu_usage_info;
213 std::optional<MemoryUsageInfo> ProfilerMetricsIOS::MemoryUsage() {
214 kern_return_t kernel_return_code;
215 task_vm_info_data_t task_memory_info;
216 mach_msg_type_number_t task_memory_info_count = TASK_VM_INFO_COUNT;
219 task_info(mach_task_self(), TASK_VM_INFO,
reinterpret_cast<task_info_t
>(&task_memory_info),
220 &task_memory_info_count);
221 if (kernel_return_code != KERN_SUCCESS) {
230 const double dirty_memory_usage =
231 static_cast<double>(task_memory_info.phys_footprint) / 1024.0 / 1024.0;
232 const double owned_shared_memory_usage =
233 static_cast<double>(task_memory_info.resident_size) / 1024.0 / 1024.0 - dirty_memory_usage;
234 flutter::MemoryUsageInfo memory_usage_info = {
235 .dirty_memory_usage = dirty_memory_usage,
236 .owned_shared_memory_usage = owned_shared_memory_usage};
237 return memory_usage_info;