Skip to content

Commit

Permalink
Open profile and chart in disconnected mode. (flutter#7784)
Browse files Browse the repository at this point in the history
  • Loading branch information
polina-c committed May 21, 2024
1 parent 6738316 commit c4d27d8
Show file tree
Hide file tree
Showing 23 changed files with 216 additions and 125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ class MemoryController extends DisposableController
@visibleForTesting ProfilePaneController? connectedProfile,
}) {
if (connectedDiff != null || connectedProfile != null) {
_mode = ControllerCreationMode.connected;
mode = ControllerCreationMode.connected;
} else {
_mode = devToolsMode;
mode = devToolsMode;
}
unawaited(_init(connectedDiff, connectedProfile));
}
Expand All @@ -50,7 +50,7 @@ class MemoryController extends DisposableController
/// DevTools mode at the time of creation of the controller.
///
/// DevTools will recreate controller when the mode changes.
late final ControllerCreationMode _mode;
late final ControllerCreationMode mode;

/// Index of the selected feature tab.
///
Expand All @@ -62,22 +62,22 @@ class MemoryController extends DisposableController

late final DiffPaneController diff;

late final ProfilePaneController profile;
late final ProfilePaneController? profile;

late final MemoryChartPaneController chart;
late final MemoryChartPaneController? chart;

late final TracingPaneController tracing;
late final TracingPaneController? tracing;

late final MemoryControlPaneController control;

@override
void dispose() {
super.dispose();
HeapClassName.dispose();
chart.dispose();
tracing.dispose();
chart?.dispose();
tracing?.dispose();
diff.dispose();
profile.dispose();
profile?.dispose();
}

static const _jsonKey = 'data';
Expand All @@ -87,7 +87,7 @@ class MemoryController extends DisposableController
@visibleForTesting ProfilePaneController? connectedProfile,
) async {
assert(!_dataInitialized.isCompleted);
switch (_mode) {
switch (mode) {
case ControllerCreationMode.disconnected:
// TODO(polina-c): load memory screen in disconnected mode, https://github.com/flutter/devtools/issues/6972
_initializeData();
Expand Down Expand Up @@ -117,6 +117,7 @@ class MemoryController extends DisposableController
}
}
assert(_dataInitialized.isCompleted);
assert(profile == null || profile!.rootPackage == diff.core.rootPackage);
}

void _initializeData({
Expand All @@ -126,24 +127,49 @@ class MemoryController extends DisposableController
}) {
assert(!_dataInitialized.isCompleted);

chart = MemoryChartPaneController(_mode, data: offlineData?.chart);
final hasData = mode != ControllerCreationMode.disconnected;
final isConnected = mode == ControllerCreationMode.connected;

chart = hasData
? MemoryChartPaneController(mode, data: offlineData?.chart)
: null;

final rootPackage = isConnected
? serviceConnection.serviceManager.rootInfoNow().package!
: null;

diff = diffPaneController ??
offlineData?.diff ??
DiffPaneController(
loader: HeapGraphLoaderRuntime(chart.data.timeline),
loader:
isConnected ? HeapGraphLoaderRuntime(chart!.data.timeline) : null,
rootPackage: rootPackage,
);
profile = profilePaneController ??
offlineData?.profile ??
ProfilePaneController(mode: _mode);

if (hasData) {
profile = profilePaneController ??
offlineData?.profile ??
ProfilePaneController(
mode: mode,
rootPackage: rootPackage!,
);
} else {
profile = null;
}

control = MemoryControlPaneController(
chart.data.timeline,
chart?.data.timeline,
mode,
exportData: exportData,
);
tracing = TracingPaneController();

tracing = hasData ? TracingPaneController() : null;

selectedFeatureTabIndex =
offlineData?.selectedTab ?? selectedFeatureTabIndex;
if (offlineData != null) profile.setFilter(offlineData.filter);
_shareClassFilterBetweenProfileAndDiff();

if (offlineData != null) profile?.setFilter(offlineData.filter);
if (hasData) _shareClassFilterBetweenProfileAndDiff();

_dataInitialized.complete();
}
Expand All @@ -158,23 +184,24 @@ class MemoryController extends DisposableController
_jsonKey: OfflineMemoryData(
diff,
profile,
chart.data,
profile.classFilter.value,
chart?.data,
diff.core.classFilter.value,
selectedTab: selectedFeatureTabIndex,
),
},
);
}

void _shareClassFilterBetweenProfileAndDiff() {
diff.derived.applyFilter(profile.classFilter.value);
final theProfile = profile!;
diff.derived.applyFilter(theProfile.classFilter.value);

profile.classFilter.addListener(() {
diff.derived.applyFilter(profile.classFilter.value);
theProfile.classFilter.addListener(() {
diff.derived.applyFilter(theProfile.classFilter.value);
});

diff.core.classFilter.addListener(() {
profile.setFilter(
theProfile.setFilter(
diff.core.classFilter.value,
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../../../shared/analytics/analytics.dart' as ga;
import '../../../shared/feature_flags.dart';
import '../../../shared/primitives/listenable.dart';
import '../../../shared/screen.dart';
import 'screen_body.dart';
Expand All @@ -26,6 +27,12 @@ class MemoryScreen extends Screen {
@override
Widget buildScreenBody(BuildContext context) => const MemoryBody();

@override
Widget? buildDisconnectedScreenBody(BuildContext context) =>
FeatureFlags.memoryOffline
? const MemoryBody()
: super.buildDisconnectedScreenBody(context);

// TODO(polina-c): when embedded and VSCode console features are implemented,
// should be in native console in VSCode
@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter/material.dart';

import '../../../shared/analytics/constants.dart' as gac;
import '../../../shared/common_widgets.dart';
import '../../../shared/primitives/simple_items.dart';
import '../../../shared/ui/tab.dart';
import '../panes/diff/diff_pane.dart';
import '../panes/profile/profile_view.dart';
Expand Down Expand Up @@ -42,42 +43,51 @@ class MemoryTabView extends StatelessWidget {
);
}

List<({DevToolsTab tab, Widget tabView})> _generateTabRecords() {
return [
(
TabAndView _diff() => (
tab: DevToolsTab.create(
key: MemoryScreenKeys.dartHeapTableProfileTab,
tabName: 'Profile Memory',
key: MemoryScreenKeys.diffTab,
gaPrefix: _gaPrefix,
tabName: 'Diff Snapshots',
),
tabView: KeepAliveWrapper(
child: AllocationProfileTableView(
controller: controller.profile,
child: DiffPane(
diffController: controller.diff,
),
),
),
(
);

TabAndView _profile() => (
tab: DevToolsTab.create(
key: MemoryScreenKeys.diffTab,
key: MemoryScreenKeys.dartHeapTableProfileTab,
tabName: 'Profile Memory',
gaPrefix: _gaPrefix,
tabName: 'Diff Snapshots',
),
tabView: KeepAliveWrapper(
child: DiffPane(
diffController: controller.diff,
child: AllocationProfileTableView(
controller: controller.profile!,
),
),
),
(
);

TabAndView _trace() => (
tab: DevToolsTab.create(
key: MemoryScreenKeys.dartHeapAllocationTracingTab,
tabName: 'Trace Instances',
gaPrefix: _gaPrefix,
),
tabView: KeepAliveWrapper(
child: TracingPane(controller: controller.tracing),
child: TracingPane(controller: controller.tracing!),
),
),
);

List<TabAndView> _generateTabRecords() {
final hasData = controller.mode != ControllerCreationMode.disconnected;
return [
if (hasData) _profile(),
// Diff is enabled even in disconnected mode to allow users to load
// snapshots from file.
_diff(),
if (hasData) _trace(),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ class OfflineMemoryData {
final ClassFilter filter; // filter is shared between tabs, so it's here

final DiffPaneController diff;
final ProfilePaneController profile;
final ChartData chart;
final ProfilePaneController? profile;
final ChartData? chart;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:flutter/material.dart';
import '../../../shared/banner_messages.dart';
import '../../../shared/common_widgets.dart';
import '../../../shared/http/http_service.dart' as http_service;
import '../../../shared/primitives/simple_items.dart';
import '../../../shared/screen.dart';
import '../../../shared/utils.dart';
import '../panes/chart/widgets/chart_pane.dart';
Expand All @@ -28,8 +29,6 @@ class _ConnectedMemoryBodyState extends State<ConnectedMemoryBody>
AutoDisposeMixin,
SingleTickerProviderStateMixin,
ProvidedControllerMixin<MemoryController, ConnectedMemoryBody> {
MemoryController get memoryController => controller;

final _focusNode = FocusNode(debugLabel: 'memory');

@override
Expand All @@ -41,20 +40,23 @@ class _ConnectedMemoryBodyState extends State<ConnectedMemoryBody>
@override
void didChangeDependencies() {
super.didChangeDependencies();
maybePushDebugModeMemoryMessage(context, ScreenMetaData.memory.id);
maybePushHttpLoggingMessage(context, ScreenMetaData.memory.id);

if (!initController()) return;

addAutoDisposeListener(http_service.httpLoggingState, () {
if (controller.mode == ControllerCreationMode.connected) {
maybePushDebugModeMemoryMessage(context, ScreenMetaData.memory.id);
maybePushHttpLoggingMessage(context, ScreenMetaData.memory.id);
});

addAutoDisposeListener(http_service.httpLoggingState, () {
maybePushHttpLoggingMessage(context, ScreenMetaData.memory.id);
});
}
}

@override
Widget build(BuildContext context) {
return FutureBuilder<void>(
future: memoryController.initialized,
future: controller.initialized,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
Expand All @@ -64,12 +66,13 @@ class _ConnectedMemoryBodyState extends State<ConnectedMemoryBody>
controller: controller.control,
),
const SizedBox(height: intermediateSpacing),
MemoryChartPane(
chart: controller.chart,
keyFocusNode: _focusNode,
),
if (controller.mode != ControllerCreationMode.disconnected)
MemoryChartPane(
chart: controller.chart!,
keyFocusNode: _focusNode,
),
Expanded(
child: MemoryTabView(memoryController),
child: MemoryTabView(controller),
),
],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,37 @@
import 'package:flutter/foundation.dart';

import '../../../../../shared/globals.dart';
import '../../../../../shared/primitives/simple_items.dart';
import '../../../shared/primitives/memory_timeline.dart';

class MemoryControlPaneController {
MemoryControlPaneController(
this.memoryTimeline, {
this.memoryTimeline,
this.mode, {
required this.exportData,
});
}) : assert(
mode == ControllerCreationMode.disconnected || memoryTimeline != null,
);

final MemoryTimeline memoryTimeline;
final ControllerCreationMode mode;
final MemoryTimeline? memoryTimeline;
final VoidCallback exportData;
final ValueNotifier<bool> isChartVisible = preferences.memory.showChart;

bool get isGcing => _gcing;
bool _gcing = false;

Future<void> gc() async {
assert(mode == ControllerCreationMode.connected);
assert(memoryTimeline != null);
_gcing = true;
try {
await serviceConnection.serviceManager.service!.getAllocationProfile(
(serviceConnection
.serviceManager.isolateManager.selectedIsolate.value?.id)!,
gc: true,
);
memoryTimeline.addGCEvent();
memoryTimeline!.addGCEvent();
notificationService.push('Successfully garbage collected.');
} finally {
_gcing = false;
Expand Down
Loading

0 comments on commit c4d27d8

Please sign in to comment.