Adding ArtificialRoot to non-deferred apps for diff table (#4338)
diff --git a/packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart b/packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart
index 71ee07d..a9602c5 100644
--- a/packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart
+++ b/packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart
@@ -67,6 +67,10 @@
static const identicalFilesError =
'Failed to load diff: OLD and NEW files are identical.';
+ static const artificialRootNodeName = 'ArtificialRoot';
+
+ static const mainNodeName = 'Main';
+
CallGraph? _analysisCallGraph;
ValueListenable<CallGraphNode?> get analysisCallGraphRoot =>
@@ -318,13 +322,13 @@
}
bool _hasDeferredInfo(Map<String, dynamic> jsonFile) {
- return jsonFile['n'] == 'ArtificialRoot';
+ return jsonFile['n'] == artificialRootNodeName;
}
Map<String, dynamic> _extractMainUnit(Map<String, dynamic> jsonFile) {
if (_hasDeferredInfo(jsonFile)) {
final main = _extractChildren(jsonFile).firstWhere(
- (child) => child['n'] == 'Main',
+ (child) => child['n'] == mainNodeName,
orElse: () => jsonFile,
);
return main;
@@ -380,8 +384,20 @@
Map<String, dynamic> diffMap;
if (oldFile.isAnalyzeSizeFile && newFile.isAnalyzeSizeFile) {
+ var oldFileJson = oldFile.data as Map<String, dynamic>;
+ var newFileJson = newFile.data as Map<String, dynamic>;
+
+ if (_hasDeferredInfo(oldFileJson) || _hasDeferredInfo(newFileJson)) {
+ _isDeferredApp.value = deferredLoadingSupportEnabled;
+
+ if (!_hasDeferredInfo(oldFileJson)) {
+ oldFileJson = _wrapInArtificialRoot(oldFileJson);
+ } else if (!_hasDeferredInfo(newFileJson)) {
+ newFileJson = _wrapInArtificialRoot(newFileJson);
+ }
+ }
+
final oldApkProgramInfo = ProgramInfo();
- final oldFileJson = oldFile.data as Map<String, dynamic>;
_apkJsonToProgramInfo(
program: oldApkProgramInfo,
parent: oldApkProgramInfo.root,
@@ -399,7 +415,6 @@
}
final newApkProgramInfo = ProgramInfo();
- final newFileJson = newFile.data as Map<String, dynamic>;
_apkJsonToProgramInfo(
program: newApkProgramInfo,
parent: newApkProgramInfo.root,
@@ -438,20 +453,23 @@
changeOldDiffFile(oldFile);
changeNewDiffFile(newFile);
- diffMap['n'] = 'Root';
+ diffMap['n'] = isDeferredApp.value ? 'Entire App' : 'Root';
// TODO(peterdjlee): Try to move the non-active tree generation to separate isolates.
_combinedDiffTreeRoot = generateDiffTree(
diffMap,
DiffTreeType.combined,
+ skipNodesWithNoByteSizeChange: !isDeferredApp.value,
);
_increasedDiffTreeRoot = generateDiffTree(
diffMap,
DiffTreeType.increaseOnly,
+ skipNodesWithNoByteSizeChange: !isDeferredApp.value,
);
_decreasedDiffTreeRoot = generateDiffTree(
diffMap,
DiffTreeType.decreaseOnly,
+ skipNodesWithNoByteSizeChange: !isDeferredApp.value,
);
changeDiffRoot(_activeDiffRoot);
@@ -459,6 +477,14 @@
_processingNotifier.value = false;
}
+ Map<String, dynamic> _wrapInArtificialRoot(Map<String, dynamic> json) {
+ json['n'] = mainNodeName;
+ return <String, dynamic>{
+ 'n': artificialRootNodeName,
+ 'children': [json],
+ };
+ }
+
ProgramInfoNode _apkJsonToProgramInfo({
required ProgramInfo program,
required ProgramInfoNode parent,
@@ -507,14 +533,16 @@
/// * [DiffTreeType.combined]: returns a tree with all nodes.
TreemapNode? generateDiffTree(
Map<String, dynamic> treeJson,
- DiffTreeType diffTreeType,
- ) {
+ DiffTreeType diffTreeType, {
+ bool skipNodesWithNoByteSizeChange = true,
+ }) {
final isLeafNode = treeJson['children'] == null;
if (!isLeafNode) {
return _buildNodeWithChildren(
treeJson,
showDiff: true,
diffTreeType: diffTreeType,
+ skipNodesWithNoByteSizeChange: skipNodesWithNoByteSizeChange,
);
} else {
// TODO(peterdjlee): Investigate why there are leaf nodes with size of null.
@@ -547,6 +575,7 @@
Map<String, dynamic> treeJson, {
bool showDiff = false,
DiffTreeType? diffTreeType,
+ bool skipNodesWithNoByteSizeChange = true,
}) {
assert(showDiff ? diffTreeType != null : true);
final rawChildren = treeJson['children'];
@@ -566,7 +595,7 @@
}
// If none of the children matched the diff tree type
- if (totalByteSize == 0) {
+ if (totalByteSize == 0 && skipNodesWithNoByteSizeChange) {
return null;
} else {
return _buildNode(