|  | // Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | import 'dart:convert'; | 
|  | import 'dart:io'; | 
|  |  | 
|  | import '../../../pkg/vm/bin/gen_kernel.dart' as gen_kernel; | 
|  |  | 
|  | Future<void> main(List<String> args) async { | 
|  | if (args.contains('--child')) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Include dart2js and prevent tree-shaking to make this program have a | 
|  | // non-trival snapshot size. | 
|  | if (args.contains('--train')) { | 
|  | args.remove('--train'); | 
|  | return gen_kernel.main(args); | 
|  | } | 
|  |  | 
|  | var tempDir; | 
|  | var events; | 
|  | try { | 
|  | tempDir = await Directory.systemTemp.createTemp(); | 
|  | final timelinePath = tempDir.uri | 
|  | .resolve('Startup-timeline.json') | 
|  | .toFilePath(); | 
|  | final p = await Process.run(Platform.executable, [ | 
|  | ...Platform.executableArguments, | 
|  | '--timeline_recorder=file:$timelinePath', | 
|  | '--timeline_streams=VM,Isolate,Embedder', | 
|  | Platform.script.toFilePath(), | 
|  | '--child', | 
|  | ]); | 
|  | if (p.exitCode != 0) { | 
|  | print(p.stdout); | 
|  | print(p.stderr); | 
|  | throw 'Child process failed: ${p.exitCode}'; | 
|  | } | 
|  |  | 
|  | events = jsonDecode(await File(timelinePath).readAsString()); | 
|  | } finally { | 
|  | await tempDir.delete(recursive: true); | 
|  | } | 
|  |  | 
|  | var mainIsolateId; | 
|  | for (final event in events) { | 
|  | if (event['name'] == 'InitializeIsolate' && | 
|  | event['args']['isolateName'] == 'main') { | 
|  | mainIsolateId = event['args']['isolateId']; | 
|  | } | 
|  | } | 
|  | if (mainIsolateId == null) { | 
|  | throw 'Could not determine main isolate'; | 
|  | } | 
|  |  | 
|  | void report(String name, String? isolateId) { | 
|  | var filtered = events.where((event) => event['name'] == name); | 
|  | if (isolateId != null) { | 
|  | filtered = filtered.where( | 
|  | (event) => event['args']['isolateId'] == isolateId, | 
|  | ); | 
|  | } | 
|  | var micros; | 
|  | final durations = filtered.where((event) => event['ph'] == 'X'); | 
|  | final begins = filtered.where((event) => event['ph'] == 'B'); | 
|  | final ends = filtered.where((event) => event['ph'] == 'E'); | 
|  | if (durations.length == 1 && begins.length == 0 && ends.length == 0) { | 
|  | micros = durations.single['dur']; | 
|  | } else if (durations.length == 0 && | 
|  | begins.length == 1 && | 
|  | ends.length == 1) { | 
|  | micros = ends.single['ts'] - begins.single['ts']; | 
|  | } else { | 
|  | print(durations.toList()); | 
|  | print(begins.toList()); | 
|  | print(ends.toList()); | 
|  | throw '$name is missing or ambiguous'; | 
|  | } | 
|  | print('Startup.$name(StartupTime): $micros us.'); | 
|  | } | 
|  |  | 
|  | report('CreateIsolateGroupAndSetupHelper', null); | 
|  | report('InitializeIsolate', mainIsolateId); | 
|  | report('ReadProgramSnapshot', mainIsolateId); | 
|  | } |