Author: [email protected]
Date: Thu Jun 18 00:59:13 2009
New Revision: 2216

Added:
    branches/bleeding_edge/test/mjsunit/tools/logreader.js
    branches/bleeding_edge/tools/logreader.js
Modified:
    branches/bleeding_edge/src/log-utils.cc
    branches/bleeding_edge/src/log.cc
    branches/bleeding_edge/tools/linux-tick-processor
    branches/bleeding_edge/tools/tickprocessor.js
    branches/bleeding_edge/tools/windows-tick-processor.bat

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


Modified: branches/bleeding_edge/src/log-utils.cc
==============================================================================
--- branches/bleeding_edge/src/log-utils.cc     (original)
+++ branches/bleeding_edge/src/log-utils.cc     Thu Jun 18 00:59:13 2009
@@ -261,14 +261,20 @@


  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);
    }
  }

Modified: branches/bleeding_edge/src/log.cc
==============================================================================
--- branches/bleeding_edge/src/log.cc   (original)
+++ branches/bleeding_edge/src/log.cc   Thu Jun 18 00:59:13 2009
@@ -627,6 +627,42 @@
  }


+#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<char, 20> prefix_;
+};
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+
  void Logger::CodeCreateEvent(LogEventsAndTags tag,
                               Code* code,
                               const char* comment) {
@@ -643,6 +679,10 @@
      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 @@
        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 @@
        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 @@
    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,46 +758,15 @@
    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<char, 20> prefix_;
-};
-
-#endif  // ENABLE_LOGGING_AND_PROFILING


  void Logger::CodeMoveEvent(Address from, Address to) {

Added: branches/bleeding_edge/test/mjsunit/tools/logreader.js
==============================================================================
--- (empty file)
+++ branches/bleeding_edge/test/mjsunit/tools/logreader.js      Thu Jun 18  
00:59:13 2009
@@ -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 <project  
root>/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"'));
+})();

Modified: branches/bleeding_edge/tools/linux-tick-processor
==============================================================================
--- branches/bleeding_edge/tools/linux-tick-processor   (original)
+++ branches/bleeding_edge/tools/linux-tick-processor   Thu Jun 18 00:59:13  
2009
@@ -12,4 +12,4 @@
  $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

Added: branches/bleeding_edge/tools/logreader.js
==============================================================================
--- (empty file)
+++ branches/bleeding_edge/tools/logreader.js   Thu Jun 18 00:59:13 2009
@@ -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.<Object>} dispatchTable A table used for parsing and  
processing
+ *     log records.
+ * @constructor
+ */
+devtools.profiler.LogReader = function(dispatchTable) {
+  /**
+   * @type {Array.<Object>}
+   */
+  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.<string>}
+   */
+  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.<string>} stack String representation of a stack.
+ * @return {Array.<number>} 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.<string>} 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.<string>} 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.<string>} 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);
+  }
+};

Modified: branches/bleeding_edge/tools/tickprocessor.js
==============================================================================
--- branches/bleeding_edge/tools/tickprocessor.js       (original)
+++ branches/bleeding_edge/tools/tickprocessor.js       Thu Jun 18 00:59:13 2009
@@ -52,8 +52,35 @@
  }


+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 @@
    // 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 @@
  // 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.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.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 @@
      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 @@
  };


-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 @@
      ];
    } catch (e) {
      // If the library cannot be found on this system let's not panic.
-    this.symbols = [ '', '' ];
+    this.symbols = ['', ''];
    }
  };


Modified: branches/bleeding_edge/tools/windows-tick-processor.bat
==============================================================================
--- branches/bleeding_edge/tools/windows-tick-processor.bat     (original)
+++ branches/bleeding_edge/tools/windows-tick-processor.bat     Thu Jun 18  
00:59:13 2009
@@ -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 %*

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to