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

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, 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 559 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 }, test: (e) => e is ServiceError).catchError((exception) { 570 }, test: (e) => e is ServiceError).catchError((exception) {
571 571
572 // ServiceException, forward to VM's ServiceException stream. 572 // ServiceException, forward to VM's ServiceException stream.
573 exceptions.add(exception); 573 exceptions.add(exception);
574 return new Future.error(exception); 574 return new Future.error(exception);
575 }, test: (e) => e is ServiceException); 575 }, test: (e) => e is ServiceException);
576 } 576 }
577 577
578 Future<ServiceObject> invokeRpc(String method, Map params) { 578 Future<ServiceObject> invokeRpc(String method, Map params) {
579 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { 579 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
580 » var obj = new ServiceObject._fromMap(this, response); 580 var obj = new ServiceObject._fromMap(this, response);
581 if (obj.canCache) { 581 if ((obj != null) && obj.canCache) {
582 _cache.putIfAbsent(id, () => obj); 582 String objId = obj.id;
583 } 583 _cache.putIfAbsent(objId, () => obj);
584 return obj; 584 }
585 return obj;
585 }); 586 });
586 } 587 }
587 588
588 Future<ObservableMap> _fetchDirect() { 589 Future<ObservableMap> _fetchDirect() {
589 return invokeRpcNoUpgrade('getVM', {}); 590 return invokeRpcNoUpgrade('getVM', {});
590 } 591 }
591 592
592 Future<ServiceObject> getFlagList() { 593 Future<ServiceObject> getFlagList() {
593 return invokeRpc('getFlagList', {}); 594 return invokeRpc('getFlagList', {});
594 } 595 }
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
770 @observable bool loading = true; 771 @observable bool loading = true;
771 @observable bool ioEnabled = false; 772 @observable bool ioEnabled = false;
772 773
773 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); 774 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
774 final TagProfile tagProfile = new TagProfile(20); 775 final TagProfile tagProfile = new TagProfile(20);
775 776
776 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { 777 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) {
777 assert(owner is VM); 778 assert(owner is VM);
778 } 779 }
779 780
780 static const TAG_ROOT_ID = 'code/tag-0'; 781 void resetCachedProfileData() {
781
782 /// Returns the Code object for the root tag.
783 Code tagRoot() {
784 // TODO(turnidge): Use get() here instead?
785 return _cache[TAG_ROOT_ID];
786 }
787
788 void processProfile(ServiceMap profile) {
789 assert(profile.type == 'CpuProfile');
790 var codeTable = new List<Code>();
791 var codeRegions = profile['codes'];
792 for (var codeRegion in codeRegions) {
793 Code code = codeRegion['code'];
794 assert(code != null);
795 codeTable.add(code);
796 }
797 _resetProfileData();
798 _updateProfileData(profile, codeTable);
799 var exclusiveTrie = profile['exclusive_trie'];
800 if (exclusiveTrie != null) {
801 profileTrieRoot = _processProfileTrie(exclusiveTrie, codeTable);
802 }
803 }
804
805 void _resetProfileData() {
806 _cache.values.forEach((value) { 782 _cache.values.forEach((value) {
807 if (value is Code) { 783 if (value is Code) {
808 Code code = value; 784 Code code = value;
809 code.resetProfileData(); 785 code.profile = null;
810 } 786 } else if (value is ServiceFunction) {
811 }); 787 ServiceFunction function = value;
812 } 788 function.profile = null;
813 789 }
814 void _updateProfileData(ServiceMap profile, List<Code> codeTable) { 790 });
815 var codeRegions = profile['codes'];
816 var sampleCount = profile['samples'];
817 for (var codeRegion in codeRegions) {
818 Code code = codeRegion['code'];
819 code.updateProfileData(codeRegion, codeTable, sampleCount);
820 }
821 } 791 }
822 792
823 /// Fetches and builds the class hierarchy for this isolate. Returns the 793 /// Fetches and builds the class hierarchy for this isolate. Returns the
824 /// Object class object. 794 /// Object class object.
825 Future<Class> getClassHierarchy() { 795 Future<Class> getClassHierarchy() {
826 return invokeRpc('getClassList', {}) 796 return invokeRpc('getClassList', {})
827 .then(_loadClasses) 797 .then(_loadClasses)
828 .then(_buildClassHierarchy); 798 .then(_buildClassHierarchy);
829 } 799 }
830 800
(...skipping 23 matching lines...) Expand all
854 } 824 }
855 } 825 }
856 assert(objectClass != null); 826 assert(objectClass != null);
857 return new Future.value(objectClass); 827 return new Future.value(objectClass);
858 } 828 }
859 829
860 ServiceObject getFromMap(ObservableMap map) { 830 ServiceObject getFromMap(ObservableMap map) {
861 if (map == null) { 831 if (map == null) {
862 return null; 832 return null;
863 } 833 }
864 String id = map['id']; 834 String mapId = map['id'];
865 var obj = _cache[id]; 835 var obj = (mapId != null) ? _cache[mapId] : null;
866 if (obj != null) { 836 if (obj != null) {
867 // Consider calling update when map is not a reference. 837 // Consider calling update when map is not a reference.
868 return obj; 838 return obj;
869 } 839 }
870 // Build the object from the map directly. 840 // Build the object from the map directly.
871 obj = new ServiceObject._fromMap(this, map); 841 obj = new ServiceObject._fromMap(this, map);
872 if (obj != null && obj.canCache) { 842 if ((obj != null) && obj.canCache) {
873 _cache[id] = obj; 843 _cache[mapId] = obj;
874 } 844 }
875 return obj; 845 return obj;
876 } 846 }
877 847
878 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { 848 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) {
879 params['isolateId'] = id; 849 params['isolateId'] = id;
880 return vm.invokeRpcNoUpgrade(method, params); 850 return vm.invokeRpcNoUpgrade(method, params);
881 } 851 }
882 852
883 Future<ServiceObject> invokeRpc(String method, Map params) { 853 Future<ServiceObject> invokeRpc(String method, Map params) {
884 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { 854 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
885 var obj = new ServiceObject._fromMap(this, response); 855 var obj = new ServiceObject._fromMap(this, response);
886 if (obj.canCache) { 856 if ((obj != null) && obj.canCache) {
887 _cache.putIfAbsent(id, () => obj); 857 String objId = obj.id;
888 } 858 _cache.putIfAbsent(objId, () => obj);
889 » return obj; 859 }
860 return obj;
890 }); 861 });
891 } 862 }
892 863
893 Future<ServiceObject> getObject(String objectId) { 864 Future<ServiceObject> getObject(String objectId) {
894 assert(objectId != null && objectId != ''); 865 assert(objectId != null && objectId != '');
895 var obj = _cache[objectId]; 866 var obj = _cache[objectId];
896 if (obj != null) { 867 if (obj != null) {
897 return obj.reload(); 868 return obj.reload();
898 } 869 }
899 Map params = { 870 Map params = {
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1035 1006
1036 Future<TagProfile> updateTagProfile() { 1007 Future<TagProfile> updateTagProfile() {
1037 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( 1008 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then(
1038 (ObservableMap map) { 1009 (ObservableMap map) {
1039 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; 1010 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0;
1040 tagProfile._processTagProfile(seconds, map); 1011 tagProfile._processTagProfile(seconds, map);
1041 return tagProfile; 1012 return tagProfile;
1042 }); 1013 });
1043 } 1014 }
1044 1015
1045 @reflectable CodeTrieNode profileTrieRoot;
1046 // The profile trie is serialized as a list of integers. Each node
1047 // is recreated by consuming some portion of the list. The format is as
1048 // follows:
1049 // [0] index into codeTable of code object.
1050 // [1] tick count (number of times this stack frame occured).
1051 // [2] child node count
1052 // Reading the trie is done by recursively reading the tree depth-first
1053 // pre-order.
1054 CodeTrieNode _processProfileTrie(List<int> data, List<Code> codeTable) {
1055 // Setup state shared across calls to _readTrieNode.
1056 _trieDataCursor = 0;
1057 _trieData = data;
1058 if (_trieData == null) {
1059 return null;
1060 }
1061 if (_trieData.length < 3) {
1062 // Not enough integers for 1 node.
1063 return null;
1064 }
1065 // Read the tree, returns the root node.
1066 return _readTrieNode(codeTable);
1067 }
1068 int _trieDataCursor;
1069 List<int> _trieData;
1070 CodeTrieNode _readTrieNode(List<Code> codeTable) {
1071 // Read index into code table.
1072 var index = _trieData[_trieDataCursor++];
1073 // Lookup code object.
1074 var code = codeTable[index];
1075 // Frame counter.
1076 var count = _trieData[_trieDataCursor++];
1077 // Create node.
1078 var node = new CodeTrieNode(code, count);
1079 // Number of children.
1080 var children = _trieData[_trieDataCursor++];
1081 // Recursively read child nodes.
1082 for (var i = 0; i < children; i++) {
1083 var child = _readTrieNode(codeTable);
1084 node.children.add(child);
1085 node.summedChildCount += child.count;
1086 }
1087 return node;
1088 }
1089
1090 ObservableList<Breakpoint> breakpoints = new ObservableList(); 1016 ObservableList<Breakpoint> breakpoints = new ObservableList();
1091 1017
1092 void _removeBreakpoint(Breakpoint bpt) { 1018 void _removeBreakpoint(Breakpoint bpt) {
1093 var script = bpt.script; 1019 var script = bpt.script;
1094 var tokenPos = bpt.tokenPos; 1020 var tokenPos = bpt.tokenPos;
1095 assert(tokenPos != null); 1021 assert(tokenPos != null);
1096 if (script.loaded) { 1022 if (script.loaded) {
1097 var line = script.tokenToLine(tokenPos); 1023 var line = script.tokenToLine(tokenPos);
1098 assert(line != null); 1024 assert(line != null);
1099 if (script.lines[line - 1] != null) { 1025 if (script.lines[line - 1] != null) {
(...skipping 761 matching lines...) Expand 10 before | Expand all | Expand 10 after
1861 1787
1862 String toString() => 'Context($length)'; 1788 String toString() => 'Context($length)';
1863 } 1789 }
1864 1790
1865 1791
1866 // TODO(koda): Sync this with VM. 1792 // TODO(koda): Sync this with VM.
1867 class FunctionKind { 1793 class FunctionKind {
1868 final String _strValue; 1794 final String _strValue;
1869 FunctionKind._internal(this._strValue); 1795 FunctionKind._internal(this._strValue);
1870 toString() => _strValue; 1796 toString() => _strValue;
1871 bool isFake() => [kCollected, kNative, kTag, kReused].contains(this); 1797 bool isSynthetic() => [kCollected, kNative, kTag, kReused].contains(this);
1872 1798
1873 static FunctionKind fromJSON(String value) { 1799 static FunctionKind fromJSON(String value) {
1874 switch(value) { 1800 switch(value) {
1875 case 'kRegularFunction': return kRegularFunction; 1801 case 'kRegularFunction': return kRegularFunction;
1876 case 'kClosureFunction': return kClosureFunction; 1802 case 'kClosureFunction': return kClosureFunction;
1877 case 'kGetterFunction': return kGetterFunction; 1803 case 'kGetterFunction': return kGetterFunction;
1878 case 'kSetterFunction': return kSetterFunction; 1804 case 'kSetterFunction': return kSetterFunction;
1879 case 'kConstructor': return kConstructor; 1805 case 'kConstructor': return kConstructor;
1880 case 'kImplicitGetter': return kImplicitGetterFunction; 1806 case 'kImplicitGetter': return kImplicitGetterFunction;
1881 case 'kImplicitSetter': return kImplicitSetterFunction; 1807 case 'kImplicitSetter': return kImplicitSetterFunction;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1920 @observable int endTokenPos; 1846 @observable int endTokenPos;
1921 @observable Code code; 1847 @observable Code code;
1922 @observable Code unoptimizedCode; 1848 @observable Code unoptimizedCode;
1923 @observable bool isOptimizable; 1849 @observable bool isOptimizable;
1924 @observable bool isInlinable; 1850 @observable bool isInlinable;
1925 @observable FunctionKind kind; 1851 @observable FunctionKind kind;
1926 @observable int deoptimizations; 1852 @observable int deoptimizations;
1927 @observable String qualifiedName; 1853 @observable String qualifiedName;
1928 @observable int usageCounter; 1854 @observable int usageCounter;
1929 @observable bool isDart; 1855 @observable bool isDart;
1856 @observable ProfileFunction profile;
1857
1858 bool get canCache => true;
1859 bool get immutable => false;
1930 1860
1931 ServiceFunction._empty(ServiceObject owner) : super._empty(owner); 1861 ServiceFunction._empty(ServiceObject owner) : super._empty(owner);
1932 1862
1933 void _update(ObservableMap map, bool mapIsRef) { 1863 void _update(ObservableMap map, bool mapIsRef) {
1934 name = map['name']; 1864 name = map['name'];
1935 vmName = (map.containsKey('vmName') ? map['vmName'] : name); 1865 vmName = (map.containsKey('vmName') ? map['vmName'] : name);
1936 1866
1937 _upgradeCollection(map, isolate); 1867 _upgradeCollection(map, isolate);
1938 1868
1939 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null; 1869 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null;
1940 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu ll; 1870 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu ll;
1941 kind = FunctionKind.fromJSON(map['kind']); 1871 kind = FunctionKind.fromJSON(map['kind']);
1942 isDart = !kind.isFake(); 1872 isDart = !kind.isSynthetic();
1943 1873
1944 if (parent == null) { 1874 if (parent == null) {
1945 qualifiedName = (owningClass != null) ? 1875 qualifiedName = (owningClass != null) ?
1946 "${owningClass.name}.${name}" : 1876 "${owningClass.name}.${name}" :
1947 name; 1877 name;
1948 } else { 1878 } else {
1949 qualifiedName = "${parent.qualifiedName}.${name}"; 1879 qualifiedName = "${parent.qualifiedName}.${name}";
1950 } 1880 }
1951 1881
1952 if (mapIsRef) { return; } 1882 if (mapIsRef) {
1883 return;
1884 }
1953 1885
1954 isStatic = map['static']; 1886 isStatic = map['static'];
1955 isConst = map['const']; 1887 isConst = map['const'];
1956 parent = map['parent']; 1888 parent = map['parent'];
1957 script = map['script']; 1889 script = map['script'];
1958 tokenPos = map['tokenPos']; 1890 tokenPos = map['tokenPos'];
1959 endTokenPos = map['endTokenPos']; 1891 endTokenPos = map['endTokenPos'];
1960 code = _convertNull(map['code']); 1892 code = _convertNull(map['code']);
1961 unoptimizedCode = _convertNull(map['unoptimizedCode']); 1893 unoptimizedCode = _convertNull(map['unoptimizedCode']);
1962 isOptimizable = map['optimizable']; 1894 isOptimizable = map['optimizable'];
1963 isInlinable = map['inlinable']; 1895 isInlinable = map['inlinable'];
1964 deoptimizations = map['deoptimizations']; 1896 deoptimizations = map['deoptimizations'];
1965 usageCounter = map['usageCounter']; 1897 usageCounter = map['usageCounter'];
1966
1967 } 1898 }
1968 } 1899 }
1969 1900
1970 1901
1971 class Field extends ServiceObject { 1902 class Field extends ServiceObject {
1972 @observable var /* Library or Class */ owner; 1903 @observable var /* Library or Class */ owner;
1973 @observable Instance declaredType; 1904 @observable Instance declaredType;
1974 @observable bool isStatic; 1905 @observable bool isStatic;
1975 @observable bool isFinal; 1906 @observable bool isFinal;
1976 @observable bool isConst; 1907 @observable bool isConst;
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
2199 } 2130 }
2200 2131
2201 void _applyHitsToLines() { 2132 void _applyHitsToLines() {
2202 for (var line in lines) { 2133 for (var line in lines) {
2203 var hits = _hits[line.line]; 2134 var hits = _hits[line.line];
2204 line.hits = hits; 2135 line.hits = hits;
2205 } 2136 }
2206 } 2137 }
2207 } 2138 }
2208 2139
2209 class CodeTick {
2210 final int address;
2211 final int exclusiveTicks;
2212 final int inclusiveTicks;
2213 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks);
2214 }
2215
2216 class PcDescriptor extends Observable { 2140 class PcDescriptor extends Observable {
2217 final int pcOffset; 2141 final int pcOffset;
2218 @reflectable final int deoptId; 2142 @reflectable final int deoptId;
2219 @reflectable final int tokenPos; 2143 @reflectable final int tokenPos;
2220 @reflectable final int tryIndex; 2144 @reflectable final int tryIndex;
2221 @reflectable final String kind; 2145 @reflectable final String kind;
2222 @observable Script script; 2146 @observable Script script;
2223 @observable String formattedLine; 2147 @observable String formattedLine;
2224 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex, 2148 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex,
2225 this.kind); 2149 this.kind);
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
2349 2273
2350 class CodeInstruction extends Observable { 2274 class CodeInstruction extends Observable {
2351 @observable final int address; 2275 @observable final int address;
2352 @observable final int pcOffset; 2276 @observable final int pcOffset;
2353 @observable final String machine; 2277 @observable final String machine;
2354 @observable final String human; 2278 @observable final String human;
2355 @observable CodeInstruction jumpTarget; 2279 @observable CodeInstruction jumpTarget;
2356 @reflectable List<PcDescriptor> descriptors = 2280 @reflectable List<PcDescriptor> descriptors =
2357 new ObservableList<PcDescriptor>(); 2281 new ObservableList<PcDescriptor>();
2358 2282
2359 static String formatPercent(num a, num total) {
2360 var percent = 100.0 * (a / total);
2361 return '${percent.toStringAsFixed(2)}%';
2362 }
2363
2364 CodeInstruction(this.address, this.pcOffset, this.machine, this.human); 2283 CodeInstruction(this.address, this.pcOffset, this.machine, this.human);
2365 2284
2366 @reflectable bool get isComment => address == 0; 2285 @reflectable bool get isComment => address == 0;
2367 @reflectable bool get hasDescriptors => descriptors.length > 0; 2286 @reflectable bool get hasDescriptors => descriptors.length > 0;
2368 2287
2369 @reflectable String formattedAddress() {
2370 if (address == 0) {
2371 return '';
2372 }
2373 return '0x${address.toRadixString(16)}';
2374 }
2375
2376 @reflectable String formattedInclusive(Code code) {
2377 if (code == null) {
2378 return '';
2379 }
2380 var tick = code.addressTicks[address];
2381 if (tick == null) {
2382 return '';
2383 }
2384 // Don't show inclusive ticks if they are the same as exclusive ticks.
2385 if (tick.inclusiveTicks == tick.exclusiveTicks) {
2386 return '';
2387 }
2388 var pcent = formatPercent(tick.inclusiveTicks, code.totalSamplesInProfile);
2389 return '$pcent (${tick.inclusiveTicks})';
2390 }
2391
2392 @reflectable String formattedExclusive(Code code) {
2393 if (code == null) {
2394 return '';
2395 }
2396 var tick = code.addressTicks[address];
2397 if (tick == null) {
2398 return '';
2399 }
2400 var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile);
2401 return '$pcent (${tick.exclusiveTicks})';
2402 }
2403
2404 bool _isJumpInstruction() { 2288 bool _isJumpInstruction() {
2405 return human.startsWith('j'); 2289 return human.startsWith('j');
2406 } 2290 }
2407 2291
2408 int _getJumpAddress() { 2292 int _getJumpAddress() {
2409 assert(_isJumpInstruction()); 2293 assert(_isJumpInstruction());
2410 var chunks = human.split(' '); 2294 var chunks = human.split(' ');
2411 if (chunks.length != 2) { 2295 if (chunks.length != 2) {
2412 // We expect jump instructions to be of the form 'j.. address'. 2296 // We expect jump instructions to be of the form 'j.. address'.
2413 return 0; 2297 return 0;
2414 } 2298 }
2415 var address = chunks[1]; 2299 var address = chunks[1];
2416 if (address.startsWith('0x')) { 2300 if (address.startsWith('0x')) {
2417 // Chop off the 0x. 2301 // Chop off the 0x.
2418 address = address.substring(2); 2302 address = address.substring(2);
2419 } 2303 }
2420 try { 2304 try {
2421 return int.parse(address, radix:16); 2305 return int.parse(address, radix:16);
2422 } catch (_) { 2306 } catch (_) {
2423 return 0; 2307 return 0;
2424 } 2308 }
2425 } 2309 }
2426 2310
2427 void _resolveJumpTarget(List<CodeInstruction> instructions) { 2311 void _resolveJumpTarget(List<CodeInstruction> instructions) {
2428 if (!_isJumpInstruction()) { 2312 if (!_isJumpInstruction()) {
2429 return; 2313 return;
2430 } 2314 }
2431 int address = _getJumpAddress(); 2315 int address = _getJumpAddress();
2432 if (address == 0) { 2316 if (address == 0) {
2433 // Could not determine jump address.
2434 Logger.root.severe('Could not determine jump address for $human');
2435 return; 2317 return;
2436 } 2318 }
2437 for (var i = 0; i < instructions.length; i++) { 2319 for (var i = 0; i < instructions.length; i++) {
2438 var instruction = instructions[i]; 2320 var instruction = instructions[i];
2439 if (instruction.address == address) { 2321 if (instruction.address == address) {
2440 jumpTarget = instruction; 2322 jumpTarget = instruction;
2441 return; 2323 return;
2442 } 2324 }
2443 } 2325 }
2444 Logger.root.severe(
2445 'Could not find instruction at ${address.toRadixString(16)}');
2446 } 2326 }
2447 } 2327 }
2448 2328
2449 class CodeKind { 2329 class CodeKind {
2450 final _value; 2330 final _value;
2451 const CodeKind._internal(this._value); 2331 const CodeKind._internal(this._value);
2452 String toString() => '$_value'; 2332 String toString() => '$_value';
2453 2333
2454 static CodeKind fromString(String s) { 2334 static CodeKind fromString(String s) {
2455 if (s == 'Native') { 2335 if (s == 'Native') {
(...skipping 10 matching lines...) Expand all
2466 Logger.root.warning('Unknown code kind $s'); 2346 Logger.root.warning('Unknown code kind $s');
2467 throw new FallThroughError(); 2347 throw new FallThroughError();
2468 } 2348 }
2469 static const Native = const CodeKind._internal('Native'); 2349 static const Native = const CodeKind._internal('Native');
2470 static const Dart = const CodeKind._internal('Dart'); 2350 static const Dart = const CodeKind._internal('Dart');
2471 static const Collected = const CodeKind._internal('Collected'); 2351 static const Collected = const CodeKind._internal('Collected');
2472 static const Reused = const CodeKind._internal('Reused'); 2352 static const Reused = const CodeKind._internal('Reused');
2473 static const Tag = const CodeKind._internal('Tag'); 2353 static const Tag = const CodeKind._internal('Tag');
2474 } 2354 }
2475 2355
2476 class CodeCallCount { 2356 class CodeInlineInterval {
2477 final Code code; 2357 final int start;
2478 final int count; 2358 final int end;
2479 CodeCallCount(this.code, this.count); 2359 final List<ServiceFunction> functions = new List<ServiceFunction>();
2480 } 2360 bool contains(int pc) => (pc >= start) && (pc < end);
2481 2361 CodeInlineInterval(this.start, this.end);
2482 class CodeTrieNode {
2483 final Code code;
2484 final int count;
2485 final children = new List<CodeTrieNode>();
2486 int summedChildCount = 0;
2487 CodeTrieNode(this.code, this.count);
2488 } 2362 }
2489 2363
2490 class Code extends ServiceObject { 2364 class Code extends ServiceObject {
2491 @observable CodeKind kind; 2365 @observable CodeKind kind;
2492 @observable int totalSamplesInProfile = 0;
2493 @reflectable int exclusiveTicks = 0;
2494 @reflectable int inclusiveTicks = 0;
2495 @reflectable int startAddress = 0;
2496 @reflectable int endAddress = 0;
2497 @reflectable final callers = new List<CodeCallCount>();
2498 @reflectable final callees = new List<CodeCallCount>();
2499 @reflectable final instructions = new ObservableList<CodeInstruction>();
2500 @reflectable final addressTicks = new ObservableMap<int, CodeTick>();
2501 @observable String formattedInclusiveTicks = '';
2502 @observable String formattedExclusiveTicks = '';
2503 @observable Instance objectPool; 2366 @observable Instance objectPool;
2504 @observable ServiceFunction function; 2367 @observable ServiceFunction function;
2505 @observable Script script; 2368 @observable Script script;
2506 @observable bool isOptimized = false; 2369 @observable bool isOptimized = false;
2507 2370 @reflectable int startAddress = 0;
2371 @reflectable int endAddress = 0;
2372 @reflectable final instructions = new ObservableList<CodeInstruction>();
2373 @observable ProfileCode profile;
2374 final List<CodeInlineInterval> inlineIntervals =
2375 new List<CodeInlineInterval>();
2376 final ObservableList<ServiceFunction> inlinedFunctions =
2377 new ObservableList<ServiceFunction>();
2508 bool get canCache => true; 2378 bool get canCache => true;
2509 bool get immutable => true; 2379 bool get immutable => true;
2510 2380
2511 Code._empty(ServiceObjectOwner owner) : super._empty(owner); 2381 Code._empty(ServiceObjectOwner owner) : super._empty(owner);
2512 2382
2513 // Reset all data associated with a profile.
2514 void resetProfileData() {
2515 totalSamplesInProfile = 0;
2516 exclusiveTicks = 0;
2517 inclusiveTicks = 0;
2518 formattedInclusiveTicks = '';
2519 formattedExclusiveTicks = '';
2520 callers.clear();
2521 callees.clear();
2522 addressTicks.clear();
2523 }
2524
2525 void _updateDescriptors(Script script) { 2383 void _updateDescriptors(Script script) {
2526 this.script = script; 2384 this.script = script;
2527 for (var instruction in instructions) { 2385 for (var instruction in instructions) {
2528 for (var descriptor in instruction.descriptors) { 2386 for (var descriptor in instruction.descriptors) {
2529 descriptor.processScript(script); 2387 descriptor.processScript(script);
2530 } 2388 }
2531 } 2389 }
2532 } 2390 }
2533 2391
2534 void loadScript() { 2392 void loadScript() {
(...skipping 28 matching lines...) Expand all
2563 /// a [ServiceError]. 2421 /// a [ServiceError].
2564 Future<ServiceObject> reload() { 2422 Future<ServiceObject> reload() {
2565 assert(kind != null); 2423 assert(kind != null);
2566 if (kind == CodeKind.Dart) { 2424 if (kind == CodeKind.Dart) {
2567 // We only reload Dart code. 2425 // We only reload Dart code.
2568 return super.reload(); 2426 return super.reload();
2569 } 2427 }
2570 return new Future.value(this); 2428 return new Future.value(this);
2571 } 2429 }
2572 2430
2573 void _resolveCalls(List<CodeCallCount> calls, List data, List<Code> codes) {
2574 // Assert that this has been cleared.
2575 assert(calls.length == 0);
2576 // Resolve.
2577 for (var i = 0; i < data.length; i += 2) {
2578 var index = int.parse(data[i]);
2579 var count = int.parse(data[i + 1]);
2580 assert(index >= 0);
2581 assert(index < codes.length);
2582 calls.add(new CodeCallCount(codes[index], count));
2583 }
2584 // Sort to descending count order.
2585 calls.sort((a, b) => b.count - a.count);
2586 }
2587
2588
2589 static String formatPercent(num a, num total) {
2590 var percent = 100.0 * (a / total);
2591 return '${percent.toStringAsFixed(2)}%';
2592 }
2593
2594 void updateProfileData(Map profileData,
2595 List<Code> codeTable,
2596 int sampleCount) {
2597 // Assert we are handed profile data for this code object.
2598 assert(profileData['code'] == this);
2599 totalSamplesInProfile = sampleCount;
2600 inclusiveTicks = int.parse(profileData['inclusive_ticks']);
2601 exclusiveTicks = int.parse(profileData['exclusive_ticks']);
2602 _resolveCalls(callers, profileData['callers'], codeTable);
2603 _resolveCalls(callees, profileData['callees'], codeTable);
2604 var ticks = profileData['ticks'];
2605 if (ticks != null) {
2606 _processTicks(ticks);
2607 }
2608 formattedInclusiveTicks =
2609 '${formatPercent(inclusiveTicks, totalSamplesInProfile)} '
2610 '($inclusiveTicks)';
2611 formattedExclusiveTicks =
2612 '${formatPercent(exclusiveTicks, totalSamplesInProfile)} '
2613 '($exclusiveTicks)';
2614 }
2615
2616 void _update(ObservableMap m, bool mapIsRef) { 2431 void _update(ObservableMap m, bool mapIsRef) {
2617 name = m['name']; 2432 name = m['name'];
2618 vmName = (m.containsKey('vmName') ? m['vmName'] : name); 2433 vmName = (m.containsKey('vmName') ? m['vmName'] : name);
2619 isOptimized = m['optimized'] != null ? m['optimized'] : false; 2434 isOptimized = m['optimized'] != null ? m['optimized'] : false;
2620 kind = CodeKind.fromString(m['kind']); 2435 kind = CodeKind.fromString(m['kind']);
2621 startAddress = int.parse(m['start'], radix:16); 2436 startAddress = int.parse(m['start'], radix:16);
2622 endAddress = int.parse(m['end'], radix:16); 2437 endAddress = int.parse(m['end'], radix:16);
2623 function = isolate.getFromMap(m['function']); 2438 function = isolate.getFromMap(m['function']);
2439 if (mapIsRef) {
2440 return;
2441 }
2442 _loaded = true;
2624 objectPool = isolate.getFromMap(m['objectPool']); 2443 objectPool = isolate.getFromMap(m['objectPool']);
2625 var disassembly = m['disassembly']; 2444 var disassembly = m['disassembly'];
2626 if (disassembly != null) { 2445 if (disassembly != null) {
2627 _processDisassembly(disassembly); 2446 _processDisassembly(disassembly);
2628 } 2447 }
2629 var descriptors = m['descriptors']; 2448 var descriptors = m['descriptors'];
2630 if (descriptors != null) { 2449 if (descriptors != null) {
2631 descriptors = descriptors['members']; 2450 descriptors = descriptors['members'];
2632 _processDescriptors(descriptors); 2451 _processDescriptors(descriptors);
2633 } 2452 }
2634 // We are loaded if we have instructions or are not Dart code.
2635 _loaded = (instructions.length != 0) || (kind != CodeKind.Dart);
2636 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart); 2453 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart);
2454 inlinedFunctions.clear();
2455 var inlinedFunctionsTable = m['inlinedFunctions'];
2456 var inlinedIntervals = m['inlinedIntervals'];
2457 if (inlinedFunctionsTable != null) {
2458 // Iterate and upgrade each ServiceFunction.
2459 for (var i = 0; i < inlinedFunctionsTable.length; i++) {
2460 // Upgrade each function and set it back in the list.
2461 var func = isolate.getFromMap(inlinedFunctionsTable[i]);
2462 inlinedFunctionsTable[i] = func;
2463 if (!inlinedFunctions.contains(func)) {
2464 inlinedFunctions.add(func);
2465 }
2466 }
2467 }
2468 if ((inlinedIntervals == null) || (inlinedFunctionsTable == null)) {
2469 // No inline information.
2470 inlineIntervals.clear();
2471 return;
2472 }
2473 _processInline(inlinedFunctionsTable, inlinedIntervals);
2474 }
2475
2476 CodeInlineInterval findInterval(int pc) {
2477 for (var i = 0; i < inlineIntervals.length; i++) {
2478 var interval = inlineIntervals[i];
2479 if (interval.contains(pc)) {
2480 return interval;
2481 }
2482 }
2483 return null;
2484 }
2485
2486 void _processInline(List<ServiceFunction> inlinedFunctionsTable,
2487 List<List<int>> inlinedIntervals) {
2488 for (var i = 0; i < inlinedIntervals.length; i++) {
2489 var inlinedInterval = inlinedIntervals[i];
2490 var start = inlinedInterval[0] + startAddress;
2491 var end = inlinedInterval[1] + startAddress;
2492 var codeInlineInterval = new CodeInlineInterval(start, end);
2493 for (var i = 2; i < inlinedInterval.length - 1; i++) {
2494 var inline_id = inlinedInterval[i];
2495 if (inline_id < 0) {
2496 continue;
2497 }
2498 var function = inlinedFunctionsTable[inline_id];
2499 codeInlineInterval.functions.add(function);
2500 }
2501 inlineIntervals.add(codeInlineInterval);
2502 }
2637 } 2503 }
2638 2504
2639 @observable bool hasDisassembly = false; 2505 @observable bool hasDisassembly = false;
2640 2506
2641 void _processDisassembly(List<String> disassembly){ 2507 void _processDisassembly(List<String> disassembly){
2642 assert(disassembly != null); 2508 assert(disassembly != null);
2643 instructions.clear(); 2509 instructions.clear();
2644 assert((disassembly.length % 3) == 0); 2510 assert((disassembly.length % 3) == 0);
2645 for (var i = 0; i < disassembly.length; i += 3) { 2511 for (var i = 0; i < disassembly.length; i += 3) {
2646 var address = 0; // Assume code comment. 2512 var address = 0; // Assume code comment.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2680 Logger.root.warning( 2546 Logger.root.warning(
2681 'Could not find instruction with pc descriptor address: $address'); 2547 'Could not find instruction with pc descriptor address: $address');
2682 } 2548 }
2683 2549
2684 void _processDescriptors(List<Map> descriptors) { 2550 void _processDescriptors(List<Map> descriptors) {
2685 for (Map descriptor in descriptors) { 2551 for (Map descriptor in descriptors) {
2686 _processDescriptor(descriptor); 2552 _processDescriptor(descriptor);
2687 } 2553 }
2688 } 2554 }
2689 2555
2690 void _processTicks(List<String> profileTicks) {
2691 assert(profileTicks != null);
2692 assert((profileTicks.length % 3) == 0);
2693 for (var i = 0; i < profileTicks.length; i += 3) {
2694 var address = int.parse(profileTicks[i], radix:16);
2695 var exclusive = int.parse(profileTicks[i + 1]);
2696 var inclusive = int.parse(profileTicks[i + 2]);
2697 var tick = new CodeTick(address, exclusive, inclusive);
2698 addressTicks[address] = tick;
2699 }
2700 }
2701
2702 /// Returns true if [address] is contained inside [this]. 2556 /// Returns true if [address] is contained inside [this].
2703 bool contains(int address) { 2557 bool contains(int address) {
2704 return (address >= startAddress) && (address < endAddress); 2558 return (address >= startAddress) && (address < endAddress);
2705 } 2559 }
2706 2560
2707 /// Sum all caller counts.
2708 int sumCallersCount() => _sumCallCount(callers);
2709 /// Specific caller count.
2710 int callersCount(Code code) => _callCount(callers, code);
2711 /// Sum of callees count.
2712 int sumCalleesCount() => _sumCallCount(callees);
2713 /// Specific callee count.
2714 int calleesCount(Code code) => _callCount(callees, code);
2715
2716 int _sumCallCount(List<CodeCallCount> calls) {
2717 var sum = 0;
2718 for (CodeCallCount caller in calls) {
2719 sum += caller.count;
2720 }
2721 return sum;
2722 }
2723
2724 int _callCount(List<CodeCallCount> calls, Code code) {
2725 for (CodeCallCount caller in calls) {
2726 if (caller.code == code) {
2727 return caller.count;
2728 }
2729 }
2730 return 0;
2731 }
2732
2733 @reflectable bool get isDartCode => kind == CodeKind.Dart; 2561 @reflectable bool get isDartCode => kind == CodeKind.Dart;
2734 } 2562 }
2735 2563
2736 2564
2737 class SocketKind { 2565 class SocketKind {
2738 final _value; 2566 final _value;
2739 const SocketKind._internal(this._value); 2567 const SocketKind._internal(this._value);
2740 String toString() => '$_value'; 2568 String toString() => '$_value';
2741 2569
2742 static SocketKind fromString(String s) { 2570 static SocketKind fromString(String s) {
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
2981 var v = list[i]; 2809 var v = list[i];
2982 if ((v is ObservableMap) && _isServiceMap(v)) { 2810 if ((v is ObservableMap) && _isServiceMap(v)) {
2983 list[i] = owner.getFromMap(v); 2811 list[i] = owner.getFromMap(v);
2984 } else if (v is ObservableList) { 2812 } else if (v is ObservableList) {
2985 _upgradeObservableList(v, owner); 2813 _upgradeObservableList(v, owner);
2986 } else if (v is ObservableMap) { 2814 } else if (v is ObservableMap) {
2987 _upgradeObservableMap(v, owner); 2815 _upgradeObservableMap(v, owner);
2988 } 2816 }
2989 } 2817 }
2990 } 2818 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/service_view.dart ('k') | runtime/observatory/lib/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698