mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
This reverts commit 68fc7231b3
.
This commit is contained in:
parent
d39aad734f
commit
3068fc4f7c
@ -13,9 +13,6 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() async {
|
setUpAll(() async {
|
||||||
driver = await FlutterDriver.connect();
|
driver = await FlutterDriver.connect();
|
||||||
|
|
||||||
// TODO(liyuqian): enable the following once it's proved to be non-flaky by transition_perf_test.dart.
|
|
||||||
// await driver.waitUntilFirstFrameRasterized();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDownAll(() async {
|
tearDownAll(() async {
|
||||||
|
@ -159,7 +159,6 @@ class StartupTest {
|
|||||||
|
|
||||||
return TaskResult.success(data, benchmarkScoreKeys: <String>[
|
return TaskResult.success(data, benchmarkScoreKeys: <String>[
|
||||||
'timeToFirstFrameMicros',
|
'timeToFirstFrameMicros',
|
||||||
'timeToFirstFrameRasterizedMicros',
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -251,7 +251,6 @@ tasks:
|
|||||||
description: >
|
description: >
|
||||||
Measures the startup time of the Complex Layout sample app on Android.
|
Measures the startup time of the Complex Layout sample app on Android.
|
||||||
stage: devicelab
|
stage: devicelab
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["mac/android"]
|
required_agent_capabilities: ["mac/android"]
|
||||||
|
|
||||||
hot_mode_dev_cycle__benchmark:
|
hot_mode_dev_cycle__benchmark:
|
||||||
@ -449,14 +448,12 @@ tasks:
|
|||||||
description: >
|
description: >
|
||||||
Measures the startup time of the Flutter Gallery app on iPhone 6.
|
Measures the startup time of the Flutter Gallery app on iPhone 6.
|
||||||
stage: devicelab_ios
|
stage: devicelab_ios
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["mac/ios"]
|
required_agent_capabilities: ["mac/ios"]
|
||||||
|
|
||||||
complex_layout_ios__start_up:
|
complex_layout_ios__start_up:
|
||||||
description: >
|
description: >
|
||||||
Measures the startup time of the Complex Layout sample app on iPhone 6.
|
Measures the startup time of the Complex Layout sample app on iPhone 6.
|
||||||
stage: devicelab_ios
|
stage: devicelab_ios
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["mac/ios"]
|
required_agent_capabilities: ["mac/ios"]
|
||||||
|
|
||||||
flutter_gallery_ios__transition_perf:
|
flutter_gallery_ios__transition_perf:
|
||||||
@ -464,7 +461,6 @@ tasks:
|
|||||||
Measures the performance of screen transitions in Flutter Gallery on
|
Measures the performance of screen transitions in Flutter Gallery on
|
||||||
iOS.
|
iOS.
|
||||||
stage: devicelab_ios
|
stage: devicelab_ios
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["mac/ios"]
|
required_agent_capabilities: ["mac/ios"]
|
||||||
|
|
||||||
hello_world_ios__compile:
|
hello_world_ios__compile:
|
||||||
@ -569,7 +565,6 @@ tasks:
|
|||||||
description: >
|
description: >
|
||||||
Measures the startup time of the Flutter Gallery app on Android.
|
Measures the startup time of the Flutter Gallery app on Android.
|
||||||
stage: devicelab
|
stage: devicelab
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["linux/android"]
|
required_agent_capabilities: ["linux/android"]
|
||||||
|
|
||||||
flutter_gallery__transition_perf:
|
flutter_gallery__transition_perf:
|
||||||
@ -577,7 +572,6 @@ tasks:
|
|||||||
Measures the performance of screen transitions in Flutter Gallery on
|
Measures the performance of screen transitions in Flutter Gallery on
|
||||||
Android.
|
Android.
|
||||||
stage: devicelab
|
stage: devicelab
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["linux/android"]
|
required_agent_capabilities: ["linux/android"]
|
||||||
|
|
||||||
flutter_gallery__transition_perf_with_semantics:
|
flutter_gallery__transition_perf_with_semantics:
|
||||||
@ -585,7 +579,6 @@ tasks:
|
|||||||
Measures the delta in performance of screen transitions without and
|
Measures the delta in performance of screen transitions without and
|
||||||
with semantics enabled.
|
with semantics enabled.
|
||||||
stage: devicelab
|
stage: devicelab
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["linux/android"]
|
required_agent_capabilities: ["linux/android"]
|
||||||
|
|
||||||
flutter_gallery__memory_nav:
|
flutter_gallery__memory_nav:
|
||||||
@ -624,7 +617,6 @@ tasks:
|
|||||||
description: >
|
description: >
|
||||||
Measures the startup time of the Flutter Gallery app on 32-bit iOS (iPhone 4S).
|
Measures the startup time of the Flutter Gallery app on 32-bit iOS (iPhone 4S).
|
||||||
stage: devicelab_ios
|
stage: devicelab_ios
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["mac/ios32"]
|
required_agent_capabilities: ["mac/ios32"]
|
||||||
|
|
||||||
flutter_gallery_ios32__transition_perf:
|
flutter_gallery_ios32__transition_perf:
|
||||||
@ -632,7 +624,6 @@ tasks:
|
|||||||
Measures the performance of screen transitions in Flutter Gallery on
|
Measures the performance of screen transitions in Flutter Gallery on
|
||||||
32-bit iOS (iPhone 4S).
|
32-bit iOS (iPhone 4S).
|
||||||
stage: devicelab_ios
|
stage: devicelab_ios
|
||||||
flaky: true
|
|
||||||
required_agent_capabilities: ["mac/ios32"]
|
required_agent_capabilities: ["mac/ios32"]
|
||||||
|
|
||||||
run_without_leak_mac:
|
run_without_leak_mac:
|
||||||
|
@ -13,9 +13,6 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() async {
|
setUpAll(() async {
|
||||||
driver = await FlutterDriver.connect();
|
driver = await FlutterDriver.connect();
|
||||||
|
|
||||||
// TODO(liyuqian): enable the following once it's proved to be non-flaky by transition_perf_test.dart.
|
|
||||||
// await driver.waitUntilFirstFrameRasterized();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDownAll(() async {
|
tearDownAll(() async {
|
||||||
|
@ -183,9 +183,6 @@ void main([List<String> args = const <String>[]]) {
|
|||||||
setUpAll(() async {
|
setUpAll(() async {
|
||||||
driver = await FlutterDriver.connect();
|
driver = await FlutterDriver.connect();
|
||||||
|
|
||||||
// Wait for the first frame to be rasterized.
|
|
||||||
await driver.waitUntilFirstFrameRasterized();
|
|
||||||
|
|
||||||
if (args.contains('--with_semantics')) {
|
if (args.contains('--with_semantics')) {
|
||||||
print('Enabeling semantics...');
|
print('Enabeling semantics...');
|
||||||
await driver.setSemantics(true);
|
await driver.setSemantics(true);
|
||||||
@ -203,6 +200,7 @@ void main([List<String> args = const <String>[]]) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('all demos', () async {
|
test('all demos', () async {
|
||||||
|
|
||||||
// Collect timeline data for just a limited set of demos to avoid OOMs.
|
// Collect timeline data for just a limited set of demos to avoid OOMs.
|
||||||
final Timeline timeline = await driver.traceAction(
|
final Timeline timeline = await driver.traceAction(
|
||||||
() async {
|
() async {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer' as developer;
|
import 'dart:developer' as developer;
|
||||||
import 'dart:ui' show AppLifecycleState, Locale, AccessibilityFeatures, FrameTiming, TimingsCallback;
|
import 'dart:ui' show AppLifecycleState, Locale, AccessibilityFeatures;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
@ -550,14 +550,6 @@ mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererB
|
|||||||
int _deferFirstFrameReportCount = 0;
|
int _deferFirstFrameReportCount = 0;
|
||||||
bool get _reportFirstFrame => _deferFirstFrameReportCount == 0;
|
bool get _reportFirstFrame => _deferFirstFrameReportCount == 0;
|
||||||
|
|
||||||
|
|
||||||
final Completer<void> _firstFrameCompleter = Completer<void>();
|
|
||||||
|
|
||||||
/// Whether the Flutter engine has rasterized the first frame.
|
|
||||||
///
|
|
||||||
/// {@macro flutter.frame_rasterized_vs_presented}
|
|
||||||
Future<void> get firstFrameRasterized => _firstFrameCompleter.future;
|
|
||||||
|
|
||||||
/// Whether the first frame has finished rendering.
|
/// Whether the first frame has finished rendering.
|
||||||
///
|
///
|
||||||
/// Only useful in profile and debug builds; in release builds, this always
|
/// Only useful in profile and debug builds; in release builds, this always
|
||||||
@ -704,24 +696,6 @@ mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererB
|
|||||||
debugBuildingDirtyElements = true;
|
debugBuildingDirtyElements = true;
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
|
|
||||||
if (_needToReportFirstFrame && _reportFirstFrame) {
|
|
||||||
assert(!_firstFrameCompleter.isCompleted);
|
|
||||||
// TODO(liyuqian): use a broadcast stream approach
|
|
||||||
final TimingsCallback oldCallback = WidgetsBinding.instance.window.onReportTimings;
|
|
||||||
WidgetsBinding.instance.window.onReportTimings = (List<FrameTiming> timings) {
|
|
||||||
if (!kReleaseMode) {
|
|
||||||
developer.Timeline.instantSync('Rasterized first useful frame');
|
|
||||||
developer.postEvent('Flutter.FirstFrame', <String, dynamic>{});
|
|
||||||
}
|
|
||||||
if (oldCallback != null) {
|
|
||||||
oldCallback(timings);
|
|
||||||
}
|
|
||||||
WidgetsBinding.instance.window.onReportTimings = oldCallback;
|
|
||||||
_firstFrameCompleter.complete();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (renderViewElement != null)
|
if (renderViewElement != null)
|
||||||
buildOwner.buildScope(renderViewElement);
|
buildOwner.buildScope(renderViewElement);
|
||||||
@ -735,10 +709,11 @@ mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererB
|
|||||||
}
|
}
|
||||||
if (!kReleaseMode) {
|
if (!kReleaseMode) {
|
||||||
if (_needToReportFirstFrame && _reportFirstFrame) {
|
if (_needToReportFirstFrame && _reportFirstFrame) {
|
||||||
developer.Timeline.instantSync('Widgets built first useful frame');
|
developer.Timeline.instantSync('Widgets completed first useful frame');
|
||||||
|
developer.postEvent('Flutter.FirstFrame', <String, dynamic>{});
|
||||||
|
_needToReportFirstFrame = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_needToReportFirstFrame = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The [Element] that is at the root of the hierarchy (and which wraps the
|
/// The [Element] that is at the root of the hierarchy (and which wraps the
|
||||||
|
@ -79,8 +79,6 @@ class TestServiceExtensionsBinding extends BindingBase
|
|||||||
await flushMicrotasks();
|
await flushMicrotasks();
|
||||||
if (ui.window.onDrawFrame != null)
|
if (ui.window.onDrawFrame != null)
|
||||||
ui.window.onDrawFrame();
|
ui.window.onDrawFrame();
|
||||||
if (ui.window.onReportTimings != null)
|
|
||||||
ui.window.onReportTimings(<ui.FrameTiming>[]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -132,26 +132,6 @@ class WaitUntilNoPendingFrame extends Command {
|
|||||||
String get kind => 'waitUntilNoPendingFrame';
|
String get kind => 'waitUntilNoPendingFrame';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Flutter Driver command that waits until the Flutter engine rasterizes the
|
|
||||||
/// first frame.
|
|
||||||
///
|
|
||||||
/// {@template flutter.frame_rasterized_vs_presented}
|
|
||||||
/// Usually, the time that a frame is rasterized is very close to the time that
|
|
||||||
/// it gets presented on the display. Specifically, rasterization is the last
|
|
||||||
/// expensive phase of a frame that's still in Flutter's control.
|
|
||||||
/// {@endtemplate}
|
|
||||||
class WaitUntilFirstFrameRasterized extends Command {
|
|
||||||
/// Creates this command.
|
|
||||||
const WaitUntilFirstFrameRasterized({ Duration timeout }) : super(timeout: timeout);
|
|
||||||
|
|
||||||
/// Deserializes this command from the value generated by [serialize].
|
|
||||||
WaitUntilFirstFrameRasterized.deserialize(Map<String, String> json)
|
|
||||||
: super.deserialize(json);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get kind => 'waitUntilFirstFrameRasterized';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Base class for Flutter Driver finders, objects that describe how the driver
|
/// Base class for Flutter Driver finders, objects that describe how the driver
|
||||||
/// should search for elements.
|
/// should search for elements.
|
||||||
abstract class SerializableFinder {
|
abstract class SerializableFinder {
|
||||||
|
@ -499,14 +499,6 @@ class FlutterDriver {
|
|||||||
await _sendCommand(WaitUntilNoTransientCallbacks(timeout: timeout));
|
await _sendCommand(WaitUntilNoTransientCallbacks(timeout: timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits until the next [Window.onReportTimings] is called.
|
|
||||||
///
|
|
||||||
/// Use this method to wait for the first frame to be rasterized during the
|
|
||||||
/// app launch.
|
|
||||||
Future<void> waitUntilFirstFrameRasterized() async {
|
|
||||||
await _sendCommand(const WaitUntilFirstFrameRasterized());
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<DriverOffset> _getOffset(SerializableFinder finder, OffsetType type, { Duration timeout }) async {
|
Future<DriverOffset> _getOffset(SerializableFinder finder, OffsetType type, { Duration timeout }) async {
|
||||||
final GetOffset command = GetOffset(finder, type, timeout: timeout);
|
final GetOffset command = GetOffset(finder, type, timeout: timeout);
|
||||||
final GetOffsetResult result = GetOffsetResult.fromJson(await _sendCommand(command));
|
final GetOffsetResult result = GetOffsetResult.fromJson(await _sendCommand(command));
|
||||||
|
@ -114,7 +114,6 @@ class FlutterDriverExtension {
|
|||||||
'waitForAbsent': _waitForAbsent,
|
'waitForAbsent': _waitForAbsent,
|
||||||
'waitUntilNoTransientCallbacks': _waitUntilNoTransientCallbacks,
|
'waitUntilNoTransientCallbacks': _waitUntilNoTransientCallbacks,
|
||||||
'waitUntilNoPendingFrame': _waitUntilNoPendingFrame,
|
'waitUntilNoPendingFrame': _waitUntilNoPendingFrame,
|
||||||
'waitUntilFirstFrameRasterized': _waitUntilFirstFrameRasterized,
|
|
||||||
'get_semantics_id': _getSemanticsId,
|
'get_semantics_id': _getSemanticsId,
|
||||||
'get_offset': _getOffset,
|
'get_offset': _getOffset,
|
||||||
'get_diagnostics_tree': _getDiagnosticsTree,
|
'get_diagnostics_tree': _getDiagnosticsTree,
|
||||||
@ -136,7 +135,6 @@ class FlutterDriverExtension {
|
|||||||
'waitForAbsent': (Map<String, String> params) => WaitForAbsent.deserialize(params),
|
'waitForAbsent': (Map<String, String> params) => WaitForAbsent.deserialize(params),
|
||||||
'waitUntilNoTransientCallbacks': (Map<String, String> params) => WaitUntilNoTransientCallbacks.deserialize(params),
|
'waitUntilNoTransientCallbacks': (Map<String, String> params) => WaitUntilNoTransientCallbacks.deserialize(params),
|
||||||
'waitUntilNoPendingFrame': (Map<String, String> params) => WaitUntilNoPendingFrame.deserialize(params),
|
'waitUntilNoPendingFrame': (Map<String, String> params) => WaitUntilNoPendingFrame.deserialize(params),
|
||||||
'waitUntilFirstFrameRasterized': (Map<String, String> params) => WaitUntilFirstFrameRasterized.deserialize(params),
|
|
||||||
'get_semantics_id': (Map<String, String> params) => GetSemanticsId.deserialize(params),
|
'get_semantics_id': (Map<String, String> params) => GetSemanticsId.deserialize(params),
|
||||||
'get_offset': (Map<String, String> params) => GetOffset.deserialize(params),
|
'get_offset': (Map<String, String> params) => GetOffset.deserialize(params),
|
||||||
'get_diagnostics_tree': (Map<String, String> params) => GetDiagnosticsTree.deserialize(params),
|
'get_diagnostics_tree': (Map<String, String> params) => GetDiagnosticsTree.deserialize(params),
|
||||||
@ -222,12 +220,6 @@ class FlutterDriverExtension {
|
|||||||
return RenderTree(RendererBinding.instance?.renderView?.toStringDeep());
|
return RenderTree(RendererBinding.instance?.renderView?.toStringDeep());
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can be used to wait for the first frame being rasterized during app launch.
|
|
||||||
Future<Result> _waitUntilFirstFrameRasterized(Command command) async {
|
|
||||||
await WidgetsBinding.instance.firstFrameRasterized;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Waits until at the end of a frame the provided [condition] is [true].
|
// Waits until at the end of a frame the provided [condition] is [true].
|
||||||
Future<void> _waitUntilFrame(bool condition(), [ Completer<void> completer ]) {
|
Future<void> _waitUntilFrame(bool condition(), [ Completer<void> completer ]) {
|
||||||
completer ??= Completer<void>();
|
completer ??= Completer<void>();
|
||||||
|
@ -14,13 +14,12 @@ import 'vmservice.dart';
|
|||||||
// Names of some of the Timeline events we care about.
|
// Names of some of the Timeline events we care about.
|
||||||
const String _kFlutterEngineMainEnterEventName = 'FlutterEngineMainEnter';
|
const String _kFlutterEngineMainEnterEventName = 'FlutterEngineMainEnter';
|
||||||
const String _kFrameworkInitEventName = 'Framework initialization';
|
const String _kFrameworkInitEventName = 'Framework initialization';
|
||||||
const String _kFirstFrameBuiltEventName = 'Widgets built first useful frame';
|
const String _kFirstUsefulFrameEventName = 'Widgets completed first useful frame';
|
||||||
const String _kFirstFrameRasterizedEventName = 'Rasterized first useful frame';
|
|
||||||
|
|
||||||
class Tracing {
|
class Tracing {
|
||||||
Tracing(this.vmService);
|
Tracing(this.vmService);
|
||||||
|
|
||||||
static const String firstUsefulFrameEventName = _kFirstFrameRasterizedEventName;
|
static const String firstUsefulFrameEventName = _kFirstUsefulFrameEventName;
|
||||||
|
|
||||||
static Future<Tracing> connect(Uri uri) async {
|
static Future<Tracing> connect(Uri uri) async {
|
||||||
final VMService observatory = await VMService.connect(uri);
|
final VMService observatory = await VMService.connect(uri);
|
||||||
@ -48,7 +47,7 @@ class Tracing {
|
|||||||
(await vmService.onTimelineEvent).listen((ServiceEvent timelineEvent) {
|
(await vmService.onTimelineEvent).listen((ServiceEvent timelineEvent) {
|
||||||
final List<Map<String, dynamic>> events = timelineEvent.timelineEvents;
|
final List<Map<String, dynamic>> events = timelineEvent.timelineEvents;
|
||||||
for (Map<String, dynamic> event in events) {
|
for (Map<String, dynamic> event in events) {
|
||||||
if (event['name'] == firstUsefulFrameEventName)
|
if (event['name'] == _kFirstUsefulFrameEventName)
|
||||||
whenFirstFrameRendered.complete();
|
whenFirstFrameRendered.complete();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -123,23 +122,16 @@ Future<void> downloadStartupTrace(VMService observatory, { bool awaitFirstFrame
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (awaitFirstFrame) {
|
if (awaitFirstFrame) {
|
||||||
final int firstFrameBuiltTimestampMicros = extractInstantEventTimestamp(_kFirstFrameBuiltEventName);
|
final int firstFrameTimestampMicros = extractInstantEventTimestamp(_kFirstUsefulFrameEventName);
|
||||||
final int firstFrameRasterizedTimestampMicros = extractInstantEventTimestamp(_kFirstFrameRasterizedEventName);
|
if (firstFrameTimestampMicros == null) {
|
||||||
if (firstFrameBuiltTimestampMicros == null || firstFrameRasterizedTimestampMicros == null) {
|
printTrace('First frame event is missing in the timeline: $timeline');
|
||||||
printTrace('First frame events are missing in the timeline: $timeline');
|
throw 'First frame event is missing in the timeline. Cannot compute startup time.';
|
||||||
throw 'First frame events are missing in the timeline. Cannot compute startup time.';
|
|
||||||
}
|
}
|
||||||
|
final int timeToFirstFrameMicros = firstFrameTimestampMicros - engineEnterTimestampMicros;
|
||||||
// To keep our old benchmarks valid, we'll preserve the
|
|
||||||
// timeToFirstFrameMicros as the firstFrameBuiltTimestampMicros.
|
|
||||||
// Additionally, we add timeToFirstFrameRasterizedMicros for a more accurate
|
|
||||||
// benchmark.
|
|
||||||
traceInfo['timeToFirstFrameRasterizedMicros'] = firstFrameRasterizedTimestampMicros - engineEnterTimestampMicros;
|
|
||||||
final int timeToFirstFrameMicros = firstFrameBuiltTimestampMicros - engineEnterTimestampMicros;
|
|
||||||
traceInfo['timeToFirstFrameMicros'] = timeToFirstFrameMicros;
|
traceInfo['timeToFirstFrameMicros'] = timeToFirstFrameMicros;
|
||||||
message = 'Time to first frame: ${timeToFirstFrameMicros ~/ 1000}ms.';
|
message = 'Time to first frame: ${timeToFirstFrameMicros ~/ 1000}ms.';
|
||||||
if (frameworkInitTimestampMicros != null)
|
if (frameworkInitTimestampMicros != null)
|
||||||
traceInfo['timeAfterFrameworkInitMicros'] = firstFrameBuiltTimestampMicros - frameworkInitTimestampMicros;
|
traceInfo['timeAfterFrameworkInitMicros'] = firstFrameTimestampMicros - frameworkInitTimestampMicros;
|
||||||
}
|
}
|
||||||
|
|
||||||
traceInfoFile.writeAsStringSync(toPrettyJson(traceInfo));
|
traceInfoFile.writeAsStringSync(toPrettyJson(traceInfo));
|
||||||
|
Loading…
Reference in New Issue
Block a user