tickprocessor.js 18 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// 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 implementations from <project root>/tools.
// Files: tools/splaytree.js tools/codemap.js tools/csvparser.js
// Files: tools/consarray.js tools/profile.js tools/profile_view.js
31
// Files: tools/logreader.js tools/arguments.js tools/tickprocessor.js
32 33
// Env: TEST_FILE_NAME

34

35 36 37
(function testArgumentsProcessor() {
  var p_default = new ArgumentsProcessor([]);
  assertTrue(p_default.parse());
38
  assertEquals(p_default.getDefaultResults(), p_default.result());
39 40 41 42 43 44 45 46 47 48

  var p_logFile = new ArgumentsProcessor(['logfile.log']);
  assertTrue(p_logFile.parse());
  assertEquals('logfile.log', p_logFile.result().logFileName);

  var p_platformAndLog = new ArgumentsProcessor(['--windows', 'winlog.log']);
  assertTrue(p_platformAndLog.parse());
  assertEquals('windows', p_platformAndLog.result().platform);
  assertEquals('winlog.log', p_platformAndLog.result().logFileName);

49
  var p_flags = new ArgumentsProcessor(['--gc', '--separate-ic=true']);
50 51 52 53
  assertTrue(p_flags.parse());
  assertEquals(TickProcessor.VmStates.GC, p_flags.result().stateFilter);
  assertTrue(p_flags.result().separateIc);

54 55 56 57 58
  var p_flags = new ArgumentsProcessor(['--gc', '--separate-ic=false']);
  assertTrue(p_flags.parse());
  assertEquals(TickProcessor.VmStates.GC, p_flags.result().stateFilter);
  assertFalse(p_flags.result().separateIc);

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
  var p_nmAndLog = new ArgumentsProcessor(['--nm=mn', 'nmlog.log']);
  assertTrue(p_nmAndLog.parse());
  assertEquals('mn', p_nmAndLog.result().nm);
  assertEquals('nmlog.log', p_nmAndLog.result().logFileName);

  var p_bad = new ArgumentsProcessor(['--unknown', 'badlog.log']);
  assertFalse(p_bad.parse());
})();


(function testUnixCppEntriesProvider() {
  var oldLoadSymbols = UnixCppEntriesProvider.prototype.loadSymbols;

  // shell executable
  UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
    this.symbols = [[
      '         U operator delete[](void*)@@GLIBCXX_3.4',
      '08049790 T _init',
      '08049f50 T _start',
78 79 80 81
      '08139150 00000b4b t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
      '08139ca0 000003f1 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
      '0813a0b0 00000855 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
      '0818b220 00000036 W v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)',
82
      '         w __gmon_start__',
83
      '081f08a0 00000004 B stdout\n'
84 85 86 87 88
    ].join('\n'), ''];
  };

  var shell_prov = new UnixCppEntriesProvider();
  var shell_syms = [];
89
  shell_prov.parseVmSymbols('shell', 0x08048000, 0x081ee000, 0,
90 91 92 93 94 95
      function (name, start, end) {
        shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
  assertEquals(
      [['_init', 0x08049790, 0x08049f50],
       ['_start', 0x08049f50, 0x08139150],
96 97 98 99
       ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139150 + 0xb4b],
       ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, 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]],
100 101 102 103 104
      shell_syms);

  // libc library
  UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
    this.symbols = [[
105 106 107 108 109 110 111
        '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'), ''];
112 113 114
  };
  var libc_prov = new UnixCppEntriesProvider();
  var libc_syms = [];
115
  libc_prov.parseVmSymbols('libc', 0xf7c5c000, 0xf7da5000, 0,
116 117 118
      function (name, start, end) {
        libc_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
119 120 121 122 123 124 125 126 127
  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);
128 129 130 131 132

  UnixCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
})();


133 134 135 136 137 138
(function testMacCppEntriesProvider() {
  var oldLoadSymbols = MacCppEntriesProvider.prototype.loadSymbols;

  // shell executable
  MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
    this.symbols = [[
139 140 141 142 143 144 145 146
      '         operator delete[]',
      '00001000 __mh_execute_header',
      '00001b00 start',
      '00001b40 dyld_stub_binding_helper',
      '0011b710 v8::internal::RegExpMacroAssembler::CheckPosition',
      '00134250 v8::internal::Runtime_StringReplaceRegExpWithString',
      '00137220 v8::internal::Runtime::GetElementOrCharAt',
      '00137400 v8::internal::Runtime_DebugGetPropertyDetails\n'
147 148 149 150 151
    ].join('\n'), ''];
  };

  var shell_prov = new MacCppEntriesProvider();
  var shell_syms = [];
152
  shell_prov.parseVmSymbols('shell', 0x00001c00, 0x00163256, 0x100,
153 154 155 156
      function (name, start, end) {
        shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
  assertEquals(
157 158 159 160 161 162
      [['start', 0x00001c00, 0x00001c40],
       ['dyld_stub_binding_helper', 0x00001c40, 0x0011b810],
       ['v8::internal::RegExpMacroAssembler::CheckPosition', 0x0011b810, 0x00134350],
       ['v8::internal::Runtime_StringReplaceRegExpWithString', 0x00134350, 0x00137320],
       ['v8::internal::Runtime::GetElementOrCharAt', 0x00137320, 0x00137500],
       ['v8::internal::Runtime_DebugGetPropertyDetails', 0x00137500, 0x00163256]],
163 164 165 166 167
      shell_syms);

  // stdc++ library
  MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
    this.symbols = [[
168 169 170 171
        '0000107a __gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector',
        '0002c410 std::basic_streambuf<char, std::char_traits<char> >::pubseekoff',
        '0002c488 std::basic_streambuf<char, std::char_traits<char> >::pubseekpos',
        '000466aa ___cxa_pure_virtual\n'].join('\n'), ''];
172 173 174
  };
  var stdc_prov = new MacCppEntriesProvider();
  var stdc_syms = [];
175
  stdc_prov.parseVmSymbols('stdc++', 0x95728fb4, 0x95770005, 0,
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
      function (name, start, end) {
        stdc_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
  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],
       ['std::basic_streambuf<char, std::char_traits<char> >::pubseekoff', 0x0002c410, 0x0002c488],
       ['std::basic_streambuf<char, std::char_traits<char> >::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;
})();


193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
(function testWindowsCppEntriesProvider() {
  var oldLoadSymbols = WindowsCppEntriesProvider.prototype.loadSymbols;

  WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) {
    this.symbols = [
      ' Start         Length     Name                   Class',
      ' 0001:00000000 000ac902H .text                   CODE',
      ' 0001:000ac910 000005e2H .text$yc                CODE',
      '  Address         Publics by Value              Rva+Base       Lib:Object',
      ' 0000:00000000       __except_list              00000000     <absolute>',
      ' 0001:00000000       ?ReadFile@@YA?AV?$Handle@VString@v8@@@v8@@PBD@Z 00401000 f   shell.obj',
      ' 0001:000000a0       ?Print@@YA?AV?$Handle@VValue@v8@@@v8@@ABVArguments@2@@Z 004010a0 f   shell.obj',
      ' 0001:00001230       ??1UTF8Buffer@internal@v8@@QAE@XZ 00402230 f   v8_snapshot:scanner.obj',
      ' 0001:00001230       ??1Utf8Value@String@v8@@QAE@XZ 00402230 f   v8_snapshot:api.obj',
      ' 0001:000954ba       __fclose_nolock            004964ba f   LIBCMT:fclose.obj',
      ' 0002:00000000       __imp__SetThreadPriority@8 004af000     kernel32:KERNEL32.dll',
      ' 0003:00000418       ?in_use_list_@PreallocatedStorage@internal@v8@@0V123@A 00544418     v8_snapshot:allocation.obj',
      ' Static symbols',
      ' 0001:00000b70       ?DefaultFatalErrorHandler@v8@@YAXPBD0@Z 00401b70 f   v8_snapshot:api.obj',
      ' 0001:000010b0       ?EnsureInitialized@v8@@YAXPBD@Z 004020b0 f   v8_snapshot:api.obj',
      ' 0001:000ad17b       ??__Fnomem@?5???2@YAPAXI@Z@YAXXZ 004ae17b f   LIBCMT:new.obj'
    ].join('\r\n');
  };
  var shell_prov = new WindowsCppEntriesProvider();
  var shell_syms = [];
218
  shell_prov.parseVmSymbols('shell.exe', 0x00400000, 0x0057c000, 0,
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
      function (name, start, end) {
        shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
  assertEquals(
      [['ReadFile', 0x00401000, 0x004010a0],
       ['Print', 0x004010a0, 0x00402230],
       ['v8::String::?1Utf8Value', 0x00402230, 0x004964ba],
       ['v8::DefaultFatalErrorHandler', 0x00401b70, 0x004020b0],
       ['v8::EnsureInitialized', 0x004020b0, 0x0057c000]],
      shell_syms);

  WindowsCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
})();


234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
// http://code.google.com/p/v8/issues/detail?id=427
(function testWindowsProcessExeAndDllMapFile() {
  function exeSymbols(exeName) {
    return [
      ' 0000:00000000       ___ImageBase               00400000     <linker-defined>',
      ' 0001:00000780       ?RunMain@@YAHHQAPAD@Z      00401780 f   shell.obj',
      ' 0001:00000ac0       _main                      00401ac0 f   shell.obj',
      ''
    ].join('\r\n');
  }

  function dllSymbols(dllName) {
    return [
      ' 0000:00000000       ___ImageBase               01c30000     <linker-defined>',
      ' 0001:00000780       _DllMain@12                01c31780 f   libcmt:dllmain.obj',
      ' 0001:00000ac0       ___DllMainCRTStartup       01c31ac0 f   libcmt:dllcrt0.obj',
      ''
    ].join('\r\n');
  }

  var oldRead = read;

  read = exeSymbols;
  var exe_exe_syms = [];
  (new WindowsCppEntriesProvider()).parseVmSymbols(
259
      'chrome.exe', 0x00400000, 0x00472000, 0,
260 261 262 263 264 265 266 267 268 269 270
      function (name, start, end) {
        exe_exe_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
  assertEquals(
      [['RunMain', 0x00401780, 0x00401ac0],
       ['_main', 0x00401ac0, 0x00472000]],
      exe_exe_syms, '.exe with .exe symbols');

  read = dllSymbols;
  var exe_dll_syms = [];
  (new WindowsCppEntriesProvider()).parseVmSymbols(
271
      'chrome.exe', 0x00400000, 0x00472000, 0,
272 273 274 275 276 277 278 279 280 281
      function (name, start, end) {
        exe_dll_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
  assertEquals(
      [],
      exe_dll_syms, '.exe with .dll symbols');

  read = dllSymbols;
  var dll_dll_syms = [];
  (new WindowsCppEntriesProvider()).parseVmSymbols(
282
      'chrome.dll', 0x01c30000, 0x02b80000, 0,
283 284 285 286 287 288 289 290 291 292 293
      function (name, start, end) {
        dll_dll_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
  assertEquals(
      [['_DllMain@12', 0x01c31780, 0x01c31ac0],
       ['___DllMainCRTStartup', 0x01c31ac0, 0x02b80000]],
      dll_dll_syms, '.dll with .dll symbols');

  read = exeSymbols;
  var dll_exe_syms = [];
  (new WindowsCppEntriesProvider()).parseVmSymbols(
294
      'chrome.dll', 0x01c30000, 0x02b80000, 0,
295 296 297 298 299 300 301 302 303 304 305
      function (name, start, end) {
        dll_exe_syms.push(Array.prototype.slice.apply(arguments, [0]));
      });
  assertEquals(
      [],
      dll_exe_syms, '.dll with .exe symbols');

  read = oldRead;
})();


306 307 308 309 310
function CppEntriesProviderMock() {
};


CppEntriesProviderMock.prototype.parseVmSymbols = function(
311
    name, startAddr, endAddr, slideAddr, symbolAdder) {
312 313
  var symbols = {
    'shell':
314
        [['v8::internal::JSObject::LookupOwnRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)', 0x080f8800, 0x080f8d90],
315 316 317
         ['v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)', 0x080f8210, 0x080f8800],
         ['v8::internal::Runtime_Math_exp(v8::internal::Arguments)', 0x08123b20, 0x08123b80]],
    '/lib32/libm-2.7.so':
318 319
        [['exp', startAddr + 0x00009e80, startAddr + 0x00009e80 + 0xa3],
         ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x000061e0 + 0x15]],
320 321 322 323 324 325 326 327 328 329
    'ffffe000-fffff000': []};
  assertTrue(name in symbols);
  var syms = symbols[name];
  for (var i = 0; i < syms.length; ++i) {
    symbolAdder.apply(null, syms[i]);
  }
};


function PrintMonitor(outputOrFileName) {
330 331 332 333 334 335 336
  this.expectedOut = outputOrFileName;
  this.outputFile = undefined;
  if (typeof outputOrFileName == 'string') {
    this.expectedOut = this.loadExpectedOutput(outputOrFileName)
    this.outputFile = outputOrFileName;
  }
  var expectedOut = this.expectedOut;
337 338 339
  var outputPos = 0;
  var diffs = this.diffs = [];
  var realOut = this.realOut = [];
340
  var unexpectedOut = this.unexpectedOut = null;
341 342 343 344 345

  this.oldPrint = print;
  print = function(str) {
    var strSplit = str.split('\n');
    for (var i = 0; i < strSplit.length; ++i) {
346
      var s = strSplit[i];
347
      realOut.push(s);
348 349 350 351 352 353 354 355
      if (outputPos < expectedOut.length) {
        if (expectedOut[outputPos] != s) {
          diffs.push('line ' + outputPos + ': expected <' +
                     expectedOut[outputPos] + '> found <' + s + '>\n');
        }
        outputPos++;
      } else {
        unexpectedOut = true;
356 357 358 359 360 361 362 363 364 365 366 367 368 369
      }
    }
  };
};


PrintMonitor.prototype.loadExpectedOutput = function(fileName) {
  var output = readFile(fileName);
  return output.split('\n');
};


PrintMonitor.prototype.finish = function() {
  print = this.oldPrint;
370
  if (this.diffs.length > 0 || this.unexpectedOut != null) {
jkummerow's avatar
jkummerow committed
371
    print("===== actual output: =====");
372
    print(this.realOut.join('\n'));
jkummerow's avatar
jkummerow committed
373
    print("===== expected output: =====");
374 375 376
    if (this.outputFile) {
      print("===== File: " + this.outputFile + " =====");
    }
jkummerow's avatar
jkummerow committed
377
    print(this.expectedOut.join('\n'));
378
    assertEquals([], this.diffs);
379
    assertNull(this.unexpectedOut);
380 381 382 383 384
  }
};


function driveTickProcessorTest(
385 386
    separateIc, separateBytecodes, separateBuiltins, separateStubs,
    ignoreUnknown, stateFilter, logInput, refOutput, onlySummary) {
387 388 389 390 391 392 393 394
  // TEST_FILE_NAME must be provided by test runner.
  assertEquals('string', typeof TEST_FILE_NAME);
  var pathLen = TEST_FILE_NAME.lastIndexOf('/');
  if (pathLen == -1) {
    pathLen = TEST_FILE_NAME.lastIndexOf('\\');
  }
  assertTrue(pathLen != -1);
  var testsPath = TEST_FILE_NAME.substr(0, pathLen + 1);
395 396
  var tp = new TickProcessor(new CppEntriesProviderMock(),
                             separateIc,
397 398 399
                             separateBytecodes,
                             separateBuiltins,
                             separateStubs,
400 401
                             TickProcessor.CALL_GRAPH_SIZE,
                             ignoreUnknown,
402 403
                             stateFilter,
                             "0",
jkummerow's avatar
jkummerow committed
404
                             "auto,auto",
405 406 407 408
                             false,
                             false,
                             false,
                             onlySummary);
409
  var pm = new PrintMonitor(testsPath + refOutput);
410
  tp.processLogFileInTest(testsPath + logInput);
411 412 413 414 415 416 417 418
  tp.printStatistics();
  pm.finish();
};


(function testProcessing() {
  var testData = {
    'Default': [
419
      false, false, true, true, false, null,
420
      'tickprocessor-test.log', 'tickprocessor-test.default', false],
421
    'SeparateIc': [
422
      true, false, true, true, false, null,
423
      'tickprocessor-test.log', 'tickprocessor-test.separate-ic', false],
424
    'IgnoreUnknown': [
425
      false, false, true, true, true, null,
426
      'tickprocessor-test.log', 'tickprocessor-test.ignore-unknown', false],
427
    'GcState': [
428
      false, false, true, true, false, TickProcessor.VmStates.GC,
429
      'tickprocessor-test.log', 'tickprocessor-test.gc-state', false],
430
    'FunctionInfo': [
431
      false, false, true, true, false, null,
432 433 434
      'tickprocessor-test-func-info.log', 'tickprocessor-test.func-info',
      false],
    'OnlySummary': [
435
      false, false, true, true, false, null,
436
      'tickprocessor-test.log', 'tickprocessor-test.only-summary', true]
437 438 439 440 441 442
  };
  for (var testName in testData) {
    print('=== testProcessing-' + testName + ' ===');
    driveTickProcessorTest.apply(null, testData[testName]);
  }
})();