diff --git a/packages/flutter_tools/lib/src/base/dds.dart b/packages/flutter_tools/lib/src/base/dds.dart index cb5dfeae77..3d57c9f12a 100644 --- a/packages/flutter_tools/lib/src/base/dds.dart +++ b/packages/flutter_tools/lib/src/base/dds.dart @@ -17,6 +17,7 @@ Future Function( bool enableAuthCodes, bool ipv6, Uri? serviceUri, + List cachedUserTags, }) ddsLauncherCallback = dds.DartDevelopmentService.startDartDevelopmentService; /// Helper class to launch a [dds.DartDevelopmentService]. Allows for us to @@ -36,6 +37,7 @@ class DartDevelopmentService { int? hostPort, bool? ipv6, bool? disableServiceAuthCodes, + bool cacheStartupProfile = false, }) async { final Uri ddsUri = Uri( scheme: 'http', @@ -52,6 +54,8 @@ class DartDevelopmentService { serviceUri: ddsUri, enableAuthCodes: disableServiceAuthCodes != true, ipv6: ipv6 ?? false, + // Enables caching of CPU samples collected during application startup. + cachedUserTags: cacheStartupProfile ? const ['AppStartUp'] : const [], ); unawaited(_ddsInstance?.done.whenComplete(() { if (!_completer.isCompleted) { diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index acb11a0a45..5d00f13525 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -46,6 +46,10 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment 'FLUTTER_TEST_OUTPUTS_DIR environment variable is set, the file ' 'will be written there instead.', ) + ..addFlag('cache-startup-profile', + help: 'Caches the CPU profile collected before the first frame for startup ' + 'analysis.', + ) ..addFlag('verbose-system-logs', negatable: false, help: 'Include verbose logging from the Flutter engine.', @@ -163,6 +167,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment bool get dumpSkpOnShaderCompilation => boolArg('dump-skp-on-shader-compilation'); bool get purgePersistentCache => boolArg('purge-persistent-cache'); bool get disableServiceAuthCodes => boolArg('disable-service-auth-codes'); + bool get cacheStartupProfile => boolArg('cache-startup-profile'); bool get runningWithPrebuiltApplication => argResults['use-application-binary'] != null; bool get trackWidgetCreation => boolArg('track-widget-creation'); bool get enableImpeller => boolArg('enable-impeller'); @@ -202,6 +207,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment buildInfo, startPaused: boolArg('start-paused'), disableServiceAuthCodes: boolArg('disable-service-auth-codes'), + cacheStartupProfile: cacheStartupProfile, enableDds: enableDds, dartEntrypointArgs: stringsArg('dart-entrypoint-args'), dartFlags: stringArg('dart-flags') ?? '', diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 0a2dcba85b..40652d80d1 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -757,6 +757,7 @@ class DebuggingOptions { this.startPaused = false, this.disableServiceAuthCodes = false, this.enableDds = true, + this.cacheStartupProfile = false, this.dartEntrypointArgs = const [], this.dartFlags = '', this.enableSoftwareRendering = false, @@ -813,6 +814,7 @@ class DebuggingOptions { dartFlags = '', disableServiceAuthCodes = false, enableDds = true, + cacheStartupProfile = false, enableSoftwareRendering = false, skiaDeterministicRendering = false, traceSkia = false, @@ -841,6 +843,7 @@ class DebuggingOptions { required this.dartEntrypointArgs, required this.disableServiceAuthCodes, required this.enableDds, + required this.cacheStartupProfile, required this.enableSoftwareRendering, required this.skiaDeterministicRendering, required this.traceSkia, @@ -883,6 +886,7 @@ class DebuggingOptions { final List dartEntrypointArgs; final bool disableServiceAuthCodes; final bool enableDds; + final bool cacheStartupProfile; final bool enableSoftwareRendering; final bool skiaDeterministicRendering; final bool traceSkia; @@ -945,6 +949,7 @@ class DebuggingOptions { 'dartEntrypointArgs': dartEntrypointArgs, 'disableServiceAuthCodes': disableServiceAuthCodes, 'enableDds': enableDds, + 'cacheStartupProfile': cacheStartupProfile, 'enableSoftwareRendering': enableSoftwareRendering, 'skiaDeterministicRendering': skiaDeterministicRendering, 'traceSkia': traceSkia, @@ -988,6 +993,7 @@ class DebuggingOptions { dartEntrypointArgs: ((json['dartEntrypointArgs'] as List?)?.cast())!, disableServiceAuthCodes: (json['disableServiceAuthCodes'] as bool?)!, enableDds: (json['enableDds'] as bool?)!, + cacheStartupProfile: (json['cacheStartupProfile'] as bool?)!, enableSoftwareRendering: (json['enableSoftwareRendering'] as bool?)!, skiaDeterministicRendering: (json['skiaDeterministicRendering'] as bool?)!, traceSkia: (json['traceSkia'] as bool?)!, diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 9d630ed9f0..73eb0c883f 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -224,6 +224,7 @@ class FlutterDevice { int hostVmServicePort, int ddsPort, bool disableServiceAuthCodes = false, + bool cacheStartupProfile = false, bool enableDds = true, @required bool allowExistingDdsInstance, bool ipv6 = false, @@ -269,6 +270,7 @@ class FlutterDevice { ipv6: ipv6, disableServiceAuthCodes: disableServiceAuthCodes, logger: globals.logger, + cacheStartupProfile: cacheStartupProfile, ); } on dds.DartDevelopmentServiceException catch (e, st) { if (!allowExistingDdsInstance || @@ -1298,7 +1300,8 @@ abstract class ResidentRunner extends ResidentHandlers { getSkSLMethod: getSkSLMethod, printStructuredErrorLogMethod: printStructuredErrorLog, ipv6: ipv6, - disableServiceAuthCodes: debuggingOptions.disableServiceAuthCodes + disableServiceAuthCodes: debuggingOptions.disableServiceAuthCodes, + cacheStartupProfile: debuggingOptions.cacheStartupProfile, ); await device.vmService.getFlutterViews(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart index 20bc230a44..9af1915227 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart @@ -802,6 +802,7 @@ class FakeDartDevelopmentService extends Fake implements DartDevelopmentService int hostPort, bool ipv6, bool disableServiceAuthCodes, + bool cacheStartupProfile = false, }) async {} @override diff --git a/packages/flutter_tools/test/general.shard/cold_test.dart b/packages/flutter_tools/test/general.shard/cold_test.dart index 60eb67a4c4..cf19d3b503 100644 --- a/packages/flutter_tools/test/general.shard/cold_test.dart +++ b/packages/flutter_tools/test/general.shard/cold_test.dart @@ -216,6 +216,7 @@ class TestFlutterDevice extends FlutterDevice { GetSkSLMethod getSkSLMethod, PrintStructuredErrorLogMethod printStructuredErrorLogMethod, bool enableDds = true, + bool cacheStartupProfile = false, bool disableServiceAuthCodes = false, int hostVmServicePort, int ddsPort, diff --git a/packages/flutter_tools/test/general.shard/drive/drive_service_test.dart b/packages/flutter_tools/test/general.shard/drive/drive_service_test.dart index 403ded6f41..16d453af7c 100644 --- a/packages/flutter_tools/test/general.shard/drive/drive_service_test.dart +++ b/packages/flutter_tools/test/general.shard/drive/drive_service_test.dart @@ -590,6 +590,7 @@ class FakeDartDevelopmentService extends Fake implements DartDevelopmentService int hostPort, bool ipv6, bool disableServiceAuthCodes, + bool cacheStartupProfile = false, }) async { started = true; } diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart index 3da33de412..be5f9b5fdd 100644 --- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart +++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart @@ -944,6 +944,7 @@ class FakeDartDevelopmentService extends Fake implements DartDevelopmentService int hostPort, bool ipv6, bool disableServiceAuthCodes, + bool cacheStartupProfile = false, }) async {} @override diff --git a/packages/flutter_tools/test/general.shard/hot_test.dart b/packages/flutter_tools/test/general.shard/hot_test.dart index 1c6623c5a5..be33212b34 100644 --- a/packages/flutter_tools/test/general.shard/hot_test.dart +++ b/packages/flutter_tools/test/general.shard/hot_test.dart @@ -709,6 +709,7 @@ class TestFlutterDevice extends FlutterDevice { PrintStructuredErrorLogMethod printStructuredErrorLogMethod, bool disableServiceAuthCodes = false, bool enableDds = true, + bool cacheStartupProfile = false, bool ipv6 = false, int hostVmServicePort, int ddsPort, diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index feb7ff42f7..e94ee0207a 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -1916,11 +1916,12 @@ flutter: fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice() ..dds = DartDevelopmentService(); - ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri}) { + ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri, List cachedUserTags}) { expect(uri, Uri(scheme: 'foo', host: 'bar')); expect(enableAuthCodes, isTrue); expect(ipv6, isFalse); expect(serviceUri, Uri(scheme: 'http', host: '127.0.0.1', port: 0)); + expect(cachedUserTags, isEmpty); throw FakeDartDevelopmentServiceException(message: 'Existing VM service clients prevent DDS from taking control.', ); @@ -1963,11 +1964,12 @@ flutter: final FakeDevice device = FakeDevice() ..dds = DartDevelopmentService(); final Completerdone = Completer(); - ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri}) async { + ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri, List cachedUserTags}) async { expect(uri, Uri(scheme: 'foo', host: 'bar')); expect(enableAuthCodes, isFalse); expect(ipv6, isTrue); expect(serviceUri, Uri(scheme: 'http', host: '::1', port: 0)); + expect(cachedUserTags, isEmpty); done.complete(); return null; }; @@ -1994,11 +1996,12 @@ flutter: // See https://github.com/flutter/flutter/issues/72385 for context. final FakeDevice device = FakeDevice() ..dds = DartDevelopmentService(); - ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri}) { + ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri, List cachedUserTags}) { expect(uri, Uri(scheme: 'foo', host: 'bar')); expect(enableAuthCodes, isTrue); expect(ipv6, isFalse); expect(serviceUri, Uri(scheme: 'http', host: '127.0.0.1', port: 0)); + expect(cachedUserTags, isEmpty); throw FakeDartDevelopmentServiceException(message: 'No URI'); }; final TestFlutterDevice flutterDevice = TestFlutterDevice( @@ -2226,6 +2229,7 @@ class FakeFlutterDevice extends Fake implements FlutterDevice { int ddsPort, bool disableServiceAuthCodes = false, bool enableDds = true, + bool cacheStartupProfile = false, @required bool allowExistingDdsInstance, bool ipv6 = false, }) async { } @@ -2268,6 +2272,7 @@ class FakeDelegateFlutterDevice extends FlutterDevice { ReloadSources reloadSources, Restart restart, bool enableDds = true, + bool cacheStartupProfile = false, bool disableServiceAuthCodes = false, bool ipv6 = false, CompileExpression compileExpression, diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 1e553d661f..30651189c6 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -1348,6 +1348,7 @@ class FakeFlutterDevice extends Fake implements FlutterDevice { int ddsPort, bool disableServiceAuthCodes = false, bool enableDds = true, + bool cacheStartupProfile = false, @required bool allowExistingDdsInstance, bool ipv6 = false, }) async { }