-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add auto-snapshotting and analytics for memory usage.
See video linked to issue: flutter/devtools#5606 Change-Id: I9f22031871e30bc7160e2c49b0423fb64df62223 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/300862 Reviewed-by: Samuel Rawlins <[email protected]> Reviewed-by: Jacob Richman <[email protected]>
- Loading branch information
Showing
7 changed files
with
230 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
pkg/analysis_server/lib/src/utilities/usage_tracking/AUTOSNAPSHOTTING.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Auto-snapshotting | ||
|
||
IMPORTANT: memory snapshots should not be requested from external users because they may contain PII. | ||
|
||
If a user reports that the process `dart:analysis_server.dart.snapshot` takes too much memory, | ||
and the issue is hard to reproduce, you may want to request memory snapshots from the user. | ||
|
||
## Request numbers | ||
|
||
Ask user to provide memory footprint for the process `dart:analysis_server.dart.snapshot`. | ||
If there are many instances of the process, ask for the biggest memory footprint among | ||
the instances. | ||
|
||
- **Mac**: column 'Real Mem' in 'Activity Monitor' | ||
- **Windows**: TODO: add content | ||
- **Linux**: TODO: add content | ||
|
||
## Create auto-snapshotting argument | ||
|
||
Based on the reported and expected values, construct auto-snapshotting argument. See example in | ||
the [test file](../../../../test/utilities/autosnapshotting/autosnapshotting_test.dart), the | ||
constant `_autosnapshottingArg`. | ||
|
||
See explanation of parameters in | ||
[documentation for AutoSnapshottingConfig](https://github.com/dart-lang/leak_tracker/blob/main/lib/src/autosnapshotting/model.dart). | ||
|
||
## Instruct user to configure analyzer | ||
|
||
Pass the created argument to the user and instruct them to configure | ||
analyzer. | ||
|
||
### For VSCode | ||
|
||
1. Open Settings > Extensions > Dart > Analyser | ||
2. Add the argument to `Dart: Analyzer Additional Args` | ||
|
||
### For Android Studio | ||
|
||
1. Double-press Shift | ||
2. Type 'Registry' into search field | ||
3. Click 'Registry...' | ||
4. Add the argument to the value of the key 'dart.server.additional.arguments' | ||
|
||
## Analyze snapshots | ||
|
||
Ask user to provide the collected snapshots and analyze them. | ||
|
||
TODO (polina-c): link DevTools documentation | ||
|
||
|
97 changes: 97 additions & 0 deletions
97
pkg/analysis_server/lib/src/utilities/usage_tracking/usage_tracking.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file | ||
// for details. 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:args/args.dart'; | ||
import 'package:collection/collection.dart'; | ||
import 'package:leak_tracker/src/usage_tracking/model.dart'; | ||
import 'package:leak_tracker/src/usage_tracking/usage_tracking.dart'; | ||
|
||
void configureMemoryUsageTracking( | ||
List<String> arguments, | ||
UsageCallback callback, | ||
) { | ||
final config = UsageTrackingConfig( | ||
interval: const Duration(seconds: 1), | ||
usageEventsConfig: UsageEventsConfig( | ||
callback, | ||
deltaMb: 512, | ||
), | ||
autoSnapshottingConfig: parseAutoSnapshottingConfig(arguments), | ||
); | ||
|
||
trackMemoryUsage(config); | ||
} | ||
|
||
/// Parses the config for autosnapshotting from CLI [args]. | ||
/// | ||
/// See example of config in tests for this function. | ||
/// | ||
/// If there is no argument that starts with '--autosnapshotting=', returns null. | ||
/// | ||
/// In case of error throws exception. | ||
AutoSnapshottingConfig? parseAutoSnapshottingConfig(List<String> args) { | ||
const argName = 'autosnapshotting'; | ||
final arg = args.firstWhereOrNull((a) => a.contains('--$argName')); | ||
if (arg == null) return null; | ||
|
||
var parser = ArgParser()..addMultiOption(argName, splitCommas: true); | ||
|
||
final parsedArgs = parser.parse([arg]); | ||
assert(parsedArgs.options.contains(argName)); | ||
|
||
final values = parsedArgs[argName] as List<String>; | ||
if (values.isEmpty) return null; | ||
|
||
final items = Map.fromEntries(values.map((e) { | ||
final keyValue = e.split('='); | ||
if (keyValue.length != 2) { | ||
throw ArgumentError( | ||
'Invalid auto-snapshotting config: $values.\n' | ||
'Expected "key-value", got "$e".', | ||
); | ||
} | ||
|
||
final keyString = keyValue[0]; | ||
try { | ||
final key = _Keys.values.byName(keyString); | ||
return MapEntry(key, keyValue[1]); | ||
} on ArgumentError { | ||
throw ArgumentError('Invalid auto-snapshotting key: $keyString".'); | ||
} | ||
})); | ||
|
||
if (!items.containsKey(_Keys.dir)) { | ||
throw ArgumentError( | ||
'${_Keys.dir.name} should be provided for auto-snapshotting.'); | ||
} | ||
|
||
return AutoSnapshottingConfig( | ||
thresholdMb: _parseKey(_Keys.thresholdMb, items, 7000), | ||
increaseMb: _parseKey(_Keys.increaseMb, items, 500), | ||
directory: items[_Keys.dir]!, | ||
directorySizeLimitMb: _parseKey(_Keys.dirLimitMb, items, 30000), | ||
minDelayBetweenSnapshots: Duration( | ||
seconds: _parseKey(_Keys.delaySec, items, 20), | ||
), | ||
); | ||
} | ||
|
||
int _parseKey(_Keys key, Map<_Keys, String> items, int defaultValue) { | ||
final value = items[key]; | ||
if (value == null || value.trim().isEmpty) return defaultValue; | ||
final result = int.tryParse(value); | ||
if (result == null) { | ||
throw ArgumentError( | ||
'Invalid auto-snapshotting value for ${key.name}: $value.'); | ||
} | ||
return result; | ||
} | ||
|
||
enum _Keys { | ||
thresholdMb, | ||
increaseMb, | ||
dir, | ||
dirLimitMb, | ||
delaySec, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
pkg/analysis_server/test/utilities/usage_tracking/usage_tracking_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file | ||
// for details. 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:analysis_server/src/utilities/usage_tracking/usage_tracking.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
group('parseAutoSnapshottingConfig', () { | ||
test('parses correct config', () { | ||
final config = parseAutoSnapshottingConfig(_argsWithSnapshotting)!; | ||
|
||
expect(config.thresholdMb, 200); | ||
expect(config.increaseMb, 100); | ||
expect(config.directory, '/Users/polinach/Downloads/analyzer_snapshots'); | ||
expect(config.directorySizeLimitMb, 10000); | ||
expect(config.minDelayBetweenSnapshots, Duration(seconds: 20)); | ||
}); | ||
|
||
test('returns null for no config', () { | ||
final config = parseAutoSnapshottingConfig(_argsNoSnapshotting); | ||
expect(config, null); | ||
}); | ||
|
||
test('throws for wrong config', () { | ||
final wrongAutosnapshottingArg = | ||
'--autosnapshotting--wrong-configuration'; | ||
|
||
expect( | ||
() => parseAutoSnapshottingConfig( | ||
[wrongAutosnapshottingArg, 'some other arg']), | ||
throwsA(isA<Object>()), | ||
); | ||
}); | ||
}); | ||
} | ||
|
||
const _argsNoSnapshotting = [ | ||
'--sdk=C:/b/s/w/ir/x/w/sdk/sdk/', | ||
'--train-using=C:/b/s/w/ir/x/w/sdk/pkg/compiler/lib' | ||
]; | ||
|
||
const _argsWithSnapshotting = [ | ||
_autosnapshottingArg, | ||
'--sdk=C:/b/s/w/ir/x/w/sdk/sdk/', | ||
'--train-using=C:/b/s/w/ir/x/w/sdk/pkg/compiler/lib' | ||
]; | ||
|
||
// This constant is referenced in README.md for auto-snapshotting. | ||
const _autosnapshottingArg = | ||
'--autosnapshotting=thresholdMb=200,increaseMb=100,dir=/Users/polinach/Downloads/analyzer_snapshots,dirLimitMb=10000,delaySec=20'; |