From a1a962f65e81c7e69228a6f318772229ae3d0d9a Mon Sep 17 00:00:00 2001 From: "mikhail.naganov@gmail.com" Date: Thu, 18 Jun 2009 07:59:13 +0000 Subject: [PATCH] Implemented processing of compressed log files. - fixed address delta calculation; - code creations are also compressed to be in sync with other events; - factored out a base class from TickProcessor to reuse code in DevTools profiler. Review URL: http://codereview.chromium.org/125256 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2216 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/log-utils.cc | 18 ++- src/log.cc | 104 ++++++++----- test/mjsunit/tools/logreader.js | 82 ++++++++++ tools/linux-tick-processor | 2 +- tools/logreader.js | 317 +++++++++++++++++++++++++++++++++++++++ tools/tickprocessor.js | 143 +++++------------- tools/windows-tick-processor.bat | 2 +- 7 files changed, 518 insertions(+), 150 deletions(-) create mode 100644 test/mjsunit/tools/logreader.js create mode 100644 tools/logreader.js diff --git a/src/log-utils.cc b/src/log-utils.cc index 028eb3a..b31864b 100644 --- a/src/log-utils.cc +++ b/src/log-utils.cc @@ -261,14 +261,20 @@ void LogMessageBuilder::AppendAddress(Address addr) { void LogMessageBuilder::AppendAddress(Address addr, Address bias) { - if (!FLAG_compress_log || bias == NULL) { + if (!FLAG_compress_log) { Append("0x%" V8PRIxPTR, addr); + } else if (bias == NULL) { + Append("%" V8PRIxPTR, addr); } else { - intptr_t delta = addr - bias; - // To avoid printing negative offsets in an unsigned form, - // we are printing an absolute value with a sign. - const char sign = delta >= 0 ? '+' : '-'; - if (sign == '-') { delta = -delta; } + uintptr_t delta; + char sign; + if (addr >= bias) { + delta = addr - bias; + sign = '+'; + } else { + delta = bias - addr; + sign = '-'; + } Append("%c%" V8PRIxPTR, sign, delta); } } diff --git a/src/log.cc b/src/log.cc index 1777234..9fbea14 100644 --- a/src/log.cc +++ b/src/log.cc @@ -627,6 +627,42 @@ void Logger::DeleteEvent(const char* name, void* object) { } +#ifdef ENABLE_LOGGING_AND_PROFILING + +// A class that contains all common code dealing with record compression. +class CompressionHelper { + public: + explicit CompressionHelper(int window_size) + : compressor_(window_size), repeat_count_(0) { } + + // Handles storing message in compressor, retrieving the previous one and + // prefixing it with repeat count, if needed. + // Returns true if message needs to be written to log. + bool HandleMessage(LogMessageBuilder* msg) { + if (!msg->StoreInCompressor(&compressor_)) { + // Current message repeats the previous one, don't write it. + ++repeat_count_; + return false; + } + if (repeat_count_ == 0) { + return msg->RetrieveCompressedPrevious(&compressor_); + } + OS::SNPrintF(prefix_, "%s,%d,", + Logger::log_events_[Logger::REPEAT_META_EVENT], + repeat_count_ + 1); + repeat_count_ = 0; + return msg->RetrieveCompressedPrevious(&compressor_, prefix_.start()); + } + + private: + LogRecordCompressor compressor_; + int repeat_count_; + EmbeddedVector prefix_; +}; + +#endif // ENABLE_LOGGING_AND_PROFILING + + void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, const char* comment) { @@ -643,6 +679,10 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, msg.Append(*p); } msg.Append('"'); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); #endif @@ -657,7 +697,12 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name) { name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); - msg.Append(",%d,\"%s\"\n", code->ExecutableSize(), *str); + msg.Append(",%d,\"%s\"", code->ExecutableSize(), *str); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } + msg.Append('\n'); msg.WriteToLogFile(); #endif } @@ -675,8 +720,13 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); - msg.Append(",%d,\"%s %s:%d\"\n", + msg.Append(",%d,\"%s %s:%d\"", code->ExecutableSize(), *str, *sourcestr, line); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } + msg.Append('\n'); msg.WriteToLogFile(); #endif } @@ -688,7 +738,12 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) { LogMessageBuilder msg; msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); - msg.Append(",%d,\"args_count: %d\"\n", code->ExecutableSize(), args_count); + msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } + msg.Append('\n'); msg.WriteToLogFile(); #endif } @@ -703,48 +758,17 @@ void Logger::RegExpCodeCreateEvent(Code* code, String* source) { msg.AppendAddress(code->address()); msg.Append(",%d,\"", code->ExecutableSize()); msg.AppendDetailed(source, false); - msg.Append("\"\n"); + msg.Append('\"'); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } + msg.Append('\n'); msg.WriteToLogFile(); #endif } -#ifdef ENABLE_LOGGING_AND_PROFILING - -// A class that contains all common code dealing with record compression. -class CompressionHelper { - public: - explicit CompressionHelper(int window_size) - : compressor_(window_size), repeat_count_(0) { } - - // Handles storing message in compressor, retrieving the previous one and - // prefixing it with repeat count, if needed. - // Returns true if message needs to be written to log. - bool HandleMessage(LogMessageBuilder* msg) { - if (!msg->StoreInCompressor(&compressor_)) { - // Current message repeats the previous one, don't write it. - ++repeat_count_; - return false; - } - if (repeat_count_ == 0) { - return msg->RetrieveCompressedPrevious(&compressor_); - } - OS::SNPrintF(prefix_, "%s,%d,", - Logger::log_events_[Logger::REPEAT_META_EVENT], - repeat_count_ + 1); - repeat_count_ = 0; - return msg->RetrieveCompressedPrevious(&compressor_, prefix_.start()); - } - - private: - LogRecordCompressor compressor_; - int repeat_count_; - EmbeddedVector prefix_; -}; - -#endif // ENABLE_LOGGING_AND_PROFILING - - void Logger::CodeMoveEvent(Address from, Address to) { #ifdef ENABLE_LOGGING_AND_PROFILING static Address prev_to_ = NULL; diff --git a/test/mjsunit/tools/logreader.js b/test/mjsunit/tools/logreader.js new file mode 100644 index 0000000..dfd7f9f --- /dev/null +++ b/test/mjsunit/tools/logreader.js @@ -0,0 +1,82 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Load CSV Parser and Log Reader implementations from /tools. +// Files: tools/csvparser.js tools/logreader.js + + +(function testAddressParser() { + var reader = new devtools.profiler.LogReader({}); + var parser = reader.createAddressParser('test'); + + // Test that 0x values are parsed, and prevAddresses_ are untouched. + assertFalse('test' in reader.prevAddresses_); + assertEquals(0, parser('0x0')); + assertFalse('test' in reader.prevAddresses_); + assertEquals(0x100, parser('0x100')); + assertFalse('test' in reader.prevAddresses_); + assertEquals(0xffffffff, parser('0xffffffff')); + assertFalse('test' in reader.prevAddresses_); + + // Test that values that has no '+' or '-' prefix are parsed + // and saved to prevAddresses_. + assertEquals(0, parser('0')); + assertEquals(0, reader.prevAddresses_.test); + assertEquals(0x100, parser('100')); + assertEquals(0x100, reader.prevAddresses_.test); + assertEquals(0xffffffff, parser('ffffffff')); + assertEquals(0xffffffff, reader.prevAddresses_.test); + + // Test that values prefixed with '+' or '-' are treated as deltas, + // and prevAddresses_ is updated. + // Set base value. + assertEquals(0x100, parser('100')); + assertEquals(0x100, reader.prevAddresses_.test); + assertEquals(0x200, parser('+100')); + assertEquals(0x200, reader.prevAddresses_.test); + assertEquals(0x100, parser('-100')); + assertEquals(0x100, reader.prevAddresses_.test); +})(); + + +(function testAddressParser() { + var reader = new devtools.profiler.LogReader({}); + + assertEquals([0x10000000, 0x10001000, 0xffff000, 0x10000000], + reader.processStack(0x10000000, ['overflow', + '+1000', '-2000', '+1000'])); +})(); + + +(function testExpandBackRef() { + var reader = new devtools.profiler.LogReader({}); + + assertEquals('aaaaaaaa', reader.expandBackRef_('aaaaaaaa')); + assertEquals('aaaaaaaa', reader.expandBackRef_('#1')); + assertEquals('bbbbaaaa', reader.expandBackRef_('bbbb#2:4')); + assertEquals('"#1:1"', reader.expandBackRef_('"#1:1"')); +})(); diff --git a/tools/linux-tick-processor b/tools/linux-tick-processor index 968c241..2de988c 100755 --- a/tools/linux-tick-processor +++ b/tools/linux-tick-processor @@ -12,4 +12,4 @@ d8_exec=$D8_PATH/d8 $d8_exec $tools_path/splaytree.js $tools_path/codemap.js \ $tools_path/csvparser.js $tools_path/consarray.js \ $tools_path/profile.js $tools_path/profile_view.js \ - $tools_path/tickprocessor.js -- $@ 2>/dev/null + $tools_path/logreader.js $tools_path/tickprocessor.js -- $@ 2>/dev/null diff --git a/tools/logreader.js b/tools/logreader.js new file mode 100644 index 0000000..78085a4 --- /dev/null +++ b/tools/logreader.js @@ -0,0 +1,317 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/** + * @fileoverview Log Reader is used to process log file produced by V8. + */ + +// Initlialize namespaces +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Base class for processing log files. + * + * @param {Array.} dispatchTable A table used for parsing and processing + * log records. + * @constructor + */ +devtools.profiler.LogReader = function(dispatchTable) { + /** + * @type {Array.} + */ + this.dispatchTable_ = dispatchTable; + this.dispatchTable_['alias'] = + { parsers: [null, null], processor: this.processAlias_ }; + this.dispatchTable_['repeat'] = + { parsers: [parseInt, 'var-args'], processor: this.processRepeat_, + backrefs: true }; + + /** + * A key-value map for aliases. Translates short name -> full name. + * @type {Object} + */ + this.aliases_ = {}; + + /** + * A key-value map for previous address values. + * @type {Object} + */ + this.prevAddresses_ = {}; + + /** + * A key-value map for events than can be backreference-compressed. + * @type {Object} + */ + this.backRefsCommands_ = {}; + this.initBackRefsCommands_(); + + /** + * Back references for decompression. + * @type {Array.} + */ + this.backRefs_ = []; +}; + + +/** + * Creates a parser for an address entry. + * + * @param {string} addressTag Address tag to perform offset decoding. + * @return {function(string):number} Address parser. + */ +devtools.profiler.LogReader.prototype.createAddressParser = function( + addressTag) { + var self = this; + return (function (str) { + var value = parseInt(str, 16); + var firstChar = str.charAt(0); + if (firstChar == '+' || firstChar == '-') { + var addr = self.prevAddresses_[addressTag]; + addr += value; + self.prevAddresses_[addressTag] = addr; + return addr; + } else if (firstChar != '0' || str.charAt(1) != 'x') { + self.prevAddresses_[addressTag] = value; + } + return value; + }); +}; + + +/** + * Expands an alias symbol, if applicable. + * + * @param {string} symbol Symbol to expand. + * @return {string} Expanded symbol, or the input symbol itself. + */ +devtools.profiler.LogReader.prototype.expandAlias = function(symbol) { + return symbol in this.aliases_ ? this.aliases_[symbol] : symbol; +}; + + +/** + * Used for printing error messages. + * + * @param {string} str Error message. + */ +devtools.profiler.LogReader.prototype.printError = function(str) { + // Do nothing. +}; + + +/** + * Processes a portion of V8 profiler event log. + * + * @param {string} chunk A portion of log. + */ +devtools.profiler.LogReader.prototype.processLogChunk = function(chunk) { + this.processLog_(chunk.split('\n')); +}; + + +/** + * Processes stack record. + * + * @param {number} pc Program counter. + * @param {Array.} stack String representation of a stack. + * @return {Array.} Processed stack. + */ +devtools.profiler.LogReader.prototype.processStack = function(pc, stack) { + var fullStack = [pc]; + var prevFrame = pc; + for (var i = 0, n = stack.length; i < n; ++i) { + var frame = stack[i]; + var firstChar = frame.charAt(0); + if (firstChar == '+' || firstChar == '-') { + // An offset from the previous frame. + prevFrame += parseInt(frame, 16); + fullStack.push(prevFrame); + // Filter out possible 'overflow' string. + } else if (firstChar != 'o') { + fullStack.push(parseInt(frame, 16)); + } + } + return fullStack; +}; + + +/** + * Returns whether a particular dispatch must be skipped. + * + * @param {!Object} dispatch Dispatch record. + * @return {boolean} True if dispatch must be skipped. + */ +devtools.profiler.LogReader.prototype.skipDispatch = function(dispatch) { + return false; +}; + + +/** + * Does a dispatch of a log record. + * + * @param {Array.} fields Log record. + * @private + */ +devtools.profiler.LogReader.prototype.dispatchLogRow_ = function(fields) { + // Obtain the dispatch. + var command = fields[0]; + if (!(command in this.dispatchTable_)) { + throw new Error('unknown command: ' + command); + } + var dispatch = this.dispatchTable_[command]; + + if (dispatch === null || this.skipDispatch(dispatch)) { + return; + } + + // Parse fields. + var parsedFields = []; + for (var i = 0; i < dispatch.parsers.length; ++i) { + var parser = dispatch.parsers[i]; + if (parser === null) { + parsedFields.push(fields[1 + i]); + } else if (typeof parser == 'function') { + parsedFields.push(parser(fields[1 + i])); + } else { + // var-args + parsedFields.push(fields.slice(1 + i)); + break; + } + } + + // Run the processor. + dispatch.processor.apply(this, parsedFields); +}; + + +/** + * Decompresses a line if it was backreference-compressed. + * + * @param {string} line Possibly compressed line. + * @return {string} Decompressed line. + * @private + */ +devtools.profiler.LogReader.prototype.expandBackRef_ = function(line) { + var backRefPos; + // Filter out case when a regexp is created containing '#'. + if (line.charAt(line.length - 1) != '"' + && (backRefPos = line.lastIndexOf('#')) != -1) { + var backRef = line.substr(backRefPos + 1); + var backRefIdx = parseInt(backRef, 10) - 1; + var colonPos = backRef.indexOf(':'); + var backRefStart = + colonPos != -1 ? parseInt(backRef.substr(colonPos + 1), 10) : 0; + line = line.substr(0, backRefPos) + + this.backRefs_[backRefIdx].substr(backRefStart); + } + this.backRefs_.unshift(line); + if (this.backRefs_.length > 10) { + this.backRefs_.length = 10; + } + return line; +}; + + +/** + * Initializes the map of backward reference compressible commands. + * @private + */ +devtools.profiler.LogReader.prototype.initBackRefsCommands_ = function() { + for (var event in this.dispatchTable_) { + var dispatch = this.dispatchTable_[event]; + if (dispatch && dispatch.backrefs) { + this.backRefsCommands_[event] = true; + } + } +}; + + +/** + * Processes alias log record. Adds an alias to a corresponding map. + * + * @param {string} symbol Short name. + * @param {string} expansion Long name. + * @private + */ +devtools.profiler.LogReader.prototype.processAlias_ = function( + symbol, expansion) { + if (expansion in this.dispatchTable_) { + this.dispatchTable_[symbol] = this.dispatchTable_[expansion]; + if (expansion in this.backRefsCommands_) { + this.backRefsCommands_[symbol] = true; + } + } else { + this.aliases_[symbol] = expansion; + } +}; + + +/** + * Processes log lines. + * + * @param {Array.} lines Log lines. + * @private + */ +devtools.profiler.LogReader.prototype.processLog_ = function(lines) { + var csvParser = new devtools.profiler.CsvParser(); + try { + for (var i = 0, n = lines.length; i < n; ++i) { + var line = lines[i]; + if (!line) { + continue; + } + if (line.charAt(0) == '#' || + line.substr(0, line.indexOf(',')) in this.backRefsCommands_) { + line = this.expandBackRef_(line); + } + var fields = csvParser.parseLine(line); + this.dispatchLogRow_(fields); + } + } catch (e) { + this.printError('line ' + (i + 1) + ': ' + (e.message || e)); + throw e; + } +}; + + +/** + * Processes repeat log record. Expands it according to calls count and + * invokes processing. + * + * @param {number} count Count. + * @param {Array.} cmd Parsed command. + * @private + */ +devtools.profiler.LogReader.prototype.processRepeat_ = function(count, cmd) { + // Replace the repeat-prefixed command from backrefs list with a non-prefixed. + this.backRefs_[0] = cmd.join(','); + for (var i = 0; i < count; ++i) { + this.dispatchLogRow_(cmd); + } +}; diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js index 3c5fab4..72d367f 100644 --- a/tools/tickprocessor.js +++ b/tools/tickprocessor.js @@ -52,8 +52,35 @@ function readFile(fileName) { } +function inherits(childCtor, parentCtor) { + function tempCtor() {}; + tempCtor.prototype = parentCtor.prototype; + childCtor.prototype = new tempCtor(); +}; + + function TickProcessor( cppEntriesProvider, separateIc, ignoreUnknown, stateFilter) { + devtools.profiler.LogReader.call(this, { + 'shared-library': { parsers: [null, parseInt, parseInt], + processor: this.processSharedLibrary }, + 'code-creation': { + parsers: [null, this.createAddressParser('code'), parseInt, null], + processor: this.processCodeCreation, backrefs: true }, + 'code-move': { parsers: [this.createAddressParser('code'), + this.createAddressParser('code-move-to')], + processor: this.processCodeMove, backrefs: true }, + 'code-delete': { parsers: [this.createAddressParser('code')], + processor: this.processCodeDelete, backrefs: true }, + 'tick': { parsers: [this.createAddressParser('code'), + this.createAddressParser('stack'), parseInt, 'var-args'], + processor: this.processTick, backrefs: true }, + 'profiler': null, + // Obsolete row types. + 'code-allocate': null, + 'begin-code-region': null, + 'end-code-region': null }); + this.cppEntriesProvider_ = cppEntriesProvider; this.ignoreUnknown_ = ignoreUnknown; this.stateFilter_ = stateFilter; @@ -86,8 +113,8 @@ function TickProcessor( // Count each tick as a time unit. this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); this.lastLogFileName_ = null; - this.aliases_ = {}; }; +inherits(TickProcessor, devtools.profiler.LogReader); TickProcessor.VmStates = { @@ -107,27 +134,17 @@ TickProcessor.CodeTypes = { // codeTypes_ map because there can be zillions of them. -TickProcessor.RecordsDispatch = { - 'shared-library': { parsers: [null, parseInt, parseInt], - processor: 'processSharedLibrary' }, - 'code-creation': { parsers: [null, parseInt, parseInt, null], - processor: 'processCodeCreation' }, - 'code-move': { parsers: [parseInt, parseInt], - processor: 'processCodeMove' }, - 'code-delete': { parsers: [parseInt], processor: 'processCodeDelete' }, - 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], - processor: 'processTick' }, - 'alias': { parsers: [null, null], processor: 'processAlias' }, - 'profiler': null, - // Obsolete row types. - 'code-allocate': null, - 'begin-code-region': null, - 'end-code-region': null -}; - TickProcessor.CALL_PROFILE_CUTOFF_PCT = 2.0; +/** + * @override + */ +TickProcessor.prototype.printError = function(str) { + print(str); +}; + + TickProcessor.prototype.setCodeType = function(name, type) { this.codeTypes_[name] = TickProcessor.CodeTypes[type]; }; @@ -151,52 +168,7 @@ TickProcessor.prototype.isJsCode = function(name) { TickProcessor.prototype.processLogFile = function(fileName) { this.lastLogFileName_ = fileName; var contents = readFile(fileName); - this.processLog(contents.split('\n')); -}; - - -TickProcessor.prototype.processLog = function(lines) { - var csvParser = new devtools.profiler.CsvParser(); - for (var i = 0, n = lines.length; i < n; ++i) { - var line = lines[i]; - if (!line) { - continue; - } - var fields = csvParser.parseLine(line); - this.dispatchLogRow(fields); - } -}; - - -TickProcessor.prototype.dispatchLogRow = function(fields) { - // Obtain the dispatch. - var command = fields[0]; - if (!(command in TickProcessor.RecordsDispatch)) { - throw new Error('unknown command: ' + command); - } - var dispatch = TickProcessor.RecordsDispatch[command]; - - if (dispatch === null) { - return; - } - - // Parse fields. - var parsedFields = []; - for (var i = 0; i < dispatch.parsers.length; ++i) { - var parser = dispatch.parsers[i]; - if (parser === null) { - parsedFields.push(fields[1 + i]); - } else if (typeof parser == 'function') { - parsedFields.push(parser(fields[1 + i])); - } else { - // var-args - parsedFields.push(fields.slice(1 + i)); - break; - } - } - - // Run the processor. - this[dispatch.processor].apply(this, parsedFields); + this.processLogChunk(contents); }; @@ -214,22 +186,10 @@ TickProcessor.prototype.processSharedLibrary = function( }; -TickProcessor.prototype.processAlias = function(symbol, expansion) { - if (expansion in TickProcessor.RecordsDispatch) { - TickProcessor.RecordsDispatch[symbol] = - TickProcessor.RecordsDispatch[expansion]; - } else { - this.aliases_[symbol] = expansion; - } -}; - - TickProcessor.prototype.processCodeCreation = function( type, start, size, name) { - if (type in this.aliases_) { - type = this.aliases_[type]; - } - var entry = this.profile_.addCode(type, name, start, size); + var entry = this.profile_.addCode( + this.expandAlias(type), name, start, size); }; @@ -256,21 +216,7 @@ TickProcessor.prototype.processTick = function(pc, sp, vmState, stack) { return; } - var fullStack = [pc]; - var prevFrame = pc; - for (var i = 0, n = stack.length; i < n; ++i) { - var frame = stack[i]; - var firstChar = frame.charAt(0); - // Leave only numbers starting with 0x. Filter possible 'overflow' string. - if (firstChar == '0') { - fullStack.push(parseInt(frame, 16)); - } else if (firstChar == '+' || firstChar == '-') { - // An offset from the previous frame. - prevFrame += parseInt(frame, 16); - fullStack.push(prevFrame); - } - } - this.profile_.recordTick(fullStack); + this.profile_.recordTick(this.processStack(pc, stack)); }; @@ -464,13 +410,6 @@ CppEntriesProvider.prototype.parseNextLine = function() { }; -function inherits(childCtor, parentCtor) { - function tempCtor() {}; - tempCtor.prototype = parentCtor.prototype; - childCtor.prototype = new tempCtor(); -}; - - function UnixCppEntriesProvider() { this.symbols = []; this.parsePos = 0; @@ -490,7 +429,7 @@ UnixCppEntriesProvider.prototype.loadSymbols = function(libName) { ]; } catch (e) { // If the library cannot be found on this system let's not panic. - this.symbols = [ '', '' ]; + this.symbols = ['', '']; } }; diff --git a/tools/windows-tick-processor.bat b/tools/windows-tick-processor.bat index 52454e3..67cbe98 100755 --- a/tools/windows-tick-processor.bat +++ b/tools/windows-tick-processor.bat @@ -2,4 +2,4 @@ SET tools_dir=%~dp0 -%tools_dir%..\d8 %tools_dir%splaytree.js %tools_dir%codemap.js %tools_dir%csvparser.js %tools_dir%consarray.js %tools_dir%profile.js %tools_dir%profile_view.js %tools_dir%tickprocessor.js -- --windows %* +%tools_dir%..\d8 %tools_dir%splaytree.js %tools_dir%codemap.js %tools_dir%csvparser.js %tools_dir%consarray.js %tools_dir%profile.js %tools_dir%profile_view.js %tools_dir%logreader.js %tools_dir%tickprocessor.js -- --windows %* -- 2.7.4