Skip to content

Commit

Permalink
Load a snapshot. (#6974)
Browse files Browse the repository at this point in the history
  • Loading branch information
polina-c authored Jan 31, 2024
1 parent 625cd85 commit 90687d2
Show file tree
Hide file tree
Showing 23 changed files with 221 additions and 109 deletions.
5 changes: 5 additions & 0 deletions packages/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"streetsidesoftware.code-spell-checker"
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class MemoryFeatureControllers {
ProfilePaneController? profilePaneController,
) {
memoryTimeline = MemoryTimeline();
diff =
diffPaneController ?? DiffPaneController(SnapshotTaker(memoryTimeline));
diff = diffPaneController ??
DiffPaneController(SnapshotTakerRuntime(memoryTimeline));
profile = profilePaneController ?? ProfilePaneController();
}

Expand All @@ -39,7 +39,7 @@ class MemoryFeatureControllers {

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

profile.dispose();
profile = ProfilePaneController();
Expand Down Expand Up @@ -210,7 +210,7 @@ class MemoryController extends DisposableController

// TODO(terry): Used to detect stream being closed from the
// memoryController dispose method. Needed when a HOT RELOAD
// will call dispose however, spinup (initState) doesn't seem
// will call dispose however, initState doesn't seem
// to happen David is working on scaffolding.
_memoryTrackerController.stream.listen(
(_) {},
Expand Down Expand Up @@ -290,7 +290,7 @@ class MemoryController extends DisposableController
}
}

/// Detect stale isolates (sentinaled), may happen after a hot restart.
/// Detect stale isolates (sentineled), may happen after a hot restart.
Future<bool> isIsolateLive(String isolateId) async {
try {
final service = serviceConnection.serviceManager.service!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:flutter/foundation.dart';
import '../../../../../shared/analytics/analytics.dart' as ga;
import '../../../../../shared/analytics/constants.dart' as gac;
import '../../../../../shared/config_specific/import_export/import_export.dart';
import '../../../../../shared/file_import.dart';
import '../../../../../shared/globals.dart';
import '../../../../../shared/memory/class_name.dart';
import '../../../shared/heap/class_filter.dart';
Expand All @@ -28,10 +29,6 @@ class DiffPaneController extends DisposableController {

final SnapshotTaker snapshotTaker;

/// If true, a snapshot is being taken.
ValueListenable<bool> get isTakingSnapshot => _isTakingSnapshot;
final _isTakingSnapshot = ValueNotifier<bool>(false);

final retainingPathController = RetainingPathController();

final core = CoreData();
Expand All @@ -42,17 +39,43 @@ class DiffPaneController extends DisposableController {
bool get hasSnapshots => core.snapshots.value.length > 1;

Future<void> takeSnapshot() async {
_isTakingSnapshot.value = true;
ga.select(
gac.memory,
gac.MemoryEvent.diffTakeSnapshotControlPane,
);

final item = SnapshotInstanceItem(
displayNumber: _nextDisplayNumber(),
isolateName: selectedIsolateName ?? '<isolate-not-detected>',
defaultName: selectedIsolateName ?? '<isolate-not-detected>',
);

await _addSnapshot(snapshotTaker, item);
derived._updateValues();
}

/// Imports snapshots from files.
///
/// Opens file selector and loads snapshots from the selected files.
Future<void> importSnapshots() async {
ga.select(
gac.memory,
gac.importFile,
);
final files = await importRawFilesFromPicker();
if (files.isEmpty) return;

final importers = files.map((file) async {
final item = SnapshotInstanceItem(defaultName: file.name);
await _addSnapshot(SnapshotTakerFromFile(file), item);
});
await Future.wait(importers);
derived._updateValues();
}

Future<void> _addSnapshot(
SnapshotTaker snapshotTaker,
SnapshotInstanceItem item,
) async {
final snapshots = core._snapshots;
snapshots.add(item);

Expand All @@ -65,8 +88,6 @@ class DiffPaneController extends DisposableController {
} finally {
final newElementIndex = snapshots.value.length - 1;
core._selectedSnapshotIndex.value = newElementIndex;
_isTakingSnapshot.value = false;
derived._updateValues();
}
}

Expand All @@ -81,7 +102,7 @@ class DiffPaneController extends DisposableController {
}

int _nextDisplayNumber() {
final numbers = core._snapshots.value.map((e) => e.displayNumber);
final numbers = core._snapshots.value.map((e) => e.displayNumber ?? 0);
assert(numbers.isNotEmpty);
return numbers.max + 1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ import '../../../../../shared/memory/adapted_heap_data.dart';
import '../../../shared/heap/heap.dart';

abstract class SnapshotItem extends DisposableController {
/// Number, that if shown in name, should be unique in the list.
///
/// If the number is not expected to be shown in UI, it should be 0.
int get displayNumber;
/// Number to show with auto-generated names that may be non unique, like isolate name.
int? get displayNumber;

ValueListenable<bool> get isProcessing => _isProcessing;
final _isProcessing = ValueNotifier<bool>(false);
Expand All @@ -23,21 +21,22 @@ abstract class SnapshotItem extends DisposableController {

class SnapshotDocItem extends SnapshotItem {
@override
int get displayNumber => 0;
int? get displayNumber => null;

@override
bool get hasData => false;
}

class SnapshotInstanceItem extends SnapshotItem {
SnapshotInstanceItem({
required this.displayNumber,
required this.isolateName,
this.displayNumber,
required this.defaultName,
}) {
_isProcessing.value = true;
}

final String isolateName;
/// Automatically assigned name like isolate name or file name.
final String defaultName;

AdaptedHeap? heap;

Expand All @@ -52,9 +51,11 @@ class SnapshotInstanceItem extends SnapshotItem {
}

@override
final int displayNumber;
final int? displayNumber;

String get name => nameOverride ?? '$isolateName-$displayNumber';
String get name =>
nameOverride ??
'$defaultName${displayNumber == null ? '' : '-$displayNumber'}';

String? nameOverride;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import '../../../../shared/analytics/constants.dart' as gac;
import '../../../../shared/common_widgets.dart';
import '../../../../shared/config_specific/launch_url/launch_url.dart';
import '../../../../shared/globals.dart';
import '../../../../shared/primitives/simple_items.dart';
import '../../shared/widgets/shared_memory_widgets.dart';
import 'controller/diff_pane_controller.dart';
Expand Down Expand Up @@ -68,7 +69,9 @@ class _SnapshotItemContent extends StatelessWidget {
children: [
Expanded(
child: Markdown(
data: _snapshotDocumentation,
data: _snapshotDocumentation(
preferences.darkModeTheme.value,
),
styleSheet: MarkdownStyleSheet(
p: Theme.of(context).regularTextStyle,
),
Expand Down Expand Up @@ -136,8 +139,12 @@ class SnapshotInstanceItemPane extends StatelessWidget {
}
}

// `\v` adds vertical space
const _snapshotDocumentation = '''
String _snapshotDocumentation(bool isDark) {
final filePostfix = isDark ? 'dark' : 'light';
final uploadImageUrl = 'assets/img/doc/upload_$filePostfix.png';

// `\v` adds vertical space
return '''
Find unexpected memory usage by comparing two heap snapshots:
\v
Expand All @@ -146,9 +153,18 @@ Find unexpected memory usage by comparing two heap snapshots:
\v
2. Take a **heap snapshot** to view current memory allocation:
2. Use one of the following ways to get a **heap snapshot**:
a. To view current memory allocation click the ● button
a. In the Snapshots panel, click the ● button
b. To import a snapshot taken with
[auto-snapshotting](https://github.com/dart-lang/leak_tracker/blob/main/doc/USAGE.md) or
[writeHeapSnapshotToFile](https://api.flutter.dev/flutter/dart-developer/NativeRuntime/writeHeapSnapshotToFile.html)
click the ![import]($uploadImageUrl) button
\v
3. Review the snapshot:
b. If you want to refine results, use the **Filter** button
Expand All @@ -158,19 +174,17 @@ Find unexpected memory usage by comparing two heap snapshots:
\v
3. Check the **diff** between snapshots to detect allocation issues:
a. Take a **snapshot**
4. Check the **diff** between snapshots to detect allocation issues:
b. Execute the feature in your application
c. Take a second snapshot. If you are experiencing DevTools crashes due to size of snapshots,
a. Get **snapshots** before and after a feature execution.
If you are experiencing DevTools crashes due to size of snapshots,
switch to the [desktop version](https://github.com/flutter/devtools/blob/master/BETA_TESTING.md).
d. While viewing the second snapshot, click **Diff with:** and select the first snapshot from the drop-down menu;
b. While viewing the second snapshot, click **Diff with:** and select the first snapshot from the drop-down menu;
the results area will display the diff
e. Use the **Filter** button to refine the diff results, if needed
c. Use the **Filter** button to refine the diff results, if needed
f. Select a class from the diff to view its retaining paths, and see which objects hold the references to those instances
d. Select a class from the diff to view its retaining paths, and see which objects hold the references to those instances
''';
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,39 @@ class SnapshotControlPane extends StatelessWidget {

@override
Widget build(BuildContext context) {
return ValueListenableBuilder<bool>(
valueListenable: controller.isTakingSnapshot,
builder: (_, isProcessing, __) {
final current = controller.core.selectedItem as SnapshotInstanceItem;
final heapIsReady = !isProcessing && current.heap != null;
if (heapIsReady) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
final current = controller.core.selectedItem as SnapshotInstanceItem;
final heapIsReady = current.heap != null;
if (heapIsReady) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Row(
children: [
_DiffDropdown(
current: current,
controller: controller,
),
const SizedBox(width: defaultSpacing),
DownloadButton(
tooltip: 'Download data in CSV format',
label: 'CSV',
minScreenWidthForTextBeforeScaling:
memoryControlsMinVerboseWidth,
gaScreen: gac.memory,
gaSelection: gac.MemoryEvent.diffSnapshotDownloadCsv,
onPressed: controller.downloadCurrentItemToCsv,
),
],
_DiffDropdown(
current: current,
controller: controller,
),
Expanded(
child: _SnapshotSizeView(
footprint: current.heap!.footprint,
),
const SizedBox(width: defaultSpacing),
DownloadButton(
tooltip: 'Download data in CSV format',
label: 'CSV',
minScreenWidthForTextBeforeScaling:
memoryControlsMinVerboseWidth,
gaScreen: gac.memory,
gaSelection: gac.MemoryEvent.diffSnapshotDownloadCsv,
onPressed: controller.downloadCurrentItemToCsv,
),
],
);
}
return const SizedBox.shrink();
},
);
),
Expanded(
child: _SnapshotSizeView(
footprint: current.heap!.footprint,
),
),
],
);
}
return const SizedBox.shrink();
}
}

Expand Down
Loading

0 comments on commit 90687d2

Please sign in to comment.