Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of service; | 5 part of service; |
| 6 | 6 |
| 7 /// A [ServiceObject] is an object known to the VM service and is tied | 7 /// A [ServiceObject] is an object known to the VM service and is tied |
| 8 /// to an owning [Isolate]. | 8 /// to an owning [Isolate]. |
| 9 abstract class ServiceObject extends Observable { | 9 abstract class ServiceObject extends Observable { |
| 10 /// The owner of this [ServiceObject]. This can be an [Isolate], a | 10 /// The owner of this [ServiceObject]. This can be an [Isolate], a |
| (...skipping 846 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 857 @observable int firstTokenPos; | 857 @observable int firstTokenPos; |
| 858 @observable int lastTokenPos; | 858 @observable int lastTokenPos; |
| 859 bool get canCache => true; | 859 bool get canCache => true; |
| 860 bool get immutable => true; | 860 bool get immutable => true; |
| 861 | 861 |
| 862 String _shortUrl; | 862 String _shortUrl; |
| 863 String _url; | 863 String _url; |
| 864 | 864 |
| 865 Script._empty(ServiceObjectOwner owner) : super._empty(owner); | 865 Script._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 866 | 866 |
| 867 ScriptLine getLine(int line) { | |
| 868 assert(line >= 1); | |
| 869 return lines[line - 1]; | |
| 870 } | |
| 871 | |
| 867 /// This function maps a token position to a line number. | 872 /// This function maps a token position to a line number. |
| 868 int tokenToLine(int token) => _tokenToLine[token]; | 873 int tokenToLine(int token) => _tokenToLine[token]; |
| 869 Map _tokenToLine; | 874 Map _tokenToLine; |
| 870 | 875 |
| 871 /// This function maps a token position to a column number. | 876 /// This function maps a token position to a column number. |
| 872 int tokenToCol(int token) => _tokenToCol[token]; | 877 int tokenToCol(int token) => _tokenToCol[token]; |
| 873 Map _tokenToCol; | 878 Map _tokenToCol; |
| 874 | 879 |
| 875 void _update(ObservableMap map, bool mapIsRef) { | 880 void _update(ObservableMap map, bool mapIsRef) { |
| 876 kind = map['kind']; | 881 kind = map['kind']; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 945 } | 950 } |
| 946 | 951 |
| 947 class CodeTick { | 952 class CodeTick { |
| 948 final int address; | 953 final int address; |
| 949 final int exclusiveTicks; | 954 final int exclusiveTicks; |
| 950 final int inclusiveTicks; | 955 final int inclusiveTicks; |
| 951 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks); | 956 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks); |
| 952 } | 957 } |
| 953 | 958 |
| 954 | 959 |
| 960 class PcDescriptor extends Observable { | |
| 961 final int address; | |
| 962 @reflectable final int deoptId; | |
| 963 @reflectable final int tokenPos; | |
| 964 @reflectable final int tryIndex; | |
| 965 @reflectable final String kind; | |
| 966 @observable Script script; | |
| 967 @observable String formattedLine; | |
| 968 PcDescriptor(this.address, this.deoptId, this.tokenPos, this.tryIndex, | |
| 969 this.kind); | |
| 970 | |
| 971 @reflectable String formattedDeoptId() { | |
| 972 if (deoptId == -1) { | |
| 973 return 'N/A'; | |
| 974 } | |
| 975 return deoptId.toString(); | |
| 976 } | |
| 977 | |
| 978 @reflectable String formattedTokenPos() { | |
| 979 if (tokenPos == -1) { | |
| 980 return ''; | |
| 981 } | |
| 982 return tokenPos.toString(); | |
| 983 } | |
| 984 | |
| 985 void processScript(Script script) { | |
| 986 this.script = null; | |
| 987 if (tokenPos == -1) { | |
| 988 return; | |
| 989 } | |
| 990 var line = script.tokenToLine(tokenPos); | |
| 991 if (line == null) { | |
| 992 return; | |
| 993 } | |
| 994 this.script = script; | |
| 995 var scriptLine = script.getLine(line); | |
| 996 formattedLine = scriptLine.text; | |
| 997 } | |
| 998 } | |
| 999 | |
| 955 class CodeInstruction extends Observable { | 1000 class CodeInstruction extends Observable { |
| 956 @observable final int address; | 1001 @observable final int address; |
| 957 @observable final String machine; | 1002 @observable final String machine; |
| 958 @observable final String human; | 1003 @observable final String human; |
| 1004 @observable CodeInstruction jumpTarget; | |
| 1005 @observable PcDescriptor descriptor; | |
|
turnidge
2014/04/28 17:41:49
from offline: support multiple descriptors.
Cutch
2014/04/28 22:48:00
Done.
| |
| 959 | 1006 |
| 960 static String formatPercent(num a, num total) { | 1007 static String formatPercent(num a, num total) { |
| 961 var percent = 100.0 * (a / total); | 1008 var percent = 100.0 * (a / total); |
| 962 return '${percent.toStringAsFixed(2)}%'; | 1009 return '${percent.toStringAsFixed(2)}%'; |
| 963 } | 1010 } |
| 964 | 1011 |
| 965 CodeInstruction(this.address, this.machine, this.human); | 1012 CodeInstruction(this.address, this.machine, this.human); |
| 966 | 1013 |
| 1014 @reflectable bool get isComment => address == 0; | |
| 1015 @reflectable bool get hasDescriptor => descriptor != null; | |
| 1016 | |
| 967 @reflectable String formattedAddress() { | 1017 @reflectable String formattedAddress() { |
| 968 if (address == 0) { | 1018 if (address == 0) { |
| 969 return ''; | 1019 return ''; |
| 970 } | 1020 } |
| 971 return '0x${address.toRadixString(16)}'; | 1021 return '0x${address.toRadixString(16)}'; |
| 972 } | 1022 } |
| 973 | 1023 |
| 974 @reflectable String formattedInclusive(Code code) { | 1024 @reflectable String formattedInclusive(Code code) { |
| 975 if (code == null) { | 1025 if (code == null) { |
| 976 return ''; | 1026 return ''; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 991 if (code == null) { | 1041 if (code == null) { |
| 992 return ''; | 1042 return ''; |
| 993 } | 1043 } |
| 994 var tick = code.addressTicks[address]; | 1044 var tick = code.addressTicks[address]; |
| 995 if (tick == null) { | 1045 if (tick == null) { |
| 996 return ''; | 1046 return ''; |
| 997 } | 1047 } |
| 998 var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile); | 1048 var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile); |
| 999 return '$pcent (${tick.exclusiveTicks})'; | 1049 return '$pcent (${tick.exclusiveTicks})'; |
| 1000 } | 1050 } |
| 1051 | |
| 1052 bool _isJumpInstruction() { | |
| 1053 return human.startsWith('j'); | |
| 1054 } | |
| 1055 | |
| 1056 int _getJumpAddress() { | |
| 1057 assert(_isJumpInstruction()); | |
| 1058 var chunks = human.split(' '); | |
| 1059 if (chunks.length != 2) { | |
| 1060 // We expect jump instructions to be of the form 'j.. address'. | |
| 1061 return 0; | |
| 1062 } | |
| 1063 var address = chunks[1]; | |
| 1064 if (address.startsWith('0x')) { | |
| 1065 // Chop off the 0x. | |
| 1066 address = address.substring(2); | |
| 1067 } | |
| 1068 try { | |
| 1069 return int.parse(address, radix:16); | |
| 1070 } catch (_) { | |
| 1071 return 0; | |
| 1072 } | |
| 1073 } | |
| 1074 | |
| 1075 void _resolveJumpTarget(List<CodeInstruction> instructions) { | |
| 1076 if (!_isJumpInstruction()) { | |
| 1077 return; | |
| 1078 } | |
| 1079 int address = _getJumpAddress(); | |
| 1080 if (address == 0) { | |
| 1081 // Could not determine jump address. | |
| 1082 print('Could not determine jump address for $human'); | |
| 1083 return; | |
| 1084 } | |
| 1085 for (var i = 0; i < instructions.length; i++) { | |
| 1086 var instruction = instructions[i]; | |
| 1087 if (instruction.address == address) { | |
| 1088 jumpTarget = instruction; | |
| 1089 return; | |
| 1090 } | |
| 1091 } | |
| 1092 print('Could not find instruction at ${address.toRadixString(16)}'); | |
| 1093 } | |
| 1001 } | 1094 } |
| 1002 | 1095 |
| 1003 class CodeKind { | 1096 class CodeKind { |
| 1004 final _value; | 1097 final _value; |
| 1005 const CodeKind._internal(this._value); | 1098 const CodeKind._internal(this._value); |
| 1006 String toString() => '$_value'; | 1099 String toString() => '$_value'; |
| 1007 | 1100 |
| 1008 static CodeKind fromString(String s) { | 1101 static CodeKind fromString(String s) { |
| 1009 if (s == 'Native') { | 1102 if (s == 'Native') { |
| 1010 return Native; | 1103 return Native; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1049 @reflectable int startAddress = 0; | 1142 @reflectable int startAddress = 0; |
| 1050 @reflectable int endAddress = 0; | 1143 @reflectable int endAddress = 0; |
| 1051 @reflectable final callers = new List<CodeCallCount>(); | 1144 @reflectable final callers = new List<CodeCallCount>(); |
| 1052 @reflectable final callees = new List<CodeCallCount>(); | 1145 @reflectable final callees = new List<CodeCallCount>(); |
| 1053 @reflectable final instructions = new ObservableList<CodeInstruction>(); | 1146 @reflectable final instructions = new ObservableList<CodeInstruction>(); |
| 1054 @reflectable final addressTicks = new ObservableMap<int, CodeTick>(); | 1147 @reflectable final addressTicks = new ObservableMap<int, CodeTick>(); |
| 1055 @observable String formattedInclusiveTicks = ''; | 1148 @observable String formattedInclusiveTicks = ''; |
| 1056 @observable String formattedExclusiveTicks = ''; | 1149 @observable String formattedExclusiveTicks = ''; |
| 1057 @observable ServiceMap objectPool; | 1150 @observable ServiceMap objectPool; |
| 1058 @observable ServiceMap function; | 1151 @observable ServiceMap function; |
| 1152 @observable Script script; | |
| 1059 String name; | 1153 String name; |
| 1060 String vmName; | 1154 String vmName; |
| 1061 | 1155 |
| 1062 bool get canCache => true; | 1156 bool get canCache => true; |
| 1063 bool get immutable => true; | 1157 bool get immutable => true; |
| 1064 | 1158 |
| 1065 Code._empty(ServiceObjectOwner owner) : super._empty(owner); | 1159 Code._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 1066 | 1160 |
| 1067 // Reset all data associated with a profile. | 1161 // Reset all data associated with a profile. |
| 1068 void resetProfileData() { | 1162 void resetProfileData() { |
| 1069 totalSamplesInProfile = 0; | 1163 totalSamplesInProfile = 0; |
| 1070 exclusiveTicks = 0; | 1164 exclusiveTicks = 0; |
| 1071 inclusiveTicks = 0; | 1165 inclusiveTicks = 0; |
| 1072 formattedInclusiveTicks = ''; | 1166 formattedInclusiveTicks = ''; |
| 1073 formattedExclusiveTicks = ''; | 1167 formattedExclusiveTicks = ''; |
| 1074 callers.clear(); | 1168 callers.clear(); |
| 1075 callees.clear(); | 1169 callees.clear(); |
| 1076 addressTicks.clear(); | 1170 addressTicks.clear(); |
| 1077 } | 1171 } |
| 1078 | 1172 |
| 1173 void _updateDescriptors(Script script) { | |
| 1174 this.script = script; | |
| 1175 for (var instruction in instructions) { | |
| 1176 if (instruction.descriptor != null) { | |
| 1177 instruction.descriptor.processScript(script); | |
| 1178 } | |
| 1179 } | |
| 1180 } | |
| 1181 | |
| 1182 void loadScript() { | |
| 1183 if (script != null) { | |
| 1184 // Already done. | |
| 1185 return; | |
| 1186 } | |
| 1187 if (kind != CodeKind.Dart){ | |
| 1188 return; | |
| 1189 } | |
| 1190 if (function == null) { | |
| 1191 return; | |
| 1192 } | |
| 1193 if (function['script'] == null) { | |
| 1194 // Attempt to load the function. | |
| 1195 function.load().then((func) { | |
| 1196 var script = function['script']; | |
| 1197 if (script == null) { | |
| 1198 // Function doesn't have an associated script. | |
| 1199 return; | |
| 1200 } | |
| 1201 // Load the script and then update descriptors. | |
| 1202 script.load().then(_updateDescriptors); | |
| 1203 }); | |
| 1204 return; | |
| 1205 } | |
| 1206 // Load the script and then update descriptors. | |
| 1207 function['script'].load().then(_updateDescriptors); | |
| 1208 } | |
| 1209 | |
| 1079 /// Reload [this]. Returns a future which completes to [this] or | 1210 /// Reload [this]. Returns a future which completes to [this] or |
| 1080 /// a [ServiceError]. | 1211 /// a [ServiceError]. |
| 1081 Future<ServiceObject> reload() { | 1212 Future<ServiceObject> reload() { |
| 1082 assert(kind != null); | 1213 assert(kind != null); |
| 1083 if (kind == CodeKind.Dart) { | 1214 if (kind == CodeKind.Dart) { |
| 1084 // We only reload Dart code. | 1215 // We only reload Dart code. |
| 1085 return super.reload(); | 1216 return super.reload(); |
| 1086 } | 1217 } |
| 1087 return new Future.value(this); | 1218 return new Future.value(this); |
| 1088 } | 1219 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1137 vmName = m['name']; | 1268 vmName = m['name']; |
| 1138 kind = CodeKind.fromString(m['kind']); | 1269 kind = CodeKind.fromString(m['kind']); |
| 1139 startAddress = int.parse(m['start'], radix:16); | 1270 startAddress = int.parse(m['start'], radix:16); |
| 1140 endAddress = int.parse(m['end'], radix:16); | 1271 endAddress = int.parse(m['end'], radix:16); |
| 1141 function = isolate.getFromMap(m['function']); | 1272 function = isolate.getFromMap(m['function']); |
| 1142 objectPool = isolate.getFromMap(m['object_pool']); | 1273 objectPool = isolate.getFromMap(m['object_pool']); |
| 1143 var disassembly = m['disassembly']; | 1274 var disassembly = m['disassembly']; |
| 1144 if (disassembly != null) { | 1275 if (disassembly != null) { |
| 1145 _processDisassembly(disassembly); | 1276 _processDisassembly(disassembly); |
| 1146 } | 1277 } |
| 1278 var descriptors = m['descriptors']; | |
| 1279 if (descriptors != null) { | |
| 1280 descriptors = descriptors['members']; | |
| 1281 _processDescriptors(descriptors); | |
| 1282 } | |
| 1147 // We are loaded if we have instructions or are not Dart code. | 1283 // We are loaded if we have instructions or are not Dart code. |
| 1148 _loaded = (instructions.length != 0) || (kind != CodeKind.Dart); | 1284 _loaded = (instructions.length != 0) || (kind != CodeKind.Dart); |
| 1149 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart); | 1285 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart); |
| 1150 } | 1286 } |
| 1151 | 1287 |
| 1152 @observable bool hasDisassembly = false; | 1288 @observable bool hasDisassembly = false; |
| 1153 | 1289 |
| 1154 void _processDisassembly(List<String> disassembly){ | 1290 void _processDisassembly(List<String> disassembly){ |
| 1155 assert(disassembly != null); | 1291 assert(disassembly != null); |
| 1156 instructions.clear(); | 1292 instructions.clear(); |
| 1157 assert((disassembly.length % 3) == 0); | 1293 assert((disassembly.length % 3) == 0); |
| 1158 for (var i = 0; i < disassembly.length; i += 3) { | 1294 for (var i = 0; i < disassembly.length; i += 3) { |
| 1159 var address = 0; // Assume code comment. | 1295 var address = 0; // Assume code comment. |
| 1160 var machine = disassembly[i + 1]; | 1296 var machine = disassembly[i + 1]; |
| 1161 var human = disassembly[i + 2]; | 1297 var human = disassembly[i + 2]; |
| 1162 if (disassembly[i] != '') { | 1298 if (disassembly[i] != '') { |
| 1163 // Not a code comment, extract address. | 1299 // Not a code comment, extract address. |
| 1164 address = int.parse(disassembly[i]); | 1300 address = int.parse(disassembly[i]); |
| 1165 } | 1301 } |
| 1166 var instruction = new CodeInstruction(address, machine, human); | 1302 var instruction = new CodeInstruction(address, machine, human); |
| 1167 instructions.add(instruction); | 1303 instructions.add(instruction); |
| 1168 } | 1304 } |
| 1305 for (var instruction in instructions) { | |
| 1306 instruction._resolveJumpTarget(instructions); | |
| 1307 } | |
| 1308 } | |
| 1309 | |
| 1310 void _processDescriptor(Map d) { | |
| 1311 var address = int.parse(d['pc'], radix:16); | |
| 1312 var deoptId = d['deoptId']; | |
| 1313 var tokenPos = d['tokenPos']; | |
| 1314 var tryIndex = d['tryIndex']; | |
| 1315 var kind = d['kind'].trim(); | |
| 1316 for (var instruction in instructions) { | |
| 1317 if (instruction.address == address) { | |
| 1318 instruction.descriptor = new PcDescriptor(address, | |
| 1319 deoptId, | |
| 1320 tokenPos, | |
| 1321 tryIndex, | |
| 1322 kind); | |
| 1323 return; | |
| 1324 } | |
| 1325 } | |
| 1326 Logger.root.warning( | |
| 1327 'Could not find instruction with pc descriptor address: $address'); | |
| 1328 } | |
| 1329 | |
| 1330 void _processDescriptors(List<Map> descriptors) { | |
| 1331 for (Map descriptor in descriptors) { | |
| 1332 _processDescriptor(descriptor); | |
| 1333 } | |
| 1169 } | 1334 } |
| 1170 | 1335 |
| 1171 void _processTicks(List<String> profileTicks) { | 1336 void _processTicks(List<String> profileTicks) { |
| 1172 assert(profileTicks != null); | 1337 assert(profileTicks != null); |
| 1173 assert((profileTicks.length % 3) == 0); | 1338 assert((profileTicks.length % 3) == 0); |
| 1174 for (var i = 0; i < profileTicks.length; i += 3) { | 1339 for (var i = 0; i < profileTicks.length; i += 3) { |
| 1175 var address = int.parse(profileTicks[i], radix:16); | 1340 var address = int.parse(profileTicks[i], radix:16); |
| 1176 var exclusive = int.parse(profileTicks[i + 1]); | 1341 var exclusive = int.parse(profileTicks[i + 1]); |
| 1177 var inclusive = int.parse(profileTicks[i + 2]); | 1342 var inclusive = int.parse(profileTicks[i + 2]); |
| 1178 var tick = new CodeTick(address, exclusive, inclusive); | 1343 var tick = new CodeTick(address, exclusive, inclusive); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1254 var v = list[i]; | 1419 var v = list[i]; |
| 1255 if ((v is ObservableMap) && _isServiceMap(v)) { | 1420 if ((v is ObservableMap) && _isServiceMap(v)) { |
| 1256 list[i] = owner.getFromMap(v); | 1421 list[i] = owner.getFromMap(v); |
| 1257 } else if (v is ObservableList) { | 1422 } else if (v is ObservableList) { |
| 1258 _upgradeObservableList(v, owner); | 1423 _upgradeObservableList(v, owner); |
| 1259 } else if (v is ObservableMap) { | 1424 } else if (v is ObservableMap) { |
| 1260 _upgradeObservableMap(v, owner); | 1425 _upgradeObservableMap(v, owner); |
| 1261 } | 1426 } |
| 1262 } | 1427 } |
| 1263 } | 1428 } |
| OLD | NEW |