Don't keep data about JS code that is never executed.

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
This commit is contained in:
mikhail.naganov@gmail.com 2009-05-08 11:27:02 +00:00
parent ebdf1d1e5b
commit 7d260e5f8c
3 changed files with 89 additions and 33 deletions

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

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

View 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) } :