Minor cleanup to CPU profile screen code (#9324)
diff --git a/packages/devtools_app/lib/src/screens/profiler/cpu_profile_model.dart b/packages/devtools_app/lib/src/screens/profiler/cpu_profile_model.dart index 4fdeda3..33413d7 100644 --- a/packages/devtools_app/lib/src/screens/profiler/cpu_profile_model.dart +++ b/packages/devtools_app/lib/src/screens/profiler/cpu_profile_model.dart
@@ -153,8 +153,8 @@ required String processId, }) async { await transformer.processData(functionProfile, processId: processId); - if (codeProfile != null) { - await transformer.processData(codeProfile!, processId: processId); + if (codeProfile case final codeProfile?) { + await transformer.processData(codeProfile, processId: processId); } } } @@ -166,11 +166,13 @@ required this.cpuSamples, required this.profileMetaData, required this.rootedAtTags, - }) { - _cpuProfileRoot = CpuStackFrame.root(profileMetaData); - } + }) : cpuProfileRoot = CpuStackFrame.root(profileMetaData); factory CpuProfileData.fromJson(Map<String, Object?> json_) { + if (json_.isEmpty) { + return CpuProfileData.empty(); + } + final json = _CpuProfileDataJson(json_); // All CPU samples. @@ -187,15 +189,17 @@ final samplePeriod = observedSamplePeriod(samples) ?? json.samplePeriod ?? 0; + final timeOriginMicros = json.timeOriginMicros; + final timeExtentMicros = json.timeExtentMicros; final profileMetaData = CpuProfileMetaData( sampleCount: json.sampleCount ?? 0, samplePeriod: samplePeriod, stackDepth: json.stackDepth ?? 0, - time: (json.timeOriginMicros != null && json.timeExtentMicros != null) + time: (timeOriginMicros != null && timeExtentMicros != null) ? (TimeRange() - ..start = Duration(microseconds: json.timeOriginMicros!) + ..start = Duration(microseconds: timeOriginMicros) ..end = Duration( - microseconds: json.timeOriginMicros! + json.timeExtentMicros!, + microseconds: timeOriginMicros + timeExtentMicros, )) : null, ); @@ -329,10 +333,10 @@ }); for (final sample in tagProfile.cpuSamples) { - String? updatedId = idMapping[sample.leafId]; + String? updatedId = idMapping[sample.leafId]!; samples.add( CpuSampleEvent( - leafId: updatedId!, + leafId: updatedId, userTag: sample.userTag, vmTag: sample.vmTag, traceJson: sample.toJson, @@ -540,7 +544,17 @@ ); } - factory CpuProfileData.empty() => CpuProfileData.fromJson({}); + factory CpuProfileData.empty() => CpuProfileData._( + stackFrames: {}, + cpuSamples: [], + profileMetaData: CpuProfileMetaData( + sampleCount: 0, + samplePeriod: 0, + stackDepth: 0, + time: null, + ), + rootedAtTags: false, + ); /// Generates [CpuProfileData] from the provided [cpuSamples]. /// @@ -556,31 +570,27 @@ // of all stacks, regardless of entrypoint. This should never be seen in the // final output from this method. const kRootId = 0; - final traceObject = <String, Object?>{ - CpuProfileData._sampleCountKey: cpuSamples.sampleCount, - CpuProfileData._samplePeriodKey: cpuSamples.samplePeriod, - CpuProfileData._stackDepthKey: cpuSamples.maxStackDepth, - CpuProfileData._timeOriginKey: cpuSamples.timeOriginMicros, - CpuProfileData._timeExtentKey: cpuSamples.timeExtentMicros, - CpuProfileData._stackFramesKey: cpuSamples.generateStackFramesJson( - isolateId: isolateId, - // We want to ensure that if [kRootId] ever changes, this change is - // propagated to [cpuSamples.generateStackFramesJson]. - // ignore: avoid_redundant_argument_values - kRootId: kRootId, - buildCodeTree: buildCodeTree, - ), - CpuProfileData._traceEventsKey: [], - }; + + // Generate the stack frames first as it builds and tracks + // the timeline tree for each sample. + final stackFrames = cpuSamples.generateStackFramesJson( + isolateId: isolateId, + // We want to ensure that if [kRootId] ever changes, this change is + // propagated to [cpuSamples.generateStackFramesJson]. + // ignore: avoid_redundant_argument_values + kRootId: kRootId, + buildCodeTree: buildCodeTree, + ); // Build the trace events. + final traceEvents = <Map<String, Object?>>[]; for (final sample in cpuSamples.samples ?? <vm_service.CpuSample>[]) { final tree = _CpuProfileTimelineTree.getTreeFromSample(sample)!; // Skip the root. if (tree.frameId == kRootId) { continue; } - (traceObject[CpuProfileData._traceEventsKey]! as List<Object?>).add({ + traceEvents.add({ 'ph': 'P', // kind = sample event 'name': '', // Blank to keep about:tracing happy 'pid': cpuSamples.pid, @@ -588,13 +598,20 @@ 'ts': sample.timestamp, 'cat': 'Dart', CpuProfileData.stackFrameIdKey: '$isolateId-${tree.frameId}', - 'args': { - if (sample.userTag != null) userTagKey: sample.userTag, - if (sample.vmTag != null) vmTagKey: sample.vmTag, - }, + 'args': {userTagKey: ?sample.userTag, vmTagKey: ?sample.vmTag}, }); } + final traceObject = <String, Object?>{ + CpuProfileData._sampleCountKey: cpuSamples.sampleCount, + CpuProfileData._samplePeriodKey: cpuSamples.samplePeriod, + CpuProfileData._stackDepthKey: cpuSamples.maxStackDepth, + CpuProfileData._timeOriginKey: cpuSamples.timeOriginMicros, + CpuProfileData._timeExtentKey: cpuSamples.timeExtentMicros, + CpuProfileData._stackFramesKey: stackFrames, + CpuProfileData._traceEventsKey: traceEvents, + }; + await _addPackageUrisToTraceObject(isolateId, traceObject); return CpuProfileData.fromJson(traceObject); @@ -674,6 +691,8 @@ final CpuProfileMetaData profileMetaData; + final CpuStackFrame cpuProfileRoot; + /// `true` if the CpuProfileData has tag-based roots. /// /// This value is used during the bottom-up transformation to ensure that the @@ -687,7 +706,7 @@ if (!processed) return <CpuStackFrame>[]; return _callTreeRoots ??= [ // Don't display the root node. - ..._cpuProfileRoot.children.map((e) => e.deepCopy()), + for (final rootChild in cpuProfileRoot.children) rootChild.deepCopy(), ]; } @@ -703,7 +722,7 @@ assert(_bottomUpRoots == null); _bottomUpRoots = await BottomUpTransformer<CpuStackFrame>() .bottomUpRootsFor( - topDownRoot: _cpuProfileRoot, + topDownRoot: cpuProfileRoot, mergeSamples: mergeCpuProfileRoots, rootedAtTags: rootedAtTags, ); @@ -711,41 +730,15 @@ List<CpuStackFrame>? _bottomUpRoots; - CpuStackFrame get cpuProfileRoot => _cpuProfileRoot; + late final Iterable<String> userTags = { + for (final cpuSample in cpuSamples) + if (cpuSample.userTag case final userTag?) userTag, + }; - Iterable<String> get userTags { - if (_userTags != null) { - return _userTags!; - } - final tags = <String>{}; - for (final cpuSample in cpuSamples) { - final tag = cpuSample.userTag; - if (tag != null) { - tags.add(tag); - } - } - _userTags = tags; - return _userTags!; - } - - Iterable<String> get vmTags { - if (_vmTags != null) { - return _vmTags!; - } - final tags = <String>{}; - for (final cpuSample in cpuSamples) { - final tag = cpuSample.vmTag; - if (tag != null) { - tags.add(tag); - } - } - return _vmTags = tags; - } - - Iterable<String>? _userTags; - Iterable<String>? _vmTags; - - late final CpuStackFrame _cpuProfileRoot; + late final Iterable<String> vmTags = { + for (final cpuSample in cpuSamples) + if (cpuSample.vmTag case final vmTag?) vmTag, + }; CpuStackFrame? selectedStackFrame; @@ -755,10 +748,10 @@ _samplePeriodKey: profileMetaData.samplePeriod, _sampleCountKey: profileMetaData.sampleCount, _stackDepthKey: profileMetaData.stackDepth, - if (profileMetaData.time?.start != null) - _timeOriginKey: profileMetaData.time!.start!.inMicroseconds, - if (profileMetaData.time?.duration != null) - _timeExtentKey: profileMetaData.time!.duration.inMicroseconds, + if (profileMetaData.time?.start case final startTime?) + _timeOriginKey: startTime.inMicroseconds, + if (profileMetaData.time?.duration case final duration?) + _timeExtentKey: duration.inMicroseconds, _stackFramesKey: stackFramesJson, _traceEventsKey: cpuSamples.map((sample) => sample.toJson).toList(), }; @@ -766,13 +759,9 @@ bool get isEmpty => profileMetaData.sampleCount == 0; @visibleForTesting - Map<String, Object?> get stackFramesJson { - final framesJson = <String, Object?>{}; - for (final sf in stackFrames.values) { - framesJson.addAll(sf.toJson); - } - return framesJson; - } + Map<String, Object?> get stackFramesJson => { + for (final sf in stackFrames.values) ...sf.toJson, + }; } extension type _CpuProfileDataJson(Map<String, Object?> json) { @@ -978,7 +967,7 @@ @override String get tooltip { - var prefix = ''; + final String? prefix; if (isNative) { prefix = '[Native]'; } else if (isDartCore) { @@ -987,8 +976,10 @@ prefix = '[Flutter]'; } else if (isTag) { prefix = '[Tag]'; + } else { + prefix = null; } - final nameWithPrefix = [prefix, name].join(' '); + final nameWithPrefix = [?prefix, name].join(' '); return [ nameWithPrefix, durationText(totalTime), @@ -1074,7 +1065,7 @@ CpuProfileData.resolvedUrlKey: rawUrl, CpuProfileData.resolvedPackageUriKey: packageUri, CpuProfileData.sourceLineKey: sourceLine, - if (parentId != null) CpuProfileData.parentIdKey: parentId, + CpuProfileData.parentIdKey: ?parentId, }, };
diff --git a/packages/devtools_app/lib/src/screens/profiler/cpu_profile_service.dart b/packages/devtools_app/lib/src/screens/profiler/cpu_profile_service.dart index 86bb46c..024de99 100644 --- a/packages/devtools_app/lib/src/screens/profiler/cpu_profile_service.dart +++ b/packages/devtools_app/lib/src/screens/profiler/cpu_profile_service.dart
@@ -37,7 +37,7 @@ const kSamples = 'samples'; const kCodeStack = '_codeStack'; - final rawSamples = (cpuSamples.json![kSamples] as List) + final rawSamples = (cpuSamples.json![kSamples] as List<Object?>) .cast<Map<String, Object?>>(); bool buildCodeProfile = false; @@ -73,7 +73,7 @@ ); } - Future clearSamples() { + Future<void> clearSamples() { return serviceConnection.serviceManager.service!.clearCpuSamples( serviceConnection .serviceManager
diff --git a/packages/devtools_app/lib/src/screens/profiler/sampling_rate.dart b/packages/devtools_app/lib/src/screens/profiler/sampling_rate.dart index fabba88..ca63726 100644 --- a/packages/devtools_app/lib/src/screens/profiler/sampling_rate.dart +++ b/packages/devtools_app/lib/src/screens/profiler/sampling_rate.dart
@@ -35,15 +35,9 @@ } extension CpuSamplingRateExtension on CpuSamplingRate { - static CpuSamplingRate fromValue(String value) { - switch (value) { - case lowProfilePeriod: - return CpuSamplingRate.low; - case highProfilePeriod: - return CpuSamplingRate.high; - case mediumProfilePeriod: - default: - return CpuSamplingRate.medium; - } - } + static CpuSamplingRate fromValue(String value) => switch (value) { + lowProfilePeriod => CpuSamplingRate.low, + highProfilePeriod => CpuSamplingRate.high, + mediumProfilePeriod || _ => CpuSamplingRate.medium, + }; }