-
Notifications
You must be signed in to change notification settings - Fork 6k
started polling the gpu usage #18752
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Has this file been copied from somewhere? If so could you add a comment pointing to the source or reference? Reading it seems like it's an accumulation of a bunch of IOKit headers into one file.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, added documentation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does copyright work when the header is an amalgamation of other (presumably copyrighted) headers? |
||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| // These declarations are an amalgamation of different headers whose | ||
| // symbols exist in IOKit.framework. The headers have been removed | ||
| // from the iOS SDKs but all the functions are documented here: | ||
| // * https://developer.apple.com/documentation/iokit/iokitlib_h?language=objc | ||
| // * https://developer.apple.com/documentation/iokit/iokit_functions?language=objc | ||
| // * file:///Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Versions/A/Headers/IOKitLib.h | ||
|
|
||
| #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG || \ | ||
| FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE | ||
| #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_IOKIT_H_ | ||
| #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_IOKIT_H_ | ||
|
|
||
| #if __cplusplus | ||
| extern "C" { | ||
| #endif // __cplusplus | ||
|
|
||
| #include <CoreFoundation/CoreFoundation.h> | ||
| #include <mach/mach.h> | ||
| #include <stdint.h> | ||
|
|
||
| #define IOKIT | ||
| #include <device/device_types.h> | ||
|
|
||
| static const char* kIOServicePlane = "IOService"; | ||
|
|
||
| typedef io_object_t io_registry_entry_t; | ||
| typedef io_object_t io_service_t; | ||
| typedef io_object_t io_connect_t; | ||
| typedef io_object_t io_iterator_t; | ||
|
|
||
| enum { | ||
| kIOReturnSuccess = 0, | ||
| }; | ||
|
|
||
| extern const mach_port_t kIOMasterPortDefault; | ||
|
|
||
| kern_return_t IOObjectRetain(io_object_t object); | ||
| kern_return_t IOObjectRelease(io_object_t object); | ||
| boolean_t IOObjectConformsTo(io_object_t object, const io_name_t name); | ||
| uint32_t IOObjectGetKernelRetainCount(io_object_t object); | ||
| kern_return_t IOObjectGetClass(io_object_t object, io_name_t name); | ||
| CFStringRef IOObjectCopyClass(io_object_t object); | ||
| CFStringRef IOObjectCopySuperclassForClass(CFStringRef name); | ||
| CFStringRef IOObjectCopyBundleIdentifierForClass(CFStringRef name); | ||
|
|
||
| io_registry_entry_t IORegistryGetRootEntry(mach_port_t master); | ||
| kern_return_t IORegistryEntryGetName(io_registry_entry_t entry, io_name_t name); | ||
| kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, | ||
| uint64_t* entryID); | ||
| kern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, | ||
| const io_name_t plane, | ||
| io_string_t path); | ||
| kern_return_t IORegistryEntryGetProperty(io_registry_entry_t entry, | ||
| const io_name_t name, | ||
| io_struct_inband_t buffer, | ||
| uint32_t* size); | ||
| kern_return_t IORegistryEntryCreateCFProperties( | ||
| io_registry_entry_t entry, | ||
| CFMutableDictionaryRef* properties, | ||
| CFAllocatorRef allocator, | ||
| uint32_t options); | ||
| CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, | ||
| CFStringRef key, | ||
| CFAllocatorRef allocator, | ||
| uint32_t options); | ||
| kern_return_t IORegistryEntrySetCFProperties(io_registry_entry_t entry, | ||
| CFTypeRef properties); | ||
|
|
||
| kern_return_t IORegistryCreateIterator(mach_port_t master, | ||
| const io_name_t plane, | ||
| uint32_t options, | ||
| io_iterator_t* it); | ||
| kern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, | ||
| const io_name_t plane, | ||
| uint32_t options, | ||
| io_iterator_t* it); | ||
| kern_return_t IORegistryEntryGetChildIterator(io_registry_entry_t entry, | ||
| const io_name_t plane, | ||
| io_iterator_t* it); | ||
| kern_return_t IORegistryEntryGetParentIterator(io_registry_entry_t entry, | ||
| const io_name_t plane, | ||
| io_iterator_t* it); | ||
| io_object_t IOIteratorNext(io_iterator_t it); | ||
| boolean_t IOIteratorIsValid(io_iterator_t it); | ||
| void IOIteratorReset(io_iterator_t it); | ||
|
|
||
| CFMutableDictionaryRef IOServiceMatching(const char* name) CF_RETURNS_RETAINED; | ||
| CFMutableDictionaryRef IOServiceNameMatching(const char* name) | ||
| CF_RETURNS_RETAINED; | ||
| io_service_t IOServiceGetMatchingService(mach_port_t master, | ||
| CFDictionaryRef matching | ||
| CF_RELEASES_ARGUMENT); | ||
| kern_return_t IOServiceGetMatchingServices(mach_port_t master, | ||
| CFDictionaryRef matching | ||
| CF_RELEASES_ARGUMENT, | ||
| io_iterator_t* it); | ||
|
|
||
| #if __cplusplus | ||
| } | ||
| #endif // __cplusplus | ||
|
|
||
| #endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_IOKIT_H_ | ||
| #endif // defined(FLUTTER_RUNTIME_MODE_DEBUG) || | ||
| // defined(FLUTTER_RUNTIME_MODE_PROFILE) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,8 @@ | |
| // found in the LICENSE file. | ||
|
|
||
| #include "flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h" | ||
| #import <Foundation/Foundation.h> | ||
| #import "IOKit.h" | ||
|
|
||
| namespace { | ||
|
|
||
|
|
@@ -28,9 +30,126 @@ | |
| } | ||
|
|
||
| namespace flutter { | ||
| namespace { | ||
|
|
||
| #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG || \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given how big this class is getting, consider moving this to
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The file is 228 lines, shrug. If you feel strongly about it I can move it. It's an easy change, just takes time with our current system. |
||
| FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE | ||
|
|
||
| template <typename T> | ||
| T ClearValue() { | ||
| return nullptr; | ||
| } | ||
|
|
||
| template <> | ||
| io_object_t ClearValue<io_object_t>() { | ||
| return 0; | ||
| } | ||
|
|
||
| template <typename T> | ||
| /// Generic RAII wrapper like unique_ptr but gives access to its handle. | ||
| class Scoped { | ||
| public: | ||
| typedef void (*Deleter)(T); | ||
| explicit Scoped(Deleter deleter) : object_(ClearValue<T>()), deleter_(deleter) {} | ||
| Scoped(T object, Deleter deleter) : object_(object), deleter_(deleter) {} | ||
| ~Scoped() { | ||
| if (object_) { | ||
| deleter_(object_); | ||
| } | ||
| } | ||
| T* handle() { | ||
| if (object_) { | ||
| deleter_(object_); | ||
| object_ = ClearValue<T>(); | ||
| } | ||
| return &object_; | ||
| } | ||
| T get() { return object_; } | ||
| void reset(T new_value) { | ||
| if (object_) { | ||
| deleter_(object_); | ||
| } | ||
| object_ = new_value; | ||
| } | ||
|
|
||
| private: | ||
| FML_DISALLOW_COPY_ASSIGN_AND_MOVE(Scoped); | ||
| T object_; | ||
| Deleter deleter_; | ||
| }; | ||
|
|
||
| void DeleteCF(CFMutableDictionaryRef value) { | ||
| CFRelease(value); | ||
| } | ||
|
|
||
| void DeleteIO(io_object_t value) { | ||
| IOObjectRelease(value); | ||
| } | ||
|
|
||
| std::optional<GpuUsageInfo> FindGpuUsageInfo(io_iterator_t iterator) { | ||
| for (Scoped<io_registry_entry_t> regEntry(IOIteratorNext(iterator), DeleteIO); regEntry.get(); | ||
| regEntry.reset(IOIteratorNext(iterator))) { | ||
| Scoped<CFMutableDictionaryRef> serviceDictionary(DeleteCF); | ||
| if (IORegistryEntryCreateCFProperties(regEntry.get(), serviceDictionary.handle(), | ||
| kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) { | ||
| continue; | ||
| } | ||
|
|
||
| NSDictionary* dictionary = | ||
| ((__bridge NSDictionary*)serviceDictionary.get())[@"PerformanceStatistics"]; | ||
| NSNumber* utilization = dictionary[@"Device Utilization %"]; | ||
| if (utilization) { | ||
| return (GpuUsageInfo){.percent_usage = [utilization doubleValue]}; | ||
| } | ||
| } | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| [[maybe_unused]] std::optional<GpuUsageInfo> FindSimulatorGpuUsageInfo() { | ||
| Scoped<io_iterator_t> iterator(DeleteIO); | ||
| if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceNameMatching("IntelAccelerator"), | ||
| iterator.handle()) == kIOReturnSuccess) { | ||
| return FindGpuUsageInfo(iterator.get()); | ||
| } | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| [[maybe_unused]] std::optional<GpuUsageInfo> FindDeviceGpuUsageInfo() { | ||
| Scoped<io_iterator_t> iterator(DeleteIO); | ||
| if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceNameMatching("sgx"), | ||
| iterator.handle()) == kIOReturnSuccess) { | ||
| for (Scoped<io_registry_entry_t> regEntry(IOIteratorNext(iterator.get()), DeleteIO); | ||
| regEntry.get(); regEntry.reset(IOIteratorNext(iterator.get()))) { | ||
| Scoped<io_iterator_t> innerIterator(DeleteIO); | ||
| if (IORegistryEntryGetChildIterator(regEntry.get(), kIOServicePlane, | ||
| innerIterator.handle()) == kIOReturnSuccess) { | ||
| std::optional<GpuUsageInfo> result = FindGpuUsageInfo(innerIterator.get()); | ||
| if (result.has_value()) { | ||
| return result; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return std::nullopt; | ||
| } | ||
|
|
||
| #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG || | ||
| // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE | ||
|
|
||
| std::optional<GpuUsageInfo> PollGpuUsage() { | ||
| #if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE || \ | ||
| FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_JIT_RELEASE) | ||
| return std::nullopt; | ||
| #elif TARGET_IPHONE_SIMULATOR | ||
| return FindSimulatorGpuUsageInfo(); | ||
| #elif TARGET_OS_IOS | ||
| return FindDeviceGpuUsageInfo(); | ||
| #endif // TARGET_IPHONE_SIMULATOR | ||
| } | ||
| } // namespace | ||
|
|
||
| ProfileSample ProfilerMetricsIOS::GenerateSample() { | ||
| return {.cpu_usage = CpuUsage(), .memory_usage = MemoryUsage()}; | ||
| return {.cpu_usage = CpuUsage(), .memory_usage = MemoryUsage(), .gpu_usage = PollGpuUsage()}; | ||
| } | ||
|
|
||
| std::optional<CpuUsageInfo> ProfilerMetricsIOS::CpuUsage() { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm surprised that out GN format presubmit doesn't account for these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, that formatter is usually pretty strict!