2424#import " flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h"
2525#import " flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
2626#import " flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h"
27+ #import " flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h"
2728#import " flutter/shell/platform/darwin/ios/ios_surface.h"
2829#import " flutter/shell/platform/darwin/ios/platform_view_ios.h"
2930#include " flutter/shell/platform/darwin/ios/rendering_api_selection.h"
31+ #include " flutter/shell/profiling/sampling_profiler.h"
3032
3133NSString * const FlutterDefaultDartEntrypoint = nil ;
34+ static constexpr int kNumProfilerSamplesPerSec = 5 ;
3235
3336@interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
3437@property (nonatomic , assign ) FlutterEngine* flutterEngine;
@@ -56,6 +59,8 @@ @implementation FlutterEngine {
5659 fml::scoped_nsobject<FlutterObservatoryPublisher> _publisher;
5760
5861 std::unique_ptr<flutter::FlutterPlatformViewsController> _platformViewsController;
62+ std::unique_ptr<flutter::ProfilerMetricsIOS> _profiler_metrics;
63+ std::unique_ptr<flutter::SamplingProfiler> _profiler;
5964
6065 // Channels
6166 fml::scoped_nsobject<FlutterPlatformPlugin> _platformPlugin;
@@ -262,6 +267,7 @@ - (void)destroyContext {
262267 [self resetChannels ];
263268 self.isolateId = nil ;
264269 _shell.reset ();
270+ _profiler.reset ();
265271 _threadHost.Reset ();
266272 _platformViewsController.reset ();
267273}
@@ -319,6 +325,14 @@ - (void)resetChannels {
319325 _settingsChannel.reset ();
320326}
321327
328+ - (void )startProfiler {
329+ _profiler_metrics = std::make_unique<flutter::ProfilerMetricsIOS>();
330+ _profiler = std::make_unique<flutter::SamplingProfiler>(
331+ _threadHost.profiler_thread ->GetTaskRunner (),
332+ [self ]() { return self->_profiler_metrics ->GenerateSample (); }, kNumProfilerSamplesPerSec );
333+ _profiler->Start ();
334+ }
335+
322336// If you add a channel, be sure to also update `resetChannels`.
323337// Channels get a reference to the engine, and therefore need manual
324338// cleanup for proper collection.
@@ -438,9 +452,18 @@ - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
438452 // initialized.
439453 fml::MessageLoop::EnsureInitializedForCurrentThread ();
440454
455+ uint32_t threadHostType = flutter::ThreadHost::Type::UI | flutter::ThreadHost::Type::GPU |
456+ flutter::ThreadHost::Type::IO;
457+ bool profilerEnabled = false ;
458+ #if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG) || \
459+ (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE)
460+ profilerEnabled = true ;
461+ #endif
462+ if (profilerEnabled) {
463+ threadHostType = threadHostType | flutter::ThreadHost::Type::Profiler;
464+ }
441465 _threadHost = {threadLabel.UTF8String , // label
442- flutter::ThreadHost::Type::UI | flutter::ThreadHost::Type::GPU |
443- flutter::ThreadHost::Type::IO};
466+ threadHostType};
444467
445468 // Lambda captures by pointers to ObjC objects are fine here because the
446469 // create call is
@@ -456,6 +479,10 @@ - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
456479 return std::make_unique<flutter::Rasterizer>(shell, shell.GetTaskRunners ());
457480 };
458481
482+ if (profilerEnabled) {
483+ [self startProfiler ];
484+ }
485+
459486 if (flutter::IsIosEmbeddedViewsPreviewEnabled ()) {
460487 // Embedded views requires the gpu and the platform views to be the same.
461488 // The plan is to eventually dynamically merge the threads when there's a
0 commit comments