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

Side by Side Diff: runtime/observatory/lib/src/service/object.dart

Issue 961483002: Fix isolate lifecycle handling in service library (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 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
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] represents a persistent object within the vm. 7 /// A [ServiceObject] represents a persistent object within the vm.
8 abstract class ServiceObject extends Observable { 8 abstract class ServiceObject extends Observable {
9 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { 9 static int LexicalSortName(ServiceObject o1, ServiceObject o2) {
10 return o1.name.compareTo(o2.name); 10 return o1.name.compareTo(o2.name);
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 /// The result may come from the cache. The result will not necessarily 320 /// The result may come from the cache. The result will not necessarily
321 /// be [loaded]. 321 /// be [loaded].
322 ServiceObject getFromMap(ObservableMap map); 322 ServiceObject getFromMap(ObservableMap map);
323 } 323 }
324 324
325 /// State for a VM being inspected. 325 /// State for a VM being inspected.
326 abstract class VM extends ServiceObjectOwner { 326 abstract class VM extends ServiceObjectOwner {
327 @reflectable VM get vm => this; 327 @reflectable VM get vm => this;
328 @reflectable Isolate get isolate => null; 328 @reflectable Isolate get isolate => null;
329 329
330 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache.
331 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
332 final ObservableMap<String,Isolate> _isolateCache =
333 new ObservableMap<String,Isolate>();
334
330 @reflectable Iterable<Isolate> get isolates => _isolateCache.values; 335 @reflectable Iterable<Isolate> get isolates => _isolateCache.values;
331 336
332 @observable String version = 'unknown'; 337 @observable String version = 'unknown';
333 @observable String targetCPU; 338 @observable String targetCPU;
334 @observable int architectureBits; 339 @observable int architectureBits;
335 @observable double uptime = 0.0; 340 @observable double uptime = 0.0;
336 @observable bool assertsEnabled = false; 341 @observable bool assertsEnabled = false;
337 @observable bool typeChecksEnabled = false; 342 @observable bool typeChecksEnabled = false;
338 @observable String pid = ''; 343 @observable String pid = '';
339 @observable DateTime lastUpdate; 344 @observable DateTime lastUpdate;
340 345
341 VM() : super._empty(null) { 346 VM() : super._empty(null) {
342 name = 'vm'; 347 name = 'vm';
343 vmName = 'vm'; 348 vmName = 'vm';
344 _cache['vm'] = this; 349 _cache['vm'] = this;
345 update(toObservable({'id':'vm', 'type':'@VM'})); 350 update(toObservable({'id':'vm', 'type':'@VM'}));
346 } 351 }
347 352
348 final StreamController<ServiceException> exceptions = 353 final StreamController<ServiceException> exceptions =
349 new StreamController.broadcast(); 354 new StreamController.broadcast();
350 final StreamController<ServiceError> errors = 355 final StreamController<ServiceError> errors =
351 new StreamController.broadcast(); 356 new StreamController.broadcast();
352 final StreamController<ServiceEvent> events = 357 final StreamController<ServiceEvent> events =
353 new StreamController.broadcast(); 358 new StreamController.broadcast();
354 359
355 void postEventMessage(String eventMessage, [dynamic data]) { 360 bool _isIsolateLifecycleEvent(String eventType) {
356 var map; 361 return _isIsolateShutdownEvent(eventType) ||
357 try { 362 _isIsolateCreatedEvent(eventType);
358 map = _parseJSON(eventMessage);
359 assert(!map.containsKey('_data'));
360 if (data != null) {
361 map['_data'] = data;
362 }
363 } catch (e, st) {
364 Logger.root.severe('Ignoring malformed event message: ${eventMessage}');
365 return;
366 }
367 if (map['type'] != 'ServiceEvent') {
368 Logger.root.severe(
369 "Expected 'ServiceEvent' but found '${map['type']}'");
370 return;
371 }
372
373 // Extract the owning isolate from the event itself.
374 String owningIsolateId = map['isolate']['id'];
375 getIsolate(owningIsolateId).then((owningIsolate) {
376 if (owningIsolate == null) {
377 // TODO(koda): Do we care about GC events in VM isolate?
378 Logger.root.severe(
379 'Ignoring event with unknown isolate id: $owningIsolateId');
380 } else {
381 var event = new ServiceObject._fromMap(owningIsolate, map);
382 events.add(event);
383 }
384 });
385 } 363 }
386 364
387 static final RegExp _currentIsolateMatcher = new RegExp(r'isolates/\d+'); 365 bool _isIsolateShutdownEvent(String eventType) {
388 static final RegExp _currentObjectMatcher = new RegExp(r'isolates/\d+/'); 366 return (eventType == 'IsolateShutdown');
389 static final String _isolatesPrefix = 'isolates/'; 367 }
390 368
391 String _parseObjectId(String id) { 369 bool _isIsolateCreatedEvent(String eventType) {
392 Match m = _currentObjectMatcher.matchAsPrefix(id); 370 return (eventType == 'IsolateCreated');
393 if (m == null) { 371 }
372
373 void postServiceEvent(String response, ByteData data) {
374 var map;
375 try {
376 map = _parseJSON(response);
377 assert(!map.containsKey('_data'));
378 if (data != null) {
379 map['_data'] = data;
380 }
381 } catch (e, st) {
382 Logger.root.severe('Ignoring malformed event response: ${response}');
383 return;
384 }
385 if (map['type'] != 'ServiceEvent') {
386 Logger.root.severe(
387 "Expected 'ServiceEvent' but found '${map['type']}'");
388 return;
389 }
390
391 var eventType = map['eventType'];
392
393 if (_isIsolateLifecycleEvent(eventType)) {
394 String isolateId = map['isolate']['id'];
395 var event;
396 if (_isIsolateCreatedEvent(eventType)) {
397 _onIsolateCreated(map['isolate']);
398 // By constructing the event *after* adding the isolate to the
399 // isolate cache, the call to getFromMap will use the cached Isolate.
400 event = new ServiceObject._fromMap(this, map);
401 } else {
402 assert(_isIsolateShutdownEvent(eventType));
403 // By constructing the event *before* removing the isolate from the
404 // isolate cache, the call to getFromMap will use the cached Isolate.
405 event = new ServiceObject._fromMap(this, map);
406 _onIsolateShutdown(isolateId);
407 }
408 assert(event != null);
409 events.add(event);
410 return;
411 }
412
413 // Extract the owning isolate from the event itself.
414 String owningIsolateId = map['isolate']['id'];
415 getIsolate(owningIsolateId).then((owningIsolate) {
416 if (owningIsolate == null) {
417 // TODO(koda): Do we care about GC events in VM isolate?
418 Logger.root.severe('Ignoring event with unknown isolate id: '
419 '$owningIsolateId');
420 return;
421 }
422 var event = new ServiceObject._fromMap(owningIsolate, map);
423 events.add(event);
424 });
425 }
426
427 Isolate _onIsolateCreated(Map isolateMap) {
428 var isolateId = isolateMap['id'];
429 assert(!_isolateCache.containsKey(isolateId));
430 Isolate isolate = new ServiceObject._fromMap(this, isolateMap);
431 _isolateCache[isolateId] = isolate;
432 notifyPropertyChange(#isolates, true, false);
433 // Eagerly load the isolate.
434 isolate.load().catchError((e) {
435 Logger.root.info('Eagerly loading an isolate failed: $e');
436 });
437 return isolate;
438 }
439
440 void _onIsolateShutdown(String isolateId) {
441 assert(_isolateCache.containsKey(isolateId));
442 _isolateCache.remove(isolateId);
443 notifyPropertyChange(#isolates, true, false);
444 }
445
446 void _updateIsolatesFromList(List isolateList) {
447 var shutdownIsolates = <String>[];
448 var createdIsolates = <Map>[];
449 var isolateStillExists = <String, bool>{};
450
451 // Start with the assumption that all isolates are gone.
452 for (var isolateId in _isolateCache.keys) {
453 isolateStillExists[isolateId] = false;
454 }
455
456 // Find created isolates and mark existing isolates as living.
457 for (var isolateMap in isolateList) {
458 var isolateId = isolateMap['id'];
459 if (!_isolateCache.containsKey(isolateId)) {
460 createdIsolates.add(isolateMap);
461 } else {
462 isolateStillExists[isolateId] = true;
463 }
464 }
465
466 // Find shutdown isolates.
467 isolateStillExists.forEach((isolateId, exists) {
468 if (!exists) {
469 shutdownIsolates.add(isolateId);
470 }
471 });
472
473 // Process shutdown.
474 for (var isolateId in shutdownIsolates) {
475 _onIsolateShutdown(isolateId);
476 }
477
478 // Process creation.
479 for (var isolateMap in createdIsolates) {
480 _onIsolateCreated(isolateMap);
481 }
482 }
483
484 static final String _isolateIdPrefix = 'isolates/';
485
486 ServiceObject getFromMap(ObservableMap map) {
487 if (map == null) {
394 return null; 488 return null;
395 } 489 }
396 return m.input.substring(m.end); 490 String id = map['id'];
397 } 491 if (!id.startsWith(_isolateIdPrefix)) {
492 // Currently the VM only supports upgrading Isolate ServiceObjects.
493 throw new UnimplementedError();
494 }
398 495
399 String _parseIsolateId(String id) { 496 // Check cache.
400 Match m = _currentIsolateMatcher.matchAsPrefix(id); 497 var isolate = _isolateCache[id];
401 if (m == null) { 498 if (isolate == null) {
402 return ''; 499 // We should never see an unknown isolate here.
500 throw new UnimplementedError();
403 } 501 }
404 return id.substring(0, m.end); 502 return isolate;
405 }
406
407 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
408 Map<String,Isolate> _isolateCache = new Map<String,Isolate>();
409
410 ServiceObject getFromMap(ObservableMap map) {
411 throw new UnimplementedError();
412 } 503 }
413 504
414 // Note that this function does not reload the isolate if it found 505 // Note that this function does not reload the isolate if it found
415 // in the cache. 506 // in the cache.
416 Future<ServiceObject> getIsolate(String isolateId) { 507 Future<ServiceObject> getIsolate(String isolateId) {
417 if (isolateId == '') { 508 return new Future.value(_isolateCache[isolateId]);
418 return new Future.value(null);
419 }
420 Isolate isolate = _isolateCache[isolateId];
421 if (isolate != null) {
422 return new Future.value(isolate);
423 }
424 // The isolate is not in the cache. Reload the vm and see if the
425 // requested isolate is found.
426 //
427 // TODO(turnidge): We don't want to reload all isolates so much.
428 // Doesn't scale well. Change this to be more fine-grained.
429 return reload().then((result) {
430 if (result is! VM) {
431 return null;
432 }
433 assert(result == this);
434 return _isolateCache[isolateId];
435 });
436 } 509 }
437 510
438 dynamic _reviver(dynamic key, dynamic value) { 511 dynamic _reviver(dynamic key, dynamic value) {
439 return value; 512 return value;
440 } 513 }
441 514
442 ObservableMap _parseJSON(String response) { 515 ObservableMap _parseJSON(String response) {
443 var map; 516 var map;
444 try { 517 try {
445 var decoder = new JsonDecoder(_reviver); 518 var decoder = new JsonDecoder(_reviver);
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 _loaded = true; 607 _loaded = true;
535 version = map['version']; 608 version = map['version'];
536 targetCPU = map['targetCPU']; 609 targetCPU = map['targetCPU'];
537 architectureBits = map['architectureBits']; 610 architectureBits = map['architectureBits'];
538 uptime = map['uptime']; 611 uptime = map['uptime'];
539 var dateInMillis = int.parse(map['date']); 612 var dateInMillis = int.parse(map['date']);
540 lastUpdate = new DateTime.fromMillisecondsSinceEpoch(dateInMillis); 613 lastUpdate = new DateTime.fromMillisecondsSinceEpoch(dateInMillis);
541 assertsEnabled = map['assertsEnabled']; 614 assertsEnabled = map['assertsEnabled'];
542 pid = map['pid']; 615 pid = map['pid'];
543 typeChecksEnabled = map['typeChecksEnabled']; 616 typeChecksEnabled = map['typeChecksEnabled'];
544 _updateIsolates(map['isolates']); 617 _updateIsolatesFromList(map['isolates']);
545 } 618 }
546 619
547 void _updateIsolates(List newIsolates) { 620 // Reload all isolates.
548 var oldIsolateCache = _isolateCache; 621 Future reloadIsolates() {
549 var newIsolateCache = new Map<String,Isolate>(); 622 var reloads = [];
550 for (var isolateMap in newIsolates) { 623 for (var isolate in isolates) {
551 var isolateId = isolateMap['id']; 624 var reload = isolate.reload().catchError((e) {
552 var isolate = oldIsolateCache[isolateId]; 625 Logger.root.info('Bulk reloading of isolates failed: $e');
553 if (isolate != null) { 626 });
554 newIsolateCache[isolateId] = isolate; 627 reloads.add(reload);
555 } else {
556 isolate = new ServiceObject._fromMap(this, isolateMap);
557 newIsolateCache[isolateId] = isolate;
558 Logger.root.info('New isolate \'${isolate.id}\'');
559 }
560 } 628 }
561 // Update the individual isolates asynchronously. 629 return Future.wait(reloads);
562 newIsolateCache.forEach((isolateId, isolate) {
563 isolate.reload();
564 });
565
566 _isolateCache = newIsolateCache;
567 } 630 }
568 } 631 }
569 632
570 /// Snapshot in time of tag counters. 633 /// Snapshot in time of tag counters.
571 class TagProfileSnapshot { 634 class TagProfileSnapshot {
572 final double seconds; 635 final double seconds;
573 final List<int> counters; 636 final List<int> counters;
574 int get sum => _sum; 637 int get sum => _sum;
575 int _sum = 0; 638 int _sum = 0;
576 TagProfileSnapshot(this.seconds, int countersLength) 639 TagProfileSnapshot(this.seconds, int countersLength)
(...skipping 2341 matching lines...) Expand 10 before | Expand all | Expand 10 after
2918 var v = list[i]; 2981 var v = list[i];
2919 if ((v is ObservableMap) && _isServiceMap(v)) { 2982 if ((v is ObservableMap) && _isServiceMap(v)) {
2920 list[i] = owner.getFromMap(v); 2983 list[i] = owner.getFromMap(v);
2921 } else if (v is ObservableList) { 2984 } else if (v is ObservableList) {
2922 _upgradeObservableList(v, owner); 2985 _upgradeObservableList(v, owner);
2923 } else if (v is ObservableMap) { 2986 } else if (v is ObservableMap) {
2924 _upgradeObservableMap(v, owner); 2987 _upgradeObservableMap(v, owner);
2925 } 2988 }
2926 } 2989 }
2927 } 2990 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/vm_view.dart ('k') | runtime/observatory/test/coverage_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698