Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of observatory; | |
| 6 | |
| 7 class CodeInstruction extends Observable { | |
| 8 @observable final int address; | |
| 9 @observable final String machine; | |
| 10 @observable final String human; | |
| 11 @observable int ticks = 0; | |
| 12 @observable String formattedTicks = ''; | |
| 13 @observable String formattedAddress() { | |
| 14 return '0x${address.toRadixString(16)}'; | |
| 15 } | |
| 16 CodeInstruction(this.address, this.machine, this.human); | |
| 17 void updateTickString(Code code) { | |
| 18 formattedTicks = ''; | |
| 19 if ((code == null) || (code.inclusiveTicks == 0)) { | |
| 20 return; | |
| 21 } | |
| 22 double percent = (ticks / code.inclusiveTicks) * 100.0; | |
| 23 if (percent <= 0.00) { | |
| 24 return; | |
| 25 } | |
| 26 formattedTicks = percent.toStringAsFixed(2); | |
|
turnidge
2014/01/17 19:30:21
Is it important to cache the formattedTicks? Woul
Cutch
2014/01/17 21:15:42
I only cache the percentage now (and only if it's
| |
| 27 } | |
| 28 } | |
| 29 | |
| 30 class CodeKind { | |
| 31 final _value; | |
| 32 const CodeKind._internal(this._value); | |
| 33 String toString() => 'CodeKind.$_value'; | |
| 34 | |
| 35 static CodeKind fromString(String s) { | |
| 36 if (s == 'Native') { | |
| 37 return Native; | |
| 38 } else if (s == 'Dart') { | |
| 39 return Dart; | |
| 40 } else if (s == 'Collected') { | |
| 41 return Collected; | |
| 42 } | |
| 43 throw new FallThroughError(); | |
| 44 } | |
| 45 static const Native = const CodeKind._internal('Native'); | |
| 46 static const Dart = const CodeKind._internal('Dart'); | |
| 47 static const Collected = const CodeKind._internal('Collected'); | |
| 48 } | |
| 49 | |
| 50 class CodeTick { | |
| 51 final int address; | |
| 52 final int ticks; | |
| 53 CodeTick(this.address, this.ticks); | |
| 54 } | |
| 55 | |
| 56 class Code extends Observable { | |
| 57 final CodeKind kind; | |
| 58 final int startAddress; | |
| 59 final int endAddress; | |
| 60 final List<CodeTick> ticks = []; | |
| 61 int inclusiveTicks = 0; | |
| 62 int exclusiveTicks = 0; | |
| 63 @observable final List<CodeInstruction> instructions = toObservable([]); | |
| 64 @observable Map functionRef = toObservable({}); | |
| 65 @observable Map codeRef = toObservable({}); | |
| 66 @observable String name; | |
| 67 @observable String user_name; | |
| 68 | |
| 69 Code(this.kind, this.name, this.startAddress, this.endAddress); | |
| 70 | |
| 71 Code.fromMap(Map m) : | |
| 72 kind = CodeKind.Dart, | |
| 73 startAddress = int.parse(m['start'], radix:16), | |
| 74 endAddress = int.parse(m['end'], radix:16) { | |
| 75 functionRef = toObservable(m['function']); | |
| 76 codeRef = { | |
| 77 'type': '@Code', | |
| 78 'id': m['id'], | |
| 79 'name': m['name'], | |
| 80 'user_name': m['user_name'] | |
| 81 }; | |
| 82 name = m['name']; | |
| 83 user_name = m['user_name']; | |
| 84 _loadInstructions(m['disassembly']); | |
| 85 } | |
| 86 | |
| 87 /// Resets all tick counts to 0. | |
| 88 void resetTicks() { | |
| 89 inclusiveTicks = 0; | |
| 90 exclusiveTicks = 0; | |
| 91 ticks.clear(); | |
| 92 for (var i = 0; i < instructions.length; i++) { | |
|
turnidge
2014/01/17 19:30:21
does this work instead of using an index to iterat
Cutch
2014/01/17 21:15:42
Done.
| |
| 93 var instruction = instructions[i]; | |
| 94 instruction.ticks = 0; | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 /// Adds [count] to the tick count for the instruction at [address]. | |
| 99 void tick(int address, int count) { | |
| 100 for (var i = 0; i < instructions.length; i++) { | |
| 101 var instruction = instructions[i]; | |
| 102 if (instruction.address == address) { | |
| 103 instruction.ticks += count; | |
| 104 return; | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 /// Clears [instructions] and then adds all instructions from | |
| 110 /// [instructionList]. | |
| 111 void _loadInstructions(List instructionList) { | |
| 112 if (instructionList == null) { | |
|
turnidge
2014/01/17 19:30:21
Does this happen?
Cutch
2014/01/17 21:15:42
Done.
| |
| 113 return; | |
| 114 } | |
| 115 instructions.clear(); | |
| 116 // Load disassembly into code object. | |
| 117 for (int i = 0; i < instructionList.length; i += 3) { | |
| 118 if (instructionList[i] == '') { | |
| 119 // Code comment. | |
| 120 // TODO(johnmccutchan): Insert code comments into instructions. | |
| 121 continue; | |
| 122 } | |
| 123 var address = int.parse(instructionList[i]); | |
| 124 var machine = instructionList[i + 1]; | |
| 125 var human = instructionList[i + 2]; | |
| 126 instructions.add(new CodeInstruction(address, machine, human)); | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 /// returns true if [address] is inside the address range. | |
| 131 bool contains(int address) { | |
| 132 return (address >= startAddress) && (address < endAddress); | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 class Profile { | |
| 137 final Isolate isolate; | |
| 138 Profile.fromMap(this.isolate, Map m) { | |
| 139 var codes = m['codes']; | |
| 140 totalSamples = m['samples']; | |
| 141 Logger.root.info('Creating profile from ${totalSamples} samples ' | |
| 142 'and ${codes.length} code objects.'); | |
| 143 isolate.resetCodeTicks(); | |
| 144 codes.forEach((code) { | |
| 145 try { | |
| 146 _processCode(code); | |
| 147 } catch (e, st) { | |
| 148 Logger.root.warning('Error processing code object.', e, st); | |
| 149 } | |
| 150 }); | |
| 151 } | |
| 152 int totalSamples = 0; | |
| 153 | |
| 154 Code _processDartCode(Map dartCode) { | |
| 155 var codeObject = dartCode['code']; | |
| 156 if ((codeObject == null)) { | |
| 157 // Detached code objects are handled like 'other' code. | |
| 158 return _processOtherCode(CodeKind.Dart, dartCode); | |
| 159 } | |
| 160 var code = new Code.fromMap(codeObject); | |
| 161 return code; | |
| 162 } | |
| 163 | |
| 164 Code _processOtherCode(CodeKind kind, Map otherCode) { | |
| 165 var startAddress = int.parse(otherCode['start'], radix:16); | |
| 166 var endAddress = int.parse(otherCode['end'], radix: 16); | |
| 167 var name = otherCode['name']; | |
| 168 assert(name != null); | |
| 169 return new Code(kind, name, startAddress, endAddress); | |
| 170 } | |
| 171 | |
| 172 void _processCode(Map profileCode) { | |
| 173 if (profileCode['type'] != 'ProfileCode') { | |
| 174 return; | |
| 175 } | |
| 176 var kind = CodeKind.fromString(profileCode['kind']); | |
| 177 var address; | |
| 178 if (kind == CodeKind.Dart) { | |
| 179 address = int.parse(profileCode['code']['start'], radix:16); | |
| 180 } else { | |
| 181 address = int.parse(profileCode['start'], radix:16); | |
| 182 } | |
| 183 var code = isolate.findCodeByAddress(address); | |
| 184 if (code == null) { | |
| 185 if (kind == CodeKind.Dart) { | |
| 186 code = _processDartCode(profileCode); | |
| 187 } else { | |
| 188 code = _processOtherCode(kind, profileCode); | |
| 189 } | |
| 190 assert(code != null); | |
| 191 Logger.root.info( | |
| 192 'Added code with 0x${address.toRadixString(16)} to isolate.'); | |
| 193 isolate.codes.add(code); | |
| 194 } | |
| 195 // Load code object tick counts and set them. | |
| 196 var inclusive = int.parse(profileCode['inclusive_ticks']); | |
| 197 var exclusive = int.parse(profileCode['exclusive_ticks']); | |
| 198 code.inclusiveTicks = inclusive; | |
| 199 code.exclusiveTicks = exclusive; | |
| 200 // Load address specific ticks. | |
| 201 List ticksList = profileCode['ticks']; | |
| 202 if (ticksList != null && (ticksList.length > 0)) { | |
| 203 for (var i = 0; i < ticksList.length; i += 2) { | |
| 204 var address = int.parse(ticksList[i], radix:16); | |
| 205 var ticks = int.parse(ticksList[i + 1]); | |
| 206 var codeTick = new CodeTick(address, ticks); | |
| 207 code.ticks.add(codeTick); | |
| 208 } | |
| 209 } | |
| 210 if ((code.ticks.length > 0) && (code.instructions.length > 0)) { | |
| 211 // Apply address ticks to instruction stream. | |
| 212 code.ticks.forEach((CodeTick tick) { | |
| 213 code.tick(tick.address, tick.ticks); | |
| 214 }); | |
| 215 code.instructions.forEach((i) { | |
| 216 i.updateTickString(code); | |
| 217 }); | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 | |
| 222 | |
|
turnidge
2014/01/17 19:30:21
Too many blank lines?
Cutch
2014/01/17 21:15:42
Done.
| |
| 223 List<Code> topExclusive(int N) { | |
|
turnidge
2014/01/17 19:30:21
N uses a non-standard variable casing. Consider "
Cutch
2014/01/17 21:15:42
Done.
| |
| 224 List<Code> exclusive = isolate.codes; | |
| 225 exclusive.sort((Code a, Code b) { | |
| 226 return b.exclusiveTicks - a.exclusiveTicks; | |
| 227 }); | |
| 228 if ((exclusive.length < N) || (N == 0)) { | |
| 229 return exclusive; | |
| 230 } | |
| 231 return exclusive.sublist(0, N); | |
| 232 } | |
| 233 | |
| 234 List<Code> topInclusive(int N) { | |
| 235 List<Code> inclusive = isolate.codes; | |
| 236 inclusive.sort((Code a, Code b) { | |
| 237 return b.inclusiveTicks - a.inclusiveTicks; | |
| 238 }); | |
| 239 if ((inclusive.length < N) || (N == 0)) { | |
| 240 return inclusive; | |
| 241 } | |
| 242 return inclusive.sublist(0, N); | |
| 243 } | |
| 244 } | |
| OLD | NEW |