Skip to content

Commit

Permalink
Refactor memory screen. (flutter#7518)
Browse files Browse the repository at this point in the history
  • Loading branch information
polina-c committed Apr 4, 2024
1 parent bfbce48 commit a91841a
Show file tree
Hide file tree
Showing 36 changed files with 869 additions and 700 deletions.
16 changes: 16 additions & 0 deletions packages/devtools_app/lib/src/screens/memory/DEPENDENCIES.md
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;
framework-->panes;
panes-->shared;
```

### Inversions
In this folder: 0

Including sub-folders: 0

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

```mermaid
flowchart TD;
memory_screen.dart-->connected;
```

### Inversions
In this folder: 0

Including sub-folders: 0

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

```mermaid
flowchart TD;
connected_screen_body.dart-->memory_controller.dart;
connected_screen_body.dart-->memory_tabs.dart;
memory_tabs.dart-->memory_controller.dart;
```

### Inversions
In this folder: 0

Including sub-folders: 0

Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@ class _ConnectedMemoryBodyState extends State<ConnectedMemoryBody>
return Column(
key: MemoryChartPane.hoverKey,
children: [
MemoryControlPane(controller: controller),
MemoryControlPane(
controller: controller.controllers.control,
),
const SizedBox(height: intermediateSpacing),
MemoryChartPane(
chartController: controller.controllers.chart,
chart: controller.controllers.chart,
keyFocusNode: _focusNode,
),
Expanded(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,34 @@ import 'dart:async';

import 'package:devtools_app_shared/utils.dart';
import 'package:flutter/foundation.dart';
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 '../../panes/chart/controller/chart_pane_controller.dart';
import '../../panes/chart/widgets/memory_android_chart.dart';
import '../../panes/chart/widgets/memory_events_pane.dart';
import '../../panes/chart/widgets/memory_vm_chart.dart';
import '../../panes/control/controller/control_pane_controller.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/primitives/memory_timeline.dart';
import 'memory_tracker.dart';

class MemoryFeatureControllers {
/// Controllers are passed for testability.
MemoryFeatureControllers(
DiffPaneController? diffPaneController,
ProfilePaneController? profilePaneController, {
required MemoryController? memoryController,
}) {
memoryTimeline = MemoryTimeline();
ProfilePaneController? profilePaneController,
) {
diff = diffPaneController ?? _createDiffController();
profile = profilePaneController ?? ProfilePaneController();

final vmChartController = VMChartController(memoryController!);
chart = MemoryChartPaneController(
event: EventChartController(memoryController),
vm: vmChartController,
android: AndroidChartController(
memoryController,
sharedLabels: vmChartController.labelTimestamps,
),
);
}

late DiffPaneController diff;
late ProfilePaneController profile;
late MemoryTimeline memoryTimeline;
late MemoryChartPaneController chart;
late MemoryChartPaneController chart = MemoryChartPaneController();
TracingPaneController tracing = TracingPaneController();
MemoryControlPaneController control = MemoryControlPaneController();
late final MemoryControlPaneController control =
MemoryControlPaneController(chart.memoryTimeline);

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

void reset() {
diff.dispose();
Expand All @@ -64,7 +45,7 @@ class MemoryFeatureControllers {
tracing.dispose();
tracing = TracingPaneController();

memoryTimeline.reset();
chart.memoryTimeline.reset();
}

void dispose() {
Expand All @@ -90,7 +71,6 @@ class MemoryController extends DisposableController
controllers = MemoryFeatureControllers(
diffPaneController,
profilePaneController,
memoryController: this,
);
shareClassFilterBetweenProfileAndDiff();
}
Expand Down Expand Up @@ -123,107 +103,6 @@ class MemoryController extends DisposableController
/// instead of the widget state.
int selectedFeatureTabIndex = 0;

void _handleConnectionStart() {
if (controllers.chart.memoryTracker == null) {
controllers.chart.memoryTracker =
MemoryTracker(controllers.memoryTimeline, controllers.chart);
controllers.chart.memoryTracker!.start();
}

// Log Flutter extension events.
// Note: We do not need to listen to event history here because we do not
// have matching historical data about total memory usage.
autoDisposeStreamSubscription(
serviceConnection.serviceManager.service!.onExtensionEvent
.listen((Event event) {
var extensionEventKind = event.extensionKind;
String? customEventKind;
if (MemoryTimeline.isCustomEvent(event.extensionKind!)) {
extensionEventKind = MemoryTimeline.devToolsExtensionEvent;
customEventKind =
MemoryTimeline.customEventName(event.extensionKind!);
}
final jsonData = event.extensionData!.data.cast<String, Object>();
// TODO(terry): Display events enabled in a settings page for now only these events.
switch (extensionEventKind) {
case 'Flutter.ImageSizesForFrame':
controllers.memoryTimeline.addExtensionEvent(
event.timestamp,
event.extensionKind,
jsonData,
);
break;
case MemoryTimeline.devToolsExtensionEvent:
controllers.memoryTimeline.addExtensionEvent(
event.timestamp,
MemoryTimeline.customDevToolsEvent,
jsonData,
customEventName: customEventKind,
);
break;
}
}),
);

autoDisposeStreamSubscription(
controllers.chart.memoryTracker!.onChange.listen((_) {
controllers.chart.memoryTrackerController
.add(controllers.chart.memoryTracker);
}),
);
autoDisposeStreamSubscription(
controllers.chart.memoryTracker!.onChange.listen((_) {
controllers.chart.memoryTrackerController
.add(controllers.chart.memoryTracker);
}),
);

// TODO(terry): Used to detect stream being closed from the
// memoryController dispose method. Needed when a HOT RELOAD
// will call dispose however, initState doesn't seem
// to happen David is working on scaffolding.
controllers.chart.memoryTrackerController.stream.listen(
(_) {},
onDone: () {
// Stop polling and reset memoryTracker.
controllers.chart.memoryTracker?.stop();
controllers.chart.memoryTracker = null;
},
);

controllers.chart.updateAndroidChartVisibility();
addAutoDisposeListener(
preferences.memory.androidCollectionEnabled,
controllers.chart.updateAndroidChartVisibility,
);
}

/// This flag will be needed for offline mode implementation.
bool offline = false;

void _handleConnectionStop() {
controllers.chart.memoryTracker?.stop();
controllers.chart.memoryTrackerController
.add(controllers.chart.memoryTracker);

controllers.reset();
controllers.chart.hasStopped = true;
}

void startTimeline() {
addAutoDisposeListener(serviceConnection.serviceManager.connectedState, () {
if (serviceConnection.serviceManager.connectedState.value.connected) {
_handleConnectionStart();
} else {
_handleConnectionStop();
}
});

if (serviceConnection.serviceManager.connectedAppInitialized) {
_handleConnectionStart();
}
}

@override
void dispose() {
super.dispose();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!---
Generated by https://github.com/polina-c/layerlens
Dependencies that create loops (inversions) are marked with `!`.
-->

```mermaid
flowchart TD;
controller-->data;
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,18 @@
<!---
Generated by https://github.com/polina-c/layerlens
Dependencies that create loops (inversions) are marked with `!`.
-->

```mermaid
flowchart TD;
chart_pane_controller.dart-->android_chart_controller.dart;
chart_pane_controller.dart-->event_chart_controller.dart;
chart_pane_controller.dart-->memory_tracker.dart;
chart_pane_controller.dart-->vm_chart_controller.dart;
```

### Inversions
In this folder: 0

Including sub-folders: 0

Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:devtools_shared/devtools_shared.dart';
import 'package:flutter/foundation.dart';

import '../../../../../shared/charts/chart_controller.dart';
import '../../../../../shared/charts/chart_trace.dart' as chart_trace;
import '../../../shared/primitives/memory_timeline.dart';
import '../data/charts.dart';

class AndroidChartController extends ChartController {
AndroidChartController(
this.memoryTimeline, {
required this.paused,
List<int> sharedLabels = const <int>[],
}) : super(
name: 'Android',
sharedLabelTimestamps: sharedLabels,
);

final ValueListenable<bool> paused;
final MemoryTimeline memoryTimeline;

// TODO(terry): Only load max visible data collected, when pruning of data
// charted is added.
/// Preload any existing data collected but not in the chart.
@override
void setupData() {
// Only display if traces have been created. Android memory may not
// have been toggled to be displayed - yet.
if (traces.isNotEmpty) {
final chartDataLength = timestampsLength;
final dataLength = memoryTimeline.data.length;

final dataRange = memoryTimeline.data.getRange(
chartDataLength,
dataLength,
);

dataRange.forEach(addSample);
}
}

/// Loads all heap samples (live data or offline).
void addSample(HeapSample sample) {
// If paused don't update the chart (data is still collected).
if (paused.value) return;

addTimestamp(sample.timestamp);

final timestamp = sample.timestamp;
final adb = sample.adbMemoryInfo;

final stackValue = adb.stack.toDouble();
addDataToTrace(
AndroidTraceName.stack.index,
chart_trace.Data(timestamp, stackValue),
);

final graphicValue = adb.graphics.toDouble();
addDataToTrace(
AndroidTraceName.graphics.index,
chart_trace.Data(
timestamp,
graphicValue,
),
);

final nativeHeapValue = adb.nativeHeap.toDouble();
addDataToTrace(
AndroidTraceName.nativeHeap.index,
chart_trace.Data(
timestamp,
nativeHeapValue,
),
);

final javaHeapValue = adb.javaHeap.toDouble();
addDataToTrace(
AndroidTraceName.javaHeap.index,
chart_trace.Data(timestamp, javaHeapValue),
);

final codeValue = adb.code.toDouble();
addDataToTrace(
AndroidTraceName.code.index,
chart_trace.Data(timestamp, codeValue),
);

final otherValue = adb.other.toDouble();
addDataToTrace(
AndroidTraceName.other.index,
chart_trace.Data(timestamp, otherValue),
);

final systemValue = adb.system.toDouble();
addDataToTrace(
AndroidTraceName.system.index,
chart_trace.Data(timestamp, systemValue),
);

final totalValue = adb.total.toDouble();
addDataToTrace(
AndroidTraceName.total.index,
chart_trace.Data(timestamp, totalValue),
);
}
}
Loading

0 comments on commit a91841a

Please sign in to comment.