Skip to content

Add serialization and show offline chart. #7614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 129 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
129 commits
Select commit Hold shift + click to select a range
c004a97
-
polina-c Apr 17, 2024
7eca578
Update model.dart
polina-c Apr 17, 2024
b35d993
Update model.dart
polina-c Apr 17, 2024
eddaa1f
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c Apr 17, 2024
756e46e
-
polina-c Apr 18, 2024
8684c58
-
polina-c Apr 18, 2024
3f33dd0
Update profile_pane_controller.dart
polina-c Apr 18, 2024
25741df
Update profile_pane_controller.dart
polina-c Apr 18, 2024
c60b98e
-
polina-c Apr 18, 2024
396ce7f
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c Apr 18, 2024
8a3b629
-
polina-c Apr 19, 2024
c28413e
Update profile_pane_controller.dart
polina-c Apr 19, 2024
bbaf14e
Update profile_pane_controller.dart
polina-c Apr 19, 2024
8dfbf50
-
polina-c Apr 19, 2024
f6b83fd
-
polina-c Apr 19, 2024
e9ac83b
-
polina-c Apr 19, 2024
46a64a0
-
polina-c Apr 19, 2024
df746cc
-
polina-c Apr 19, 2024
69fdb05
-
polina-c Apr 19, 2024
82564bc
-
polina-c Apr 19, 2024
e4a4efa
-
polina-c Apr 20, 2024
c7a23bf
Merge branch 'gc-stats' into profile1
polina-c Apr 20, 2024
8e8af7a
Update gc_stats.dart
polina-c Apr 20, 2024
eed9879
Update gc_stats.dart
polina-c Apr 20, 2024
f40c377
-
polina-c Apr 21, 2024
d43f02e
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c Apr 22, 2024
c8ed523
-
polina-c Apr 22, 2024
33e06dd
-
polina-c Apr 23, 2024
bdba538
-
polina-c Apr 23, 2024
d6ab8f0
Update memory_timeline.dart
polina-c Apr 24, 2024
d78f710
Update chart_pane_controller.dart
polina-c Apr 24, 2024
2b2106b
-
polina-c Apr 24, 2024
0f42342
-
polina-c Apr 24, 2024
864f5d1
-
polina-c Apr 24, 2024
e0ae211
-
polina-c Apr 24, 2024
d84fdf3
-
polina-c Apr 24, 2024
edc00b1
Merge branch 'refactor' into profile1
polina-c Apr 24, 2024
dc7f26a
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c Apr 24, 2024
47b29b1
-
polina-c Apr 24, 2024
3116379
-
polina-c Apr 24, 2024
6fd13c4
Merge branch 'refactor' into profile1
polina-c Apr 24, 2024
29d3c63
Update memory_controller.dart
polina-c Apr 24, 2024
6c86e1f
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c Apr 24, 2024
7946b77
-
polina-c Apr 25, 2024
98ec6a4
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c Apr 25, 2024
bb82f00
Update offline_data.dart
polina-c Apr 25, 2024
4085f2a
Update chart_pane_controller.dart
polina-c Apr 25, 2024
a8e4ac0
-
polina-c Apr 25, 2024
5054ea9
-
polina-c Apr 25, 2024
aa90de3
-
polina-c Apr 25, 2024
6318170
-
polina-c Apr 25, 2024
6eb8409
Update vm_chart.dart
polina-c Apr 25, 2024
7dbb3e2
-
polina-c Apr 25, 2024
cc11ea7
Update vm_chart_controller.dart
polina-c Apr 25, 2024
df8b8d2
-
polina-c Apr 25, 2024
08cc3d8
Update vm_chart.dart
polina-c Apr 25, 2024
28413fe
Update vm_chart_controller.dart
polina-c Apr 25, 2024
f3d089a
-
polina-c Apr 25, 2024
d4ec16a
-
polina-c Apr 25, 2024
7f7f68e
-
polina-c Apr 25, 2024
7662210
-
polina-c Apr 25, 2024
5fac57d
-
polina-c Apr 25, 2024
0a9a4be
-
polina-c Apr 25, 2024
d2843af
Update events_chart.dart
polina-c Apr 25, 2024
8ba09a6
Update events_chart.dart
polina-c Apr 25, 2024
1c48245
-
polina-c Apr 25, 2024
f669e2a
-
polina-c Apr 25, 2024
fc42147
-
polina-c Apr 25, 2024
02c2c06
-
polina-c Apr 25, 2024
2db214b
Update memory_chart.dart
polina-c Apr 25, 2024
7af2302
Update event_chart_controller.dart
polina-c Apr 25, 2024
a3cdb0d
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c Apr 25, 2024
d1c4c14
Merge branch 'move' into profile1
polina-c Apr 25, 2024
a1e0759
-
polina-c Apr 25, 2024
1783728
Update memory_timeline.dart
polina-c Apr 26, 2024
d8a61c5
Merge branch 'move' into profile1
polina-c Apr 26, 2024
bbbe855
-
polina-c Apr 26, 2024
b24b938
Merge branch 'move' of github.com:polina-c/devtools; branch 'master' …
polina-c Apr 26, 2024
0a01970
Update vm_developer_common_widgets_test.dart
polina-c Apr 26, 2024
67465cd
Update vm_developer_common_widgets_test.dart
polina-c Apr 26, 2024
82717ab
Merge branch 'move' into profile1
polina-c Apr 26, 2024
ec79211
-
polina-c Apr 26, 2024
6c247d4
Update legend.dart
polina-c Apr 26, 2024
6c4ee49
-
polina-c Apr 26, 2024
4b36dcd
Update memory_screen_test.dart
polina-c Apr 26, 2024
dc0f7ab
Merge branch 'move' into profile1
polina-c Apr 26, 2024
27feae4
Update memory_screen_test.dart
polina-c Apr 26, 2024
364897d
Update memory_screen_test.dart
polina-c Apr 26, 2024
02f08e6
-
polina-c Apr 26, 2024
6d30b8c
Merge branch 'move' into profile1
polina-c Apr 26, 2024
ff2c13e
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c Apr 26, 2024
18d8ca8
Update chart_connection.dart
polina-c Apr 26, 2024
fc6577a
Update chart_connection.dart
polina-c Apr 26, 2024
980af0d
-
polina-c Apr 26, 2024
6f1dd10
-
polina-c Apr 29, 2024
3016324
Update chart_connection.dart
polina-c Apr 29, 2024
3588189
Update chart_connection.dart
polina-c Apr 29, 2024
0150b54
Update chart_connection.dart
polina-c Apr 29, 2024
8cd4cf6
Update chart_connection.dart
polina-c Apr 29, 2024
2eea0ac
-
polina-c Apr 30, 2024
7094095
-
polina-c Apr 30, 2024
e18340b
-
polina-c Apr 30, 2024
bec346c
-
polina-c Apr 30, 2024
dac5ec2
Update chart_data.dart
polina-c Apr 30, 2024
4fc2ff6
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c May 1, 2024
f132615
Update chart_pane_controller.dart
polina-c May 1, 2024
9f52f81
Update chart_pane_controller.dart
polina-c May 1, 2024
69e6c57
-
polina-c May 1, 2024
7ec0aab
-
polina-c May 1, 2024
fea1d0c
-
polina-c May 1, 2024
b255be6
Update chart_connection.dart
polina-c May 1, 2024
4caa78c
Update chart_connection.dart
polina-c May 1, 2024
7b05c33
k1
polina-c May 1, 2024
3bec7b5
k2
polina-c May 1, 2024
4b39a30
-
polina-c May 1, 2024
3a4d29a
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c May 1, 2024
7f45b3a
Update memory_controller.dart
polina-c May 2, 2024
f22bc4a
-
polina-c May 2, 2024
6932cc3
-
polina-c May 2, 2024
5c4e921
-
polina-c May 2, 2024
fc8b4e1
Update chart_connection.dart
polina-c May 2, 2024
4f7ab88
Update chart_connection.dart
polina-c May 2, 2024
3157239
Update chart_connection.dart
polina-c May 2, 2024
b571356
Update chart_connection.dart
polina-c May 3, 2024
598c8ff
Merge branch 'master' of github.com:flutter/devtools into profile1
polina-c May 3, 2024
5fbd893
-
polina-c May 3, 2024
2c632df
-
polina-c May 3, 2024
8ed0a4f
Update chart_pane_controller.dart
polina-c May 4, 2024
8eb3685
Update chart_pane_controller.dart
polina-c May 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and some items of
When an object owns and exposes a (listenable) value,
more complicated than just public field
we declare the related class members always in the same order,
without new lines separating the members,
in compliance with
[Flutter repo style guide]( https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#order-other-class-members-in-a-way-that-makes-sense):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:devtools_app_shared/utils.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import '../../../shared/globals.dart';
import '../../../shared/memory/class_name.dart';
import '../../../shared/memory/heap_graph_loader.dart';
import '../../../shared/offline_data.dart';
Expand Down Expand Up @@ -36,20 +37,20 @@ class MemoryController extends DisposableController
@visibleForTesting ProfilePaneController? connectedProfile,
}) {
if (connectedDiff != null || connectedProfile != null) {
_mode = DevToolsMode.connected;
_mode = ControllerCreationMode.connected;
} else {
_mode = devToolsMode;
}
unawaited(_init(connectedDiff, connectedProfile));
}

Future<void> get initialized => _initialized.future;
final _initialized = Completer<void>();
Future<void> get initialized => _dataInitialized.future;
final _dataInitialized = Completer<void>();

/// DevTools mode at the time of creation of the controller.
///
/// DevTools will recreate controller when the mode changes.
late final DevToolsMode _mode;
late final ControllerCreationMode _mode;

/// Index of the selected feature tab.
///
Expand Down Expand Up @@ -85,19 +86,20 @@ class MemoryController extends DisposableController
@visibleForTesting DiffPaneController? connectedDiff,
@visibleForTesting ProfilePaneController? connectedProfile,
) async {
assert(!_initialized.isCompleted);
assert(!_dataInitialized.isCompleted);
switch (_mode) {
case DevToolsMode.disconnected:
case ControllerCreationMode.disconnected:
// TODO(polina-c): load memory screen in disconnected mode, https://github.com/flutter/devtools/issues/6972
_initializeData();
case DevToolsMode.connected:
case ControllerCreationMode.connected:
await serviceConnection.serviceManager.onServiceAvailable;
_initializeData(
diffPaneController: connectedDiff,
profilePaneController: connectedProfile,
);
case DevToolsMode.offlineData:
case ControllerCreationMode.offlineData:
assert(connectedDiff == null && connectedProfile == null);
await maybeLoadOfflineData(
final loaded = await maybeLoadOfflineData(
ScreenMetaData.memory.id,
createData: (json) {
final data = json[_jsonKey];
Expand All @@ -109,31 +111,32 @@ class MemoryController extends DisposableController
);
// [maybeLoadOfflineData] will be a noop if there is no offline data for the memory screen,
// so ensure we still call [_initializedData] if it has not been called.
if (!_initialized.isCompleted) _initializeData();
assert(_initialized.isCompleted);
assert(loaded == _dataInitialized.isCompleted);
if (!_dataInitialized.isCompleted) {
_initializeData();
}
}
assert(_initialized.isCompleted);
assert(_dataInitialized.isCompleted);
}

void _initializeData({
OfflineMemoryData? offlineData,
@visibleForTesting DiffPaneController? diffPaneController,
@visibleForTesting ProfilePaneController? profilePaneController,
}) {
assert(!_initialized.isCompleted);
assert(!_dataInitialized.isCompleted);

chart = offlineData?.chart ?? MemoryChartPaneController(_mode);
chart = MemoryChartPaneController(_mode, data: offlineData?.chart);
diff = diffPaneController ??
offlineData?.diff ??
DiffPaneController(
loader: HeapGraphLoaderRuntime(chart.data.timeline),
);
profile = profilePaneController ??
offlineData?.profile ??
ProfilePaneController();
ProfilePaneController(mode: _mode);
control = MemoryControlPaneController(
chart.data.timeline,
isChartVisible: chart.isChartVisible,
exportData: exportData,
);
tracing = TracingPaneController();
Expand All @@ -142,24 +145,26 @@ class MemoryController extends DisposableController
if (offlineData != null) profile.setFilter(offlineData.filter);
_shareClassFilterBetweenProfileAndDiff();

_initialized.complete();
_dataInitialized.complete();
}

@override
OfflineScreenData prepareOfflineScreenData() => OfflineScreenData(
screenId: ScreenMetaData.memory.id,
data: {
// Passing serializable data without conversion to json here
// to skip serialization when data are passed in-process.
_jsonKey: OfflineMemoryData(
diff,
profile,
chart,
profile.classFilter.value,
selectedTab: selectedFeatureTabIndex,
),
},
);
OfflineScreenData prepareOfflineScreenData() {
return OfflineScreenData(
screenId: ScreenMetaData.memory.id,
data: {
// Passing serializable data without conversion to json here
// to skip serialization when data is passed in-process.
_jsonKey: OfflineMemoryData(
diff,
profile,
chart.data,
profile.classFilter.value,
selectedTab: selectedFeatureTabIndex,
),
},
);
}

void _shareClassFilterBetweenProfileAndDiff() {
diff.derived.applyFilter(profile.classFilter.value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../../panes/chart/controller/chart_pane_controller.dart';
import '../../panes/chart/controller/chart_data.dart';
import '../../panes/diff/controller/diff_pane_controller.dart';
import '../../panes/profile/profile_pane_controller.dart';
import '../../shared/heap/class_filter.dart';
Expand Down Expand Up @@ -30,7 +30,7 @@ class OfflineMemoryData {
return OfflineMemoryData(
DiffPaneController.fromJson(item(_Json.diffData)),
ProfilePaneController.fromJson(item(_Json.profileData)),
MemoryChartPaneController.fromJson(item(_Json.chartData)),
ChartData.fromJson(item(_Json.chartData)),
ClassFilter.fromJson(item(_Json.classFilter)),
selectedTab: json[_Json.selectedTab] as int? ?? 0,
);
Expand All @@ -41,7 +41,7 @@ class OfflineMemoryData {

final DiffPaneController diff;
final ProfilePaneController profile;
final MemoryChartPaneController chart;
final ChartData chart;

Map<String, dynamic> toJson() {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

import 'package:devtools_app_shared/utils.dart';
import 'package:flutter/foundation.dart';

import '../../../../../shared/globals.dart';
import '../../../../../shared/utils.dart';
import '../../../shared/primitives/memory_timeline.dart';
import '../data/primitives.dart';
import 'memory_tracker.dart';
Expand All @@ -23,9 +22,9 @@ import 'memory_tracker.dart';
///
/// All interactions between chart and vm are initiated by this class.
/// So, if this class is not instantiated, the interaction does not happen.
class ChartConnection extends DisposableController
class ChartVmConnection extends DisposableController
with AutoDisposeControllerMixin {
ChartConnection(this.timeline, {required this.isAndroidChartVisible});
ChartVmConnection(this.timeline, {required this.isAndroidChartVisible});

final MemoryTimeline timeline;
final ValueListenable<bool> isAndroidChartVisible;
Expand All @@ -35,36 +34,67 @@ class ChartConnection extends DisposableController
isAndroidChartVisible: isAndroidChartVisible,
);

Timer? _pollingTimer;
bool _connected = false;
bool initialized = false;

DebounceTimer? _polling;

late final bool isDeviceAndroid;

/// Initializes the connection.
///
/// This method should be called without async gap after validation that
/// the application is still connected.
void init() {
if (initialized) return;

assert(serviceConnection.serviceManager.connectedState.value.connected);

late final isDeviceAndroid =
serviceConnection.serviceManager.vm?.operatingSystem == 'android';
isDeviceAndroid =
serviceConnection.serviceManager.vm?.operatingSystem == 'android';

addAutoDisposeListener(serviceConnection.serviceManager.connectedState, () {
final connected =
serviceConnection.serviceManager.connectedState.value.connected;
if (!connected) {
_polling?.cancel();
}
});

Future<void> maybeConnect() async {
if (_connected) return;
await serviceConnection.serviceManager.onServiceAvailable;
autoDisposeStreamSubscription(
serviceConnection.serviceManager.service!.onExtensionEvent
.listen(_memoryTracker.onMemoryData),
);

autoDisposeStreamSubscription(
serviceConnection.serviceManager.service!.onGCEvent
.listen(_memoryTracker.onGCEvent),
);
await _onPoll();
_connected = true;
}

Future<void> _onPoll() async {
_pollingTimer = null;
await _memoryTracker.pollMemory();
_pollingTimer = Timer(chartUpdateDelay, _onPoll);
_polling = DebounceTimer.periodic(
chartUpdateDelay,
() async {
if (!serviceConnection.serviceManager.connectedState.value.connected) {
_polling?.cancel();
return;
}
try {
await _memoryTracker.pollMemory();
} catch (e) {
if (serviceConnection.serviceManager.connectedState.value.connected) {
rethrow;
}
}
},
);

initialized = true;
}

@override
void dispose() {
_pollingTimer?.cancel();
_polling?.cancel();
_polling?.dispose();
_polling = null;
super.dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,80 @@ import '../../../../../shared/primitives/simple_items.dart';
import '../../../shared/primitives/memory_timeline.dart';
import '../data/primitives.dart';

class _Json {
static const isDeviceAndroid = 'isAndroid';
static const timeline = 'timeline';
static const interval = 'interval';
static const isLegendVisible = 'isLegendVisible';
}

/// Chart data, that should be saved when transferred to offline data mode.
class ChartData {
ChartData({required this.isDeviceAndroid});
ChartData({
required ControllerCreationMode mode,
this.isDeviceAndroid,
MemoryTimeline? timeline,
ChartInterval? interval,
bool? isLegendVisible,
}) : assert(
mode == ControllerCreationMode.connected ||
(mode == ControllerCreationMode.offlineData &&
isDeviceAndroid != null &&
timeline != null &&
interval != null &&
isLegendVisible != null),
),
_displayInterval =
ValueNotifier<ChartInterval>(interval ?? ChartInterval.theDefault),
_isLegendVisible = ValueNotifier<bool>(isLegendVisible ?? true) {
this.timeline = timeline ?? MemoryTimeline();
}

factory ChartData.fromJson(Map<String, dynamic> json) {
final result = ChartData(
mode: ControllerCreationMode.offlineData,
isDeviceAndroid: json[_Json.isDeviceAndroid] as bool? ?? false,
timeline:
MemoryTimeline.fromJson(json[_Json.timeline] as Map<String, dynamic>),
interval: ChartInterval.byName(json[_Json.interval]) ??
ChartInterval.theDefault,
isLegendVisible: json[_Json.isLegendVisible] as bool?,
);
return result;
}

Map<String, dynamic> toJson() {
return {
_Json.isDeviceAndroid: isDeviceAndroid ?? false,
_Json.timeline: timeline.toJson(),
_Json.interval: displayInterval.name,
_Json.isLegendVisible: isLegendVisible.value,
};
}

/// Wether device is android, if [mode] is not [DevToolsMode.connected].
/// Whether the device is an Android device.
///
/// If [mode] is [DevToolsMode.connected], this value is null
/// and chart visibility should be detected based on connected app.
final bool? isDeviceAndroid;
/// If connected to application, this value is set after the class creation,
/// by the instance owner.
bool? isDeviceAndroid;

final MemoryTimeline timeline = MemoryTimeline();
late final MemoryTimeline timeline;

/// Default is to display default tick width based on width of chart of the collected
/// data in the chart.
ChartInterval get displayInterval => _displayInterval.value;
final _displayInterval =
ValueNotifier<ChartInterval>(ChartInterval.theDefault);
final ValueNotifier<ChartInterval> _displayInterval;
set displayInterval(ChartInterval interval) {
_displayInterval.value = interval;
}

ValueListenable<bool> get isLegendVisible => _legendVisibleNotifier;
final _legendVisibleNotifier = ValueNotifier<bool>(true);
ValueListenable<bool> get isLegendVisible => _isLegendVisible;
late final ValueNotifier<bool> _isLegendVisible;
bool toggleLegendVisibility() =>
_legendVisibleNotifier.value = !_legendVisibleNotifier.value;
_isLegendVisible.value = !_isLegendVisible.value;

void dispose() {
_displayInterval.dispose();
_legendVisibleNotifier.dispose();
_isLegendVisible.dispose();
}
}
Loading
Loading