OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 function readFile(fileName) { | 45 function readFile(fileName) { |
46 try { | 46 try { |
47 return read(fileName); | 47 return read(fileName); |
48 } catch (e) { | 48 } catch (e) { |
49 print(fileName + ': ' + (e.message || e)); | 49 print(fileName + ': ' + (e.message || e)); |
50 throw e; | 50 throw e; |
51 } | 51 } |
52 } | 52 } |
53 | 53 |
54 | 54 |
| 55 function inherits(childCtor, parentCtor) { |
| 56 function tempCtor() {}; |
| 57 tempCtor.prototype = parentCtor.prototype; |
| 58 childCtor.prototype = new tempCtor(); |
| 59 }; |
| 60 |
| 61 |
55 function TickProcessor( | 62 function TickProcessor( |
56 cppEntriesProvider, separateIc, ignoreUnknown, stateFilter) { | 63 cppEntriesProvider, separateIc, ignoreUnknown, stateFilter) { |
| 64 devtools.profiler.LogReader.call(this, { |
| 65 'shared-library': { parsers: [null, parseInt, parseInt], |
| 66 processor: this.processSharedLibrary }, |
| 67 'code-creation': { |
| 68 parsers: [null, this.createAddressParser('code'), parseInt, null], |
| 69 processor: this.processCodeCreation, backrefs: true }, |
| 70 'code-move': { parsers: [this.createAddressParser('code'), |
| 71 this.createAddressParser('code-move-to')], |
| 72 processor: this.processCodeMove, backrefs: true }, |
| 73 'code-delete': { parsers: [this.createAddressParser('code')], |
| 74 processor: this.processCodeDelete, backrefs: true }, |
| 75 'tick': { parsers: [this.createAddressParser('code'), |
| 76 this.createAddressParser('stack'), parseInt, 'var-args'], |
| 77 processor: this.processTick, backrefs: true }, |
| 78 'profiler': null, |
| 79 // Obsolete row types. |
| 80 'code-allocate': null, |
| 81 'begin-code-region': null, |
| 82 'end-code-region': null }); |
| 83 |
57 this.cppEntriesProvider_ = cppEntriesProvider; | 84 this.cppEntriesProvider_ = cppEntriesProvider; |
58 this.ignoreUnknown_ = ignoreUnknown; | 85 this.ignoreUnknown_ = ignoreUnknown; |
59 this.stateFilter_ = stateFilter; | 86 this.stateFilter_ = stateFilter; |
60 var ticks = this.ticks_ = | 87 var ticks = this.ticks_ = |
61 { total: 0, unaccounted: 0, excluded: 0, gc: 0 }; | 88 { total: 0, unaccounted: 0, excluded: 0, gc: 0 }; |
62 | 89 |
63 Profile.prototype.handleUnknownCode = function( | 90 Profile.prototype.handleUnknownCode = function( |
64 operation, addr, opt_stackPos) { | 91 operation, addr, opt_stackPos) { |
65 var op = devtools.profiler.Profile.Operation; | 92 var op = devtools.profiler.Profile.Operation; |
66 switch (operation) { | 93 switch (operation) { |
(...skipping 12 matching lines...) Expand all Loading... |
79 } | 106 } |
80 break; | 107 break; |
81 } | 108 } |
82 }; | 109 }; |
83 | 110 |
84 this.profile_ = new Profile(separateIc); | 111 this.profile_ = new Profile(separateIc); |
85 this.codeTypes_ = {}; | 112 this.codeTypes_ = {}; |
86 // Count each tick as a time unit. | 113 // Count each tick as a time unit. |
87 this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); | 114 this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); |
88 this.lastLogFileName_ = null; | 115 this.lastLogFileName_ = null; |
89 this.aliases_ = {}; | |
90 }; | 116 }; |
| 117 inherits(TickProcessor, devtools.profiler.LogReader); |
91 | 118 |
92 | 119 |
93 TickProcessor.VmStates = { | 120 TickProcessor.VmStates = { |
94 JS: 0, | 121 JS: 0, |
95 GC: 1, | 122 GC: 1, |
96 COMPILER: 2, | 123 COMPILER: 2, |
97 OTHER: 3, | 124 OTHER: 3, |
98 EXTERNAL: 4 | 125 EXTERNAL: 4 |
99 }; | 126 }; |
100 | 127 |
101 | 128 |
102 TickProcessor.CodeTypes = { | 129 TickProcessor.CodeTypes = { |
103 CPP: 0, | 130 CPP: 0, |
104 SHARED_LIB: 1 | 131 SHARED_LIB: 1 |
105 }; | 132 }; |
106 // Otherwise, this is JS-related code. We are not adding it to | 133 // Otherwise, this is JS-related code. We are not adding it to |
107 // codeTypes_ map because there can be zillions of them. | 134 // codeTypes_ map because there can be zillions of them. |
108 | 135 |
109 | 136 |
110 TickProcessor.RecordsDispatch = { | 137 TickProcessor.CALL_PROFILE_CUTOFF_PCT = 2.0; |
111 'shared-library': { parsers: [null, parseInt, parseInt], | 138 |
112 processor: 'processSharedLibrary' }, | 139 |
113 'code-creation': { parsers: [null, parseInt, parseInt, null], | 140 /** |
114 processor: 'processCodeCreation' }, | 141 * @override |
115 'code-move': { parsers: [parseInt, parseInt], | 142 */ |
116 processor: 'processCodeMove' }, | 143 TickProcessor.prototype.printError = function(str) { |
117 'code-delete': { parsers: [parseInt], processor: 'processCodeDelete' }, | 144 print(str); |
118 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], | |
119 processor: 'processTick' }, | |
120 'alias': { parsers: [null, null], processor: 'processAlias' }, | |
121 'profiler': null, | |
122 // Obsolete row types. | |
123 'code-allocate': null, | |
124 'begin-code-region': null, | |
125 'end-code-region': null | |
126 }; | 145 }; |
127 | 146 |
128 TickProcessor.CALL_PROFILE_CUTOFF_PCT = 2.0; | |
129 | |
130 | 147 |
131 TickProcessor.prototype.setCodeType = function(name, type) { | 148 TickProcessor.prototype.setCodeType = function(name, type) { |
132 this.codeTypes_[name] = TickProcessor.CodeTypes[type]; | 149 this.codeTypes_[name] = TickProcessor.CodeTypes[type]; |
133 }; | 150 }; |
134 | 151 |
135 | 152 |
136 TickProcessor.prototype.isSharedLibrary = function(name) { | 153 TickProcessor.prototype.isSharedLibrary = function(name) { |
137 return this.codeTypes_[name] == TickProcessor.CodeTypes.SHARED_LIB; | 154 return this.codeTypes_[name] == TickProcessor.CodeTypes.SHARED_LIB; |
138 }; | 155 }; |
139 | 156 |
140 | 157 |
141 TickProcessor.prototype.isCppCode = function(name) { | 158 TickProcessor.prototype.isCppCode = function(name) { |
142 return this.codeTypes_[name] == TickProcessor.CodeTypes.CPP; | 159 return this.codeTypes_[name] == TickProcessor.CodeTypes.CPP; |
143 }; | 160 }; |
144 | 161 |
145 | 162 |
146 TickProcessor.prototype.isJsCode = function(name) { | 163 TickProcessor.prototype.isJsCode = function(name) { |
147 return !(name in this.codeTypes_); | 164 return !(name in this.codeTypes_); |
148 }; | 165 }; |
149 | 166 |
150 | 167 |
151 TickProcessor.prototype.processLogFile = function(fileName) { | 168 TickProcessor.prototype.processLogFile = function(fileName) { |
152 this.lastLogFileName_ = fileName; | 169 this.lastLogFileName_ = fileName; |
153 var contents = readFile(fileName); | 170 var contents = readFile(fileName); |
154 this.processLog(contents.split('\n')); | 171 this.processLogChunk(contents); |
155 }; | 172 }; |
156 | 173 |
157 | 174 |
158 TickProcessor.prototype.processLog = function(lines) { | |
159 var csvParser = new devtools.profiler.CsvParser(); | |
160 for (var i = 0, n = lines.length; i < n; ++i) { | |
161 var line = lines[i]; | |
162 if (!line) { | |
163 continue; | |
164 } | |
165 var fields = csvParser.parseLine(line); | |
166 this.dispatchLogRow(fields); | |
167 } | |
168 }; | |
169 | |
170 | |
171 TickProcessor.prototype.dispatchLogRow = function(fields) { | |
172 // Obtain the dispatch. | |
173 var command = fields[0]; | |
174 if (!(command in TickProcessor.RecordsDispatch)) { | |
175 throw new Error('unknown command: ' + command); | |
176 } | |
177 var dispatch = TickProcessor.RecordsDispatch[command]; | |
178 | |
179 if (dispatch === null) { | |
180 return; | |
181 } | |
182 | |
183 // Parse fields. | |
184 var parsedFields = []; | |
185 for (var i = 0; i < dispatch.parsers.length; ++i) { | |
186 var parser = dispatch.parsers[i]; | |
187 if (parser === null) { | |
188 parsedFields.push(fields[1 + i]); | |
189 } else if (typeof parser == 'function') { | |
190 parsedFields.push(parser(fields[1 + i])); | |
191 } else { | |
192 // var-args | |
193 parsedFields.push(fields.slice(1 + i)); | |
194 break; | |
195 } | |
196 } | |
197 | |
198 // Run the processor. | |
199 this[dispatch.processor].apply(this, parsedFields); | |
200 }; | |
201 | |
202 | |
203 TickProcessor.prototype.processSharedLibrary = function( | 175 TickProcessor.prototype.processSharedLibrary = function( |
204 name, startAddr, endAddr) { | 176 name, startAddr, endAddr) { |
205 var entry = this.profile_.addStaticCode(name, startAddr, endAddr); | 177 var entry = this.profile_.addStaticCode(name, startAddr, endAddr); |
206 this.setCodeType(entry.getName(), 'SHARED_LIB'); | 178 this.setCodeType(entry.getName(), 'SHARED_LIB'); |
207 | 179 |
208 var self = this; | 180 var self = this; |
209 var libFuncs = this.cppEntriesProvider_.parseVmSymbols( | 181 var libFuncs = this.cppEntriesProvider_.parseVmSymbols( |
210 name, startAddr, endAddr, function(fName, fStart, fEnd) { | 182 name, startAddr, endAddr, function(fName, fStart, fEnd) { |
211 self.profile_.addStaticCode(fName, fStart, fEnd); | 183 self.profile_.addStaticCode(fName, fStart, fEnd); |
212 self.setCodeType(fName, 'CPP'); | 184 self.setCodeType(fName, 'CPP'); |
213 }); | 185 }); |
214 }; | 186 }; |
215 | 187 |
216 | 188 |
217 TickProcessor.prototype.processAlias = function(symbol, expansion) { | |
218 if (expansion in TickProcessor.RecordsDispatch) { | |
219 TickProcessor.RecordsDispatch[symbol] = | |
220 TickProcessor.RecordsDispatch[expansion]; | |
221 } else { | |
222 this.aliases_[symbol] = expansion; | |
223 } | |
224 }; | |
225 | |
226 | |
227 TickProcessor.prototype.processCodeCreation = function( | 189 TickProcessor.prototype.processCodeCreation = function( |
228 type, start, size, name) { | 190 type, start, size, name) { |
229 if (type in this.aliases_) { | 191 var entry = this.profile_.addCode( |
230 type = this.aliases_[type]; | 192 this.expandAlias(type), name, start, size); |
231 } | |
232 var entry = this.profile_.addCode(type, name, start, size); | |
233 }; | 193 }; |
234 | 194 |
235 | 195 |
236 TickProcessor.prototype.processCodeMove = function(from, to) { | 196 TickProcessor.prototype.processCodeMove = function(from, to) { |
237 this.profile_.moveCode(from, to); | 197 this.profile_.moveCode(from, to); |
238 }; | 198 }; |
239 | 199 |
240 | 200 |
241 TickProcessor.prototype.processCodeDelete = function(start) { | 201 TickProcessor.prototype.processCodeDelete = function(start) { |
242 this.profile_.deleteCode(start); | 202 this.profile_.deleteCode(start); |
243 }; | 203 }; |
244 | 204 |
245 | 205 |
246 TickProcessor.prototype.includeTick = function(vmState) { | 206 TickProcessor.prototype.includeTick = function(vmState) { |
247 return this.stateFilter_ == null || this.stateFilter_ == vmState; | 207 return this.stateFilter_ == null || this.stateFilter_ == vmState; |
248 }; | 208 }; |
249 | 209 |
250 | 210 |
251 TickProcessor.prototype.processTick = function(pc, sp, vmState, stack) { | 211 TickProcessor.prototype.processTick = function(pc, sp, vmState, stack) { |
252 this.ticks_.total++; | 212 this.ticks_.total++; |
253 if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++; | 213 if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++; |
254 if (!this.includeTick(vmState)) { | 214 if (!this.includeTick(vmState)) { |
255 this.ticks_.excluded++; | 215 this.ticks_.excluded++; |
256 return; | 216 return; |
257 } | 217 } |
258 | 218 |
259 var fullStack = [pc]; | 219 this.profile_.recordTick(this.processStack(pc, stack)); |
260 var prevFrame = pc; | |
261 for (var i = 0, n = stack.length; i < n; ++i) { | |
262 var frame = stack[i]; | |
263 var firstChar = frame.charAt(0); | |
264 // Leave only numbers starting with 0x. Filter possible 'overflow' string. | |
265 if (firstChar == '0') { | |
266 fullStack.push(parseInt(frame, 16)); | |
267 } else if (firstChar == '+' || firstChar == '-') { | |
268 // An offset from the previous frame. | |
269 prevFrame += parseInt(frame, 16); | |
270 fullStack.push(prevFrame); | |
271 } | |
272 } | |
273 this.profile_.recordTick(fullStack); | |
274 }; | 220 }; |
275 | 221 |
276 | 222 |
277 TickProcessor.prototype.printStatistics = function() { | 223 TickProcessor.prototype.printStatistics = function() { |
278 print('Statistical profiling result from ' + this.lastLogFileName_ + | 224 print('Statistical profiling result from ' + this.lastLogFileName_ + |
279 ', (' + this.ticks_.total + | 225 ', (' + this.ticks_.total + |
280 ' ticks, ' + this.ticks_.unaccounted + ' unaccounted, ' + | 226 ' ticks, ' + this.ticks_.unaccounted + ' unaccounted, ' + |
281 this.ticks_.excluded + ' excluded).'); | 227 this.ticks_.excluded + ' excluded).'); |
282 | 228 |
283 if (this.ticks_.total == 0) return; | 229 if (this.ticks_.total == 0) return; |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 | 403 |
458 CppEntriesProvider.prototype.loadSymbols = function(libName) { | 404 CppEntriesProvider.prototype.loadSymbols = function(libName) { |
459 }; | 405 }; |
460 | 406 |
461 | 407 |
462 CppEntriesProvider.prototype.parseNextLine = function() { | 408 CppEntriesProvider.prototype.parseNextLine = function() { |
463 return false; | 409 return false; |
464 }; | 410 }; |
465 | 411 |
466 | 412 |
467 function inherits(childCtor, parentCtor) { | |
468 function tempCtor() {}; | |
469 tempCtor.prototype = parentCtor.prototype; | |
470 childCtor.prototype = new tempCtor(); | |
471 }; | |
472 | |
473 | |
474 function UnixCppEntriesProvider() { | 413 function UnixCppEntriesProvider() { |
475 this.symbols = []; | 414 this.symbols = []; |
476 this.parsePos = 0; | 415 this.parsePos = 0; |
477 }; | 416 }; |
478 inherits(UnixCppEntriesProvider, CppEntriesProvider); | 417 inherits(UnixCppEntriesProvider, CppEntriesProvider); |
479 | 418 |
480 | 419 |
481 UnixCppEntriesProvider.FUNC_RE = /^([0-9a-fA-F]{8}) [tTwW] (.*)$/; | 420 UnixCppEntriesProvider.FUNC_RE = /^([0-9a-fA-F]{8}) [tTwW] (.*)$/; |
482 | 421 |
483 | 422 |
484 UnixCppEntriesProvider.prototype.loadSymbols = function(libName) { | 423 UnixCppEntriesProvider.prototype.loadSymbols = function(libName) { |
485 this.parsePos = 0; | 424 this.parsePos = 0; |
486 try { | 425 try { |
487 this.symbols = [ | 426 this.symbols = [ |
488 os.system('nm', ['-C', '-n', libName], -1, -1), | 427 os.system('nm', ['-C', '-n', libName], -1, -1), |
489 os.system('nm', ['-C', '-n', '-D', libName], -1, -1) | 428 os.system('nm', ['-C', '-n', '-D', libName], -1, -1) |
490 ]; | 429 ]; |
491 } catch (e) { | 430 } catch (e) { |
492 // If the library cannot be found on this system let's not panic. | 431 // If the library cannot be found on this system let's not panic. |
493 this.symbols = [ '', '' ]; | 432 this.symbols = ['', '']; |
494 } | 433 } |
495 }; | 434 }; |
496 | 435 |
497 | 436 |
498 UnixCppEntriesProvider.prototype.parseNextLine = function() { | 437 UnixCppEntriesProvider.prototype.parseNextLine = function() { |
499 if (this.symbols.length == 0) { | 438 if (this.symbols.length == 0) { |
500 return false; | 439 return false; |
501 } | 440 } |
502 var lineEndPos = this.symbols[0].indexOf('\n', this.parsePos); | 441 var lineEndPos = this.symbols[0].indexOf('\n', this.parsePos); |
503 if (lineEndPos == -1) { | 442 if (lineEndPos == -1) { |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 | 592 |
654 var params = processArguments(arguments); | 593 var params = processArguments(arguments); |
655 var tickProcessor = new TickProcessor( | 594 var tickProcessor = new TickProcessor( |
656 params.platform == 'unix' ? new UnixCppEntriesProvider() : | 595 params.platform == 'unix' ? new UnixCppEntriesProvider() : |
657 new WindowsCppEntriesProvider(), | 596 new WindowsCppEntriesProvider(), |
658 params.separateIc, | 597 params.separateIc, |
659 params.ignoreUnknown, | 598 params.ignoreUnknown, |
660 params.stateFilter); | 599 params.stateFilter); |
661 tickProcessor.processLogFile(params.logFileName); | 600 tickProcessor.processLogFile(params.logFileName); |
662 tickProcessor.printStatistics(); | 601 tickProcessor.printStatistics(); |
OLD | NEW |