| 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 |