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

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;
1774
1775 bool get canCache => true;
1776 bool get immutable => false;
1867 1777
1868 ServiceFunction._empty(ServiceObject owner) : super._empty(owner); 1778 ServiceFunction._empty(ServiceObject owner) : super._empty(owner);
1869 1779
1870 void _update(ObservableMap map, bool mapIsRef) { 1780 void _update(ObservableMap map, bool mapIsRef) {
1871 name = map['name']; 1781 name = map['name'];
1872 vmName = (map.containsKey('vmName') ? map['vmName'] : name); 1782 vmName = (map.containsKey('vmName') ? map['vmName'] : name);
1873 1783
1874 _upgradeCollection(map, isolate); 1784 _upgradeCollection(map, isolate);
1875 1785
1876 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null; 1786 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null;
1877 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu ll; 1787 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu ll;
1878 kind = FunctionKind.fromJSON(map['kind']); 1788 kind = FunctionKind.fromJSON(map['kind']);
1879 isDart = !kind.isFake(); 1789 isDart = !kind.isSynthetic();
1880 1790
1881 if (parent == null) { 1791 if (parent == null) {
1882 qualifiedName = (owningClass != null) ? 1792 qualifiedName = (owningClass != null) ?
1883 "${owningClass.name}.${name}" : 1793 "${owningClass.name}.${name}" :
1884 name; 1794 name;
1885 } else { 1795 } else {
1886 qualifiedName = "${parent.qualifiedName}.${name}"; 1796 qualifiedName = "${parent.qualifiedName}.${name}";
1887 } 1797 }
1888 1798
1889 if (mapIsRef) { return; } 1799 if (mapIsRef) {
1800 return;
1801 }
1890 1802
1891 isStatic = map['static']; 1803 isStatic = map['static'];
1892 isConst = map['const']; 1804 isConst = map['const'];
1893 parent = map['parent']; 1805 parent = map['parent'];
1894 script = map['script']; 1806 script = map['script'];
1895 tokenPos = map['tokenPos']; 1807 tokenPos = map['tokenPos'];
1896 endTokenPos = map['endTokenPos']; 1808 endTokenPos = map['endTokenPos'];
1897 code = _convertNull(map['code']); 1809 code = _convertNull(map['code']);
1898 unoptimizedCode = _convertNull(map['unoptimizedCode']); 1810 unoptimizedCode = _convertNull(map['unoptimizedCode']);
1899 isOptimizable = map['optimizable']; 1811 isOptimizable = map['optimizable'];
1900 isInlinable = map['inlinable']; 1812 isInlinable = map['inlinable'];
1901 deoptimizations = map['deoptimizations']; 1813 deoptimizations = map['deoptimizations'];
1902 usageCounter = map['usageCounter']; 1814 usageCounter = map['usageCounter'];
1903
1904 } 1815 }
1905 } 1816 }
1906 1817
1907 1818
1908 class Field extends ServiceObject { 1819 class Field extends ServiceObject {
1909 @observable var /* Library or Class */ owner; 1820 @observable var /* Library or Class */ owner;
1910 @observable Instance declaredType; 1821 @observable Instance declaredType;
1911 @observable bool isStatic; 1822 @observable bool isStatic;
1912 @observable bool isFinal; 1823 @observable bool isFinal;
1913 @observable bool isConst; 1824 @observable bool isConst;
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
2136 } 2047 }
2137 2048
2138 void _applyHitsToLines() { 2049 void _applyHitsToLines() {
2139 for (var line in lines) { 2050 for (var line in lines) {
2140 var hits = _hits[line.line]; 2051 var hits = _hits[line.line];
2141 line.hits = hits; 2052 line.hits = hits;
2142 } 2053 }
2143 } 2054 }
2144 } 2055 }
2145 2056
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 { 2057 class PcDescriptor extends Observable {
2154 final int pcOffset; 2058 final int pcOffset;
2155 @reflectable final int deoptId; 2059 @reflectable final int deoptId;
2156 @reflectable final int tokenPos; 2060 @reflectable final int tokenPos;
2157 @reflectable final int tryIndex; 2061 @reflectable final int tryIndex;
2158 @reflectable final String kind; 2062 @reflectable final String kind;
2159 @observable Script script; 2063 @observable Script script;
2160 @observable String formattedLine; 2064 @observable String formattedLine;
2161 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex, 2065 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex,
2162 this.kind); 2066 this.kind);
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
2286 2190
2287 class CodeInstruction extends Observable { 2191 class CodeInstruction extends Observable {
2288 @observable final int address; 2192 @observable final int address;
2289 @observable final int pcOffset; 2193 @observable final int pcOffset;
2290 @observable final String machine; 2194 @observable final String machine;
2291 @observable final String human; 2195 @observable final String human;
2292 @observable CodeInstruction jumpTarget; 2196 @observable CodeInstruction jumpTarget;
2293 @reflectable List<PcDescriptor> descriptors = 2197 @reflectable List<PcDescriptor> descriptors =
2294 new ObservableList<PcDescriptor>(); 2198 new ObservableList<PcDescriptor>();
2295 2199
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); 2200 CodeInstruction(this.address, this.pcOffset, this.machine, this.human);
2302 2201
2303 @reflectable bool get isComment => address == 0; 2202 @reflectable bool get isComment => address == 0;
2304 @reflectable bool get hasDescriptors => descriptors.length > 0; 2203 @reflectable bool get hasDescriptors => descriptors.length > 0;
2305 2204
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() { 2205 bool _isJumpInstruction() {
2342 return human.startsWith('j'); 2206 return human.startsWith('j');
2343 } 2207 }
2344 2208
2345 int _getJumpAddress() { 2209 int _getJumpAddress() {
2346 assert(_isJumpInstruction()); 2210 assert(_isJumpInstruction());
2347 var chunks = human.split(' '); 2211 var chunks = human.split(' ');
2348 if (chunks.length != 2) { 2212 if (chunks.length != 2) {
2349 // We expect jump instructions to be of the form 'j.. address'. 2213 // We expect jump instructions to be of the form 'j.. address'.
2350 return 0; 2214 return 0;
2351 } 2215 }
2352 var address = chunks[1]; 2216 var address = chunks[1];
2353 if (address.startsWith('0x')) { 2217 if (address.startsWith('0x')) {
2354 // Chop off the 0x. 2218 // Chop off the 0x.
2355 address = address.substring(2); 2219 address = address.substring(2);
2356 } 2220 }
2357 try { 2221 try {
2358 return int.parse(address, radix:16); 2222 return int.parse(address, radix:16);
2359 } catch (_) { 2223 } catch (_) {
2360 return 0; 2224 return 0;
2361 } 2225 }
2362 } 2226 }
2363 2227
2364 void _resolveJumpTarget(List<CodeInstruction> instructions) { 2228 void _resolveJumpTarget(List<CodeInstruction> instructions) {
2365 if (!_isJumpInstruction()) { 2229 if (!_isJumpInstruction()) {
2366 return; 2230 return;
2367 } 2231 }
2368 int address = _getJumpAddress(); 2232 int address = _getJumpAddress();
2369 if (address == 0) { 2233 if (address == 0) {
2370 // Could not determine jump address.
2371 Logger.root.severe('Could not determine jump address for $human');
2372 return; 2234 return;
2373 } 2235 }
2374 for (var i = 0; i < instructions.length; i++) { 2236 for (var i = 0; i < instructions.length; i++) {
2375 var instruction = instructions[i]; 2237 var instruction = instructions[i];
2376 if (instruction.address == address) { 2238 if (instruction.address == address) {
2377 jumpTarget = instruction; 2239 jumpTarget = instruction;
2378 return; 2240 return;
2379 } 2241 }
2380 } 2242 }
2381 Logger.root.severe(
2382 'Could not find instruction at ${address.toRadixString(16)}');
2383 } 2243 }
2384 } 2244 }
2385 2245
2386 class CodeKind { 2246 class CodeKind {
2387 final _value; 2247 final _value;
2388 const CodeKind._internal(this._value); 2248 const CodeKind._internal(this._value);
2389 String toString() => '$_value'; 2249 String toString() => '$_value';
2390 2250
2391 static CodeKind fromString(String s) { 2251 static CodeKind fromString(String s) {
2392 if (s == 'Native') { 2252 if (s == 'Native') {
(...skipping 10 matching lines...) Expand all
2403 Logger.root.warning('Unknown code kind $s'); 2263 Logger.root.warning('Unknown code kind $s');
2404 throw new FallThroughError(); 2264 throw new FallThroughError();
2405 } 2265 }
2406 static const Native = const CodeKind._internal('Native'); 2266 static const Native = const CodeKind._internal('Native');
2407 static const Dart = const CodeKind._internal('Dart'); 2267 static const Dart = const CodeKind._internal('Dart');
2408 static const Collected = const CodeKind._internal('Collected'); 2268 static const Collected = const CodeKind._internal('Collected');
2409 static const Reused = const CodeKind._internal('Reused'); 2269 static const Reused = const CodeKind._internal('Reused');
2410 static const Tag = const CodeKind._internal('Tag'); 2270 static const Tag = const CodeKind._internal('Tag');
2411 } 2271 }
2412 2272
2413 class CodeCallCount { 2273 class CodeInlineInterval {
2414 final Code code; 2274 final int start;
2415 final int count; 2275 final int end;
2416 CodeCallCount(this.code, this.count); 2276 final List<ServiceFunction> functions = new List<ServiceFunction>();
2417 } 2277 bool contains(int pc) => (pc >= start) && (pc < end);
2418 2278 CodeInlineInterval(this.start, this.end);
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 } 2279 }
2426 2280
2427 class Code extends ServiceObject { 2281 class Code extends ServiceObject {
2428 @observable CodeKind kind; 2282 @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; 2283 @observable Instance objectPool;
2441 @observable ServiceFunction function; 2284 @observable ServiceFunction function;
2442 @observable Script script; 2285 @observable Script script;
2443 @observable bool isOptimized = false; 2286 @observable bool isOptimized = false;
2444 2287 @reflectable int startAddress = 0;
2288 @reflectable int endAddress = 0;
2289 @reflectable final instructions = new ObservableList<CodeInstruction>();
2290 @observable ProfileCode profile;
2291 final List<CodeInlineInterval> inlineIntervals =
2292 new List<CodeInlineInterval>();
2293 final ObservableList<ServiceFunction> inlinedFunctions =
2294 new ObservableList<ServiceFunction>();
2445 bool get canCache => true; 2295 bool get canCache => true;
2446 bool get immutable => true; 2296 bool get immutable => true;
2447 2297
2448 Code._empty(ServiceObjectOwner owner) : super._empty(owner); 2298 Code._empty(ServiceObjectOwner owner) : super._empty(owner);
2449 2299
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) { 2300 void _updateDescriptors(Script script) {
2463 this.script = script; 2301 this.script = script;
2464 for (var instruction in instructions) { 2302 for (var instruction in instructions) {
2465 for (var descriptor in instruction.descriptors) { 2303 for (var descriptor in instruction.descriptors) {
2466 descriptor.processScript(script); 2304 descriptor.processScript(script);
2467 } 2305 }
2468 } 2306 }
2469 } 2307 }
2470 2308
2471 void loadScript() { 2309 void loadScript() {
(...skipping 28 matching lines...) Expand all
2500 /// a [ServiceError]. 2338 /// a [ServiceError].
2501 Future<ServiceObject> reload() { 2339 Future<ServiceObject> reload() {
2502 assert(kind != null); 2340 assert(kind != null);
2503 if (kind == CodeKind.Dart) { 2341 if (kind == CodeKind.Dart) {
2504 // We only reload Dart code. 2342 // We only reload Dart code.
2505 return super.reload(); 2343 return super.reload();
2506 } 2344 }
2507 return new Future.value(this); 2345 return new Future.value(this);
2508 } 2346 }
2509 2347
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) { 2348 void _update(ObservableMap m, bool mapIsRef) {
2554 name = m['name']; 2349 name = m['name'];
2555 vmName = (m.containsKey('vmName') ? m['vmName'] : name); 2350 vmName = (m.containsKey('vmName') ? m['vmName'] : name);
2556 isOptimized = m['optimized'] != null ? m['optimized'] : false; 2351 isOptimized = m['optimized'] != null ? m['optimized'] : false;
2557 kind = CodeKind.fromString(m['kind']); 2352 kind = CodeKind.fromString(m['kind']);
2558 startAddress = int.parse(m['start'], radix:16); 2353 startAddress = int.parse(m['start'], radix:16);
2559 endAddress = int.parse(m['end'], radix:16); 2354 endAddress = int.parse(m['end'], radix:16);
2560 function = isolate.getFromMap(m['function']); 2355 function = isolate.getFromMap(m['function']);
2356 if (mapIsRef) {
2357 return;
2358 }
2359 _loaded = true;
2561 objectPool = isolate.getFromMap(m['objectPool']); 2360 objectPool = isolate.getFromMap(m['objectPool']);
2562 var disassembly = m['disassembly']; 2361 var disassembly = m['disassembly'];
2563 if (disassembly != null) { 2362 if (disassembly != null) {
2564 _processDisassembly(disassembly); 2363 _processDisassembly(disassembly);
2565 } 2364 }
2566 var descriptors = m['descriptors']; 2365 var descriptors = m['descriptors'];
2567 if (descriptors != null) { 2366 if (descriptors != null) {
2568 descriptors = descriptors['members']; 2367 descriptors = descriptors['members'];
2569 _processDescriptors(descriptors); 2368 _processDescriptors(descriptors);
2570 } 2369 }
2571 // We are loaded if we have instructions or are not Dart code.
2572 _loaded = (instructions.length != 0) || (kind != CodeKind.Dart);
2573 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart); 2370 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart);
2371 inlinedFunctions.clear();
2372 var inlinedFunctionsTable = m['inlinedFunctions'];
2373 var inlinedIntervals = m['inlinedIntervals'];
2374 if (inlinedFunctionsTable != null) {
2375 // Iterate and upgrade each ServiceFunction.
2376 for (var i = 0; i < inlinedFunctionsTable.length; i++) {
2377 // Upgrade each function and set it back in the list.
2378 var func = isolate.getFromMap(inlinedFunctionsTable[i]);
2379 inlinedFunctionsTable[i] = func;
2380 if (!inlinedFunctions.contains(func)) {
2381 inlinedFunctions.add(func);
2382 }
2383 }
2384 }
2385 if ((inlinedIntervals == null) || (inlinedFunctionsTable == null)) {
2386 // No inline information.
2387 inlineIntervals.clear();
2388 return;
2389 }
2390 _processInline(inlinedFunctionsTable, inlinedIntervals);
2391 }
2392
2393 CodeInlineInterval findInterval(int pc) {
2394 for (var i = 0; i < inlineIntervals.length; i++) {
2395 var interval = inlineIntervals[i];
2396 if (interval.contains(pc)) {
2397 return interval;
2398 }
2399 }
2400 return null;
2401 }
2402
2403 void _processInline(List<ServiceFunction> inlinedFunctionsTable,
2404 List<List<int>> inlinedIntervals) {
2405 for (var i = 0; i < inlinedIntervals.length; i++) {
2406 var inlinedInterval = inlinedIntervals[i];
2407 var start = inlinedInterval[0] + startAddress;
2408 var end = inlinedInterval[1] + startAddress;
2409 var codeInlineInterval = new CodeInlineInterval(start, end);
2410 for (var i = 2; i < inlinedInterval.length - 1; i++) {
2411 var inline_id = inlinedInterval[i];
2412 if (inline_id < 0) {
2413 continue;
2414 }
2415 var function = inlinedFunctionsTable[inline_id];
2416 codeInlineInterval.functions.add(function);
2417 }
2418 inlineIntervals.add(codeInlineInterval);
2419 }
2574 } 2420 }
2575 2421
2576 @observable bool hasDisassembly = false; 2422 @observable bool hasDisassembly = false;
2577 2423
2578 void _processDisassembly(List<String> disassembly){ 2424 void _processDisassembly(List<String> disassembly){
2579 assert(disassembly != null); 2425 assert(disassembly != null);
2580 instructions.clear(); 2426 instructions.clear();
2581 assert((disassembly.length % 3) == 0); 2427 assert((disassembly.length % 3) == 0);
2582 for (var i = 0; i < disassembly.length; i += 3) { 2428 for (var i = 0; i < disassembly.length; i += 3) {
2583 var address = 0; // Assume code comment. 2429 var address = 0; // Assume code comment.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2617 Logger.root.warning( 2463 Logger.root.warning(
2618 'Could not find instruction with pc descriptor address: $address'); 2464 'Could not find instruction with pc descriptor address: $address');
2619 } 2465 }
2620 2466
2621 void _processDescriptors(List<Map> descriptors) { 2467 void _processDescriptors(List<Map> descriptors) {
2622 for (Map descriptor in descriptors) { 2468 for (Map descriptor in descriptors) {
2623 _processDescriptor(descriptor); 2469 _processDescriptor(descriptor);
2624 } 2470 }
2625 } 2471 }
2626 2472
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]. 2473 /// Returns true if [address] is contained inside [this].
2640 bool contains(int address) { 2474 bool contains(int address) {
2641 return (address >= startAddress) && (address < endAddress); 2475 return (address >= startAddress) && (address < endAddress);
2642 } 2476 }
2643 2477
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; 2478 @reflectable bool get isDartCode => kind == CodeKind.Dart;
2671 } 2479 }
2672 2480
2673 2481
2674 class SocketKind { 2482 class SocketKind {
2675 final _value; 2483 final _value;
2676 const SocketKind._internal(this._value); 2484 const SocketKind._internal(this._value);
2677 String toString() => '$_value'; 2485 String toString() => '$_value';
2678 2486
2679 static SocketKind fromString(String s) { 2487 static SocketKind fromString(String s) {
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
2918 var v = list[i]; 2726 var v = list[i];
2919 if ((v is ObservableMap) && _isServiceMap(v)) { 2727 if ((v is ObservableMap) && _isServiceMap(v)) {
2920 list[i] = owner.getFromMap(v); 2728 list[i] = owner.getFromMap(v);
2921 } else if (v is ObservableList) { 2729 } else if (v is ObservableList) {
2922 _upgradeObservableList(v, owner); 2730 _upgradeObservableList(v, owner);
2923 } else if (v is ObservableMap) { 2731 } else if (v is ObservableMap) {
2924 _upgradeObservableMap(v, owner); 2732 _upgradeObservableMap(v, owner);
2925 } 2733 }
2926 } 2734 }
2927 } 2735 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698