From e0b829b1a5e783a15f9b7d3ac7f00d3104453f77 Mon Sep 17 00:00:00 2001 From: "mikhail.naganov@gmail.com" Date: Tue, 14 Jul 2009 09:47:44 +0000 Subject: [PATCH] TickProcessor: more accurate mapping of statically compiled code on Linux. 'nm' is now called with an option to report function code sizes. Static code entries are restricted to the sizes reported, and the remaining unnamed code is attributed to a library as a whole. This makes reports more accurate, as some functions are tiny, but has chunks of unnamed code behind them. This change doesn't affect reporting on Windows, as in .map files function code sizes aren't specified. Review URL: http://codereview.chromium.org/149513 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2455 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- test/mjsunit/tools/codemap.js | 30 ++++- test/mjsunit/tools/profile.js | 4 +- test/mjsunit/tools/tickprocessor-test.default | 25 ++-- .../tools/tickprocessor-test.ignore-unknown | 25 ++-- test/mjsunit/tools/tickprocessor-test.separate-ic | 29 ++--- test/mjsunit/tools/tickprocessor.js | 131 ++++++++++++++++----- tools/codemap.js | 36 +++++- tools/profile.js | 18 ++- tools/tickprocessor.js | 43 +++++-- 9 files changed, 239 insertions(+), 102 deletions(-) diff --git a/test/mjsunit/tools/codemap.js b/test/mjsunit/tools/codemap.js index 55b8758..06a91e8 100644 --- a/test/mjsunit/tools/codemap.js +++ b/test/mjsunit/tools/codemap.js @@ -46,11 +46,11 @@ function assertNoEntry(codeMap, addr) { }; -(function testStaticCode() { +(function testLibrariesAndStaticCode() { var codeMap = new devtools.profiler.CodeMap(); - codeMap.addStaticCode(0x1500, newCodeEntry(0x3000, 'lib1')); - codeMap.addStaticCode(0x15500, newCodeEntry(0x5000, 'lib2')); - codeMap.addStaticCode(0x155500, newCodeEntry(0x10000, 'lib3')); + codeMap.addLibrary(0x1500, newCodeEntry(0x3000, 'lib1')); + codeMap.addLibrary(0x15500, newCodeEntry(0x5000, 'lib2')); + codeMap.addLibrary(0x155500, newCodeEntry(0x10000, 'lib3')); assertNoEntry(codeMap, 0); assertNoEntry(codeMap, 0x1500 - 1); assertEntry(codeMap, 'lib1', 0x1500); @@ -71,6 +71,28 @@ function assertNoEntry(codeMap, addr) { assertEntry(codeMap, 'lib3', 0x155500 + 0x10000 - 1); assertNoEntry(codeMap, 0x155500 + 0x10000); assertNoEntry(codeMap, 0xFFFFFFFF); + + codeMap.addStaticCode(0x1510, newCodeEntry(0x30, 'lib1-f1')); + codeMap.addStaticCode(0x1600, newCodeEntry(0x50, 'lib1-f2')); + codeMap.addStaticCode(0x15520, newCodeEntry(0x100, 'lib2-f1')); + assertEntry(codeMap, 'lib1', 0x1500); + assertEntry(codeMap, 'lib1', 0x1510 - 1); + assertEntry(codeMap, 'lib1-f1', 0x1510); + assertEntry(codeMap, 'lib1-f1', 0x1510 + 0x15); + assertEntry(codeMap, 'lib1-f1', 0x1510 + 0x30 - 1); + assertEntry(codeMap, 'lib1', 0x1510 + 0x30); + assertEntry(codeMap, 'lib1', 0x1600 - 1); + assertEntry(codeMap, 'lib1-f2', 0x1600); + assertEntry(codeMap, 'lib1-f2', 0x1600 + 0x30); + assertEntry(codeMap, 'lib1-f2', 0x1600 + 0x50 - 1); + assertEntry(codeMap, 'lib1', 0x1600 + 0x50); + assertEntry(codeMap, 'lib2', 0x15500); + assertEntry(codeMap, 'lib2', 0x15520 - 1); + assertEntry(codeMap, 'lib2-f1', 0x15520); + assertEntry(codeMap, 'lib2-f1', 0x15520 + 0x80); + assertEntry(codeMap, 'lib2-f1', 0x15520 + 0x100 - 1); + assertEntry(codeMap, 'lib2', 0x15520 + 0x100); + })(); diff --git a/test/mjsunit/tools/profile.js b/test/mjsunit/tools/profile.js index 49eef3b..9ed851b 100644 --- a/test/mjsunit/tools/profile.js +++ b/test/mjsunit/tools/profile.js @@ -72,10 +72,10 @@ ProfileTestDriver.prototype.funcAddrs_ = { ProfileTestDriver.prototype.addFunctions_ = function() { - this.profile.addStaticCode('lib1', 0x11000, 0x12000); + this.profile.addLibrary('lib1', 0x11000, 0x12000); this.profile.addStaticCode('lib1-f1', 0x11100, 0x11900); this.profile.addStaticCode('lib1-f2', 0x11200, 0x11500); - this.profile.addStaticCode('lib2', 0x21000, 0x22000); + this.profile.addLibrary('lib2', 0x21000, 0x22000); this.profile.addStaticCode('lib2-f1', 0x21100, 0x21900); this.profile.addStaticCode('lib2-f2', 0x21200, 0x21500); this.profile.addCode('T', 'F1', 0x50100, 0x100); diff --git a/test/mjsunit/tools/tickprocessor-test.default b/test/mjsunit/tools/tickprocessor-test.default index a689ea8..702f4bc 100644 --- a/test/mjsunit/tools/tickprocessor-test.default +++ b/test/mjsunit/tools/tickprocessor-test.default @@ -6,20 +6,19 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). [Shared libraries]: ticks total nonlib name - 2 15.4% 0.0% /lib32/libm-2.7.so + 3 23.1% 0.0% /lib32/libm-2.7.so 1 7.7% 0.0% ffffe000-fffff000 [JavaScript]: ticks total nonlib name - 1 7.7% 10.0% LazyCompile: exp native math.js:41 + 1 7.7% 11.1% LazyCompile: exp native math.js:41 [C++]: ticks total nonlib name - 2 15.4% 20.0% v8::internal::Runtime_Math_exp(v8::internal::Arguments) - 1 7.7% 10.0% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*) - 1 7.7% 10.0% v8::internal::HashTable::FindEntry(v8::internal::String*) - 1 7.7% 10.0% fegetexcept - 1 7.7% 10.0% exp + 2 15.4% 22.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments) + 1 7.7% 11.1% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*) + 1 7.7% 11.1% v8::internal::HashTable::FindEntry(v8::internal::String*) + 1 7.7% 11.1% exp [GC]: ticks total nonlib name @@ -31,11 +30,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). Callers occupying less than 2.0% are not shown. ticks parent name - 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments) - 2 100.0% LazyCompile: exp native math.js:41 - 2 100.0% Script: exp.js + 3 23.1% /lib32/libm-2.7.so + 3 100.0% LazyCompile: exp native math.js:41 + 3 100.0% Script: exp.js - 2 15.4% /lib32/libm-2.7.so + 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments) 2 100.0% LazyCompile: exp native math.js:41 2 100.0% Script: exp.js @@ -47,10 +46,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). 1 7.7% ffffe000-fffff000 - 1 7.7% fegetexcept - 1 100.0% LazyCompile: exp native math.js:41 - 1 100.0% Script: exp.js - 1 7.7% exp 1 100.0% LazyCompile: exp native math.js:41 1 100.0% Script: exp.js diff --git a/test/mjsunit/tools/tickprocessor-test.ignore-unknown b/test/mjsunit/tools/tickprocessor-test.ignore-unknown index 87beb08..306d646 100644 --- a/test/mjsunit/tools/tickprocessor-test.ignore-unknown +++ b/test/mjsunit/tools/tickprocessor-test.ignore-unknown @@ -2,20 +2,19 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). [Shared libraries]: ticks total nonlib name - 2 18.2% 0.0% /lib32/libm-2.7.so + 3 27.3% 0.0% /lib32/libm-2.7.so 1 9.1% 0.0% ffffe000-fffff000 [JavaScript]: ticks total nonlib name - 1 9.1% 12.5% LazyCompile: exp native math.js:41 + 1 9.1% 14.3% LazyCompile: exp native math.js:41 [C++]: ticks total nonlib name - 2 18.2% 25.0% v8::internal::Runtime_Math_exp(v8::internal::Arguments) - 1 9.1% 12.5% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*) - 1 9.1% 12.5% v8::internal::HashTable::FindEntry(v8::internal::String*) - 1 9.1% 12.5% fegetexcept - 1 9.1% 12.5% exp + 2 18.2% 28.6% v8::internal::Runtime_Math_exp(v8::internal::Arguments) + 1 9.1% 14.3% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*) + 1 9.1% 14.3% v8::internal::HashTable::FindEntry(v8::internal::String*) + 1 9.1% 14.3% exp [GC]: ticks total nonlib name @@ -27,11 +26,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). Callers occupying less than 2.0% are not shown. ticks parent name - 2 18.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments) - 2 100.0% LazyCompile: exp native math.js:41 - 2 100.0% Script: exp.js + 3 27.3% /lib32/libm-2.7.so + 3 100.0% LazyCompile: exp native math.js:41 + 3 100.0% Script: exp.js - 2 18.2% /lib32/libm-2.7.so + 2 18.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments) 2 100.0% LazyCompile: exp native math.js:41 2 100.0% Script: exp.js @@ -43,10 +42,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). 1 9.1% ffffe000-fffff000 - 1 9.1% fegetexcept - 1 100.0% LazyCompile: exp native math.js:41 - 1 100.0% Script: exp.js - 1 9.1% exp 1 100.0% LazyCompile: exp native math.js:41 1 100.0% Script: exp.js diff --git a/test/mjsunit/tools/tickprocessor-test.separate-ic b/test/mjsunit/tools/tickprocessor-test.separate-ic index 7eb3d9a..3a2041b 100644 --- a/test/mjsunit/tools/tickprocessor-test.separate-ic +++ b/test/mjsunit/tools/tickprocessor-test.separate-ic @@ -6,22 +6,21 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). [Shared libraries]: ticks total nonlib name - 2 15.4% 0.0% /lib32/libm-2.7.so + 3 23.1% 0.0% /lib32/libm-2.7.so 1 7.7% 0.0% ffffe000-fffff000 [JavaScript]: ticks total nonlib name - 1 7.7% 10.0% LoadIC: j - 1 7.7% 10.0% LoadIC: i - 1 7.7% 10.0% LazyCompile: exp native math.js:41 + 1 7.7% 11.1% LoadIC: j + 1 7.7% 11.1% LoadIC: i + 1 7.7% 11.1% LazyCompile: exp native math.js:41 [C++]: ticks total nonlib name - 2 15.4% 20.0% v8::internal::Runtime_Math_exp(v8::internal::Arguments) - 1 7.7% 10.0% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*) - 1 7.7% 10.0% v8::internal::HashTable::FindEntry(v8::internal::String*) - 1 7.7% 10.0% fegetexcept - 1 7.7% 10.0% exp + 2 15.4% 22.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments) + 1 7.7% 11.1% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*) + 1 7.7% 11.1% v8::internal::HashTable::FindEntry(v8::internal::String*) + 1 7.7% 11.1% exp [GC]: ticks total nonlib name @@ -33,11 +32,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). Callers occupying less than 2.0% are not shown. ticks parent name - 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments) - 2 100.0% LazyCompile: exp native math.js:41 - 2 100.0% Script: exp.js + 3 23.1% /lib32/libm-2.7.so + 3 100.0% LazyCompile: exp native math.js:41 + 3 100.0% Script: exp.js - 2 15.4% /lib32/libm-2.7.so + 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments) 2 100.0% LazyCompile: exp native math.js:41 2 100.0% Script: exp.js @@ -49,10 +48,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded). 1 7.7% ffffe000-fffff000 - 1 7.7% fegetexcept - 1 100.0% LazyCompile: exp native math.js:41 - 1 100.0% Script: exp.js - 1 7.7% exp 1 100.0% LazyCompile: exp native math.js:41 1 100.0% Script: exp.js diff --git a/test/mjsunit/tools/tickprocessor.js b/test/mjsunit/tools/tickprocessor.js index 587106a..00c3fb1 100644 --- a/test/mjsunit/tools/tickprocessor.js +++ b/test/mjsunit/tools/tickprocessor.js @@ -31,6 +31,7 @@ // Files: tools/logreader.js tools/tickprocessor.js // Env: TEST_FILE_NAME + (function testArgumentsProcessor() { var p_default = new ArgumentsProcessor([]); assertTrue(p_default.parse()); @@ -69,12 +70,12 @@ ' U operator delete[](void*)@@GLIBCXX_3.4', '08049790 T _init', '08049f50 T _start', - '08139150 t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', - '08139ca0 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle, unsigned int)', - '0813a0b0 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', - '08181d30 W v8::internal::RegExpMacroAssemblerIrregexp::stack_limit_slack()', + '08139150 00000b4b t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', + '08139ca0 000003f1 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle, unsigned int)', + '0813a0b0 00000855 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', + '0818b220 00000036 W v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)', ' w __gmon_start__', - '081f08a0 B stdout' + '081f08a0 00000004 B stdout\n' ].join('\n'), '']; }; @@ -87,22 +88,22 @@ assertEquals( [['_init', 0x08049790, 0x08049f50], ['_start', 0x08049f50, 0x08139150], - ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139ca0], - ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle, unsigned int)', 0x08139ca0, 0x0813a0b0], - ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x08181d30], - ['v8::internal::RegExpMacroAssemblerIrregexp::stack_limit_slack()', 0x08181d30, 0x081ee000]], + ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139150 + 0xb4b], + ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle, unsigned int)', 0x08139ca0, 0x08139ca0 + 0x3f1], + ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x0813a0b0 + 0x855], + ['v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)', 0x0818b220, 0x0818b220 + 0x36]], shell_syms); // libc library UnixCppEntriesProvider.prototype.loadSymbols = function(libName) { this.symbols = [[ - '000162a0 T __libc_init_first', - '0002a5f0 T __isnan', - '0002a5f0 W isnan', - '0002aaa0 W scalblnf', - '0002aaa0 W scalbnf', - '0011a340 T __libc_thread_freeres', - '00128860 R _itoa_lower_digits'].join('\n'), '']; + '000162a0 00000005 T __libc_init_first', + '0002a5f0 0000002d T __isnan', + '0002a5f0 0000002d W isnan', + '0002aaa0 0000000d W scalblnf', + '0002aaa0 0000000d W scalbnf', + '0011a340 00000048 T __libc_thread_freeres', + '00128860 00000024 R _itoa_lower_digits\n'].join('\n'), '']; }; var libc_prov = new UnixCppEntriesProvider(); var libc_syms = []; @@ -110,17 +111,81 @@ function (name, start, end) { libc_syms.push(Array.prototype.slice.apply(arguments, [0])); }); - assertEquals( - [['__libc_init_first', 0xf7c5c000 + 0x000162a0, 0xf7c5c000 + 0x0002a5f0], - ['isnan', 0xf7c5c000 + 0x0002a5f0, 0xf7c5c000 + 0x0002aaa0], - ['scalbnf', 0xf7c5c000 + 0x0002aaa0, 0xf7c5c000 + 0x0011a340], - ['__libc_thread_freeres', 0xf7c5c000 + 0x0011a340, 0xf7da5000]], - libc_syms); + var libc_ref_syms = [['__libc_init_first', 0x000162a0, 0x000162a0 + 0x5], + ['__isnan', 0x0002a5f0, 0x0002a5f0 + 0x2d], + ['scalblnf', 0x0002aaa0, 0x0002aaa0 + 0xd], + ['__libc_thread_freeres', 0x0011a340, 0x0011a340 + 0x48]]; + for (var i = 0; i < libc_ref_syms.length; ++i) { + libc_ref_syms[i][1] += 0xf7c5c000; + libc_ref_syms[i][2] += 0xf7c5c000; + } + assertEquals(libc_ref_syms, libc_syms); UnixCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols; })(); +(function testMacCppEntriesProvider() { + var oldLoadSymbols = MacCppEntriesProvider.prototype.loadSymbols; + + // shell executable + MacCppEntriesProvider.prototype.loadSymbols = function(libName) { + this.symbols = [[ + ' U operator delete[]', + '00001000 A __mh_execute_header', + '00001b00 T start', + '00001b40 t dyld_stub_binding_helper', + '0011b710 T v8::internal::RegExpMacroAssembler::CheckPosition', + '00134250 t v8::internal::Runtime_StringReplaceRegExpWithString', + '00137220 T v8::internal::Runtime::GetElementOrCharAt', + '00137400 t v8::internal::Runtime_DebugGetPropertyDetails', + '001c1a80 b _private_mem\n' + ].join('\n'), '']; + }; + + var shell_prov = new MacCppEntriesProvider(); + var shell_syms = []; + shell_prov.parseVmSymbols('shell', 0x00001b00, 0x00163156, + function (name, start, end) { + shell_syms.push(Array.prototype.slice.apply(arguments, [0])); + }); + assertEquals( + [['start', 0x00001b00, 0x00001b40], + ['dyld_stub_binding_helper', 0x00001b40, 0x0011b710], + ['v8::internal::RegExpMacroAssembler::CheckPosition', 0x0011b710, 0x00134250], + ['v8::internal::Runtime_StringReplaceRegExpWithString', 0x00134250, 0x00137220], + ['v8::internal::Runtime::GetElementOrCharAt', 0x00137220, 0x00137400], + ['v8::internal::Runtime_DebugGetPropertyDetails', 0x00137400, 0x00163156]], + shell_syms); + + // stdc++ library + MacCppEntriesProvider.prototype.loadSymbols = function(libName) { + this.symbols = [[ + '0000107a T __gnu_cxx::balloc::__mini_vector::_Alloc_block*, __gnu_cxx::bitmap_allocator::_Alloc_block*> >::__mini_vector', + '0002c410 T std::basic_streambuf >::pubseekoff', + '0002c488 T std::basic_streambuf >::pubseekpos', + '000466aa T ___cxa_pure_virtual\n'].join('\n'), '']; + }; + var stdc_prov = new MacCppEntriesProvider(); + var stdc_syms = []; + stdc_prov.parseVmSymbols('stdc++', 0x95728fb4, 0x95770005, + function (name, start, end) { + stdc_syms.push(Array.prototype.slice.apply(arguments, [0])); + }); + var stdc_ref_syms = [['__gnu_cxx::balloc::__mini_vector::_Alloc_block*, __gnu_cxx::bitmap_allocator::_Alloc_block*> >::__mini_vector', 0x0000107a, 0x0002c410], + ['std::basic_streambuf >::pubseekoff', 0x0002c410, 0x0002c488], + ['std::basic_streambuf >::pubseekpos', 0x0002c488, 0x000466aa], + ['___cxa_pure_virtual', 0x000466aa, 0x95770005 - 0x95728fb4]]; + for (var i = 0; i < stdc_ref_syms.length; ++i) { + stdc_ref_syms[i][1] += 0x95728fb4; + stdc_ref_syms[i][2] += 0x95728fb4; + } + assertEquals(stdc_ref_syms, stdc_syms); + + MacCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols; +})(); + + (function testWindowsCppEntriesProvider() { var oldLoadSymbols = WindowsCppEntriesProvider.prototype.loadSymbols; @@ -174,8 +239,8 @@ CppEntriesProviderMock.prototype.parseVmSymbols = function( ['v8::internal::HashTable::FindEntry(v8::internal::String*)', 0x080f8210, 0x080f8800], ['v8::internal::Runtime_Math_exp(v8::internal::Arguments)', 0x08123b20, 0x08123b80]], '/lib32/libm-2.7.so': - [['exp', startAddr + 0x00009e80, startAddr + 0x00009f30], - ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x00008b10]], + [['exp', startAddr + 0x00009e80, startAddr + 0x00009e80 + 0xa3], + ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x000061e0 + 0x15]], 'ffffe000-fffff000': []}; assertTrue(name in symbols); var syms = symbols[name]; @@ -191,6 +256,7 @@ function PrintMonitor(outputOrFileName) { var outputPos = 0; var diffs = this.diffs = []; var realOut = this.realOut = []; + var unexpectedOut = this.unexpectedOut = null; this.oldPrint = print; print = function(str) { @@ -198,13 +264,15 @@ function PrintMonitor(outputOrFileName) { for (var i = 0; i < strSplit.length; ++i) { s = strSplit[i]; realOut.push(s); - assertTrue(outputPos < expectedOut.length, - 'unexpected output: "' + s + '"'); - if (expectedOut[outputPos] != s) { - diffs.push('line ' + outputPos + ': expected <' + - expectedOut[outputPos] + '> found <' + s + '>\n'); + if (outputPos < expectedOut.length) { + if (expectedOut[outputPos] != s) { + diffs.push('line ' + outputPos + ': expected <' + + expectedOut[outputPos] + '> found <' + s + '>\n'); + } + outputPos++; + } else { + unexpectedOut = true; } - outputPos++; } }; }; @@ -218,9 +286,10 @@ PrintMonitor.prototype.loadExpectedOutput = function(fileName) { PrintMonitor.prototype.finish = function() { print = this.oldPrint; - if (this.diffs.length > 0) { + if (this.diffs.length > 0 || this.unexpectedOut != null) { print(this.realOut.join('\n')); assertEquals([], this.diffs); + assertNull(this.unexpectedOut); } }; diff --git a/tools/codemap.js b/tools/codemap.js index d6df7fa..404127f 100644 --- a/tools/codemap.js +++ b/tools/codemap.js @@ -48,11 +48,16 @@ devtools.profiler.CodeMap = function() { this.dynamicsNameGen_ = new devtools.profiler.CodeMap.NameGenerator(); /** - * Static code entries. Used for libraries code. + * Static code entries. Used for statically compiled code. */ this.statics_ = new goog.structs.SplayTree(); /** + * Libraries entries. Used for the whole static code libraries. + */ + this.libraries_ = new goog.structs.SplayTree(); + + /** * Map of memory pages occupied with static code. */ this.pages_ = []; @@ -108,6 +113,19 @@ devtools.profiler.CodeMap.prototype.deleteCode = function(start) { /** + * Adds a library entry. + * + * @param {number} start The starting address. + * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object. + */ +devtools.profiler.CodeMap.prototype.addLibrary = function( + start, codeEntry) { + this.markPages_(start, start + codeEntry.size); + this.libraries_.insert(start, codeEntry); +}; + + +/** * Adds a static code entry. * * @param {number} start The starting address. @@ -115,7 +133,6 @@ devtools.profiler.CodeMap.prototype.deleteCode = function(start) { */ devtools.profiler.CodeMap.prototype.addStaticCode = function( start, codeEntry) { - this.markPages_(start, start + codeEntry.size); this.statics_.insert(start, codeEntry); }; @@ -157,7 +174,10 @@ devtools.profiler.CodeMap.prototype.findInTree_ = function(tree, addr) { devtools.profiler.CodeMap.prototype.findEntry = function(addr) { var pageAddr = addr >>> devtools.profiler.CodeMap.PAGE_ALIGNMENT; if (pageAddr in this.pages_) { - return this.findInTree_(this.statics_, addr); + // Static code entries can contain "holes" of unnamed code. + // In this case, the whole library is assigned to this address. + return this.findInTree_(this.statics_, addr) || + this.findInTree_(this.libraries_, addr); } var min = this.dynamics_.findMin(); var max = this.dynamics_.findMax(); @@ -176,7 +196,7 @@ devtools.profiler.CodeMap.prototype.findEntry = function(addr) { /** - * Returns an array of all dynamic code entries, including deleted ones. + * Returns an array of all dynamic code entries. */ devtools.profiler.CodeMap.prototype.getAllDynamicEntries = function() { return this.dynamics_.exportValues(); @@ -192,6 +212,14 @@ devtools.profiler.CodeMap.prototype.getAllStaticEntries = function() { /** + * Returns an array of all libraries entries. + */ +devtools.profiler.CodeMap.prototype.getAllLibrariesEntries = function() { + return this.libraries_.exportValues(); +}; + + +/** * Creates a code entry object. * * @param {number} size Code entry size in bytes. diff --git a/tools/profile.js b/tools/profile.js index 614c635..db4b542 100644 --- a/tools/profile.js +++ b/tools/profile.js @@ -86,7 +86,23 @@ devtools.profiler.Profile.prototype.handleUnknownCode = function( /** - * Registers static (library) code entry. + * Registers a library. + * + * @param {string} name Code entry name. + * @param {number} startAddr Starting address. + * @param {number} endAddr Ending address. + */ +devtools.profiler.Profile.prototype.addLibrary = function( + name, startAddr, endAddr) { + var entry = new devtools.profiler.CodeMap.CodeEntry( + endAddr - startAddr, name); + this.codeMap_.addLibrary(startAddr, entry); + return entry; +}; + + +/** + * Registers statically compiled code entry. * * @param {string} name Code entry name. * @param {number} startAddr Starting address. diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js index 7da99e4..efd9750 100644 --- a/tools/tickprocessor.js +++ b/tools/tickprocessor.js @@ -174,7 +174,7 @@ TickProcessor.prototype.processLogFile = function(fileName) { TickProcessor.prototype.processSharedLibrary = function( name, startAddr, endAddr) { - var entry = this.profile_.addStaticCode(name, startAddr, endAddr); + var entry = this.profile_.addLibrary(name, startAddr, endAddr); this.setCodeType(entry.getName(), 'SHARED_LIB'); var self = this; @@ -380,14 +380,21 @@ CppEntriesProvider.prototype.parseVmSymbols = function( var prevEntry; - function addPrevEntry(end) { + function addEntry(funcInfo) { // Several functions can be mapped onto the same address. To avoid // creating zero-sized entries, skip such duplicates. // Also double-check that function belongs to the library address space. - if (prevEntry && prevEntry.start < end && - prevEntry.start >= libStart && end <= libEnd) { - processorFunc(prevEntry.name, prevEntry.start, end); + if (prevEntry && !prevEntry.end && + prevEntry.start < funcInfo.start && + prevEntry.start >= libStart && funcInfo.start <= libEnd) { + processorFunc(prevEntry.name, prevEntry.start, funcInfo.start); } + if (funcInfo.end && + (!prevEntry || prevEntry.start != funcInfo.start) && + funcInfo.start >= libStart && funcInfo.end <= libEnd) { + processorFunc(funcInfo.name, funcInfo.start, funcInfo.end); + } + prevEntry = funcInfo; } while (true) { @@ -400,10 +407,12 @@ CppEntriesProvider.prototype.parseVmSymbols = function( if (funcInfo.start < libStart && funcInfo.start < libEnd - libStart) { funcInfo.start += libStart; } - addPrevEntry(funcInfo.start); - prevEntry = funcInfo; + if (funcInfo.size) { + funcInfo.end = funcInfo.start + funcInfo.size; + } + addEntry(funcInfo); } - addPrevEntry(libEnd); + addEntry({name: '', start: libEnd}); }; @@ -420,7 +429,7 @@ function UnixCppEntriesProvider(nmExec) { this.symbols = []; this.parsePos = 0; this.nmExec = nmExec; - this.FUNC_RE = /^([0-9a-fA-F]{8}) [tTwW] (.*)$/; + this.FUNC_RE = /^([0-9a-fA-F]{8}) ([0-9a-fA-F]{8} )?[tTwW] (.*)$/; }; inherits(UnixCppEntriesProvider, CppEntriesProvider); @@ -429,8 +438,8 @@ UnixCppEntriesProvider.prototype.loadSymbols = function(libName) { this.parsePos = 0; try { this.symbols = [ - os.system(this.nmExec, ['-C', '-n', libName], -1, -1), - os.system(this.nmExec, ['-C', '-n', '-D', libName], -1, -1) + os.system(this.nmExec, ['-C', '-n', '-S', libName], -1, -1), + os.system(this.nmExec, ['-C', '-n', '-S', '-D', libName], -1, -1) ]; } catch (e) { // If the library cannot be found on this system let's not panic. @@ -453,13 +462,21 @@ UnixCppEntriesProvider.prototype.parseNextLine = function() { var line = this.symbols[0].substring(this.parsePos, lineEndPos); this.parsePos = lineEndPos + 1; var fields = line.match(this.FUNC_RE); - return fields ? { name: fields[2], start: parseInt(fields[1], 16) } : null; + var funcInfo = null; + if (fields) { + funcInfo = { name: fields[3], start: parseInt(fields[1], 16) }; + if (fields[2]) { + funcInfo.size = parseInt(fields[2], 16); + } + } + return funcInfo; }; function MacCppEntriesProvider(nmExec) { UnixCppEntriesProvider.call(this, nmExec); - this.FUNC_RE = /^([0-9a-fA-F]{8}) [iItT] (.*)$/; + // Note an empty group. It is required, as UnixCppEntriesProvider expects 3 groups. + this.FUNC_RE = /^([0-9a-fA-F]{8}) ()[iItT] (.*)$/; }; inherits(MacCppEntriesProvider, UnixCppEntriesProvider); -- 2.7.4