Home | History | Annotate | Download | only in tools
      1 // Copyright 2009 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 // This test case is not compatible with optimization stress because the
     29 // generated profile will look vastly different when more is optimized.
     30 // Flags: --nostress-opt --noalways-opt
     31 
     32 // Load implementations from <project root>/tools.
     33 // Files: tools/splaytree.js tools/codemap.js tools/csvparser.js
     34 // Files: tools/consarray.js tools/profile.js tools/profile_view.js
     35 // Files: tools/logreader.js tools/tickprocessor.js
     36 // Env: TEST_FILE_NAME
     37 
     38 
     39 (function testArgumentsProcessor() {
     40   var p_default = new ArgumentsProcessor([]);
     41   assertTrue(p_default.parse());
     42   assertEquals(ArgumentsProcessor.DEFAULTS, p_default.result());
     43 
     44   var p_logFile = new ArgumentsProcessor(['logfile.log']);
     45   assertTrue(p_logFile.parse());
     46   assertEquals('logfile.log', p_logFile.result().logFileName);
     47 
     48   var p_platformAndLog = new ArgumentsProcessor(['--windows', 'winlog.log']);
     49   assertTrue(p_platformAndLog.parse());
     50   assertEquals('windows', p_platformAndLog.result().platform);
     51   assertEquals('winlog.log', p_platformAndLog.result().logFileName);
     52 
     53   var p_flags = new ArgumentsProcessor(['--gc', '--separate-ic']);
     54   assertTrue(p_flags.parse());
     55   assertEquals(TickProcessor.VmStates.GC, p_flags.result().stateFilter);
     56   assertTrue(p_flags.result().separateIc);
     57 
     58   var p_nmAndLog = new ArgumentsProcessor(['--nm=mn', 'nmlog.log']);
     59   assertTrue(p_nmAndLog.parse());
     60   assertEquals('mn', p_nmAndLog.result().nm);
     61   assertEquals('nmlog.log', p_nmAndLog.result().logFileName);
     62 
     63   var p_bad = new ArgumentsProcessor(['--unknown', 'badlog.log']);
     64   assertFalse(p_bad.parse());
     65 })();
     66 
     67 
     68 (function testUnixCppEntriesProvider() {
     69   var oldLoadSymbols = UnixCppEntriesProvider.prototype.loadSymbols;
     70 
     71   // shell executable
     72   UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
     73     this.symbols = [[
     74       '         U operator delete[](void*)@@GLIBCXX_3.4',
     75       '08049790 T _init',
     76       '08049f50 T _start',
     77       '08139150 00000b4b t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
     78       '08139ca0 000003f1 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
     79       '0813a0b0 00000855 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
     80       '0818b220 00000036 W v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)',
     81       '         w __gmon_start__',
     82       '081f08a0 00000004 B stdout\n'
     83     ].join('\n'), ''];
     84   };
     85 
     86   var shell_prov = new UnixCppEntriesProvider();
     87   var shell_syms = [];
     88   shell_prov.parseVmSymbols('shell', 0x08048000, 0x081ee000,
     89       function (name, start, end) {
     90         shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
     91       });
     92   assertEquals(
     93       [['_init', 0x08049790, 0x08049f50],
     94        ['_start', 0x08049f50, 0x08139150],
     95        ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139150 + 0xb4b],
     96        ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)', 0x08139ca0, 0x08139ca0 + 0x3f1],
     97        ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x0813a0b0 + 0x855],
     98        ['v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)', 0x0818b220, 0x0818b220 + 0x36]],
     99       shell_syms);
    100 
    101   // libc library
    102   UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
    103     this.symbols = [[
    104         '000162a0 00000005 T __libc_init_first',
    105         '0002a5f0 0000002d T __isnan',
    106         '0002a5f0 0000002d W isnan',
    107         '0002aaa0 0000000d W scalblnf',
    108         '0002aaa0 0000000d W scalbnf',
    109         '0011a340 00000048 T __libc_thread_freeres',
    110         '00128860 00000024 R _itoa_lower_digits\n'].join('\n'), ''];
    111   };
    112   var libc_prov = new UnixCppEntriesProvider();
    113   var libc_syms = [];
    114   libc_prov.parseVmSymbols('libc', 0xf7c5c000, 0xf7da5000,
    115       function (name, start, end) {
    116         libc_syms.push(Array.prototype.slice.apply(arguments, [0]));
    117       });
    118   var libc_ref_syms = [['__libc_init_first', 0x000162a0, 0x000162a0 + 0x5],
    119        ['__isnan', 0x0002a5f0, 0x0002a5f0 + 0x2d],
    120        ['scalblnf', 0x0002aaa0, 0x0002aaa0 + 0xd],
    121        ['__libc_thread_freeres', 0x0011a340, 0x0011a340 + 0x48]];
    122   for (var i = 0; i < libc_ref_syms.length; ++i) {
    123     libc_ref_syms[i][1] += 0xf7c5c000;
    124     libc_ref_syms[i][2] += 0xf7c5c000;
    125   }
    126   assertEquals(libc_ref_syms, libc_syms);
    127 
    128   UnixCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
    129 })();
    130 
    131 
    132 (function testMacCppEntriesProvider() {
    133   var oldLoadSymbols = MacCppEntriesProvider.prototype.loadSymbols;
    134 
    135   // shell executable
    136   MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
    137     this.symbols = [[
    138       '         U operator delete[]',
    139       '00001000 A __mh_execute_header',
    140       '00001b00 T start',
    141       '00001b40 t dyld_stub_binding_helper',
    142       '0011b710 T v8::internal::RegExpMacroAssembler::CheckPosition',
    143       '00134250 t v8::internal::Runtime_StringReplaceRegExpWithString',
    144       '00137220 T v8::internal::Runtime::GetElementOrCharAt',
    145       '00137400 t v8::internal::Runtime_DebugGetPropertyDetails',
    146       '001c1a80 b _private_mem\n'
    147     ].join('\n'), ''];
    148   };
    149 
    150   var shell_prov = new MacCppEntriesProvider();
    151   var shell_syms = [];
    152   shell_prov.parseVmSymbols('shell', 0x00001b00, 0x00163156,
    153       function (name, start, end) {
    154         shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
    155       });
    156   assertEquals(
    157       [['start', 0x00001b00, 0x00001b40],
    158        ['dyld_stub_binding_helper', 0x00001b40, 0x0011b710],
    159        ['v8::internal::RegExpMacroAssembler::CheckPosition', 0x0011b710, 0x00134250],
    160        ['v8::internal::Runtime_StringReplaceRegExpWithString', 0x00134250, 0x00137220],
    161        ['v8::internal::Runtime::GetElementOrCharAt', 0x00137220, 0x00137400],
    162        ['v8::internal::Runtime_DebugGetPropertyDetails', 0x00137400, 0x00163156]],
    163       shell_syms);
    164 
    165   // stdc++ library
    166   MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
    167     this.symbols = [[
    168         '0000107a T __gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector',
    169         '0002c410 T std::basic_streambuf<char, std::char_traits<char> >::pubseekoff',
    170         '0002c488 T std::basic_streambuf<char, std::char_traits<char> >::pubseekpos',
    171         '000466aa T ___cxa_pure_virtual\n'].join('\n'), ''];
    172   };
    173   var stdc_prov = new MacCppEntriesProvider();
    174   var stdc_syms = [];
    175   stdc_prov.parseVmSymbols('stdc++', 0x95728fb4, 0x95770005,
    176       function (name, start, end) {
    177         stdc_syms.push(Array.prototype.slice.apply(arguments, [0]));
    178       });
    179   var stdc_ref_syms = [['__gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector', 0x0000107a, 0x0002c410],
    180        ['std::basic_streambuf<char, std::char_traits<char> >::pubseekoff', 0x0002c410, 0x0002c488],
    181        ['std::basic_streambuf<char, std::char_traits<char> >::pubseekpos', 0x0002c488, 0x000466aa],
    182        ['___cxa_pure_virtual', 0x000466aa, 0x95770005 - 0x95728fb4]];
    183   for (var i = 0; i < stdc_ref_syms.length; ++i) {
    184     stdc_ref_syms[i][1] += 0x95728fb4;
    185     stdc_ref_syms[i][2] += 0x95728fb4;
    186   }
    187   assertEquals(stdc_ref_syms, stdc_syms);
    188 
    189   MacCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
    190 })();
    191 
    192 
    193 (function testWindowsCppEntriesProvider() {
    194   var oldLoadSymbols = WindowsCppEntriesProvider.prototype.loadSymbols;
    195 
    196   WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
    197     this.symbols = [
    198       ' Start         Length     Name                   Class',
    199       ' 0001:00000000 000ac902H .text                   CODE',
    200       ' 0001:000ac910 000005e2H .text$yc                CODE',
    201       '  Address         Publics by Value              Rva+Base       Lib:Object',
    202       ' 0000:00000000       __except_list              00000000     <absolute>',
    203       ' 0001:00000000       ?ReadFile@@YA?AV?$Handle@VString@v8@@@v8@@PBD@Z 00401000 f   shell.obj',
    204       ' 0001:000000a0       ?Print@@YA?AV?$Handle@VValue@v8@@@v8@@ABVArguments@2@@Z 004010a0 f   shell.obj',
    205       ' 0001:00001230       ??1UTF8Buffer@internal@v8@@QAE@XZ 00402230 f   v8_snapshot:scanner.obj',
    206       ' 0001:00001230       ??1Utf8Value@String@v8@@QAE@XZ 00402230 f   v8_snapshot:api.obj',
    207       ' 0001:000954ba       __fclose_nolock            004964ba f   LIBCMT:fclose.obj',
    208       ' 0002:00000000       __imp__SetThreadPriority@8 004af000     kernel32:KERNEL32.dll',
    209       ' 0003:00000418       ?in_use_list_@PreallocatedStorage@internal@v8@@0V123@A 00544418     v8_snapshot:allocation.obj',
    210       ' Static symbols',
    211       ' 0001:00000b70       ?DefaultFatalErrorHandler@v8@@YAXPBD0@Z 00401b70 f   v8_snapshot:api.obj',
    212       ' 0001:000010b0       ?EnsureInitialized@v8@@YAXPBD@Z 004020b0 f   v8_snapshot:api.obj',
    213       ' 0001:000ad17b       ??__Fnomem@?5???2@YAPAXI@Z@YAXXZ 004ae17b f   LIBCMT:new.obj'
    214     ].join('\r\n');
    215   };
    216   var shell_prov = new WindowsCppEntriesProvider();
    217   var shell_syms = [];
    218   shell_prov.parseVmSymbols('shell.exe', 0x00400000, 0x0057c000,
    219       function (name, start, end) {
    220         shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
    221       });
    222   assertEquals(
    223       [['ReadFile', 0x00401000, 0x004010a0],
    224        ['Print', 0x004010a0, 0x00402230],
    225        ['v8::String::?1Utf8Value', 0x00402230, 0x004964ba],
    226        ['v8::DefaultFatalErrorHandler', 0x00401b70, 0x004020b0],
    227        ['v8::EnsureInitialized', 0x004020b0, 0x0057c000]],
    228       shell_syms);
    229 
    230   WindowsCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
    231 })();
    232 
    233 
    234 // http://code.google.com/p/v8/issues/detail?id=427
    235 (function testWindowsProcessExeAndDllMapFile() {
    236   function exeSymbols(exeName) {
    237     return [
    238       ' 0000:00000000       ___ImageBase               00400000     <linker-defined>',
    239       ' 0001:00000780       ?RunMain@@YAHHQAPAD@Z      00401780 f   shell.obj',
    240       ' 0001:00000ac0       _main                      00401ac0 f   shell.obj',
    241       ''
    242     ].join('\r\n');
    243   }
    244 
    245   function dllSymbols(dllName) {
    246     return [
    247       ' 0000:00000000       ___ImageBase               01c30000     <linker-defined>',
    248       ' 0001:00000780       _DllMain@12                01c31780 f   libcmt:dllmain.obj',
    249       ' 0001:00000ac0       ___DllMainCRTStartup       01c31ac0 f   libcmt:dllcrt0.obj',
    250       ''
    251     ].join('\r\n');
    252   }
    253 
    254   var oldRead = read;
    255 
    256   read = exeSymbols;
    257   var exe_exe_syms = [];
    258   (new WindowsCppEntriesProvider()).parseVmSymbols(
    259       'chrome.exe', 0x00400000, 0x00472000,
    260       function (name, start, end) {
    261         exe_exe_syms.push(Array.prototype.slice.apply(arguments, [0]));
    262       });
    263   assertEquals(
    264       [['RunMain', 0x00401780, 0x00401ac0],
    265        ['_main', 0x00401ac0, 0x00472000]],
    266       exe_exe_syms, '.exe with .exe symbols');
    267 
    268   read = dllSymbols;
    269   var exe_dll_syms = [];
    270   (new WindowsCppEntriesProvider()).parseVmSymbols(
    271       'chrome.exe', 0x00400000, 0x00472000,
    272       function (name, start, end) {
    273         exe_dll_syms.push(Array.prototype.slice.apply(arguments, [0]));
    274       });
    275   assertEquals(
    276       [],
    277       exe_dll_syms, '.exe with .dll symbols');
    278 
    279   read = dllSymbols;
    280   var dll_dll_syms = [];
    281   (new WindowsCppEntriesProvider()).parseVmSymbols(
    282       'chrome.dll', 0x01c30000, 0x02b80000,
    283       function (name, start, end) {
    284         dll_dll_syms.push(Array.prototype.slice.apply(arguments, [0]));
    285       });
    286   assertEquals(
    287       [['_DllMain@12', 0x01c31780, 0x01c31ac0],
    288        ['___DllMainCRTStartup', 0x01c31ac0, 0x02b80000]],
    289       dll_dll_syms, '.dll with .dll symbols');
    290 
    291   read = exeSymbols;
    292   var dll_exe_syms = [];
    293   (new WindowsCppEntriesProvider()).parseVmSymbols(
    294       'chrome.dll', 0x01c30000, 0x02b80000,
    295       function (name, start, end) {
    296         dll_exe_syms.push(Array.prototype.slice.apply(arguments, [0]));
    297       });
    298   assertEquals(
    299       [],
    300       dll_exe_syms, '.dll with .exe symbols');
    301 
    302   read = oldRead;
    303 })();
    304 
    305 
    306 function CppEntriesProviderMock() {
    307 };
    308 
    309 
    310 CppEntriesProviderMock.prototype.parseVmSymbols = function(
    311     name, startAddr, endAddr, symbolAdder) {
    312   var symbols = {
    313     'shell':
    314         [['v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)', 0x080f8800, 0x080f8d90],
    315          ['v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)', 0x080f8210, 0x080f8800],
    316          ['v8::internal::Runtime_Math_exp(v8::internal::Arguments)', 0x08123b20, 0x08123b80]],
    317     '/lib32/libm-2.7.so':
    318         [['exp', startAddr + 0x00009e80, startAddr + 0x00009e80 + 0xa3],
    319          ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x000061e0 + 0x15]],
    320     'ffffe000-fffff000': []};
    321   assertTrue(name in symbols);
    322   var syms = symbols[name];
    323   for (var i = 0; i < syms.length; ++i) {
    324     symbolAdder.apply(null, syms[i]);
    325   }
    326 };
    327 
    328 
    329 function PrintMonitor(outputOrFileName) {
    330   var expectedOut = typeof outputOrFileName == 'string' ?
    331       this.loadExpectedOutput(outputOrFileName) : outputOrFileName;
    332   var outputPos = 0;
    333   var diffs = this.diffs = [];
    334   var realOut = this.realOut = [];
    335   var unexpectedOut = this.unexpectedOut = null;
    336 
    337   this.oldPrint = print;
    338   print = function(str) {
    339     var strSplit = str.split('\n');
    340     for (var i = 0; i < strSplit.length; ++i) {
    341       var s = strSplit[i];
    342       realOut.push(s);
    343       if (outputPos < expectedOut.length) {
    344         if (expectedOut[outputPos] != s) {
    345           diffs.push('line ' + outputPos + ': expected <' +
    346                      expectedOut[outputPos] + '> found <' + s + '>\n');
    347         }
    348         outputPos++;
    349       } else {
    350         unexpectedOut = true;
    351       }
    352     }
    353   };
    354 };
    355 
    356 
    357 PrintMonitor.prototype.loadExpectedOutput = function(fileName) {
    358   var output = readFile(fileName);
    359   return output.split('\n');
    360 };
    361 
    362 
    363 PrintMonitor.prototype.finish = function() {
    364   print = this.oldPrint;
    365   if (this.diffs.length > 0 || this.unexpectedOut != null) {
    366     print(this.realOut.join('\n'));
    367     assertEquals([], this.diffs);
    368     assertNull(this.unexpectedOut);
    369   }
    370 };
    371 
    372 
    373 function driveTickProcessorTest(
    374     separateIc, ignoreUnknown, stateFilter, logInput, refOutput) {
    375   // TEST_FILE_NAME must be provided by test runner.
    376   assertEquals('string', typeof TEST_FILE_NAME);
    377   var pathLen = TEST_FILE_NAME.lastIndexOf('/');
    378   if (pathLen == -1) {
    379     pathLen = TEST_FILE_NAME.lastIndexOf('\\');
    380   }
    381   assertTrue(pathLen != -1);
    382   var testsPath = TEST_FILE_NAME.substr(0, pathLen + 1);
    383   var tp = new TickProcessor(new CppEntriesProviderMock(),
    384                              separateIc,
    385                              TickProcessor.CALL_GRAPH_SIZE,
    386                              ignoreUnknown,
    387                              stateFilter,
    388                              undefined,
    389                              "0",
    390                              "auto,auto");
    391   var pm = new PrintMonitor(testsPath + refOutput);
    392   tp.processLogFileInTest(testsPath + logInput);
    393   tp.printStatistics();
    394   pm.finish();
    395 };
    396 
    397 
    398 (function testProcessing() {
    399   var testData = {
    400     'Default': [
    401       false, false, null,
    402       'tickprocessor-test.log', 'tickprocessor-test.default'],
    403     'SeparateIc': [
    404       true, false, null,
    405       'tickprocessor-test.log', 'tickprocessor-test.separate-ic'],
    406     'IgnoreUnknown': [
    407       false, true, null,
    408       'tickprocessor-test.log', 'tickprocessor-test.ignore-unknown'],
    409     'GcState': [
    410       false, false, TickProcessor.VmStates.GC,
    411       'tickprocessor-test.log', 'tickprocessor-test.gc-state'],
    412     'FunctionInfo': [
    413       false, false, null,
    414       'tickprocessor-test-func-info.log', 'tickprocessor-test.func-info']
    415   };
    416   for (var testName in testData) {
    417     print('=== testProcessing-' + testName + ' ===');
    418     driveTickProcessorTest.apply(null, testData[testName]);
    419   }
    420 })();
    421