Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1058)

Unified Diff: pkg/compiler/tool/track_memory.dart

Issue 1384833002: add tool to track memory watermark (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/tool/track_memory.dart
diff --git a/pkg/compiler/tool/track_memory.dart b/pkg/compiler/tool/track_memory.dart
new file mode 100644
index 0000000000000000000000000000000000000000..effd92f000fb3b93fad985d8be7892f6a96b9d8d
--- /dev/null
+++ b/pkg/compiler/tool/track_memory.dart
@@ -0,0 +1,193 @@
+// Copyright (c) 2015, 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.
+
+/// A script to track the high water-mark of memory usage of an application.
+/// To monitor how much memory dart2js is using, run dart2js as follows:
+///
+/// DART_VM_OPTIONS=--observe dart2js ...
+///
+/// and run this script immediately after.
+library compiler.tool.track_memory;
+
+import 'dart:math' show max;
+import 'dart:io';
+import 'dart:async';
+
+import 'dart:convert';
+
+/// Socket to connect to the vm observatory service.
+WebSocket socket;
+
+main(args) async {
+ _printHeader();
+ _showProgress(0, 0, 0, 0);
+ try {
+ var port = args.length > 0 ? int.parse(args[0]) : 8181;
+ socket = await WebSocket.connect('ws://localhost:$port/ws');
+ socket.listen(_handleResponse);
+ await _resumeMainIsolateIfPaused();
+ _streamListen('GC');
+ _streamListen('Isolate');
+ _streamListen('Debug');
+ } catch (e) {
+ // TODO(sigmund): add better error messages, maybe option to retry.
+ print('\n${_RED}error${_NONE}: $e');
+ print('usage:\n'
+ ' Start a Dart process with the --observe flag (and optionally '
+ 'the --pause_isolates_on_start flag), then invoke:\n'
+ ' dart tool/track_memory.dart [<port>]\n'
+ ' by default port is 8181');
+ }
+}
+
+/// Internal counter for request ids.
+int _requestId = 0;
+Map _pendingResponses = {};
+
+/// Subscribe to listen to a vm service data stream.
+_streamListen(String streamId) =>
+ _sendMessage('streamListen', {'streamId': '$streamId'});
+
+/// Tell the vm service to resume a specific isolate.
+_resumeIsolate(String isolateId) =>
+ _sendMessage('resume', {'isolateId': '$isolateId'});
+
+/// Resumes the main isolate if it was paused on start.
+_resumeMainIsolateIfPaused() async {
+ var vm = await _sendMessage('getVM');
+ var isolateId = vm['isolates'][0]['id'];
+ var isolate = await _sendMessage('getIsolate', {'isolateId': isolateId});
+ bool isPaused = isolate['pauseEvent']['kind'] == 'PauseStart';
+ if (isPaused) _resumeIsolate(isolateId);
+}
+
+/// Send a message to the vm service.
+Future _sendMessage(String method, [Map args= const {}]) {
+ var id = _requestId++;
+ _pendingResponses[id] = new Completer();
+ socket.add(JSON.encode({
+ 'jsonrpc': '2.0',
+ 'id': '$id',
+ 'method': '$method',
+ 'params': args,
+ }));
+ return _pendingResponses[id].future;
+}
+
+/// Handle all responses
+_handleResponse(String s) {
+ var json = JSON.decode(s);
+ if (json['method'] != 'streamNotify') {
+ var id = json['id'];
+ if (id is String) id = int.parse(id);
+ if (id == null || !_pendingResponses.containsKey(id)) return;
+ _pendingResponses.remove(id).complete(json['result']);
+ return;
+ }
+
+ // isolate pauses on exit automatically. We detect this to stop and exit.
+ if (json['params']['streamId'] == 'Debug') {
+ _handleDebug(json);
+ } else if (json['params']['streamId'] == 'Isolate') {
+ _handleIsolate(json);
+ } else if (json['params']['streamId'] == 'GC') {
+ _handleGC(json);
+ }
+}
+
+/// Handle a `Debug` notification.
+_handleDebug(Map json) {
+ var isolateId = json['params']['event']['isolate']['id'];
+ if (json['params']['event']['kind'] == 'PauseStart') {
+ _resumeIsolate(isolateId);
+ } if (json['params']['event']['kind'] == 'PauseExit') {
+ _resumeIsolate(isolateId);
+ }
+}
+
+/// Handle a `Isolate` notification.
+_handleIsolate(Map json) {
+ if (json['params']['event']['kind'] == 'IsolateExit') {
+ print('');
+ socket.close();
+ }
+}
+
+/// Handle a `GC` notification.
+_handleGC(Map json) {
+ // print(new JsonEncoder.withIndent(' ').convert(json));
+ var event = json['params']['event'];
+ var newUsed = event['new']['used'];
+ var newCapacity = event['new']['capacity'];
+ var oldUsed = event['old']['used'];
+ var oldCapacity = event['old']['capacity'];
+ _showProgress(newUsed, newCapacity, oldUsed, oldCapacity);
+}
+
+int lastNewUsed = 0;
+int lastOldUsed = 0;
+int lastMaxUsed = 0;
+int lastNewCapacity = 0;
+int lastOldCapacity = 0;
+int lastMaxCapacity = 0;
+
+/// Shows a status line with use/capacity numbers for new/old/total/max,
+/// highlighting in red when capacity increases, and in green when it decreases.
+_showProgress(newUsed, newCapacity, oldUsed, oldCapacity) {
+ var sb = new StringBuffer();
+ sb.write('\r '); // replace the status-line in place
+ _writeNumber(sb, lastNewUsed, newUsed);
+ _writeNumber(sb, lastNewCapacity, newCapacity, color: true);
+
+ sb.write(' | ');
+ _writeNumber(sb, lastOldUsed, oldUsed);
+ _writeNumber(sb, lastOldCapacity, oldCapacity, color: true);
+
+ sb.write(' | ');
+ _writeNumber(sb, lastNewUsed + lastOldUsed, newUsed + oldUsed);
+ _writeNumber(sb, lastNewCapacity + lastOldCapacity, newCapacity + oldCapacity,
+ color: true);
+
+ sb.write(' | ');
+ var maxUsed = max(lastMaxUsed, newUsed + oldUsed);
+ var maxCapacity = max(lastMaxCapacity, newCapacity + oldCapacity);
+ _writeNumber(sb, lastMaxUsed, maxUsed);
+ _writeNumber(sb, lastMaxCapacity, maxCapacity, color: true);
+ stdout.write('$sb');
+
+ lastNewUsed = newUsed;
+ lastOldUsed = oldUsed;
+ lastMaxUsed = maxUsed;
+ lastNewCapacity = newCapacity;
+ lastOldCapacity = oldCapacity;
+ lastMaxCapacity = maxCapacity;
+}
+
+const mega = 1024 * 1024;
+_writeNumber(sb, before, now, {color: false}) {
+ if (color) sb.write(before < now ? _RED : before > now ? _GREEN : '');
+ var string;
+ if (now < 1024) {
+ string = ' ${now}b';
+ } else if (now < mega) {
+ string = ' ${(now/1024).toStringAsFixed(0)}K';
+ } else {
+ string = ' ${(now/mega).toStringAsFixed(1)}M';
+ }
+ if (string.length < 10) string = '${' ' * (8 - string.length)}$string';
+ sb.write(string);
+ if (color) sb.write(before != now ? _NONE : '');
+ return before > now;
+}
+
+_printHeader() {
+ print('''
+Memory usage:
+ new generation | old generation | total | max
+ in-use/capacity | in-use/capacity | in-use/capacity | in-use/capacity ''');
+}
+
+const _RED = '\x1b[31m';
+const _GREEN = '\x1b[32m';
+const _NONE = '\x1b[0m';
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698