Don't keep data about JS code that is never executed.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 8 May 2009 11:27:02 +0000 (11:27 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 8 May 2009 11:27:02 +0000 (11:27 +0000)
This reduces memory usage of tickprocessor. Thanks to William Hesse for pointing out this issue.

Also speed up static symbols loading.

Review URL: http://codereview.chromium.org/113101

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1902 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

test/mjsunit/tools/codemap.js
tools/codemap.js
tools/tickprocessor.js

index fdad819..55b8758 100644 (file)
@@ -123,4 +123,36 @@ function assertNoEntry(codeMap, addr) {
   codeMap.addCode(0x1700, newCodeEntry(0x100, 'code'));
   assertEntry(codeMap, 'code', 0x1500);
   assertEntry(codeMap, 'code {1}', 0x1700);
+  // Test name stability.
+  assertEntry(codeMap, 'code', 0x1500);
+  assertEntry(codeMap, 'code {1}', 0x1700);
+})();
+
+
+(function testStaticEntriesExport() {
+  var codeMap = new devtools.profiler.CodeMap();
+  codeMap.addStaticCode(0x1500, newCodeEntry(0x3000, 'lib1'));
+  codeMap.addStaticCode(0x15500, newCodeEntry(0x5000, 'lib2'));
+  codeMap.addStaticCode(0x155500, newCodeEntry(0x10000, 'lib3'));
+  var allStatics = codeMap.getAllStaticEntries();
+  allStatics.sort();
+  assertEquals(['lib1: 3000', 'lib2: 5000', 'lib3: 10000'], allStatics);
+})();
+
+
+(function testDynamicEntriesExport() {
+  var codeMap = new devtools.profiler.CodeMap();
+  codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1'));
+  codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2'));
+  codeMap.addCode(0x1900, newCodeEntry(0x50, 'code3'));
+  var allDynamics = codeMap.getAllDynamicEntries();
+  allDynamics.sort();
+  assertEquals(['code1: 200', 'code2: 100', 'code3: 50'], allDynamics);
+  codeMap.deleteCode(0x1700);
+  var allDynamics2 = codeMap.getAllDynamicEntries();
+  allDynamics2.sort();
+  assertEquals(['code1: 200', 'code3: 50'], allDynamics2);
+  codeMap.deleteCode(0x1500);
+  var allDynamics3 = codeMap.getAllDynamicEntries();
+  assertEquals(['code3: 50'], allDynamics3);
 })();
index 32e03d6..3766db0 100644 (file)
@@ -43,10 +43,8 @@ devtools.profiler.CodeMap = function() {
   this.dynamics_ = new goog.structs.SplayTree();
 
   /**
-   * Deleted code entries. Used for code collected by the GC.
+   * Name generator for entries having duplicate names.
    */
-  this.deleted_ = [];
-
   this.dynamicsNameGen_ = new devtools.profiler.CodeMap.NameGenerator();
 
   /**
@@ -81,8 +79,6 @@ devtools.profiler.CodeMap.PAGE_SIZE =
  * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object.
  */
 devtools.profiler.CodeMap.prototype.addCode = function(start, codeEntry) {
-  var entryName = this.dynamicsNameGen_.getName(codeEntry.name);
-  codeEntry.name = entryName;
   this.dynamics_.insert(start, codeEntry);
 };
 
@@ -102,14 +98,12 @@ devtools.profiler.CodeMap.prototype.moveCode = function(from, to) {
 
 /**
  * Discards a dynamic code entry. Throws an exception if there is no dynamic
- * code entry with the specified starting address. The entry will still be
- * returned from the 'getAllDynamicEntries' method.
+ * code entry with the specified starting address.
  *
  * @param {number} start The starting address of the entry being deleted.
  */
 devtools.profiler.CodeMap.prototype.deleteCode = function(start) {
   var removedNode = this.dynamics_.remove(start);
-  this.deleted_.push(removedNode.value);
 };
 
 
@@ -168,7 +162,14 @@ devtools.profiler.CodeMap.prototype.findEntry = function(addr) {
   var min = this.dynamics_.findMin();
   var max = this.dynamics_.findMax();
   if (max != null && addr < (max.key + max.value.size) && addr >= min.key) {
-    return this.findInTree_(this.dynamics_, addr);
+    var dynaEntry = this.findInTree_(this.dynamics_, addr);
+    if (dynaEntry == null) return null;
+    // Dedupe entry name.
+    if (!dynaEntry.nameUpdated_) {
+      dynaEntry.name = this.dynamicsNameGen_.getName(dynaEntry.name);
+      dynaEntry.nameUpdated_ = true;
+    }
+    return dynaEntry;
   }
   return null;
 };
@@ -178,8 +179,7 @@ devtools.profiler.CodeMap.prototype.findEntry = function(addr) {
  * Returns an array of all dynamic code entries, including deleted ones.
  */
 devtools.profiler.CodeMap.prototype.getAllDynamicEntries = function() {
-  var dynamicEntries = this.dynamics_.exportValues();
-  return dynamicEntries.concat(this.deleted_);
+  return this.dynamics_.exportValues();
 };
 
 
@@ -201,6 +201,7 @@ devtools.profiler.CodeMap.prototype.getAllStaticEntries = function() {
 devtools.profiler.CodeMap.CodeEntry = function(size, opt_name) {
   this.size = size;
   this.name = opt_name || '';
+  this.nameUpdated_ = false;
 };
 
 
index 64020ca..196daa9 100644 (file)
@@ -99,10 +99,11 @@ TickProcessor.VmStates = {
 
 
 TickProcessor.CodeTypes = {
-  JS: 0,
-  CPP: 1,
-  SHARED_LIB: 2
+  CPP: 0,
+  SHARED_LIB: 1
 };
+// Otherwise, this is JS-related code. We are not adding it to
+// codeTypes_ map because there can be zillions of them.
 
 
 TickProcessor.RecordsDispatch = {
@@ -142,7 +143,7 @@ TickProcessor.prototype.isCppCode = function(name) {
 
 
 TickProcessor.prototype.isJsCode = function(name) {
-  return this.codeTypes_[name] == TickProcessor.CodeTypes.JS;
+  return !(name in this.codeTypes_);
 };
 
 
@@ -220,7 +221,6 @@ TickProcessor.prototype.processSharedLibrary = function(
 TickProcessor.prototype.processCodeCreation = function(
     type, start, size, name) {
   var entry = this.profile_.addCode(type, name, start, size);
-  this.setCodeType(entry.getName(), 'JS');
 };
 
 
@@ -415,8 +415,7 @@ function CppEntriesProvider() {
 
 CppEntriesProvider.prototype.parseVmSymbols = function(
     libName, libStart, libEnd, processorFunc) {
-  var syms = this.loadSymbols(libName);
-  if (syms.length == 0) return;
+  this.loadSymbols(libName);
 
   var prevEntry;
 
@@ -428,11 +427,12 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
     }
   }
 
-  for (var i = 0, n = syms.length; i < n; ++i) {
-    var line = syms[i];
-    var funcInfo = this.parseLine(line);
-    if (!funcInfo) {
+  while (true) {
+    var funcInfo = this.parseNextLine();
+    if (funcInfo === null) {
       continue;
+    } else if (funcInfo === false) {
+      break;
     }
     if (funcInfo.start < libStart && funcInfo.start < libEnd - libStart) {
       funcInfo.start += libStart;
@@ -445,12 +445,11 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
 
 
 CppEntriesProvider.prototype.loadSymbols = function(libName) {
-  return [];
 };
 
 
-CppEntriesProvider.prototype.parseLine = function(line) {
-  return { name: '', start: 0 };
+CppEntriesProvider.prototype.parseNextLine = function() {
+  return false;
 };
 
 
@@ -462,6 +461,8 @@ function inherits(childCtor, parentCtor) {
 
 
 function UnixCppEntriesProvider() {
+  this.symbols = [];
+  this.parsePos = 0;
 };
 inherits(UnixCppEntriesProvider, CppEntriesProvider);
 
@@ -470,20 +471,35 @@ UnixCppEntriesProvider.FUNC_RE = /^([0-9a-fA-F]{8}) . (.*)$/;
 
 
 UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
-  var normalSyms = os.system('nm', ['-C', '-n', libName], -1, -1);
-  var dynaSyms = os.system('nm', ['-C', '-n', '-D', libName], -1, -1);
-  var syms = (normalSyms + dynaSyms).split('\n');
-  return syms;
+  this.symbols = [
+    os.system('nm', ['-C', '-n', libName], -1, -1),
+    os.system('nm', ['-C', '-n', '-D', libName], -1, -1)
+  ];
+  this.parsePos = 0;
 };
 
 
-UnixCppEntriesProvider.prototype.parseLine = function(line) {
+UnixCppEntriesProvider.prototype.parseNextLine = function() {
+  if (this.symbols.length == 0) {
+    return false;
+  }
+  var lineEndPos = this.symbols[0].indexOf('\n', this.parsePos);
+  if (lineEndPos == -1) {
+    this.symbols.shift();
+    this.parsePos = 0;
+    return this.parseNextLine();
+  }
+
+  var line = this.symbols[0].substring(this.parsePos, lineEndPos);
+  this.parsePos = lineEndPos + 1;
   var fields = line.match(UnixCppEntriesProvider.FUNC_RE);
   return fields ? { name: fields[2], start: parseInt(fields[1], 16) } : null;
 };
 
 
 function WindowsCppEntriesProvider() {
+  this.symbols = '';
+  this.parsePos = 0;
 };
 inherits(WindowsCppEntriesProvider, CppEntriesProvider);
 
@@ -498,13 +514,20 @@ WindowsCppEntriesProvider.FUNC_RE =
 WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
   var fileNameFields = libName.match(WindowsCppEntriesProvider.FILENAME_RE);
   // Only try to load symbols for the .exe file.
-  if (!fileNameFields) return [];
+  if (!fileNameFields) return;
   var mapFileName = fileNameFields[1] + '.map';
-  return readFile(mapFileName).split('\r\n');
+  this.symbols = readFile(mapFileName);
 };
 
 
-WindowsCppEntriesProvider.prototype.parseLine = function(line) {
+WindowsCppEntriesProvider.prototype.parseNextLine = function() {
+  var lineEndPos = this.symbols.indexOf('\r\n', this.parsePos);
+  if (lineEndPos == -1) {
+    return false;
+  }
+
+  var line = this.symbols.substring(this.parsePos, lineEndPos);
+  this.parsePos = lineEndPos + 2;
   var fields = line.match(WindowsCppEntriesProvider.FUNC_RE);
   return fields ?
       { name: this.unmangleName(fields[1]), start: parseInt(fields[2], 16) } :