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

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

Issue 928833003: Add Function based profile tree (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 // TODO(koda): Do we care about GC events in VM isolate? 377 // TODO(koda): Do we care about GC events in VM isolate?
378 Logger.root.severe( 378 Logger.root.severe(
379 'Ignoring event with unknown isolate id: $owningIsolateId'); 379 'Ignoring event with unknown isolate id: $owningIsolateId');
380 } else { 380 } else {
381 var event = new ServiceObject._fromMap(owningIsolate, map); 381 var event = new ServiceObject._fromMap(owningIsolate, map);
382 events.add(event); 382 events.add(event);
383 } 383 }
384 }); 384 });
385 } 385 }
386 386
387 static final RegExp _currentIsolateMatcher = new RegExp(r'isolates/\d+');
388 static final RegExp _currentObjectMatcher = new RegExp(r'isolates/\d+/');
389 static final String _isolatesPrefix = 'isolates/';
390
391 String _parseObjectId(String id) {
392 Match m = _currentObjectMatcher.matchAsPrefix(id);
393 if (m == null) {
394 return null;
395 }
396 return m.input.substring(m.end);
397 }
398
399 String _parseIsolateId(String id) {
400 Match m = _currentIsolateMatcher.matchAsPrefix(id);
401 if (m == null) {
402 return '';
403 }
404 return id.substring(0, m.end);
405 }
406
407 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); 387 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
408 Map<String,Isolate> _isolateCache = new Map<String,Isolate>(); 388 Map<String,Isolate> _isolateCache = new Map<String,Isolate>();
409 389
410 ServiceObject getFromMap(ObservableMap map) { 390 ServiceObject getFromMap(ObservableMap map) {
411 throw new UnimplementedError(); 391 throw new UnimplementedError();
412 } 392 }
413 393
414 // Note that this function does not reload the isolate if it found 394 // Note that this function does not reload the isolate if it found
415 // in the cache. 395 // in the cache.
416 Future<ServiceObject> getIsolate(String isolateId) { 396 Future<ServiceObject> getIsolate(String isolateId) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 }, test: (e) => e is ServiceError).catchError((exception) { 477 }, test: (e) => e is ServiceError).catchError((exception) {
498 478
499 // ServiceException, forward to VM's ServiceException stream. 479 // ServiceException, forward to VM's ServiceException stream.
500 exceptions.add(exception); 480 exceptions.add(exception);
501 return new Future.error(exception); 481 return new Future.error(exception);
502 }, test: (e) => e is ServiceException); 482 }, test: (e) => e is ServiceException);
503 } 483 }
504 484
505 Future<ServiceObject> invokeRpc(String method, Map params) { 485 Future<ServiceObject> invokeRpc(String method, Map params) {
506 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { 486 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
507 » var obj = new ServiceObject._fromMap(this, response); 487 var obj = new ServiceObject._fromMap(this, response);
508 if (obj.canCache) { 488 if ((obj != null) && obj.canCache) {
509 _cache.putIfAbsent(id, () => obj); 489 String objId = obj.id;
510 } 490 _cache.putIfAbsent(objId, () => obj);
511 return obj; 491 }
492 return obj;
512 }); 493 });
513 } 494 }
514 495
515 Future<ObservableMap> _fetchDirect() { 496 Future<ObservableMap> _fetchDirect() {
516 return invokeRpcNoUpgrade('getVM', {}); 497 return invokeRpcNoUpgrade('getVM', {});
517 } 498 }
518 499
519 Future<ServiceObject> getFlagList() { 500 Future<ServiceObject> getFlagList() {
520 return invokeRpc('getFlagList', {}); 501 return invokeRpc('getFlagList', {});
521 } 502 }
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
707 @observable bool loading = true; 688 @observable bool loading = true;
708 @observable bool ioEnabled = false; 689 @observable bool ioEnabled = false;
709 690
710 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); 691 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
711 final TagProfile tagProfile = new TagProfile(20); 692 final TagProfile tagProfile = new TagProfile(20);
712 693
713 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { 694 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) {
714 assert(owner is VM); 695 assert(owner is VM);
715 } 696 }
716 697
717 static const TAG_ROOT_ID = 'code/tag-0'; 698 void resetCachedProfileData() {
718
719 /// Returns the Code object for the root tag.
720 Code tagRoot() {
721 // TODO(turnidge): Use get() here instead?
722 return _cache[TAG_ROOT_ID];
723 }
724
725 void processProfile(ServiceMap profile) {
726 assert(profile.type == 'CpuProfile');
727 var codeTable = new List<Code>();
728 var codeRegions = profile['codes'];
729 for (var codeRegion in codeRegions) {
730 Code code = codeRegion['code'];
731 assert(code != null);
732 codeTable.add(code);
733 }
734 _resetProfileData();
735 _updateProfileData(profile, codeTable);
736 var exclusiveTrie = profile['exclusive_trie'];
737 if (exclusiveTrie != null) {
738 profileTrieRoot = _processProfileTrie(exclusiveTrie, codeTable);
739 }
740 }
741
742 void _resetProfileData() {
743 _cache.values.forEach((value) { 699 _cache.values.forEach((value) {
744 if (value is Code) { 700 if (value is Code) {
745 Code code = value; 701 Code code = value;
746 code.resetProfileData(); 702 code.profile = null;
747 } 703 } else if (value is ServiceFunction) {
748 }); 704 ServiceFunction function = value;
749 } 705 function.profile = null;
750 706 }
751 void _updateProfileData(ServiceMap profile, List<Code> codeTable) { 707 });
752 var codeRegions = profile['codes'];
753 var sampleCount = profile['samples'];
754 for (var codeRegion in codeRegions) {
755 Code code = codeRegion['code'];
756 code.updateProfileData(codeRegion, codeTable, sampleCount);
757 }
758 } 708 }
759 709
760 /// Fetches and builds the class hierarchy for this isolate. Returns the 710 /// Fetches and builds the class hierarchy for this isolate. Returns the
761 /// Object class object. 711 /// Object class object.
762 Future<Class> getClassHierarchy() { 712 Future<Class> getClassHierarchy() {
763 return invokeRpc('getClassList', {}) 713 return invokeRpc('getClassList', {})
764 .then(_loadClasses) 714 .then(_loadClasses)
765 .then(_buildClassHierarchy); 715 .then(_buildClassHierarchy);
766 } 716 }
767 717
(...skipping 23 matching lines...) Expand all
791 } 741 }
792 } 742 }
793 assert(objectClass != null); 743 assert(objectClass != null);
794 return new Future.value(objectClass); 744 return new Future.value(objectClass);
795 } 745 }
796 746
797 ServiceObject getFromMap(ObservableMap map) { 747 ServiceObject getFromMap(ObservableMap map) {
798 if (map == null) { 748 if (map == null) {
799 return null; 749 return null;
800 } 750 }
801 String id = map['id']; 751 String mapId = map['id'];
802 var obj = _cache[id]; 752 var obj = (mapId != null) ? _cache[mapId] : null;
803 if (obj != null) { 753 if (obj != null) {
804 // Consider calling update when map is not a reference. 754 // Consider calling update when map is not a reference.
805 return obj; 755 return obj;
806 } 756 }
807 // Build the object from the map directly. 757 // Build the object from the map directly.
808 obj = new ServiceObject._fromMap(this, map); 758 obj = new ServiceObject._fromMap(this, map);
809 if (obj != null && obj.canCache) { 759 if ((obj != null) && obj.canCache) {
810 _cache[id] = obj; 760 _cache[mapId] = obj;
811 } 761 }
812 return obj; 762 return obj;
813 } 763 }
814 764
815 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { 765 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) {
816 params['isolateId'] = id; 766 params['isolateId'] = id;
817 return vm.invokeRpcNoUpgrade(method, params); 767 return vm.invokeRpcNoUpgrade(method, params);
818 } 768 }
819 769
820 Future<ServiceObject> invokeRpc(String method, Map params) { 770 Future<ServiceObject> invokeRpc(String method, Map params) {
821 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { 771 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
822 var obj = new ServiceObject._fromMap(this, response); 772 var obj = new ServiceObject._fromMap(this, response);
823 if (obj.canCache) { 773 if ((obj != null) && obj.canCache) {
824 _cache.putIfAbsent(id, () => obj); 774 String objId = obj.id;
825 } 775 _cache.putIfAbsent(objId, () => obj);
826 » return obj; 776 }
777 return obj;
827 }); 778 });
828 } 779 }
829 780
830 Future<ServiceObject> getObject(String objectId) { 781 Future<ServiceObject> getObject(String objectId) {
831 assert(objectId != null && objectId != ''); 782 assert(objectId != null && objectId != '');
832 var obj = _cache[objectId]; 783 var obj = _cache[objectId];
833 if (obj != null) { 784 if (obj != null) {
834 return obj.reload(); 785 return obj.reload();
835 } 786 }
836 Map params = { 787 Map params = {
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 923
973 Future<TagProfile> updateTagProfile() { 924 Future<TagProfile> updateTagProfile() {
974 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( 925 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then(
975 (ObservableMap map) { 926 (ObservableMap map) {
976 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; 927 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0;
977 tagProfile._processTagProfile(seconds, map); 928 tagProfile._processTagProfile(seconds, map);
978 return tagProfile; 929 return tagProfile;
979 }); 930 });
980 } 931 }
981 932
982 @reflectable CodeTrieNode profileTrieRoot;
983 // The profile trie is serialized as a list of integers. Each node
984 // is recreated by consuming some portion of the list. The format is as
985 // follows:
986 // [0] index into codeTable of code object.
987 // [1] tick count (number of times this stack frame occured).
988 // [2] child node count
989 // Reading the trie is done by recursively reading the tree depth-first
990 // pre-order.
991 CodeTrieNode _processProfileTrie(List<int> data, List<Code> codeTable) {
992 // Setup state shared across calls to _readTrieNode.
993 _trieDataCursor = 0;
994 _trieData = data;
995 if (_trieData == null) {
996 return null;
997 }
998 if (_trieData.length < 3) {
999 // Not enough integers for 1 node.
1000 return null;
1001 }
1002 // Read the tree, returns the root node.
1003 return _readTrieNode(codeTable);
1004 }
1005 int _trieDataCursor;
1006 List<int> _trieData;
1007 CodeTrieNode _readTrieNode(List<Code> codeTable) {
1008 // Read index into code table.
1009 var index = _trieData[_trieDataCursor++];
1010 // Lookup code object.
1011 var code = codeTable[index];
1012 // Frame counter.
1013 var count = _trieData[_trieDataCursor++];
1014 // Create node.
1015 var node = new CodeTrieNode(code, count);
1016 // Number of children.
1017 var children = _trieData[_trieDataCursor++];
1018 // Recursively read child nodes.
1019 for (var i = 0; i < children; i++) {
1020 var child = _readTrieNode(codeTable);
1021 node.children.add(child);
1022 node.summedChildCount += child.count;
1023 }
1024 return node;
1025 }
1026
1027 ObservableList<Breakpoint> breakpoints = new ObservableList(); 933 ObservableList<Breakpoint> breakpoints = new ObservableList();
1028 934
1029 void _removeBreakpoint(Breakpoint bpt) { 935 void _removeBreakpoint(Breakpoint bpt) {
1030 var script = bpt.script; 936 var script = bpt.script;
1031 var tokenPos = bpt.tokenPos; 937 var tokenPos = bpt.tokenPos;
1032 assert(tokenPos != null); 938 assert(tokenPos != null);
1033 if (script.loaded) { 939 if (script.loaded) {
1034 var line = script.tokenToLine(tokenPos); 940 var line = script.tokenToLine(tokenPos);
1035 assert(line != null); 941 assert(line != null);
1036 if (script.lines[line - 1] != null) { 942 if (script.lines[line - 1] != null) {
(...skipping 761 matching lines...) Expand 10 before | Expand all | Expand 10 after
1798 1704
1799 String toString() => 'Context($length)'; 1705 String toString() => 'Context($length)';
1800 } 1706 }
1801 1707
1802 1708
1803 // TODO(koda): Sync this with VM. 1709 // TODO(koda): Sync this with VM.
1804 class FunctionKind { 1710 class FunctionKind {
1805 final String _strValue; 1711 final String _strValue;
1806 FunctionKind._internal(this._strValue); 1712 FunctionKind._internal(this._strValue);
1807 toString() => _strValue; 1713 toString() => _strValue;
1808 bool isFake() => [kCollected, kNative, kTag, kReused].contains(this); 1714 bool isSynthetic() => [kCollected, kNative, kTag, kReused].contains(this);
1809 1715
1810 static FunctionKind fromJSON(String value) { 1716 static FunctionKind fromJSON(String value) {
1811 switch(value) { 1717 switch(value) {
1812 case 'kRegularFunction': return kRegularFunction; 1718 case 'kRegularFunction': return kRegularFunction;
1813 case 'kClosureFunction': return kClosureFunction; 1719 case 'kClosureFunction': return kClosureFunction;
1814 case 'kGetterFunction': return kGetterFunction; 1720 case 'kGetterFunction': return kGetterFunction;
1815 case 'kSetterFunction': return kSetterFunction; 1721 case 'kSetterFunction': return kSetterFunction;
1816 case 'kConstructor': return kConstructor; 1722 case 'kConstructor': return kConstructor;
1817 case 'kImplicitGetter': return kImplicitGetterFunction; 1723 case 'kImplicitGetter': return kImplicitGetterFunction;
1818 case 'kImplicitSetter': return kImplicitSetterFunction; 1724 case 'kImplicitSetter': return kImplicitSetterFunction;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1857 @observable int endTokenPos; 1763 @observable int endTokenPos;
1858 @observable Code code; 1764 @observable Code code;
1859 @observable Code unoptimizedCode; 1765 @observable Code unoptimizedCode;
1860 @observable bool isOptimizable; 1766 @observable bool isOptimizable;
1861 @observable bool isInlinable; 1767 @observable bool isInlinable;
1862 @observable FunctionKind kind; 1768 @observable FunctionKind kind;
1863 @observable int deoptimizations; 1769 @observable int deoptimizations;
1864 @observable String qualifiedName; 1770 @observable String qualifiedName;
1865 @observable int usageCounter; 1771 @observable int usageCounter;
1866 @observable bool isDart; 1772 @observable bool isDart;
1773 @observable ProfileFunction profile;
1867 1774
1868 ServiceFunction._empty(ServiceObject owner) : super._empty(owner); 1775 ServiceFunction._empty(ServiceObject owner) : super._empty(owner);
1869 1776
1870 void _update(ObservableMap map, bool mapIsRef) { 1777 void _update(ObservableMap map, bool mapIsRef) {
1871 name = map['name']; 1778 name = map['name'];
1872 vmName = (map.containsKey('vmName') ? map['vmName'] : name); 1779 vmName = (map.containsKey('vmName') ? map['vmName'] : name);
1873 1780
1874 _upgradeCollection(map, isolate); 1781 _upgradeCollection(map, isolate);
1875 1782
1876 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null; 1783 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null;
1877 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu ll; 1784 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu ll;
1878 kind = FunctionKind.fromJSON(map['kind']); 1785 kind = FunctionKind.fromJSON(map['kind']);
1879 isDart = !kind.isFake(); 1786 isDart = !kind.isSynthetic();
1880 1787
1881 if (parent == null) { 1788 if (parent == null) {
1882 qualifiedName = (owningClass != null) ? 1789 qualifiedName = (owningClass != null) ?
1883 "${owningClass.name}.${name}" : 1790 "${owningClass.name}.${name}" :
1884 name; 1791 name;
1885 } else { 1792 } else {
1886 qualifiedName = "${parent.qualifiedName}.${name}"; 1793 qualifiedName = "${parent.qualifiedName}.${name}";
1887 } 1794 }
1888 1795
1889 if (mapIsRef) { return; } 1796 if (mapIsRef) {
1797 return;
1798 }
1890 1799
1891 isStatic = map['static']; 1800 isStatic = map['static'];
1892 isConst = map['const']; 1801 isConst = map['const'];
1893 parent = map['parent']; 1802 parent = map['parent'];
1894 script = map['script']; 1803 script = map['script'];
1895 tokenPos = map['tokenPos']; 1804 tokenPos = map['tokenPos'];
1896 endTokenPos = map['endTokenPos']; 1805 endTokenPos = map['endTokenPos'];
1897 code = _convertNull(map['code']); 1806 code = _convertNull(map['code']);
1898 unoptimizedCode = _convertNull(map['unoptimizedCode']); 1807 unoptimizedCode = _convertNull(map['unoptimizedCode']);
1899 isOptimizable = map['optimizable']; 1808 isOptimizable = map['optimizable'];
1900 isInlinable = map['inlinable']; 1809 isInlinable = map['inlinable'];
1901 deoptimizations = map['deoptimizations']; 1810 deoptimizations = map['deoptimizations'];
1902 usageCounter = map['usageCounter']; 1811 usageCounter = map['usageCounter'];
1903
1904 } 1812 }
1905 } 1813 }
1906 1814
1907 1815
1908 class Field extends ServiceObject { 1816 class Field extends ServiceObject {
1909 @observable var /* Library or Class */ owner; 1817 @observable var /* Library or Class */ owner;
1910 @observable Instance declaredType; 1818 @observable Instance declaredType;
1911 @observable bool isStatic; 1819 @observable bool isStatic;
1912 @observable bool isFinal; 1820 @observable bool isFinal;
1913 @observable bool isConst; 1821 @observable bool isConst;
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
2136 } 2044 }
2137 2045
2138 void _applyHitsToLines() { 2046 void _applyHitsToLines() {
2139 for (var line in lines) { 2047 for (var line in lines) {
2140 var hits = _hits[line.line]; 2048 var hits = _hits[line.line];
2141 line.hits = hits; 2049 line.hits = hits;
2142 } 2050 }
2143 } 2051 }
2144 } 2052 }
2145 2053
2146 class CodeTick {
2147 final int address;
2148 final int exclusiveTicks;
2149 final int inclusiveTicks;
2150 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks);
2151 }
2152
2153 class PcDescriptor extends Observable { 2054 class PcDescriptor extends Observable {
2154 final int pcOffset; 2055 final int pcOffset;
2155 @reflectable final int deoptId; 2056 @reflectable final int deoptId;
2156 @reflectable final int tokenPos; 2057 @reflectable final int tokenPos;
2157 @reflectable final int tryIndex; 2058 @reflectable final int tryIndex;
2158 @reflectable final String kind; 2059 @reflectable final String kind;
2159 @observable Script script; 2060 @observable Script script;
2160 @observable String formattedLine; 2061 @observable String formattedLine;
2161 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex, 2062 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex,
2162 this.kind); 2063 this.kind);
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
2286 2187
2287 class CodeInstruction extends Observable { 2188 class CodeInstruction extends Observable {
2288 @observable final int address; 2189 @observable final int address;
2289 @observable final int pcOffset; 2190 @observable final int pcOffset;
2290 @observable final String machine; 2191 @observable final String machine;
2291 @observable final String human; 2192 @observable final String human;
2292 @observable CodeInstruction jumpTarget; 2193 @observable CodeInstruction jumpTarget;
2293 @reflectable List<PcDescriptor> descriptors = 2194 @reflectable List<PcDescriptor> descriptors =
2294 new ObservableList<PcDescriptor>(); 2195 new ObservableList<PcDescriptor>();
2295 2196
2296 static String formatPercent(num a, num total) {
2297 var percent = 100.0 * (a / total);
2298 return '${percent.toStringAsFixed(2)}%';
2299 }
2300
2301 CodeInstruction(this.address, this.pcOffset, this.machine, this.human); 2197 CodeInstruction(this.address, this.pcOffset, this.machine, this.human);
2302 2198
2303 @reflectable bool get isComment => address == 0; 2199 @reflectable bool get isComment => address == 0;
2304 @reflectable bool get hasDescriptors => descriptors.length > 0; 2200 @reflectable bool get hasDescriptors => descriptors.length > 0;
2305 2201
2306 @reflectable String formattedAddress() {
2307 if (address == 0) {
2308 return '';
2309 }
2310 return '0x${address.toRadixString(16)}';
2311 }
2312
2313 @reflectable String formattedInclusive(Code code) {
2314 if (code == null) {
2315 return '';
2316 }
2317 var tick = code.addressTicks[address];
2318 if (tick == null) {
2319 return '';
2320 }
2321 // Don't show inclusive ticks if they are the same as exclusive ticks.
2322 if (tick.inclusiveTicks == tick.exclusiveTicks) {
2323 return '';
2324 }
2325 var pcent = formatPercent(tick.inclusiveTicks, code.totalSamplesInProfile);
2326 return '$pcent (${tick.inclusiveTicks})';
2327 }
2328
2329 @reflectable String formattedExclusive(Code code) {
2330 if (code == null) {
2331 return '';
2332 }
2333 var tick = code.addressTicks[address];
2334 if (tick == null) {
2335 return '';
2336 }
2337 var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile);
2338 return '$pcent (${tick.exclusiveTicks})';
2339 }
2340
2341 bool _isJumpInstruction() { 2202 bool _isJumpInstruction() {
2342 return human.startsWith('j'); 2203 return human.startsWith('j');
2343 } 2204 }
2344 2205
2345 int _getJumpAddress() { 2206 int _getJumpAddress() {
2346 assert(_isJumpInstruction()); 2207 assert(_isJumpInstruction());
2347 var chunks = human.split(' '); 2208 var chunks = human.split(' ');
2348 if (chunks.length != 2) { 2209 if (chunks.length != 2) {
2349 // We expect jump instructions to be of the form 'j.. address'. 2210 // We expect jump instructions to be of the form 'j.. address'.
2350 return 0; 2211 return 0;
2351 } 2212 }
2352 var address = chunks[1]; 2213 var address = chunks[1];
2353 if (address.startsWith('0x')) { 2214 if (address.startsWith('0x')) {
2354 // Chop off the 0x. 2215 // Chop off the 0x.
2355 address = address.substring(2); 2216 address = address.substring(2);
2356 } 2217 }
2357 try { 2218 try {
2358 return int.parse(address, radix:16); 2219 return int.parse(address, radix:16);
2359 } catch (_) { 2220 } catch (_) {
2360 return 0; 2221 return 0;
2361 } 2222 }
2362 } 2223 }
2363 2224
2364 void _resolveJumpTarget(List<CodeInstruction> instructions) { 2225 void _resolveJumpTarget(List<CodeInstruction> instructions) {
2365 if (!_isJumpInstruction()) { 2226 if (!_isJumpInstruction()) {
2366 return; 2227 return;
2367 } 2228 }
2368 int address = _getJumpAddress(); 2229 int address = _getJumpAddress();
2369 if (address == 0) { 2230 if (address == 0) {
2370 // Could not determine jump address.
2371 Logger.root.severe('Could not determine jump address for $human');
2372 return; 2231 return;
2373 } 2232 }
2374 for (var i = 0; i < instructions.length; i++) { 2233 for (var i = 0; i < instructions.length; i++) {
2375 var instruction = instructions[i]; 2234 var instruction = instructions[i];
2376 if (instruction.address == address) { 2235 if (instruction.address == address) {
2377 jumpTarget = instruction; 2236 jumpTarget = instruction;
2378 return; 2237 return;
2379 } 2238 }
2380 } 2239 }
2381 Logger.root.severe(
2382 'Could not find instruction at ${address.toRadixString(16)}');
2383 } 2240 }
2384 } 2241 }
2385 2242
2386 class CodeKind { 2243 class CodeKind {
2387 final _value; 2244 final _value;
2388 const CodeKind._internal(this._value); 2245 const CodeKind._internal(this._value);
2389 String toString() => '$_value'; 2246 String toString() => '$_value';
2390 2247
2391 static CodeKind fromString(String s) { 2248 static CodeKind fromString(String s) {
2392 if (s == 'Native') { 2249 if (s == 'Native') {
(...skipping 10 matching lines...) Expand all
2403 Logger.root.warning('Unknown code kind $s'); 2260 Logger.root.warning('Unknown code kind $s');
2404 throw new FallThroughError(); 2261 throw new FallThroughError();
2405 } 2262 }
2406 static const Native = const CodeKind._internal('Native'); 2263 static const Native = const CodeKind._internal('Native');
2407 static const Dart = const CodeKind._internal('Dart'); 2264 static const Dart = const CodeKind._internal('Dart');
2408 static const Collected = const CodeKind._internal('Collected'); 2265 static const Collected = const CodeKind._internal('Collected');
2409 static const Reused = const CodeKind._internal('Reused'); 2266 static const Reused = const CodeKind._internal('Reused');
2410 static const Tag = const CodeKind._internal('Tag'); 2267 static const Tag = const CodeKind._internal('Tag');
2411 } 2268 }
2412 2269
2413 class CodeCallCount {
2414 final Code code;
2415 final int count;
2416 CodeCallCount(this.code, this.count);
2417 }
2418
2419 class CodeTrieNode {
2420 final Code code;
2421 final int count;
2422 final children = new List<CodeTrieNode>();
2423 int summedChildCount = 0;
2424 CodeTrieNode(this.code, this.count);
2425 }
2426
2427 class Code extends ServiceObject { 2270 class Code extends ServiceObject {
2428 @observable CodeKind kind; 2271 @observable CodeKind kind;
2429 @observable int totalSamplesInProfile = 0;
2430 @reflectable int exclusiveTicks = 0;
2431 @reflectable int inclusiveTicks = 0;
2432 @reflectable int startAddress = 0;
2433 @reflectable int endAddress = 0;
2434 @reflectable final callers = new List<CodeCallCount>();
2435 @reflectable final callees = new List<CodeCallCount>();
2436 @reflectable final instructions = new ObservableList<CodeInstruction>();
2437 @reflectable final addressTicks = new ObservableMap<int, CodeTick>();
2438 @observable String formattedInclusiveTicks = '';
2439 @observable String formattedExclusiveTicks = '';
2440 @observable Instance objectPool; 2272 @observable Instance objectPool;
2441 @observable ServiceFunction function; 2273 @observable ServiceFunction function;
2442 @observable Script script; 2274 @observable Script script;
2443 @observable bool isOptimized = false; 2275 @observable bool isOptimized = false;
2276 @reflectable int startAddress = 0;
2277 @reflectable int endAddress = 0;
2278 @reflectable final instructions = new ObservableList<CodeInstruction>();
2279 @observable ProfileCode profile;
2444 2280
2445 bool get canCache => true; 2281 bool get canCache => true;
2446 bool get immutable => true; 2282 bool get immutable => true;
2447 2283
2448 Code._empty(ServiceObjectOwner owner) : super._empty(owner); 2284 Code._empty(ServiceObjectOwner owner) : super._empty(owner);
2449 2285
2450 // Reset all data associated with a profile.
2451 void resetProfileData() {
2452 totalSamplesInProfile = 0;
2453 exclusiveTicks = 0;
2454 inclusiveTicks = 0;
2455 formattedInclusiveTicks = '';
2456 formattedExclusiveTicks = '';
2457 callers.clear();
2458 callees.clear();
2459 addressTicks.clear();
2460 }
2461
2462 void _updateDescriptors(Script script) { 2286 void _updateDescriptors(Script script) {
2463 this.script = script; 2287 this.script = script;
2464 for (var instruction in instructions) { 2288 for (var instruction in instructions) {
2465 for (var descriptor in instruction.descriptors) { 2289 for (var descriptor in instruction.descriptors) {
2466 descriptor.processScript(script); 2290 descriptor.processScript(script);
2467 } 2291 }
2468 } 2292 }
2469 } 2293 }
2470 2294
2471 void loadScript() { 2295 void loadScript() {
(...skipping 28 matching lines...) Expand all
2500 /// a [ServiceError]. 2324 /// a [ServiceError].
2501 Future<ServiceObject> reload() { 2325 Future<ServiceObject> reload() {
2502 assert(kind != null); 2326 assert(kind != null);
2503 if (kind == CodeKind.Dart) { 2327 if (kind == CodeKind.Dart) {
2504 // We only reload Dart code. 2328 // We only reload Dart code.
2505 return super.reload(); 2329 return super.reload();
2506 } 2330 }
2507 return new Future.value(this); 2331 return new Future.value(this);
2508 } 2332 }
2509 2333
2510 void _resolveCalls(List<CodeCallCount> calls, List data, List<Code> codes) {
2511 // Assert that this has been cleared.
2512 assert(calls.length == 0);
2513 // Resolve.
2514 for (var i = 0; i < data.length; i += 2) {
2515 var index = int.parse(data[i]);
2516 var count = int.parse(data[i + 1]);
2517 assert(index >= 0);
2518 assert(index < codes.length);
2519 calls.add(new CodeCallCount(codes[index], count));
2520 }
2521 // Sort to descending count order.
2522 calls.sort((a, b) => b.count - a.count);
2523 }
2524
2525
2526 static String formatPercent(num a, num total) {
2527 var percent = 100.0 * (a / total);
2528 return '${percent.toStringAsFixed(2)}%';
2529 }
2530
2531 void updateProfileData(Map profileData,
2532 List<Code> codeTable,
2533 int sampleCount) {
2534 // Assert we are handed profile data for this code object.
2535 assert(profileData['code'] == this);
2536 totalSamplesInProfile = sampleCount;
2537 inclusiveTicks = int.parse(profileData['inclusive_ticks']);
2538 exclusiveTicks = int.parse(profileData['exclusive_ticks']);
2539 _resolveCalls(callers, profileData['callers'], codeTable);
2540 _resolveCalls(callees, profileData['callees'], codeTable);
2541 var ticks = profileData['ticks'];
2542 if (ticks != null) {
2543 _processTicks(ticks);
2544 }
2545 formattedInclusiveTicks =
2546 '${formatPercent(inclusiveTicks, totalSamplesInProfile)} '
2547 '($inclusiveTicks)';
2548 formattedExclusiveTicks =
2549 '${formatPercent(exclusiveTicks, totalSamplesInProfile)} '
2550 '($exclusiveTicks)';
2551 }
2552
2553 void _update(ObservableMap m, bool mapIsRef) { 2334 void _update(ObservableMap m, bool mapIsRef) {
2554 name = m['name']; 2335 name = m['name'];
2555 vmName = (m.containsKey('vmName') ? m['vmName'] : name); 2336 vmName = (m.containsKey('vmName') ? m['vmName'] : name);
2556 isOptimized = m['optimized'] != null ? m['optimized'] : false; 2337 isOptimized = m['optimized'] != null ? m['optimized'] : false;
2557 kind = CodeKind.fromString(m['kind']); 2338 kind = CodeKind.fromString(m['kind']);
2558 startAddress = int.parse(m['start'], radix:16); 2339 startAddress = int.parse(m['start'], radix:16);
2559 endAddress = int.parse(m['end'], radix:16); 2340 endAddress = int.parse(m['end'], radix:16);
2560 function = isolate.getFromMap(m['function']); 2341 function = isolate.getFromMap(m['function']);
2342 if (mapIsRef) {
2343 return;
2344 }
2561 objectPool = isolate.getFromMap(m['objectPool']); 2345 objectPool = isolate.getFromMap(m['objectPool']);
2562 var disassembly = m['disassembly']; 2346 var disassembly = m['disassembly'];
2563 if (disassembly != null) { 2347 if (disassembly != null) {
2564 _processDisassembly(disassembly); 2348 _processDisassembly(disassembly);
2565 } 2349 }
2566 var descriptors = m['descriptors']; 2350 var descriptors = m['descriptors'];
2567 if (descriptors != null) { 2351 if (descriptors != null) {
2568 descriptors = descriptors['members']; 2352 descriptors = descriptors['members'];
2569 _processDescriptors(descriptors); 2353 _processDescriptors(descriptors);
2570 } 2354 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
2617 Logger.root.warning( 2401 Logger.root.warning(
2618 'Could not find instruction with pc descriptor address: $address'); 2402 'Could not find instruction with pc descriptor address: $address');
2619 } 2403 }
2620 2404
2621 void _processDescriptors(List<Map> descriptors) { 2405 void _processDescriptors(List<Map> descriptors) {
2622 for (Map descriptor in descriptors) { 2406 for (Map descriptor in descriptors) {
2623 _processDescriptor(descriptor); 2407 _processDescriptor(descriptor);
2624 } 2408 }
2625 } 2409 }
2626 2410
2627 void _processTicks(List<String> profileTicks) {
2628 assert(profileTicks != null);
2629 assert((profileTicks.length % 3) == 0);
2630 for (var i = 0; i < profileTicks.length; i += 3) {
2631 var address = int.parse(profileTicks[i], radix:16);
2632 var exclusive = int.parse(profileTicks[i + 1]);
2633 var inclusive = int.parse(profileTicks[i + 2]);
2634 var tick = new CodeTick(address, exclusive, inclusive);
2635 addressTicks[address] = tick;
2636 }
2637 }
2638
2639 /// Returns true if [address] is contained inside [this]. 2411 /// Returns true if [address] is contained inside [this].
2640 bool contains(int address) { 2412 bool contains(int address) {
2641 return (address >= startAddress) && (address < endAddress); 2413 return (address >= startAddress) && (address < endAddress);
2642 } 2414 }
2643 2415
2644 /// Sum all caller counts.
2645 int sumCallersCount() => _sumCallCount(callers);
2646 /// Specific caller count.
2647 int callersCount(Code code) => _callCount(callers, code);
2648 /// Sum of callees count.
2649 int sumCalleesCount() => _sumCallCount(callees);
2650 /// Specific callee count.
2651 int calleesCount(Code code) => _callCount(callees, code);
2652
2653 int _sumCallCount(List<CodeCallCount> calls) {
2654 var sum = 0;
2655 for (CodeCallCount caller in calls) {
2656 sum += caller.count;
2657 }
2658 return sum;
2659 }
2660
2661 int _callCount(List<CodeCallCount> calls, Code code) {
2662 for (CodeCallCount caller in calls) {
2663 if (caller.code == code) {
2664 return caller.count;
2665 }
2666 }
2667 return 0;
2668 }
2669
2670 @reflectable bool get isDartCode => kind == CodeKind.Dart; 2416 @reflectable bool get isDartCode => kind == CodeKind.Dart;
2671 } 2417 }
2672 2418
2673 2419
2674 class SocketKind { 2420 class SocketKind {
2675 final _value; 2421 final _value;
2676 const SocketKind._internal(this._value); 2422 const SocketKind._internal(this._value);
2677 String toString() => '$_value'; 2423 String toString() => '$_value';
2678 2424
2679 static SocketKind fromString(String s) { 2425 static SocketKind fromString(String s) {
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
2918 var v = list[i]; 2664 var v = list[i];
2919 if ((v is ObservableMap) && _isServiceMap(v)) { 2665 if ((v is ObservableMap) && _isServiceMap(v)) {
2920 list[i] = owner.getFromMap(v); 2666 list[i] = owner.getFromMap(v);
2921 } else if (v is ObservableList) { 2667 } else if (v is ObservableList) {
2922 _upgradeObservableList(v, owner); 2668 _upgradeObservableList(v, owner);
2923 } else if (v is ObservableMap) { 2669 } else if (v is ObservableMap) {
2924 _upgradeObservableMap(v, owner); 2670 _upgradeObservableMap(v, owner);
2925 } 2671 }
2926 } 2672 }
2927 } 2673 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698