Skip to content

Commit

Permalink
Export snapshot. (flutter#7197)
Browse files Browse the repository at this point in the history
Primary purpose of this PR is to implement export for snapshots.

For release notes:
<img width="233" alt="Screenshot 2024-03-07 at 11 01 08�AM" src="https://github.com/flutter/devtools/assets/12115586/6889070b-febf-48f3-8456-cf9081b0d1bc">

Side effects of this PR are:
1. Refactored structure of snapshot diffing, because we want to store the snapshot in original format
2. Improved performance of snapshotting (increased number of snapshots that can be taken 10 times and performance 2 times).

Also this PR suggests to un-ignore DEPENDENCIES.md for folders where they help to understand code. 

Performance for DevTools in release mode, in chrome, connected to and on mac in debug mode, home page, on polina-c's mac:

1. Gallery, taking snapshots sequentially, one after another:
- Original: 3 snapshots takes 30 sec, crash happens on 6th snapshot
- New, before upgrade of vm_service: three snapshots 15 sec, OOM crash on 60th snapshot  

2. DevTools, with every screen opened, memory chart collapsed (per activity monitor takes almost 3 GB):
- Original: crash on first snapshot
- New: first snapshot takes ~10 min, crash on second one

TODO for this PR:
  • Loading branch information
polina-c committed Mar 22, 2024
1 parent e7d70c6 commit 355d416
Show file tree
Hide file tree
Showing 79 changed files with 2,366 additions and 1,714 deletions.
7 changes: 7 additions & 0 deletions packages/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@
"--dart-define=enable_experiments=true"
],
},
{
"name": "devtools + release",
"request": "launch",
"type": "dart",
"program": "devtools_app/lib/main.dart",
"flutterMode": "release",
},
{
"name": "memory/default",
"request": "launch",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,23 @@ import 'package:vm_service/vm_service.dart';

import '../../../../shared/globals.dart';
import '../../../../shared/memory/class_name.dart';
import '../../../../shared/memory/heap_graph_loader.dart';
import '../../../../shared/utils.dart';
import '../../panes/chart/primitives.dart';
import '../../panes/diff/controller/diff_pane_controller.dart';
import '../../panes/profile/profile_pane_controller.dart';
import '../../panes/tracing/tracing_pane_controller.dart';
import '../../shared/heap/model.dart';
import '../../shared/primitives/memory_timeline.dart';
import 'memory_protocol.dart';

class MemoryFeatureControllers {
/// [diffPaneController] is passed for testability.
/// Controllers are passed for testability.
MemoryFeatureControllers(
DiffPaneController? diffPaneController,
ProfilePaneController? profilePaneController,
) {
memoryTimeline = MemoryTimeline();
diff = diffPaneController ??
DiffPaneController(SnapshotTakerRuntime(memoryTimeline));
diff = diffPaneController ?? _createDiffController();
profile = profilePaneController ?? ProfilePaneController();
}

Expand All @@ -37,9 +36,12 @@ class MemoryFeatureControllers {
late MemoryTimeline memoryTimeline;
TracingPaneController tracing = TracingPaneController();

DiffPaneController _createDiffController() =>
DiffPaneController(HeapGraphLoaderRuntime(memoryTimeline));

void reset() {
diff.dispose();
diff = DiffPaneController(SnapshotTakerRuntime(memoryTimeline));
diff = _createDiffController();

profile.dispose();
profile = ProfilePaneController();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!DEPENDENCIES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!---
Generated by https://github.com/polina-c/layerlens
Dependencies that create loops (inversions) are marked with `!`.
-->

```mermaid
flowchart TD;
controller-->data;
diff_pane.dart-->controller;
diff_pane.dart-->widgets;
widgets-->controller;
widgets-->data;
```

### Inversions
In this folder: 0

Including sub-folders: 0

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!---
Generated by https://github.com/polina-c/layerlens
Dependencies that create loops (inversions) are marked with `!`.
-->

```mermaid
flowchart TD;
diff_pane_controller.dart-->class_data.dart;
diff_pane_controller.dart-->item_controller.dart;
```

### Inversions
In this folder: 0

Including sub-folders: 0

Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

import 'package:flutter/foundation.dart';

import '../../../../../shared/memory/adapted_heap_data.dart';
import '../../../../../shared/memory/classes.dart';
import '../../../../../shared/memory/heap_object.dart';
import '../../../../../shared/memory/retaining_path.dart';
import '../../../shared/heap/class_filter.dart';
import '../../../shared/heap/heap.dart';
import '../../../shared/primitives/simple_elements.dart';
import '../data/classes_diff.dart';

Expand Down Expand Up @@ -35,13 +36,13 @@ class ClassesTableSingleData {
final ClassFilterData filterData;

/// Selected class.
final selection = ValueNotifier<SingleClassStats?>(null);
final selection = ValueNotifier<SingleClassData?>(null);
}

class ClassesTableDiffData {
ClassesTableDiffData({
required this.before,
required this.after,
required this.heapBefore,
required this.heapAfter,
required this.filterData,
});

Expand All @@ -52,14 +53,40 @@ class ClassesTableDiffData {
// to subscribe for the changes, for performance reasons.

/// Function to get selected first heap to diff.
final HeapDataCallback before;
final HeapDataCallback heapBefore;

/// Function to get selected second heap to diff.
final HeapDataCallback after;
final HeapDataCallback heapAfter;

/// Current class filter data.
final ClassFilterData filterData;

/// Selected class.
final selection = ValueNotifier<DiffClassData?>(null);
}

/// Data for visualization of a path.
///
/// Is instantiated only to visualize the selected path,
/// not for each path in snapshot.
class PathData {
PathData(this.classData, this.path);

final ClassData classData;
final PathFromRoot path;

ObjectSetStats get objects => classData.byPath[path]!;

@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) {
return false;
}
return other is PathData &&
other.classData.className == classData.className &&
other.path == path;
}

@override
int get hashCode => Object.hash(classData.className, path);
}
Loading

0 comments on commit 355d416

Please sign in to comment.