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

Side by Side Diff: runtime/bin/vmservice/client/lib/src/service/object.dart

Issue 205713004: Add isolate tag-profile and better handling of errors (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/vmservice/client/lib/src/elements/vm_view.dart ('k') | runtime/vm/isolate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of service; 5 part of service;
6 6
7 /// A [ServiceObject] is an object known to the VM service and is tied 7 /// A [ServiceObject] is an object known to the VM service and is tied
8 /// to an owning [Isolate]. 8 /// to an owning [Isolate].
9 abstract class ServiceObject extends Observable { 9 abstract class ServiceObject extends Observable {
10 /// The owner of this [ServiceObject]. This can be an [Isolate], a 10 /// The owner of this [ServiceObject]. This can be an [Isolate], a
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 46
47 @observable String name; 47 @observable String name;
48 @observable String vmName; 48 @observable String vmName;
49 49
50 /// Creates an empty [ServiceObject]. 50 /// Creates an empty [ServiceObject].
51 ServiceObject._empty(this._owner); 51 ServiceObject._empty(this._owner);
52 52
53 /// Creates a [ServiceObject] initialized from [map]. 53 /// Creates a [ServiceObject] initialized from [map].
54 factory ServiceObject._fromMap(ServiceObjectOwner owner, 54 factory ServiceObject._fromMap(ServiceObjectOwner owner,
55 ObservableMap map) { 55 ObservableMap map) {
56 if (map == null) {
57 return null;
58 }
56 if (!_isServiceMap(map)) { 59 if (!_isServiceMap(map)) {
57 Logger.root.severe('Malformed service object: $map'); 60 Logger.root.severe('Malformed service object: $map');
58 } 61 }
59 assert(_isServiceMap(map)); 62 assert(_isServiceMap(map));
60 var type = _stripRef(map['type']); 63 var type = _stripRef(map['type']);
61 var obj = null; 64 var obj = null;
62 assert(type != 'VM'); 65 assert(type != 'VM');
63 switch (type) { 66 switch (type) {
64 case 'Code': 67 case 'Code':
65 obj = new Code._empty(owner); 68 obj = new Code._empty(owner);
66 break; 69 break;
67 case 'Error': 70 case 'Error':
68 obj = new ServiceError._empty(owner); 71 obj = new DartError._empty(owner);
69 break; 72 break;
70 case 'Isolate': 73 case 'Isolate':
71 obj = new Isolate._empty(owner); 74 obj = new Isolate._empty(owner);
72 break; 75 break;
76 case 'ServiceError':
77 obj = new ServiceError._empty(owner);
78 break;
79 case 'ServiceException':
80 obj = new ServiceException._empty(owner);
81 break;
73 case 'Script': 82 case 'Script':
74 obj = new Script._empty(owner); 83 obj = new Script._empty(owner);
75 break; 84 break;
76 default: 85 default:
77 obj = new ServiceMap._empty(owner); 86 obj = new ServiceMap._empty(owner);
78 } 87 }
79 obj.update(map); 88 obj.update(map);
80 return obj; 89 return obj;
81 } 90 }
82 91
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 @observable String architecture = 'unknown'; 170 @observable String architecture = 'unknown';
162 @observable double uptime = 0.0; 171 @observable double uptime = 0.0;
163 172
164 VM() : super._empty(null) { 173 VM() : super._empty(null) {
165 name = 'vm'; 174 name = 'vm';
166 vmName = 'vm'; 175 vmName = 'vm';
167 _cache['vm'] = this; 176 _cache['vm'] = this;
168 update(toObservable({'id':'vm', 'type':'@VM'})); 177 update(toObservable({'id':'vm', 'type':'@VM'}));
169 } 178 }
170 179
180 final StreamController<ServiceException> exceptions =
181 new StreamController.broadcast();
182 final StreamController<ServiceError> errors =
183 new StreamController.broadcast();
184
171 static final RegExp _currentIsolateMatcher = new RegExp(r'isolates/\d+'); 185 static final RegExp _currentIsolateMatcher = new RegExp(r'isolates/\d+');
172 static final RegExp _currentObjectMatcher = new RegExp(r'isolates/\d+(/|$)'); 186 static final RegExp _currentObjectMatcher = new RegExp(r'isolates/\d+/');
173 static final String _isolatesPrefix = 'isolates/'; 187 static final String _isolatesPrefix = 'isolates/';
174 188
175 String _parseObjectId(String id) { 189 String _parseObjectId(String id) {
176 Match m = _currentObjectMatcher.matchAsPrefix(id); 190 Match m = _currentObjectMatcher.matchAsPrefix(id);
177 if (m == null) { 191 if (m == null) {
178 return null; 192 return null;
179 } 193 }
180 return m.input.substring(m.end); 194 return m.input.substring(m.end);
181 } 195 }
182 196
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 // Cache miss. Get the object from the vm directly. 255 // Cache miss. Get the object from the vm directly.
242 return getAsMap(id).then((ObservableMap map) { 256 return getAsMap(id).then((ObservableMap map) {
243 var obj = new ServiceObject._fromMap(this, map); 257 var obj = new ServiceObject._fromMap(this, map);
244 if (obj.canCache) { 258 if (obj.canCache) {
245 _cache.putIfAbsent(id, () => obj); 259 _cache.putIfAbsent(id, () => obj);
246 } 260 }
247 return obj; 261 return obj;
248 }); 262 });
249 } 263 }
250 264
251 /// Gets [id] as an [ObservableMap] from the service directly. 265 /// Gets [id] as an [ObservableMap] from the service directly. If
266 /// an error occurs, the future is completed as an error with a
267 /// ServiceError or ServiceException. Therefore any chained then() calls
268 /// will only receive a map encoding a valid ServiceObject.
252 Future<ObservableMap> getAsMap(String id) { 269 Future<ObservableMap> getAsMap(String id) {
253 return getString(id).then((response) { 270 return getString(id).then((response) {
254 try { 271 try {
255 var map = JSON.decode(response); 272 var map = toObservable(JSON.decode(response));
256 return toObservable(map); 273 // Verify that the top level response is a service map.
274 if (!_isServiceMap(map)) {
275 return new Future.error(
276 new ServiceObject._fromMap(this, toObservable({
277 'type': 'ServiceException',
278 'id': '',
279 'kind': 'FormatException',
280 'response': map,
281 'message': 'Top level service responses must be service maps.',
282 })));
283 }
284 // Preemptively capture ServiceError and ServiceExceptions.
285 if (map['type'] == 'ServiceError') {
286 return new Future.error(new ServiceObject._fromMap(this, map));
287 } else if (map['type'] == 'ServiceException') {
288 return new Future.error(new ServiceObject._fromMap(this, map));
289 }
290 // map is now guaranteed to be a non-error/exception ServiceObject.
291 return map;
257 } catch (e, st) { 292 } catch (e, st) {
258 return toObservable({ 293 print(e);
259 'type': 'Error', 294 print(st);
295 return new Future.error(
296 new ServiceObject._fromMap(this, toObservable({
297 'type': 'ServiceException',
260 'id': '', 298 'id': '',
261 'kind': 'DecodeError', 299 'kind': 'DecodeException',
262 'message': '$e', 300 'response': response,
263 }); 301 'message': 'Could not decode JSON: $e',
302 })));
264 } 303 }
265 }).catchError((error) { 304 }).catchError((error) {
266 return toObservable({ 305 // ServiceError, forward to VM's ServiceError stream.
267 'type': 'Error', 306 errors.add(error);
268 'id': '', 307 return new Future.error(error);
269 'kind': 'LastResort', 308 }, test: (e) => e is ServiceError).catchError((exception) {
270 'message': '$error' 309 // ServiceException, forward to VM's ServiceException stream.
271 }); 310 exceptions.add(exception);
272 }); 311 return new Future.error(exception);
312 }, test: (e) => e is ServiceException);
273 } 313 }
274 314
275 /// Get [id] as a [String] from the service directly. See [getAsMap]. 315 /// Get [id] as a [String] from the service directly. See [getAsMap].
276 Future<String> getString(String id); 316 Future<String> getString(String id);
277 317
278 void _update(ObservableMap map, bool mapIsRef) { 318 void _update(ObservableMap map, bool mapIsRef) {
279 if (mapIsRef) { 319 if (mapIsRef) {
280 return; 320 return;
281 } 321 }
282 _loaded = true; 322 _loaded = true;
(...skipping 19 matching lines...) Expand all
302 } 342 }
303 // Update the individual isolates asynchronously. 343 // Update the individual isolates asynchronously.
304 newIsolateCache.forEach((isolateId, isolate) { 344 newIsolateCache.forEach((isolateId, isolate) {
305 isolate.reload(); 345 isolate.reload();
306 }); 346 });
307 347
308 _isolateCache = newIsolateCache; 348 _isolateCache = newIsolateCache;
309 } 349 }
310 } 350 }
311 351
352 /// Snapshot in time of tag counters.
353 class TagProfileSnapshot {
354 final double seconds;
355 final List<int> counters;
356 int get sum => _sum;
357 int _sum = 0;
358 TagProfileSnapshot(this.seconds, int countersLength)
359 : counters = new List<int>(countersLength);
360
361 /// Set [counters] and update [sum].
362 void set(List<int> counters) {
363 this.counters.setAll(0, counters);
364 for (var i = 0; i < this.counters.length; i++) {
365 _sum += this.counters[i];
366 }
367 }
368
369 /// Set [counters] with the delta from [counters] to [old_counters]
370 /// and update [sum].
371 void delta(List<int> counters, List<int> old_counters) {
372 for (var i = 0; i < this.counters.length; i++) {
373 this.counters[i] = counters[i] - old_counters[i];
374 _sum += this.counters[i];
375 }
376 }
377
378 /// Update [counters] with new maximum values seen in [counters].
379 void max(List<int> counters) {
380 for (var i = 0; i < counters.length; i++) {
381 var c = counters[i];
382 this.counters[i] = this.counters[i] > c ? this.counters[i] : c;
383 }
384 }
385
386 /// Zero [counters].
387 void zero() {
388 for (var i = 0; i < counters.length; i++) {
389 counters[i] = 0;
390 }
391 }
392 }
393
394 class TagProfile {
395 final List<String> names = new List<String>();
396 final List<TagProfileSnapshot> snapshots = new List<TagProfileSnapshot>();
397 double get updatedAtSeconds => _seconds;
398 double _seconds;
399 TagProfileSnapshot _maxSnapshot;
400 int _historySize;
401 int _countersLength = 0;
402
403 TagProfile(this._historySize);
404
405 void _processTagProfile(double seconds, ObservableMap tagProfile) {
406 _seconds = seconds;
407 var counters = tagProfile['counters'];
408 if (names.length == 0) {
409 // Initialization.
410 names.addAll(tagProfile['names']);
411 _countersLength = tagProfile['counters'].length;
412 for (var i = 0; i < _historySize; i++) {
413 var snapshot = new TagProfileSnapshot(0.0, _countersLength);
414 snapshot.zero();
415 snapshots.add(snapshot);
416 }
417 // The counters monotonically grow, keep track of the maximum value.
418 _maxSnapshot = new TagProfileSnapshot(0.0, _countersLength);
419 _maxSnapshot.set(counters);
420 return;
421 }
422 var snapshot = new TagProfileSnapshot(seconds, _countersLength);
423 // We snapshot the delta from the current counters to the maximum counter
424 // values.
425 snapshot.delta(counters, _maxSnapshot.counters);
426 _maxSnapshot.max(counters);
427 snapshots.add(snapshot);
428 // Only keep _historySize snapshots.
429 if (snapshots.length > _historySize) {
430 snapshots.removeAt(0);
431 }
432 }
433 }
434
312 /// State for a running isolate. 435 /// State for a running isolate.
313 class Isolate extends ServiceObjectOwner { 436 class Isolate extends ServiceObjectOwner {
314 @reflectable VM get vm => owner; 437 @reflectable VM get vm => owner;
315 @reflectable Isolate get isolate => this; 438 @reflectable Isolate get isolate => this;
316 439
317 String get link => _id; 440 String get link => _id;
318 String get hashLink => '#/$_id'; 441 String get hashLink => '#/$_id';
319 442
320 @observable bool pausedOnStart = false; 443 @observable bool pausedOnStart = false;
321 @observable bool pausedOnExit = false; 444 @observable bool pausedOnExit = false;
322 @observable bool running = false; 445 @observable bool running = false;
323 @observable bool idle = false; 446 @observable bool idle = false;
324 447
325 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); 448 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
449 final TagProfile tagProfile = new TagProfile(20);
326 450
327 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner); 451 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) {
452 assert(owner is VM);
453 }
328 454
329 /// Creates a link to [id] relative to [this]. 455 /// Creates a link to [id] relative to [this].
330 @reflectable String relativeLink(String id) => '${this.id}/$id'; 456 @reflectable String relativeLink(String id) => '${this.id}/$id';
331 /// Creates a relative link to [id] with a '#/' prefix. 457 /// Creates a relative link to [id] with a '#/' prefix.
332 @reflectable String relativeHashLink(String id) => '#/${relativeLink(id)}'; 458 @reflectable String relativeHashLink(String id) => '#/${relativeLink(id)}';
333 459
334 static const TAG_ROOT_ID = 'code/tag-0'; 460 static const TAG_ROOT_ID = 'code/tag-0';
335 461
336 /// Returns the Code object for the root tag. 462 /// Returns the Code object for the root tag.
337 Code tagRoot() { 463 Code tagRoot() {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 } 531 }
406 // Build the object from the map directly. 532 // Build the object from the map directly.
407 obj = new ServiceObject._fromMap(this, map); 533 obj = new ServiceObject._fromMap(this, map);
408 if (obj.canCache) { 534 if (obj.canCache) {
409 _cache[id] = obj; 535 _cache[id] = obj;
410 } 536 }
411 return obj; 537 return obj;
412 } 538 }
413 539
414 Future<ServiceObject> get(String id) { 540 Future<ServiceObject> get(String id) {
541 // Do not allow null ids or empty ids.
542 assert(id != null && id != '');
415 var obj = _cache[id]; 543 var obj = _cache[id];
416 if (obj != null) { 544 if (obj != null) {
417 return obj.reload(); 545 return obj.reload();
418 } 546 }
419 // Cache miss. Get the object from the vm directly. 547 // Cache miss. Get the object from the vm directly.
420 return vm.getAsMap(relativeLink(id)).then((ObservableMap map) { 548 return vm.getAsMap(relativeLink(id)).then((ObservableMap map) {
421 var obj = new ServiceObject._fromMap(this, map); 549 var obj = new ServiceObject._fromMap(this, map);
422 if (obj.canCache) { 550 if (obj.canCache) {
423 _cache.putIfAbsent(id, () => obj); 551 _cache.putIfAbsent(id, () => obj);
424 } 552 }
(...skipping 12 matching lines...) Expand all
437 @observable final Map<String, double> timers = 565 @observable final Map<String, double> timers =
438 toObservable(new Map<String, double>()); 566 toObservable(new Map<String, double>());
439 567
440 @observable int newHeapUsed = 0; 568 @observable int newHeapUsed = 0;
441 @observable int oldHeapUsed = 0; 569 @observable int oldHeapUsed = 0;
442 @observable int newHeapCapacity = 0; 570 @observable int newHeapCapacity = 0;
443 @observable int oldHeapCapacity = 0; 571 @observable int oldHeapCapacity = 0;
444 572
445 @observable String fileAndLine; 573 @observable String fileAndLine;
446 574
575 @observable DartError error;
576
447 void _update(ObservableMap map, bool mapIsRef) { 577 void _update(ObservableMap map, bool mapIsRef) {
448 mainPort = map['mainPort']; 578 mainPort = map['mainPort'];
449 name = map['name']; 579 name = map['name'];
450 vmName = map['name']; 580 vmName = map['name'];
451 if (mapIsRef) { 581 if (mapIsRef) {
452 return; 582 return;
453 } 583 }
454 _loaded = true; 584 _loaded = true;
455 _upgradeCollection(map, isolate); 585 _upgradeCollection(map, isolate);
456 if (map['rootLib'] == null || 586 if (map['rootLib'] == null ||
(...skipping 28 matching lines...) Expand all
485 newHeapUsed = map['heap']['usedNew']; 615 newHeapUsed = map['heap']['usedNew'];
486 oldHeapUsed = map['heap']['usedOld']; 616 oldHeapUsed = map['heap']['usedOld'];
487 newHeapCapacity = map['heap']['capacityNew']; 617 newHeapCapacity = map['heap']['capacityNew'];
488 oldHeapCapacity = map['heap']['capacityOld']; 618 oldHeapCapacity = map['heap']['capacityOld'];
489 619
490 // Isolate status 620 // Isolate status
491 pausedOnStart = map['pausedOnStart']; 621 pausedOnStart = map['pausedOnStart'];
492 pausedOnExit = map['pausedOnExit']; 622 pausedOnExit = map['pausedOnExit'];
493 running = map['topFrame'] != null; 623 running = map['topFrame'] != null;
494 idle = !pausedOnStart && !pausedOnExit && !running; 624 idle = !pausedOnStart && !pausedOnExit && !running;
625 error = map['error'];
626 }
627
628 Future<TagProfile> updateTagProfile() {
629 return vm.getAsMap(relativeLink('profile/tag')).then((ObservableMap m) {
630 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0;
631 tagProfile._processTagProfile(seconds, m);
632 return tagProfile;
633 });
495 } 634 }
496 635
497 @reflectable CodeTrieNode profileTrieRoot; 636 @reflectable CodeTrieNode profileTrieRoot;
498 // The profile trie is serialized as a list of integers. Each node 637 // The profile trie is serialized as a list of integers. Each node
499 // is recreated by consuming some portion of the list. The format is as 638 // is recreated by consuming some portion of the list. The format is as
500 // follows: 639 // follows:
501 // [0] index into codeTable of code object. 640 // [0] index into codeTable of code object.
502 // [1] tick count (number of times this stack frame occured). 641 // [1] tick count (number of times this stack frame occured).
503 // [2] child node count 642 // [2] child node count
504 // Reading the trie is done by recursively reading the tree depth-first 643 // Reading the trie is done by recursively reading the tree depth-first
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 bool deliverChanges() => _map.deliverChanges(); 735 bool deliverChanges() => _map.deliverChanges();
597 void notifyChange(ChangeRecord record) => _map.notifyChange(record); 736 void notifyChange(ChangeRecord record) => _map.notifyChange(record);
598 notifyPropertyChange(Symbol field, Object oldValue, Object newValue) => 737 notifyPropertyChange(Symbol field, Object oldValue, Object newValue) =>
599 _map.notifyPropertyChange(field, oldValue, newValue); 738 _map.notifyPropertyChange(field, oldValue, newValue);
600 void observed() => _map.observed(); 739 void observed() => _map.observed();
601 void unobserved() => _map.unobserved(); 740 void unobserved() => _map.unobserved();
602 Stream<List<ChangeRecord>> get changes => _map.changes; 741 Stream<List<ChangeRecord>> get changes => _map.changes;
603 bool get hasObservers => _map.hasObservers; 742 bool get hasObservers => _map.hasObservers;
604 } 743 }
605 744
745 /// A [DartError] is peered to a Dart Error object.
746 class DartError extends ServiceObject {
747 DartError._empty(ServiceObject owner) : super._empty(owner);
748
749 @observable String kind;
750 @observable String message;
751 @observable ServiceMap exception;
752 @observable ServiceMap stacktrace;
753
754 void _update(ObservableMap map, bool mapIsRef) {
755 kind = map['kind'];
756 message = map['message'];
757 exception = new ServiceObject._fromMap(owner, map['exception']);
758 stacktrace = new ServiceObject._fromMap(owner, map['stacktrace']);
759 name = 'DartError $kind';
760 vmName = name;
761 }
762 }
763
764 /// A [ServiceError] is an error that was triggered in the service
765 /// server or client. Errors are prorammer mistakes that could have
766 /// been prevented, for example, requesting a non-existant path over the
767 /// service.
606 class ServiceError extends ServiceObject { 768 class ServiceError extends ServiceObject {
607 ServiceError._empty(ServiceObjectOwner owner) : super._empty(owner); 769 ServiceError._empty(ServiceObjectOwner owner) : super._empty(owner);
608 770
609 @observable String kind; 771 @observable String kind;
610 @observable String message; 772 @observable String message;
611 773
612 void _update(ObservableMap map, bool mapIsRef) { 774 void _update(ObservableMap map, bool mapIsRef) {
613 _loaded = true; 775 _loaded = true;
614 kind = map['kind']; 776 kind = map['kind'];
615 message = map['message']; 777 message = map['message'];
616 name = 'ServiceError $kind'; 778 name = 'ServiceError $kind';
617 vmName = name; 779 vmName = name;
618 } 780 }
781 }
619 782
620 // TODO: stackTrace? 783 /// A [ServiceException] is an exception that was triggered in the service
784 /// server or client. Exceptions are events that should be handled,
785 /// for example, an isolate went away or the connection to the VM was lost.
786 class ServiceException extends ServiceObject {
787 ServiceException._empty(ServiceObject owner) : super._empty(owner);
788
789 @observable String kind;
790 @observable String message;
791 @observable dynamic response;
792
793 void _update(ObservableMap map, bool mapIsRef) {
794 kind = map['kind'];
795 message = map['message'];
796 response = map['response'];
797 name = 'ServiceException $kind';
798 vmName = name;
799 }
621 } 800 }
622 801
623 class ScriptLine { 802 class ScriptLine {
624 @reflectable final int line; 803 @reflectable final int line;
625 @reflectable final String text; 804 @reflectable final String text;
626 ScriptLine(this.line, this.text); 805 ScriptLine(this.line, this.text);
627 } 806 }
628 807
629 class Script extends ServiceObject { 808 class Script extends ServiceObject {
630 @reflectable final lines = new ObservableList<ScriptLine>(); 809 @reflectable final lines = new ObservableList<ScriptLine>();
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
993 var v = list[i]; 1172 var v = list[i];
994 if ((v is ObservableMap) && _isServiceMap(v)) { 1173 if ((v is ObservableMap) && _isServiceMap(v)) {
995 list[i] = owner.getFromMap(v); 1174 list[i] = owner.getFromMap(v);
996 } else if (v is ObservableList) { 1175 } else if (v is ObservableList) {
997 _upgradeObservableList(v, owner); 1176 _upgradeObservableList(v, owner);
998 } else if (v is ObservableMap) { 1177 } else if (v is ObservableMap) {
999 _upgradeObservableMap(v, owner); 1178 _upgradeObservableMap(v, owner);
1000 } 1179 }
1001 } 1180 }
1002 } 1181 }
OLDNEW
« no previous file with comments | « runtime/bin/vmservice/client/lib/src/elements/vm_view.dart ('k') | runtime/vm/isolate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698