trace_event_importer_test.html revision cef7893435aa41160dd1255c43cb8498279738cc
1<!DOCTYPE html> 2<!-- 3Copyright (c) 2013 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7 8<link rel="import" href="/tracing/core/test_utils.html"> 9<link rel="import" href="/tracing/extras/importer/trace_event_importer.html"> 10<link rel="import" href="/tracing/extras/measure/measure.html"> 11<link rel="import" href="/tracing/importer/import.html"> 12<link rel="import" href="/tracing/model/memory_dump_test_utils.html"> 13<link rel="import" href="/tracing/model/scoped_id.html"> 14<link rel="import" href="/tracing/model/vm_region.html"> 15<link rel="import" href="/tracing/value/numeric.html"> 16<link rel="import" href="/tracing/value/time_display_mode.html"> 17<link rel="import" href="/tracing/value/unit.html"> 18 19<script> 20'use strict'; 21 22tr.b.unittest.testSuite(function() { 23 var findSliceNamed = tr.c.TestUtils.findSliceNamed; 24 var ColorScheme = tr.b.ColorScheme; 25 var MeasureAsyncSlice = tr.e.measure.MeasureAsyncSlice; 26 var ScopedId = tr.model.ScopedId; 27 var VMRegion = tr.model.VMRegion; 28 var ScalarNumeric = tr.v.ScalarNumeric; 29 var unitlessNumber_smallerIsBetter = 30 tr.v.Unit.byName.unitlessNumber_smallerIsBetter; 31 var checkDumpNumericsAndDiagnostics = 32 tr.model.MemoryDumpTestUtils.checkDumpNumericsAndDiagnostics; 33 var checkVMRegions = tr.model.MemoryDumpTestUtils.checkVMRegions; 34 35 function makeModel(events, opt_shift, opt_prune) { 36 return tr.c.TestUtils.newModelWithEvents([events], { 37 shiftWorldToZero: opt_shift, 38 pruneEmptyContainers: opt_prune 39 }); 40 } 41 42 function makeUnshiftedModel(events) { 43 return makeModel(events, false); 44 } 45 46 function checkHeapEntry(entry, expectedDump, expectedSize, expectedTitles, 47 expectedObjectTypeName) { 48 assert.strictEqual(entry.heapDump, expectedDump); 49 assert.strictEqual(entry.size, expectedSize); 50 assert.strictEqual(entry.objectTypeName, expectedObjectTypeName); 51 if (expectedTitles === undefined) { 52 assert.isUndefined(entry.leafStackFrame); 53 } else { 54 assert.deepEqual( 55 entry.leafStackFrame.getUserFriendlyStackTrace(), expectedTitles); 56 } 57 } 58 59 function getFrame(heapEntry, distance) { 60 var frame = heapEntry.leafStackFrame; 61 for (; distance > 0; distance--) 62 frame = frame.parentFrame; 63 return frame; 64 } 65 66 test('canImportEmpty', function() { 67 assert.isFalse(tr.e.importer.TraceEventImporter.canImport([])); 68 assert.isFalse(tr.e.importer.TraceEventImporter.canImport('')); 69 }); 70 71 test('basicSingleThreadNonnestedParsing', function() { 72 var events = [ 73 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, 74 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}, 75 {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B'}, 76 {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E'} 77 ]; 78 79 var m = makeModel(events); 80 assert.equal(m.numProcesses, 1); 81 var p = m.processes[52]; 82 assert.isDefined(p); 83 84 assert.equal(p.numThreads, 1); 85 var t = p.threads[53]; 86 assert.isDefined(t); 87 assert.equal(t.sliceGroup.length, 2); 88 assert.equal(t.tid, 53); 89 var slice = t.sliceGroup.slices[0]; 90 assert.equal(slice.title, 'a'); 91 assert.equal(slice.category, 'foo'); 92 assert.equal(slice.start, 0); 93 assert.closeTo((560 - 520) / 1000, slice.duration, 1e-5); 94 assert.equal(slice.subSlices.length, 0); 95 96 slice = t.sliceGroup.slices[1]; 97 assert.equal(slice.title, 'b'); 98 assert.equal(slice.category, 'bar'); 99 assert.closeTo((629 - 520) / 1000, slice.start, 1e-5); 100 assert.closeTo((631 - 629) / 1000, slice.duration, 1e-5); 101 assert.equal(slice.subSlices.length, 0); 102 }); 103 104 test('basicSingleThreadNonnestedParsingWithCpuDuration', function() { 105 var events = [ 106 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B', tts: 221}, // @suppress longLineCheck 107 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E', tts: 259}, // @suppress longLineCheck 108 {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B', tts: 329}, // @suppress longLineCheck 109 {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E', tts: 331} // @suppress longLineCheck 110 ]; 111 112 var m = makeModel(events); 113 assert.equal(m.numProcesses, 1); 114 var p = m.processes[52]; 115 assert.isDefined(p); 116 117 assert.equal(p.numThreads, 1); 118 var t = p.threads[53]; 119 assert.isDefined(t); 120 assert.equal(t.sliceGroup.length, 2); 121 assert.equal(t.tid, 53); 122 var slice = t.sliceGroup.slices[0]; 123 assert.equal(slice.title, 'a'); 124 assert.equal(slice.category, 'foo'); 125 assert.equal(slice.start, 0); 126 assert.closeTo((560 - 520) / 1000, slice.duration, 1e-5); 127 assert.closeTo((259 - 221) / 1000, slice.cpuDuration, 1e-5); 128 assert.equal(slice.subSlices.length, 0); 129 130 slice = t.sliceGroup.slices[1]; 131 assert.equal(slice.title, 'b'); 132 assert.equal(slice.category, 'bar'); 133 assert.closeTo((629 - 520) / 1000, slice.start, 1e-5); 134 assert.closeTo((631 - 629) / 1000, slice.duration, 1e-5); 135 assert.closeTo((331 - 329) / 1000, slice.cpuDuration, 1e-5); 136 assert.equal(slice.subSlices.length, 0); 137 }); 138 139 test('argumentDupeCreatesNonFailingImportError', function() { 140 var events = [ 141 {name: 'a', 142 args: {'x': 1}, 143 pid: 1, 144 ts: 520, 145 cat: 'foo', 146 tid: 1, 147 ph: 'B'}, 148 {name: 'a', 149 args: {'x': 2}, 150 pid: 1, 151 ts: 560, 152 cat: 'foo', 153 tid: 1, 154 ph: 'E'} 155 ]; 156 157 var m = makeModel(events); 158 var t = m.processes[1].threads[1]; 159 var sA = findSliceNamed(t.sliceGroup, 'a'); 160 161 assert.equal(sA.args.x, 2); 162 assert.isTrue(m.hasImportWarnings); 163 assert.equal(1, m.importWarnings.length); 164 }); 165 166 test('importMissingArgs', function() { 167 var events = [ 168 {name: 'a', pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, 169 {name: 'a', pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}, 170 {name: 'b', pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'I'} 171 ]; 172 173 // This should not throw an exception. 174 makeModel(events); 175 }); 176 177 test('importDoesNotChokeOnNulls', function() { 178 var events = [ 179 {name: 'a', args: { foo: null }, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, // @suppress longLineCheck 180 {name: 'a', pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 181 ]; 182 183 // This should not throw an exception. 184 makeModel(events); 185 }); 186 187 test('categoryBeginEndMismatchPrefersBegin', function() { 188 var events = [ 189 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, 190 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'bar', tid: 53, ph: 'E'} 191 ]; 192 193 var m = makeModel(events); 194 assert.equal(m.numProcesses, 1); 195 var p = m.processes[52]; 196 assert.isDefined(p); 197 198 assert.equal(p.numThreads, 1); 199 var t = p.threads[53]; 200 assert.isDefined(t); 201 assert.equal(t.sliceGroup.length, 1); 202 assert.equal(t.tid, 53); 203 var slice = t.sliceGroup.slices[0]; 204 assert.equal(slice.title, 'a'); 205 assert.equal(slice.category, 'foo'); 206 }); 207 208 test('beginEndNameMismatch', function() { 209 var events = [ 210 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, 211 {name: 'b', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 212 ]; 213 214 var m = makeModel(events); 215 assert.isTrue(m.hasImportWarnings); 216 assert.equal(m.importWarnings.length, 1); 217 }); 218 219 test('nestedParsing', function() { 220 var events = [ 221 {name: 'a', args: {}, pid: 1, ts: 1, tts: 1, cat: 'foo', tid: 1, ph: 'B'}, 222 {name: 'b', args: {}, pid: 1, ts: 2, tts: 2, cat: 'bar', tid: 1, ph: 'B'}, 223 {name: 'b', args: {}, pid: 1, ts: 3, tts: 3, cat: 'bar', tid: 1, ph: 'E'}, 224 {name: 'a', args: {}, pid: 1, ts: 4, tts: 3, cat: 'foo', tid: 1, ph: 'E'} 225 ]; 226 var m = makeModel(events, false); 227 var t = m.processes[1].threads[1]; 228 229 var sA = findSliceNamed(t.sliceGroup, 'a'); 230 var sB = findSliceNamed(t.sliceGroup, 'b'); 231 232 assert.equal(sA.title, 'a'); 233 assert.equal(sA.category, 'foo'); 234 assert.equal(sA.start, 0.001); 235 assert.equal(sA.duration, 0.003); 236 assert.equal(sA.selfTime, 0.002); 237 assert.equal(sA.cpuSelfTime, 0.001); 238 239 assert.equal(sB.title, 'b'); 240 assert.equal(sB.category, 'bar'); 241 assert.equal(sB.start, 0.002); 242 assert.equal(sB.duration, 0.001); 243 244 assert.equal(1, sA.subSlices.length); 245 assert.equal(sB, sA.subSlices[0]); 246 assert.equal(sA, sB.parentSlice); 247 }); 248 249 test('nestedParsingWithTwoSubSlices', function() { 250 var events = [ 251 {name: 'a', args: {}, pid: 1, ts: 1, tts: 1, cat: 'foo', tid: 1, ph: 'B'}, 252 {name: 'b', args: {}, pid: 1, ts: 2, tts: 2, cat: 'bar', tid: 1, ph: 'B'}, 253 {name: 'b', args: {}, pid: 1, ts: 3, tts: 3, cat: 'bar', tid: 1, ph: 'E'}, 254 {name: 'c', args: {}, pid: 1, ts: 5, tts: 5, cat: 'baz', tid: 1, ph: 'B'}, 255 {name: 'c', args: {}, pid: 1, ts: 7, tts: 6, cat: 'baz', tid: 1, ph: 'E'}, 256 {name: 'a', args: {}, pid: 1, ts: 8, tts: 8, cat: 'foo', tid: 1, ph: 'E'} 257 ]; 258 var m = makeModel(events, false); 259 var t = m.processes[1].threads[1]; 260 261 var sA = findSliceNamed(t.sliceGroup, 'a'); 262 var sB = findSliceNamed(t.sliceGroup, 'b'); 263 var sC = findSliceNamed(t.sliceGroup, 'c'); 264 265 assert.equal(sA.title, 'a'); 266 assert.equal(sA.category, 'foo'); 267 assert.equal(sA.start, 0.001); 268 assert.equal(sA.duration, 0.007); 269 assert.equal(sA.selfTime, 0.004); 270 assert.equal(sA.cpuSelfTime, 0.005); 271 272 assert.equal(sB.title, 'b'); 273 assert.equal(sB.category, 'bar'); 274 assert.equal(sB.start, 0.002); 275 assert.equal(sB.duration, 0.001); 276 277 assert.equal(sC.title, 'c'); 278 assert.equal(sC.category, 'baz'); 279 assert.equal(sC.start, 0.005); 280 assert.equal(sC.duration, 0.002); 281 282 assert.equal(sA.subSlices.length, 2); 283 assert.equal(sA.subSlices[0], sB); 284 assert.equal(sA.subSlices[1], sC); 285 assert.equal(sB.parentSlice, sA); 286 assert.equal(sC.parentSlice, sA); 287 }); 288 289 test('nestedParsingWithDoubleNesting', function() { 290 var events = [ 291 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 292 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'B'}, 293 {name: 'c', args: {}, pid: 1, ts: 3, cat: 'baz', tid: 1, ph: 'B'}, 294 {name: 'c', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'E'}, 295 {name: 'b', args: {}, pid: 1, ts: 7, cat: 'bar', tid: 1, ph: 'E'}, 296 {name: 'a', args: {}, pid: 1, ts: 8, cat: 'foo', tid: 1, ph: 'E'} 297 ]; 298 var m = makeModel(events, false); 299 var t = m.processes[1].threads[1]; 300 301 var sA = findSliceNamed(t.sliceGroup, 'a'); 302 var sB = findSliceNamed(t.sliceGroup, 'b'); 303 var sC = findSliceNamed(t.sliceGroup, 'c'); 304 305 assert.equal(sA.title, 'a'); 306 assert.equal(sA.category, 'foo'); 307 assert.equal(sA.start, 0.001); 308 assert.equal(sA.duration, 0.007); 309 assert.equal(sA.selfTime, 0.002); 310 311 assert.equal(sB.title, 'b'); 312 assert.equal(sB.category, 'bar'); 313 assert.equal(sB.start, 0.002); 314 assert.equal(sB.duration, 0.005); 315 assert.equal(sA.selfTime, 0.002); 316 317 assert.equal(sC.title, 'c'); 318 assert.equal(sC.category, 'baz'); 319 assert.equal(sC.start, 0.003); 320 assert.equal(sC.duration, 0.002); 321 322 assert.equal(sA.subSlices.length, 1); 323 assert.equal(sA.subSlices[0], sB); 324 assert.equal(sB.parentSlice, sA); 325 326 assert.equal(sB.subSlices.length, 1); 327 assert.equal(sB.subSlices[0], sC); 328 assert.equal(sC.parentSlice, sB); 329 }); 330 331 332 test('autoclosing', function() { 333 var events = [ 334 // Slice that doesn't finish. 335 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 336 337 // Slice that does finish to give an 'end time' to make autoclosing work. 338 {name: 'b', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'}, 339 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'} 340 ]; 341 var m = makeUnshiftedModel(events); 342 var p = m.processes[1]; 343 var t1 = p.threads[1]; 344 var t2 = p.threads[2]; 345 assert.isTrue(t1.sliceGroup.slices[0].didNotFinish); 346 assert.equal(t1.sliceGroup.slices[0].end, 0.001); 347 }); 348 349 test('autoclosingLoneBegin', function() { 350 var events = [ 351 // Slice that doesn't finish. 352 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'} 353 ]; 354 var m = makeModel(events); 355 var p = m.processes[1]; 356 var t = p.threads[1]; 357 var slice = t.sliceGroup.slices[0]; 358 assert.equal(slice.title, 'a'); 359 assert.equal(slice.category, 'foo'); 360 assert.isTrue(slice.didNotFinish); 361 assert.equal(slice.start, 0); 362 assert.equal(slice.duration, 0); 363 }); 364 365 test('autoclosingWithSubTasks', function() { 366 var events = [ 367 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 368 {name: 'b1', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'}, 369 {name: 'b1', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'}, 370 {name: 'b2', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'} 371 ]; 372 var m = makeModel(events, false); 373 var t = m.processes[1].threads[1]; 374 375 var sA = findSliceNamed(t.sliceGroup, 'a'); 376 var sB1 = findSliceNamed(t.sliceGroup, 'b1'); 377 var sB2 = findSliceNamed(t.sliceGroup, 'b2'); 378 379 assert.equal(sA.end, 0.003); 380 assert.equal(sB1.end, 0.003); 381 assert.equal(sB2.end, 0.003); 382 }); 383 384 test('autoclosingWithEventsOutsideBounds', function() { 385 var events = [ 386 // Slice that begins before min and ends after max of the other threads. 387 {name: 'a', args: {}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'B'}, 388 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'}, 389 390 // Slice that does finish to give an 'end time' to establish a basis 391 {name: 'c', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'}, 392 {name: 'c', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'} 393 ]; 394 var m = makeModel(events); 395 var p = m.processes[1]; 396 var t = p.threads[1]; 397 assert.equal(t.sliceGroup.length, 2); 398 399 var slice = findSliceNamed(t.sliceGroup, 'a'); 400 assert.equal(slice.title, 'a'); 401 assert.equal(slice.category, 'foo'); 402 assert.equal(slice.start, 0); 403 assert.equal(slice.duration, 0.003); 404 405 var t2 = p.threads[2]; 406 var slice2 = findSliceNamed(t2.sliceGroup, 'c'); 407 assert.equal(slice2.title, 'c'); 408 assert.equal(slice2.category, 'bar'); 409 assert.equal(slice2.start, 0.001); 410 assert.equal(slice2.duration, 0.001); 411 412 assert.equal(m.bounds.min, 0.000); 413 assert.equal(m.bounds.max, 0.003); 414 }); 415 416 test('nestedAutoclosing', function() { 417 var events = [ 418 // Tasks that don't finish. 419 {name: 'a1', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 420 {name: 'a2', args: {}, pid: 1, ts: 1.5, cat: 'foo', tid: 1, ph: 'B'}, 421 422 // Slice that does finish to give an 'end time' to make autoclosing work. 423 {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'}, 424 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'} 425 ]; 426 var m = makeUnshiftedModel(events, false); 427 var t1 = m.processes[1].threads[1]; 428 var t2 = m.processes[1].threads[2]; 429 430 var sA1 = findSliceNamed(t1.sliceGroup, 'a1'); 431 var sA2 = findSliceNamed(t1.sliceGroup, 'a2'); 432 var sB = findSliceNamed(t2.sliceGroup, 'b'); 433 434 assert.equal(sA1.end, 0.0015); 435 assert.equal(sA2.end, 0.0015); 436 }); 437 438 test('taskColoring', function() { 439 // The test below depends on hashing of 'a' != 'b'. Fail early if that 440 // assumption is incorrect. 441 assert.notEqual(ColorScheme.getStringHash('a'), 442 ColorScheme.getStringHash('b')); 443 444 var events = [ 445 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 446 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, 447 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 1, ph: 'B'}, 448 {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 1, ph: 'E'}, 449 {name: 'a', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'B'}, 450 {name: 'a', args: {}, pid: 1, ts: 6, cat: 'baz', tid: 1, ph: 'E'} 451 ]; 452 var m = makeModel(events); 453 var p = m.processes[1]; 454 var t = p.threads[1]; 455 var a1 = t.sliceGroup.slices[0]; 456 assert.equal(a1.title, 'a'); 457 assert.equal(a1.category, 'foo'); 458 var b = t.sliceGroup.slices[1]; 459 assert.equal(b.title, 'b'); 460 assert.equal(b.category, 'bar'); 461 assert.notEqual(b.colorId, a1.colorId); 462 var a2 = t.sliceGroup.slices[2]; 463 assert.equal(a2.title, 'a'); 464 assert.equal(a2.category, 'baz'); 465 assert.equal(a1.colorId, a2.colorId); 466 }); 467 468 test('durationColorArgument', function() { 469 var events = [ 470 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B', cname: 'thread_state_unknown'}, // @suppress longLineCheck 471 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'E', cname: 'thread_state_unknown'} // @suppress longLineCheck 472 ]; 473 474 var m = makeModel(events); 475 var p = m.processes[1]; 476 var t = p.threads[1]; 477 assert.equal(t.sliceGroup.slices[0].colorId, 478 ColorScheme.getColorIdForReservedName('thread_state_unknown')); 479 }); 480 481 test('durationColorEnd', function() { 482 var events = [ 483 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B', cname: 'thread_state_sleeping'}, // @suppress longLineCheck 484 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'E', cname: 'thread_state_unknown'} // @suppress longLineCheck 485 ]; 486 487 var m = makeModel(events); 488 var p = m.processes[1]; 489 var t = p.threads[1]; 490 assert.equal(t.sliceGroup.slices[0].colorId, 491 ColorScheme.getColorIdForReservedName('thread_state_unknown')); 492 }); 493 494 test('completeColorArgument', function() { 495 var events = [ 496 {name: 'a', args: {}, pid: 1, ts: 1, dur: 1, cat: 'foo', tid: 1, ph: 'X', cname: 'generic_work'} // @suppress longLineCheck 497 ]; 498 499 var m = makeModel(events); 500 var p = m.processes[1]; 501 var t = p.threads[1]; 502 assert.equal(t.sliceGroup.slices[0].colorId, 503 ColorScheme.getColorIdForReservedName('generic_work')); 504 }); 505 506 test('asyncColorArgument', function() { 507 var events = [ 508 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'b', id: 1, cname: 'generic_work'}, // @suppress longLineCheck 509 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'e', id: 1, cname: 'generic_work'} // @suppress longLineCheck 510 ]; 511 512 var m = makeModel(events); 513 var p = m.processes[1]; 514 var t = p.threads[1]; 515 assert.equal(t.asyncSliceGroup.slices[0].colorId, 516 ColorScheme.getColorIdForReservedName('generic_work')); 517 }); 518 519 test('asyncColorEnd', function() { 520 var events = [ 521 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'b', id: 1, cname: 'thread_state_unknown'}, // @suppress longLineCheck 522 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'e', id: 1, cname: 'generic_work'} // @suppress longLineCheck 523 ]; 524 525 var m = makeModel(events); 526 var p = m.processes[1]; 527 var t = p.threads[1]; 528 assert.equal(t.asyncSliceGroup.slices[0].colorId, 529 ColorScheme.getColorIdForReservedName('generic_work')); 530 }); 531 532 test('instantThreadColorArgument', function() { 533 var events = [ 534 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'I', id: 1, cname: 'generic_work'} // @suppress longLineCheck 535 ]; 536 537 var m = makeModel(events); 538 var p = m.processes[1]; 539 var t = p.threads[1]; 540 assert.equal(t.sliceGroup.slices[0].colorId, 541 ColorScheme.getColorIdForReservedName('generic_work')); 542 }); 543 544 test('instantProcessColorArgument', function() { 545 var events = [ 546 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'I', id: 1, s: 'p', cname: 'generic_work'} // @suppress longLineCheck 547 ]; 548 549 var m = makeModel(events); 550 var p = m.processes[1]; 551 assert.equal(p.instantEvents[0].colorId, 552 ColorScheme.getColorIdForReservedName('generic_work')); 553 }); 554 555 test('counterColorArgument', function() { 556 var events = [ 557 {name: 'a', args: {'cats': 10}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'C', id: 1, cname: 'generic_work'} // @suppress longLineCheck 558 ]; 559 560 var m = makeModel(events); 561 var p = m.processes[1]; 562 assert.equal(p.counters['foo.a[1]'].series[0].color, 563 ColorScheme.getColorIdForReservedName('generic_work')); 564 assert.equal(p.counters['foo.a[1]'].series.length, 1); 565 }); 566 567 test('objectColorArgument', function() { 568 var events = [ 569 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'N', id: 1, cname: 'generic_work'}, // @suppress longLineCheck 570 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'O', id: 1, cname: 'generic_work'}, // @suppress longLineCheck 571 {name: 'a', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'D', id: 1, cname: 'generic_work'} // @suppress longLineCheck 572 ]; 573 574 var m = makeModel(events); 575 var p = m.processes[1]; 576 var i = p.objects.instanceMapsByScopedId_['ptr'][1].instances[0]; 577 assert.equal(i.colorId, 578 ColorScheme.getColorIdForReservedName('generic_work')); 579 }); 580 581 test('objectColorEnd', function() { 582 var events = [ 583 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'N', id: 1, cname: 'thread_state_sleeping'}, // @suppress longLineCheck 584 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'O', id: 1, cname: 'thread_state_unknown'}, // @suppress longLineCheck 585 {name: 'a', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'D', id: 1, cname: 'generic_work'} // @suppress longLineCheck 586 ]; 587 588 var m = makeModel(events); 589 var p = m.processes[1]; 590 var i = p.objects.instanceMapsByScopedId_['ptr'][1].instances[0]; 591 assert.equal(i.colorId, 592 ColorScheme.getColorIdForReservedName('generic_work')); 593 }); 594 595 test('multipleThreadParsing', function() { 596 var events = [ 597 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 598 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, 599 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 2, ph: 'B'}, 600 {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 2, ph: 'E'} 601 ]; 602 var m = makeModel(events); 603 assert.equal(m.numProcesses, 1); 604 var p = m.processes[1]; 605 assert.isDefined(p); 606 607 assert.equal(p.numThreads, 2); 608 609 // Check thread 1. 610 var t = p.threads[1]; 611 assert.isDefined(t); 612 assert.equal(t.sliceGroup.length, 1); 613 assert.equal(t.tid, 1); 614 615 var slice = t.sliceGroup.slices[0]; 616 assert.equal(slice.title, 'a'); 617 assert.equal(slice.category, 'foo'); 618 assert.equal(slice.start, 0); 619 assert.equal(slice.duration, (2 - 1) / 1000); 620 assert.equal(slice.subSlices.length, 0); 621 622 // Check thread 2. 623 var t = p.threads[2]; 624 assert.isDefined(t); 625 assert.equal(t.sliceGroup.length, 1); 626 assert.equal(t.tid, 2); 627 628 slice = t.sliceGroup.slices[0]; 629 assert.equal(slice.title, 'b'); 630 assert.equal(slice.category, 'bar'); 631 assert.equal(slice.start, (3 - 1) / 1000); 632 assert.equal(slice.duration, (4 - 3) / 1000); 633 assert.equal(slice.subSlices.length, 0); 634 }); 635 636 test('multiplePidParsing', function() { 637 var events = [ 638 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 639 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, 640 {name: 'b', args: {}, pid: 2, ts: 3, cat: 'bar', tid: 2, ph: 'B'}, 641 {name: 'b', args: {}, pid: 2, ts: 4, cat: 'bar', tid: 2, ph: 'E'} 642 ]; 643 var m = makeModel(events); 644 assert.equal(m.numProcesses, 2); 645 var p = m.processes[1]; 646 assert.isDefined(p); 647 648 assert.equal(p.numThreads, 1); 649 650 // Check process 1 thread 1. 651 var t = p.threads[1]; 652 assert.isDefined(t); 653 assert.equal(t.sliceGroup.length, 1); 654 assert.equal(t.tid, 1); 655 656 var slice = t.sliceGroup.slices[0]; 657 assert.equal(slice.title, 'a'); 658 assert.equal(slice.category, 'foo'); 659 assert.equal(slice.start, 0); 660 assert.equal(slice.duration, (2 - 1) / 1000); 661 assert.equal(slice.subSlices.length, 0); 662 663 // Check process 2 thread 2. 664 var p = m.processes[2]; 665 assert.isDefined(p); 666 assert.equal(p.numThreads, 1); 667 var t = p.threads[2]; 668 assert.isDefined(t); 669 assert.equal(t.sliceGroup.length, 1); 670 assert.equal(t.tid, 2); 671 672 slice = t.sliceGroup.slices[0]; 673 assert.equal(slice.title, 'b'); 674 assert.equal(slice.category, 'bar'); 675 assert.equal(slice.start, (3 - 1) / 1000); 676 assert.equal(slice.duration, (4 - 3) / 1000); 677 assert.equal(slice.subSlices.length, 0); 678 679 // Check getAllThreads. 680 assert.deepEqual(m.getAllThreads(), 681 [m.processes[1].threads[1], m.processes[2].threads[2]]); 682 }); 683 684 // Process names. 685 test('processNames', function() { 686 var events = [ 687 {name: 'process_name', args: {name: 'SomeProcessName'}, 688 pid: 1, ts: 0, tid: 1, ph: 'M'}, 689 {name: 'process_name', args: {name: 'SomeProcessName'}, 690 pid: 2, ts: 0, tid: 1, ph: 'M'} 691 ]; 692 var m = makeModel(events); 693 assert.equal(m.processes[1].name, 'SomeProcessName'); 694 }); 695 696 // Process labels. 697 test('processLabels', function() { 698 var events = [ 699 {name: 'process_labels', args: {labels: 'foo,bar,bar,foo,baz'}, 700 pid: 1, ts: 0, tid: 1, ph: 'M'}, 701 {name: 'process_labels', args: {labels: 'baz'}, 702 pid: 2, ts: 0, tid: 1, ph: 'M'} 703 ]; 704 var m = makeModel(events); 705 assert.deepEqual(m.processes[1].labels, ['foo', 'bar', 'baz']); 706 assert.deepEqual(m.processes[2].labels, ['baz']); 707 }); 708 709 // Process sort index. 710 test('processSortIndex', function() { 711 var events = [ 712 {name: 'process_name', args: {name: 'First'}, 713 pid: 2, ts: 0, tid: 1, ph: 'M'}, 714 {name: 'process_name', args: {name: 'Second'}, 715 pid: 2, ts: 0, tid: 1, ph: 'M'}, 716 {name: 'process_sort_index', args: {sort_index: 1}, 717 pid: 1, ts: 0, tid: 1, ph: 'M'} 718 ]; 719 var m = makeModel(events); 720 721 // By name, p1 is before p2. But, its sort index overrides that. 722 assert.isAbove(m.processes[1].compareTo(m.processes[2]), 0); 723 }); 724 725 // Thread names. 726 test('threadNames', function() { 727 var events = [ 728 {name: 'thread_name', args: {name: 'Thread 1'}, 729 pid: 1, ts: 0, tid: 1, ph: 'M'}, 730 {name: 'thread_name', args: {name: 'Thread 2'}, 731 pid: 2, ts: 0, tid: 2, ph: 'M'} 732 ]; 733 var m = makeModel(events, false, false); 734 assert.equal(m.processes[1].threads[1].name, 'Thread 1'); 735 assert.equal(m.processes[2].threads[2].name, 'Thread 2'); 736 }); 737 738 // Thread sort index. 739 test('threadSortIndex', function() { 740 var events = [ 741 {name: 'thread_name', args: {name: 'Thread 1'}, 742 pid: 1, ts: 0, tid: 1, ph: 'M'}, 743 {name: 'thread_name', args: {name: 'Thread 2'}, 744 pid: 1, ts: 0, tid: 2, ph: 'M'}, 745 {name: 'thread_sort_index', args: {sort_index: 1}, 746 pid: 1, ts: 0, tid: 1, ph: 'M'} 747 ]; 748 var m = makeModel(events, false, false); 749 750 // By name, t1 is before t2. But, its sort index overrides that. 751 var t1 = m.processes[1].threads[1]; 752 var t2 = m.processes[1].threads[2]; 753 assert.isAbove(t1.compareTo(t2), 0); 754 }); 755 756 // CPU counts. 757 test('cpuCounts', function() { 758 var events = [ 759 {name: 'num_cpus', args: {number: 4}, 760 pid: 7, ts: 0, tid: 0, ph: 'M'}, 761 {name: 'num_cpus', args: {number: 4}, 762 pid: 14, ts: 0, tid: 0, ph: 'M'} 763 ]; 764 var m = makeModel(events); 765 assert.equal(m.kernel.softwareMeasuredCpuCount, 4); 766 assert.equal(m.kernel.bestGuessAtCpuCount, 4); 767 }); 768 769 test('cpuCountsWithSandboxBeingConfused', function() { 770 var events = [ 771 {name: 'num_cpus', args: {number: 4}, 772 pid: 7, ts: 0, tid: 0, ph: 'M'}, 773 {name: 'num_cpus', args: {number: 1}, 774 pid: 14, ts: 0, tid: 0, ph: 'M'} 775 ]; 776 var m = makeModel(events); 777 assert.equal(m.kernel.softwareMeasuredCpuCount, 4); 778 assert.equal(m.kernel.bestGuessAtCpuCount, 4); 779 }); 780 781 test('parsingWhenEndComesFirst', function() { 782 var events = [ 783 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'E'}, 784 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'B'}, 785 {name: 'a', args: {}, pid: 1, ts: 5, cat: 'foo', tid: 1, ph: 'E'} 786 ]; 787 var m = makeModel(events, false); 788 var p = m.processes[1]; 789 var t = p.threads[1]; 790 assert.equal(t.sliceGroup.length, 1); 791 assert.equal(t.sliceGroup.slices[0].title, 'a'); 792 assert.equal(t.sliceGroup.slices[0].category, 'foo'); 793 assert.equal(t.sliceGroup.slices[0].start, 0.004); 794 assert.equal(t.sliceGroup.slices[0].duration, 0.001); 795 assert.isTrue(m.hasImportWarnings); 796 assert.equal(m.importWarnings.length, 1); 797 }); 798 799 test('immediateParsing', function() { 800 var events = [ 801 // Need to include immediates inside a task so the timeline 802 // recentering/zeroing doesn't clobber their timestamp. 803 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 804 {name: 'immediate', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'I'}, 805 {name: 'slower', args: {}, pid: 1, ts: 4, cat: 'baz', tid: 1, ph: 'i'}, 806 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'} 807 ]; 808 var m = makeModel(events, false); 809 var p = m.processes[1]; 810 var t = p.threads[1]; 811 812 assert.equal(t.sliceGroup.length, 3); 813 assert.equal(t.sliceGroup.slices[0].start, 0.001); 814 assert.equal(t.sliceGroup.slices[0].duration, 0.003); 815 assert.equal(t.sliceGroup.slices[1].start, 0.002); 816 assert.equal(t.sliceGroup.slices[1].duration, 0); 817 assert.equal(t.sliceGroup.slices[2].start, 0.004); 818 819 var slice = findSliceNamed(t.sliceGroup, 'a'); 820 assert.equal(slice.title, 'a'); 821 assert.equal(slice.category, 'foo'); 822 assert.equal(slice.duration, 0.003); 823 824 var immed = findSliceNamed(t.sliceGroup, 'immediate'); 825 assert.equal(immed.title, 'immediate'); 826 assert.equal(immed.category, 'bar'); 827 assert.equal(immed.start, 0.002); 828 assert.equal(immed.duration, 0); 829 830 var slower = findSliceNamed(t.sliceGroup, 'slower'); 831 assert.equal(slower.title, 'slower'); 832 assert.equal(slower.category, 'baz'); 833 assert.equal(slower.start, 0.004); 834 assert.equal(slower.duration, 0); 835 }); 836 837 test('simpleCounter', function() { 838 var events = [ 839 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1, 840 ph: 'C'}, 841 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, 842 ph: 'C'}, 843 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 20, cat: 'foo', tid: 1, 844 ph: 'C'} 845 846 ]; 847 var m = makeModel(events); 848 var p = m.processes[1]; 849 var ctr = m.processes[1].counters['foo.ctr']; 850 851 assert.equal(ctr.name, 'ctr'); 852 assert.equal(ctr.category, 'foo'); 853 assert.equal(ctr.numSamples, 3); 854 assert.equal(ctr.numSeries, 1); 855 856 assert.equal(ctr.series[0].name, 'value'); 857 assert.equal(ctr.series[0].color, 858 ColorScheme.getColorIdForGeneralPurposeString('ctr.value')); 859 860 assert.deepEqual(ctr.timestamps, [0, 0.01, 0.02]); 861 862 var samples = []; 863 ctr.series[0].samples.forEach(function(sample) { 864 samples.push(sample.value); 865 }); 866 assert.deepEqual(samples, [0, 10, 0]); 867 868 assert.deepEqual(ctr.totals, [0, 10, 0]); 869 assert.equal(ctr.maxTotal, 10); 870 }); 871 872 test('instanceCounter', function() { 873 var events = [ 874 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1, 875 ph: 'C', id: 0}, 876 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, 877 ph: 'C', id: 0}, 878 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, 879 ph: 'C', id: 1}, 880 {name: 'ctr', args: {'value': 20}, pid: 1, ts: 15, cat: 'foo', tid: 1, 881 ph: 'C', id: 1}, 882 {name: 'ctr', args: {'value': 30}, pid: 1, ts: 18, cat: 'foo', tid: 1, 883 ph: 'C', id: 1}, 884 {name: 'ctr', args: {'value': 40}, pid: 1, ts: 20, cat: 'bar', tid: 1, 885 ph: 'C', id: 2} 886 ]; 887 var m = makeModel(events); 888 var p = m.processes[1]; 889 var ctr = m.processes[1].counters['foo.ctr[0]']; 890 assert.equal(ctr.name, 'ctr[0]'); 891 assert.equal(ctr.category, 'foo'); 892 assert.equal(ctr.numSamples, 2); 893 assert.equal(ctr.numSeries, 1); 894 895 assert.deepEqual(ctr.timestamps, [0, 0.01]); 896 var samples = []; 897 ctr.series[0].samples.forEach(function(sample) { 898 samples.push(sample.value); 899 }); 900 assert.deepEqual(samples, [0, 10]); 901 902 ctr = m.processes[1].counters['foo.ctr[1]']; 903 assert.equal(ctr.name, 'ctr[1]'); 904 assert.equal(ctr.category, 'foo'); 905 assert.equal(ctr.numSamples, 3); 906 assert.equal(ctr.numSeries, 1); 907 assert.deepEqual(ctr.timestamps, [0.01, 0.015, 0.018]); 908 909 samples = []; 910 ctr.series[0].samples.forEach(function(sample) { 911 samples.push(sample.value); 912 }); 913 assert.deepEqual(samples, [10, 20, 30]); 914 915 ctr = m.processes[1].counters['bar.ctr[2]']; 916 assert.equal(ctr.name, 'ctr[2]'); 917 assert.equal(ctr.category, 'bar'); 918 assert.equal(ctr.numSamples, 1); 919 assert.equal(ctr.numSeries, 1); 920 assert.deepEqual(ctr.timestamps, [0.02]); 921 var samples = []; 922 ctr.series[0].samples.forEach(function(sample) { 923 samples.push(sample.value); 924 }); 925 assert.deepEqual(samples, [40]); 926 }); 927 928 test('multiCounterUpdateBounds', function() { 929 var ctr = new tr.model.Counter(undefined, 'testBasicCounter', 930 '', 'testBasicCounter'); 931 var value1Series = new tr.model.CounterSeries( 932 'value1', 'testBasicCounter.value1'); 933 var value2Series = new tr.model.CounterSeries( 934 'value2', 'testBasicCounter.value2'); 935 ctr.addSeries(value1Series); 936 ctr.addSeries(value2Series); 937 938 value1Series.addCounterSample(0, 0); 939 value1Series.addCounterSample(1, 1); 940 value1Series.addCounterSample(2, 1); 941 value1Series.addCounterSample(3, 2); 942 value1Series.addCounterSample(4, 3); 943 value1Series.addCounterSample(5, 1); 944 value1Series.addCounterSample(6, 3); 945 value1Series.addCounterSample(7, 3.1); 946 947 value2Series.addCounterSample(0, 0); 948 value2Series.addCounterSample(1, 0); 949 value2Series.addCounterSample(2, 1); 950 value2Series.addCounterSample(3, 1.1); 951 value2Series.addCounterSample(4, 0); 952 value2Series.addCounterSample(5, 7); 953 value2Series.addCounterSample(6, 0); 954 value2Series.addCounterSample(7, 0.5); 955 956 ctr.updateBounds(); 957 958 assert.equal(ctr.bounds.min, 0); 959 assert.equal(ctr.bounds.max, 7); 960 assert.equal(ctr.maxTotal, 8); 961 assert.deepEqual([0, 0, 962 1, 1, 963 1, 2, 964 2, 3.1, 965 3, 3, 966 1, 8, 967 3, 3, 968 3.1, 3.6], ctr.totals); 969 }); 970 971 test('multiCounter', function() { 972 var events = [ 973 {name: 'ctr', args: {'value1': 0, 'value2': 7}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'C'}, // @suppress longLineCheck 974 {name: 'ctr', args: {'value1': 10, 'value2': 4}, pid: 1, ts: 10, cat: 'foo', tid: 1, ph: 'C'}, // @suppress longLineCheck 975 {name: 'ctr', args: {'value1': 0, 'value2': 1 }, pid: 1, ts: 20, cat: 'foo', tid: 1, ph: 'C'} // @suppress longLineCheck 976 ]; 977 var m = makeModel(events); 978 var p = m.processes[1]; 979 var ctr = m.processes[1].counters['foo.ctr']; 980 assert.equal(ctr.name, 'ctr'); 981 982 assert.equal(ctr.name, 'ctr'); 983 assert.equal(ctr.category, 'foo'); 984 assert.equal(ctr.numSamples, 3); 985 assert.equal(ctr.numSeries, 2); 986 987 assert.equal(ctr.series[0].name, 'value1'); 988 assert.equal(ctr.series[1].name, 'value2'); 989 assert.equal(ctr.series[0].color, 990 ColorScheme.getColorIdForGeneralPurposeString('ctr.value1')); 991 assert.equal(ctr.series[1].color, 992 ColorScheme.getColorIdForGeneralPurposeString('ctr.value2')); 993 994 assert.deepEqual(ctr.timestamps, [0, 0.01, 0.02]); 995 var samples = []; 996 ctr.series[0].samples.forEach(function(sample) { 997 samples.push(sample.value); 998 }); 999 assert.deepEqual(samples, [0, 10, 0]); 1000 1001 var samples1 = []; 1002 ctr.series[1].samples.forEach(function(sample) { 1003 samples1.push(sample.value); 1004 }); 1005 assert.deepEqual(samples1, [7, 4, 1]); 1006 assert.deepEqual([0, 7, 1007 10, 14, 1008 0, 1], ctr.totals); 1009 assert.equal(ctr.maxTotal, 14); 1010 }); 1011 1012 test('importObjectInsteadOfArray', function() { 1013 var events = { traceEvents: [ 1014 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 1015 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 1016 ] }; 1017 1018 var m = makeModel(events); 1019 assert.equal(m.numProcesses, 1); 1020 }); 1021 1022 test('importString', function() { 1023 var events = [ 1024 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 1025 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 1026 ]; 1027 1028 var m = makeModel(JSON.stringify(events)); 1029 assert.equal(m.numProcesses, 1); 1030 }); 1031 1032 test('importStringWithLeadingSpaces', function() { 1033 var events = [ 1034 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 1035 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 1036 ]; 1037 1038 var m = makeModel(' ' + JSON.stringify(events)); 1039 assert.equal(m.numProcesses, 1); 1040 }); 1041 1042 test('importStringWithTrailingNewLine', function() { 1043 var events = [ 1044 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 1045 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 1046 ]; 1047 1048 var m = makeModel(JSON.stringify(events) + '\n'); 1049 assert.equal(m.numProcesses, 1); 1050 }); 1051 1052 test('importStringWithMissingCloseSquareBracket', function() { 1053 var events = [ 1054 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 1055 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 1056 ]; 1057 1058 var tmp = JSON.stringify(events); 1059 assert.equal(tmp[tmp.length - 1], ']'); 1060 1061 // Drop off the trailing ] 1062 var dropped = tmp.substring(0, tmp.length - 1); 1063 var m = makeModel(dropped); 1064 assert.equal(m.numProcesses, 1); 1065 }); 1066 1067 test('importStringWithEndingCommaButMissingCloseSquareBracket', function() { 1068 var lines = [ 1069 '[', 1070 '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', // @suppress longLineCheck 1071 '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' // @suppress longLineCheck 1072 ]; 1073 var text = lines.join('\n'); 1074 1075 var m = makeModel(text); 1076 assert.equal(m.numProcesses, 1); 1077 assert.equal(m.processes[52].threads[53].sliceGroup.length, 1); 1078 }); 1079 1080 test('importStringWithMissingCloseSquareBracketAndNewline', function() { 1081 var events = [ 1082 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 1083 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 1084 ]; 1085 1086 var tmp = JSON.stringify(events); 1087 assert.equal(tmp[tmp.length - 1], ']'); 1088 1089 // Drop off the trailing ] and add a newline 1090 var dropped = tmp.substring(0, tmp.length - 1); 1091 var m = makeModel(dropped + '\n'); 1092 assert.equal(m.numProcesses, 1); 1093 }); 1094 1095 test('ImportStringEndingCommaButMissingCloseSquareBracketCRLF', function() { 1096 var lines = [ 1097 '[', 1098 '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', // @suppress longLineCheck 1099 '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' // @suppress longLineCheck 1100 ]; 1101 var text = lines.join('\r\n'); 1102 1103 var m = makeModel(text); 1104 assert.equal(m.numProcesses, 1); 1105 assert.equal(m.processes[52].threads[53].sliceGroup.length, 1); 1106 }); 1107 1108 test('importOldFormat', function() { 1109 var lines = [ 1110 '[', 1111 '{"cat":"a","pid":9,"tid":8,"ts":194,"ph":"E","name":"I","args":{}},', 1112 '{"cat":"b","pid":9,"tid":8,"ts":194,"ph":"B","name":"I","args":{}}', 1113 ']' 1114 ]; 1115 var text = lines.join('\n'); 1116 var m = makeModel(text); 1117 assert.equal(m.numProcesses, 1); 1118 assert.equal(m.processes[9].threads[8].sliceGroup.length, 1); 1119 }); 1120 1121 test('startFinishOneSliceOneThread', function() { 1122 var events = [ 1123 // Time is intentionally out of order. 1124 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'cat', tid: 53, 1125 ph: 'F', id: 72}, 1126 {name: 'a', pid: 52, ts: 524, cat: 'cat', tid: 53, 1127 ph: 'S', id: 72, args: {'foo': 'bar'}} 1128 ]; 1129 1130 var m = makeModel(events); 1131 var t = m.processes[52].threads[53]; 1132 assert.isDefined(t); 1133 assert.equal(t.asyncSliceGroup.slices.length, 1); 1134 assert.equal(t.asyncSliceGroup.slices[0].title, 'a'); 1135 assert.equal(t.asyncSliceGroup.slices[0].category, 'cat'); 1136 assert.isTrue(t.asyncSliceGroup.slices[0].isTopLevel); 1137 assert.equal(t.asyncSliceGroup.slices[0].id, 72); 1138 assert.equal(t.asyncSliceGroup.slices[0].args.foo, 'bar'); 1139 assert.equal(t.asyncSliceGroup.slices[0].start, 0); 1140 assert.closeTo( 1141 (60 - 24) / 1000, t.asyncSliceGroup.slices[0].duration, 1e-5); 1142 assert.equal(t.asyncSliceGroup.slices[0].startThread, t); 1143 assert.equal(t.asyncSliceGroup.slices[0].endThread, t); 1144 }); 1145 1146 test('endArgsAddedToSlice', function() { 1147 var events = [ 1148 {name: 'a', args: {x: 1}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, 1149 {name: 'a', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 1150 ]; 1151 1152 var m = makeModel(events); 1153 assert.equal(m.numProcesses, 1); 1154 var p = m.processes[52]; 1155 assert.isDefined(p); 1156 1157 assert.equal(p.numThreads, 1); 1158 var t = p.threads[53]; 1159 assert.isDefined(t); 1160 assert.equal(t.sliceGroup.length, 1); 1161 assert.equal(t.tid, 53); 1162 var slice = t.sliceGroup.slices[0]; 1163 assert.equal(slice.title, 'a'); 1164 assert.equal(slice.category, 'foo'); 1165 assert.equal(slice.start, 0); 1166 assert.equal(slice.subSlices.length, 0); 1167 assert.equal(slice.args['x'], 1); 1168 assert.equal(slice.args['y'], 2); 1169 }); 1170 1171 test('endArgOverrwritesOriginalArgValueIfDuplicated', function() { 1172 var events = [ 1173 {name: 'b', args: {z: 3}, pid: 52, ts: 629, cat: 'foo', tid: 53, ph: 'B'}, 1174 {name: 'b', args: {z: 4}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'} 1175 ]; 1176 1177 var m = makeModel(events); 1178 assert.equal(m.numProcesses, 1); 1179 var p = m.processes[52]; 1180 assert.isDefined(p); 1181 1182 assert.equal(p.numThreads, 1); 1183 var t = p.threads[53]; 1184 assert.isDefined(t); 1185 var slice = t.sliceGroup.slices[0]; 1186 assert.equal(slice.title, 'b'); 1187 assert.equal(slice.category, 'foo'); 1188 assert.equal(slice.start, 0); 1189 assert.equal(slice.subSlices.length, 0); 1190 assert.equal(slice.args['z'], 4); 1191 }); 1192 1193 test('asyncEndArgsAddedToSlice', function() { 1194 var events = [ 1195 // Time is intentionally out of order. 1196 {name: 'c', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1197 ph: 'F', id: 72}, 1198 {name: 'c', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1199 ph: 'S', id: 72} 1200 ]; 1201 1202 var m = makeModel(events); 1203 var t = m.processes[52].threads[53]; 1204 assert.isDefined(t); 1205 assert.equal(t.asyncSliceGroup.slices.length, 1); 1206 var parentSlice = t.asyncSliceGroup.slices[0]; 1207 assert.equal(parentSlice.title, 'c'); 1208 assert.equal(parentSlice.category, 'foo'); 1209 assert.isTrue(parentSlice.isTopLevel); 1210 assert.equal(parentSlice.args['x'], 1); 1211 assert.equal(parentSlice.args['y'], 2); 1212 1213 assert.isDefined(parentSlice.subSlices); 1214 assert.equal(parentSlice.subSlices.length, 0); 1215 }); 1216 1217 test('asyncEndArgOverwritesOriginalArgValueIfDuplicated', function() { 1218 var events = [ 1219 // Time is intentionally out of order. 1220 {name: 'd', args: {z: 4}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1221 ph: 'F', id: 72}, 1222 {name: 'd', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1223 ph: 'S', id: 72} 1224 ]; 1225 1226 var m = makeModel(events); 1227 var t = m.processes[52].threads[53]; 1228 assert.isDefined(t); 1229 assert.equal(t.asyncSliceGroup.slices.length, 1); 1230 var parentSlice = t.asyncSliceGroup.slices[0]; 1231 assert.equal(parentSlice.title, 'd'); 1232 assert.equal(parentSlice.category, 'foo'); 1233 assert.isTrue(parentSlice.isTopLevel); 1234 assert.equal(parentSlice.args['z'], 4); 1235 1236 assert.isDefined(parentSlice.subSlices); 1237 assert.equal(parentSlice.subSlices.length, 0); 1238 }); 1239 1240 test('asyncStepsInOneThread', function() { 1241 var events = [ 1242 // Time is intentionally out of order. 1243 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'F', id: 72}, // @suppress longLineCheck 1244 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53, ph: 'T', id: 72}, // @suppress longLineCheck 1245 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'S', id: 72} // @suppress longLineCheck 1246 ]; 1247 1248 var m = makeModel(events); 1249 var t = m.processes[52].threads[53]; 1250 assert.isDefined(t); 1251 assert.equal(t.asyncSliceGroup.slices.length, 1); 1252 var parentSlice = t.asyncSliceGroup.slices[0]; 1253 assert.equal(parentSlice.title, 'a'); 1254 assert.equal(parentSlice.category, 'foo'); 1255 assert.isTrue(parentSlice.isTopLevel); 1256 assert.equal(parentSlice.start, 0); 1257 assert.equal(parentSlice.args['x'], 1); 1258 assert.isUndefined(parentSlice.args['y']); 1259 assert.equal(parentSlice.args['z'], 3); 1260 1261 assert.isDefined(parentSlice.subSlices); 1262 assert.equal(parentSlice.subSlices.length, 1); 1263 1264 var subSlice = parentSlice.subSlices[0]; 1265 assert.equal(subSlice.title, 'a:s1'); 1266 assert.equal(subSlice.category, 'foo'); 1267 assert.isFalse(subSlice.isTopLevel); 1268 assert.closeTo((548 - 524) / 1000, subSlice.start, 1e-5); 1269 assert.closeTo((560 - 548) / 1000, subSlice.duration, 1e-5); 1270 assert.isUndefined(subSlice.args['x']); 1271 assert.equal(subSlice.args['y'], 2); 1272 assert.isUndefined(subSlice.args['z']); 1273 }); 1274 1275 test('asyncStepsMissingStart', function() { 1276 var events = [ 1277 // Time is intentionally out of order. 1278 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1279 ph: 'F', id: 72}, 1280 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', 1281 tid: 53, ph: 'T', id: 72} 1282 ]; 1283 1284 var m = makeModel(events); 1285 var t = m.processes[52].threads[53]; 1286 assert.isUndefined(t); 1287 }); 1288 1289 test('asyncStepsMissingFinish', function() { 1290 var events = [ 1291 // Time is intentionally out of order. 1292 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', 1293 tid: 53, ph: 'T', id: 72}, 1294 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1295 ph: 'S', id: 72} 1296 ]; 1297 1298 var m = makeModel(events); 1299 var t = m.processes[52].threads[53]; 1300 assert.isUndefined(t); 1301 }); 1302 1303 test('asyncStepEndEvent', function() { 1304 var events = [ 1305 // Time is intentionally out of order. 1306 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1307 ph: 'F', id: 72}, 1308 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', 1309 tid: 53, ph: 'p', id: 72}, 1310 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1311 ph: 'S', id: 72} 1312 ]; 1313 1314 var m = makeModel(events); 1315 var t = m.processes[52].threads[53]; 1316 assert.isDefined(t); 1317 assert.equal(t.asyncSliceGroup.slices.length, 1); 1318 var parentSlice = t.asyncSliceGroup.slices[0]; 1319 assert.equal(parentSlice.title, 'a'); 1320 assert.equal(parentSlice.category, 'foo'); 1321 assert.isTrue(parentSlice.isTopLevel); 1322 assert.equal(parentSlice.start, 0); 1323 assert.equal(parentSlice.args['x'], 1); 1324 assert.isUndefined(parentSlice.args['y']); 1325 assert.equal(parentSlice.args['z'], 3); 1326 1327 assert.isDefined(parentSlice.subSlices); 1328 assert.equal(parentSlice.subSlices.length, 1); 1329 var subSlice = parentSlice.subSlices[0]; 1330 assert.equal(subSlice.title, 'a:s1'); 1331 assert.equal(subSlice.category, 'foo'); 1332 assert.isFalse(subSlice.isTopLevel); 1333 assert.equal(subSlice.start, 0); 1334 assert.closeTo((548 - 524) / 1000, subSlice.duration, 1e-5); 1335 assert.isUndefined(subSlice.args['x']); 1336 assert.equal(subSlice.args['y'], 2); 1337 assert.isUndefined(subSlice.args['z']); 1338 }); 1339 1340 test('asyncStepMismatch', function() { 1341 var events = [ 1342 // Time is intentionally out of order. 1343 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1344 ph: 'F', id: 72}, 1345 {name: 'a', args: {step: 's2'}, pid: 52, ts: 548, cat: 'foo', tid: 53, 1346 ph: 'T', id: 72}, 1347 {name: 'a', args: {step: 's1'}, pid: 52, ts: 548, cat: 'foo', tid: 53, 1348 ph: 'p', id: 72}, 1349 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1350 ph: 'S', id: 72} 1351 ]; 1352 1353 var m = makeModel(events); 1354 var t = m.processes[52].threads[53]; 1355 assert.isUndefined(t); 1356 assert.isTrue(m.hasImportWarnings); 1357 }); 1358 1359 test('asyncSliceWithoutCPUDuration', function() { 1360 var events = [ 1361 // Async slice without tts field. 1362 {name: 'a', args: {params: ''}, pid: 52, ts: 10, cat: 'foo', tid: 53, 1363 id: 72, ph: 'b'}, 1364 {name: 'a', args: {params: ''}, pid: 52, ts: 20, cat: 'foo', tid: 53, 1365 id: 72, ph: 'e'}, 1366 // Async slice with tts field but without use_async_tts marker field. 1367 {name: 'b', args: {params: ''}, pid: 52, ts: 30, cat: 'foo', tid: 53, 1368 id: 72, ph: 'b', tts: 30000}, 1369 {name: 'b', args: {params: ''}, pid: 52, ts: 40, cat: 'foo', tid: 53, 1370 id: 72, ph: 'e', tts: 40000}, 1371 // Async slice with tts field but with use_async_tts marker set to 0. 1372 {name: 'c', args: {params: ''}, pid: 52, ts: 50000, cat: 'foo', tid: 53, 1373 id: 72, ph: 'b', tts: 50000, use_async_tts: 0}, 1374 {name: 'c', args: {params: ''}, pid: 52, ts: 60000, cat: 'foo', tid: 53, 1375 id: 72, ph: 'e', tts: 60000, use_async_tts: 0} 1376 ]; 1377 1378 var m = makeModel(events); 1379 var t = m.processes[52].threads[53]; 1380 assert.isDefined(t); 1381 assert.equal(t.asyncSliceGroup.slices.length, 3); 1382 1383 var noTTSNoField = t.asyncSliceGroup.slices[0]; 1384 assert.isUndefined(noTTSNoField.cpuStart); 1385 assert.isUndefined(noTTSNoField.cpuDuration); 1386 1387 var TTSNoField = t.asyncSliceGroup.slices[1]; 1388 assert.isUndefined(TTSNoField.cpuStart); 1389 assert.isUndefined(TTSNoField.cpuDuration); 1390 1391 var TTSZeroField = t.asyncSliceGroup.slices[2]; 1392 assert.isUndefined(TTSZeroField.cpuStart); 1393 assert.isUndefined(TTSZeroField.cpuDuration); 1394 }); 1395 1396 test('asyncSliceWithCPUDuration', function() { 1397 var events = [ 1398 {name: 'a', args: {params: ''}, pid: 52, ts: 50000, cat: 'foo', tid: 53, 1399 id: 72, ph: 'b', tts: 100000, use_async_tts: 1}, 1400 {name: 'a', args: {params: ''}, pid: 52, ts: 60000, cat: 'foo', tid: 53, 1401 id: 72, ph: 'e', tts: 105000, use_async_tts: 1} 1402 ]; 1403 1404 var m = makeModel(events); 1405 var t = m.processes[52].threads[53]; 1406 assert.isDefined(t); 1407 assert.equal(t.asyncSliceGroup.slices.length, 1); 1408 1409 var asyncSlice = t.asyncSliceGroup.slices[0]; 1410 assert.isDefined(asyncSlice); 1411 assert.equal(asyncSlice.duration, 10); 1412 assert.equal(asyncSlice.cpuStart, 100); 1413 assert.equal(asyncSlice.cpuDuration, 5); 1414 }); 1415 1416 test('nestableAsyncBasic', function() { 1417 var events = [ 1418 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1419 ph: 'b', id: 72}, 1420 {name: 'b', args: {x: 1}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1421 ph: 'b', id: 72}, 1422 {name: 'b', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1423 ph: 'e', id: 72}, 1424 {name: 'a', args: {}, pid: 52, ts: 565, cat: 'foo', tid: 53, 1425 ph: 'e', id: 72} 1426 ]; 1427 1428 var m = makeModel(events); 1429 var t = m.processes[52].threads[53]; 1430 assert.isDefined(t); 1431 assert.equal(t.asyncSliceGroup.slices.length, 1); 1432 var parentSlice = t.asyncSliceGroup.slices[0]; 1433 assert.equal(parentSlice.title, 'a'); 1434 assert.equal(parentSlice.category, 'foo'); 1435 assert.isTrue(parentSlice.isTopLevel); 1436 1437 assert.isDefined(parentSlice.subSlices); 1438 assert.equal(parentSlice.subSlices.length, 1); 1439 var subSlice = parentSlice.subSlices[0]; 1440 assert.isFalse(subSlice.isTopLevel); 1441 // Arguments should include both BEGIN and END event. 1442 assert.equal(subSlice.args['x'], 1); 1443 assert.equal(subSlice.args['y'], 2); 1444 assert.sameMembers(subSlice.subSlices, []); 1445 }); 1446 1447 1448 test('nestableAsyncNoArgs', function() { 1449 var events = [ 1450 {name: 'name', pid: 52, ts: 525, cat: 'foo', tid: 53, 1451 ph: 'b', id: 72}, 1452 {name: 'name', pid: 52, ts: 560, cat: 'foo', tid: 53, 1453 ph: 'e', id: 72} 1454 ]; 1455 1456 var m = makeModel(events); 1457 var t = m.processes[52].threads[53]; 1458 assert.isDefined(t); 1459 assert.equal(t.asyncSliceGroup.slices.length, 1); 1460 var slice = t.asyncSliceGroup.slices[0]; 1461 assert.equal(slice.title, 'name'); 1462 assert.equal(slice.category, 'foo'); 1463 assert.isTrue(slice.isTopLevel); 1464 1465 assert.isDefined(slice.subSlices); 1466 assert.equal(slice.subSlices.length, 0); 1467 1468 assert.deepEqual(slice.args, {}); 1469 }); 1470 1471 test('nestableAsyncCombinedParams', function() { 1472 var events = [ 1473 {name: 'a', args: {x: 1, params: {p1: 'hello', p2: 123}}, 1474 pid: 52, ts: 525, cat: 'foo', tid: 53, ph: 'b', id: 72}, 1475 {name: 'a', args: {y: 2, params: {p3: 'hi'}}, pid: 52, ts: 560, 1476 cat: 'foo', tid: 53, ph: 'e', id: 72}, 1477 {name: 'b', args: {params: {p4: 'foo'}}, 1478 pid: 52, ts: 525, cat: 'foo', tid: 53, ph: 'b', id: 73}, 1479 {name: 'b', args: {params: ''}, pid: 52, ts: 560, 1480 cat: 'foo', tid: 53, ph: 'e', id: 73}, 1481 {name: 'c', args: {params: {p5: 'bar'}}, 1482 pid: 52, ts: 525, cat: 'foo', tid: 53, ph: 'b', id: 74}, 1483 {name: 'c', args: {}, pid: 52, ts: 560, 1484 cat: 'foo', tid: 53, ph: 'e', id: 74} 1485 ]; 1486 1487 var m = makeModel(events); 1488 var t = m.processes[52].threads[53]; 1489 assert.isDefined(t); 1490 assert.equal(t.asyncSliceGroup.slices.length, 3); 1491 1492 var sliceA = t.asyncSliceGroup.slices[0]; 1493 // Arguments should include both BEGIN and END event. 1494 assert.equal(sliceA.args['x'], 1); 1495 assert.equal(sliceA.args['y'], 2); 1496 var paramsA = sliceA.args['params']; 1497 assert.isDefined(paramsA); 1498 assert.equal(paramsA.p1, 'hello'); 1499 assert.equal(paramsA.p2, 123); 1500 assert.equal(paramsA.p3, 'hi'); 1501 assert.isTrue(sliceA.isTopLevel); 1502 1503 var sliceB = t.asyncSliceGroup.slices[1]; 1504 // Arguments should include both BEGIN and END event. 1505 var paramsB = sliceB.args['params']; 1506 assert.isDefined(paramsB); 1507 assert.equal(paramsB.p4, 'foo'); 1508 assert.isTrue(sliceB.isTopLevel); 1509 1510 var sliceC = t.asyncSliceGroup.slices[2]; 1511 // Arguments should include both BEGIN and END event. 1512 var paramsC = sliceC.args['params']; 1513 assert.isDefined(paramsC); 1514 assert.equal(paramsC.p5, 'bar'); 1515 assert.isTrue(sliceC.isTopLevel); 1516 }); 1517 1518 test('nestableAsyncManyLevels', function() { 1519 // There are 5 nested levels. 1520 var events = [ 1521 {name: 'l1', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1522 ph: 'b', id: 72}, 1523 {name: 'l2', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1524 ph: 'b', id: 72}, 1525 {name: 'l3', args: {}, pid: 52, ts: 526, cat: 'foo', tid: 53, 1526 ph: 'b', id: 72}, 1527 {name: 'l4', args: {}, pid: 52, ts: 527, cat: 'foo', tid: 53, 1528 ph: 'b', id: 72}, 1529 {name: 'l5', args: {}, pid: 52, ts: 528, cat: 'foo', tid: 53, 1530 ph: 'b', id: 72}, 1531 {name: 'l5', args: {}, pid: 52, ts: 529, cat: 'foo', tid: 53, 1532 ph: 'e', id: 72}, 1533 {name: 'l4', args: {}, pid: 52, ts: 530, cat: 'foo', tid: 53, 1534 ph: 'e', id: 72}, 1535 {name: 'l3', args: {}, pid: 52, ts: 531, cat: 'foo', tid: 53, 1536 ph: 'e', id: 72}, 1537 {name: 'l2', args: {}, pid: 52, ts: 532, cat: 'foo', tid: 53, 1538 ph: 'e', id: 72}, 1539 {name: 'l1', args: {}, pid: 52, ts: 533, cat: 'foo', tid: 53, 1540 ph: 'e', id: 72} 1541 ]; 1542 1543 var m = makeModel(events); 1544 var t = m.processes[52].threads[53]; 1545 assert.isDefined(t); 1546 // Perfectly matched events should not produce a warning. 1547 assert.isFalse(m.hasImportWarnings); 1548 assert.equal(t.asyncSliceGroup.slices.length, 1); 1549 1550 var l1Slice = t.asyncSliceGroup.slices[0]; 1551 assert.equal(l1Slice.title, 'l1'); 1552 assert.closeTo(0, l1Slice.start, 1e-5); 1553 assert.closeTo(9 / 1000, l1Slice.duration, 1e-5); 1554 assert.isTrue(l1Slice.isTopLevel); 1555 1556 assert.isDefined(l1Slice.subSlices); 1557 assert.equal(l1Slice.subSlices.length, 1); 1558 var l2Slice = l1Slice.subSlices[0]; 1559 assert.equal(l2Slice.title, 'l2'); 1560 assert.closeTo(1 / 1000, l2Slice.start, 1e-5); 1561 assert.closeTo(7 / 1000, l2Slice.duration, 1e-5); 1562 assert.isFalse(l2Slice.isTopLevel); 1563 1564 assert.isDefined(l2Slice.subSlices); 1565 assert.equal(l2Slice.subSlices.length, 1); 1566 var l3Slice = l2Slice.subSlices[0]; 1567 assert.equal(l3Slice.title, 'l3'); 1568 assert.closeTo(2 / 1000, l3Slice.start, 1e-5); 1569 assert.closeTo(5 / 1000, l3Slice.duration, 1e-5); 1570 assert.isFalse(l3Slice.isTopLevel); 1571 1572 assert.isDefined(l3Slice.subSlices); 1573 assert.equal(l3Slice.subSlices.length, 1); 1574 var l4Slice = l3Slice.subSlices[0]; 1575 assert.equal(l4Slice.title, 'l4'); 1576 assert.closeTo(3 / 1000, l4Slice.start, 1e-5); 1577 assert.closeTo(3 / 1000, l4Slice.duration, 1e-5); 1578 assert.isFalse(l4Slice.isTopLevel); 1579 1580 assert.isDefined(l4Slice.subSlices); 1581 assert.equal(l4Slice.subSlices.length, 1); 1582 var l5Slice = l4Slice.subSlices[0]; 1583 assert.equal(l5Slice.title, 'l5'); 1584 assert.closeTo(4 / 1000, l5Slice.start, 1e-5); 1585 assert.closeTo(1 / 1000, l5Slice.duration, 1e-5); 1586 assert.isFalse(l5Slice.isTopLevel); 1587 }); 1588 1589 test('nestableAsyncInstantEvent', function() { 1590 var events = [ 1591 {name: 'c', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1592 ph: 'n', id: 71}, 1593 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1594 ph: 'b', id: 72}, 1595 {name: 'd', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1596 ph: 'n', id: 72}, 1597 {name: 'a', args: {}, pid: 52, ts: 565, cat: 'foo', tid: 53, 1598 ph: 'e', id: 72} 1599 ]; 1600 1601 var m = makeModel(events); 1602 var t = m.processes[52].threads[53]; 1603 assert.isDefined(t); 1604 assert.equal(t.asyncSliceGroup.slices.length, 2); 1605 var instantSlice = t.asyncSliceGroup.slices[0]; 1606 assert.equal(instantSlice.title, 'c'); 1607 assert.closeTo(0, instantSlice.start, 1e-5); 1608 assert.closeTo(0, instantSlice.duration, 1e-5); 1609 assert.sameMembers(instantSlice.subSlices, []); 1610 assert.isTrue(instantSlice.isTopLevel); 1611 1612 var nestedSlice = t.asyncSliceGroup.slices[1]; 1613 assert.equal(nestedSlice.title, 'a'); 1614 assert.closeTo(0, nestedSlice.start, 1e-5); 1615 assert.closeTo((565 - 524) / 1000, nestedSlice.duration, 1e-5); 1616 assert.isTrue(nestedSlice.isTopLevel); 1617 assert.isDefined(nestedSlice.subSlices); 1618 assert.equal(nestedSlice.subSlices.length, 1); 1619 var nestedInstantSlice = nestedSlice.subSlices[0]; 1620 assert.sameMembers(nestedInstantSlice.subSlices, []); 1621 assert.equal(nestedInstantSlice.title, 'd'); 1622 assert.isFalse(nestedInstantSlice.isTopLevel); 1623 }); 1624 1625 test('nestableAsyncUnmatchedOuterBeginEvent', function() { 1626 var events = [ 1627 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1628 ph: 'b', id: 72}, 1629 {name: 'b', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1630 ph: 'b', id: 72}, 1631 {name: 'b', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1632 ph: 'e', id: 72} 1633 ]; 1634 1635 var m = makeModel(events); 1636 var t = m.processes[52].threads[53]; 1637 assert.isDefined(t); 1638 // Unmatched BEGIN should produce a warning. 1639 assert.isTrue(m.hasImportWarnings); 1640 assert.equal(t.asyncSliceGroup.slices.length, 1); 1641 var parentSlice = t.asyncSliceGroup.slices[0]; 1642 assert.equal(parentSlice.title, 'a'); 1643 assert.equal(parentSlice.category, 'foo'); 1644 assert.isTrue(parentSlice.isTopLevel); 1645 assert.closeTo(0, parentSlice.start, 0.0001); 1646 // Unmatched BEGIN event ends at the last event of that ID. 1647 assert.closeTo(36 / 1000, parentSlice.duration, 0.0001); 1648 // Arguments should include only include its arguments. 1649 assert.isUndefined(parentSlice.args['y']); 1650 assert.equal(parentSlice.args['x'], 1); 1651 assert.isDefined(parentSlice.error); 1652 1653 assert.isDefined(parentSlice.subSlices); 1654 assert.equal(parentSlice.subSlices.length, 1); 1655 var subSlice = parentSlice.subSlices[0]; 1656 assert.isFalse(subSlice.isTopLevel); 1657 assert.closeTo(1 / 1000, subSlice.start, 1e-5); 1658 assert.closeTo(35 / 1000, subSlice.duration, 1e-5); 1659 assert.sameMembers(subSlice.subSlices, []); 1660 // Arguments should include those of the END event. 1661 assert.equal(subSlice.args['y'], 2); 1662 assert.sameMembers(subSlice.subSlices, []); 1663 }); 1664 1665 test('nestableAsyncUnmatchedInnerBeginEvent', function() { 1666 var events = [ 1667 {name: 'a', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1668 ph: 'b', id: 72}, 1669 {name: 'c', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1670 ph: 'n', id: 72}, 1671 {name: 'b', args: {x: 1}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1672 ph: 'b', id: 72}, 1673 {name: 'a', args: {y: 2}, pid: 52, ts: 565, cat: 'foo', tid: 53, 1674 ph: 'e', id: 72} 1675 ]; 1676 1677 var m = makeModel(events); 1678 var t = m.processes[52].threads[53]; 1679 assert.isDefined(t); 1680 // Unmatched BEGIN should produce a warning. 1681 assert.isTrue(m.hasImportWarnings); 1682 assert.equal(t.asyncSliceGroup.slices.length, 1); 1683 var parentSlice = t.asyncSliceGroup.slices[0]; 1684 assert.equal(parentSlice.title, 'a'); 1685 assert.equal(parentSlice.category, 'foo'); 1686 assert.isTrue(parentSlice.isTopLevel); 1687 assert.closeTo(0, parentSlice.start, 1e-5); 1688 assert.closeTo(41 / 1000, parentSlice.duration, 1e-5); 1689 // Arguments should include both BEGIN and END event. 1690 assert.equal(parentSlice.args['y'], 2); 1691 assert.equal(parentSlice.args['z'], 3); 1692 assert.isUndefined(parentSlice.args['x']); 1693 1694 assert.isDefined(parentSlice.subSlices); 1695 assert.equal(parentSlice.subSlices.length, 2); 1696 var subSliceInstant = parentSlice.subSlices[0]; 1697 var subSliceUnmatched = parentSlice.subSlices[1]; 1698 assert.equal(subSliceInstant.title, 'c'); 1699 assert.isFalse(subSliceInstant.isTopLevel); 1700 assert.equal(subSliceUnmatched.title, 'b'); 1701 assert.isFalse(subSliceUnmatched.isTopLevel); 1702 // Unmatched BEGIN ends at the last event of that ID. 1703 assert.closeTo(1 / 1000, subSliceUnmatched.start, 1e-5); 1704 assert.closeTo(40 / 1000, subSliceUnmatched.duration, 1e-5); 1705 assert.sameMembers(subSliceUnmatched.subSlices, []); 1706 assert.equal(subSliceUnmatched.args['x'], 1); 1707 assert.isUndefined(subSliceUnmatched['y']); 1708 assert.isDefined(subSliceUnmatched.error); 1709 assert.closeTo(1 / 1000, subSliceInstant.start, 1e-5); 1710 assert.closeTo(0, subSliceInstant.duration, 1e-5); 1711 assert.sameMembers(subSliceInstant.subSlices, []); 1712 }); 1713 1714 test('nestableAsyncUnmatchedOuterEndEvent', function() { 1715 // Events are intentionally out-of-order. 1716 var events = [ 1717 {name: 'b', args: {x: 1}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1718 ph: 'b', id: 72}, 1719 {name: 'b', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, 1720 ph: 'e', id: 72}, 1721 {name: 'a', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1722 ph: 'e', id: 72} 1723 ]; 1724 1725 var m = makeModel(events); 1726 var t = m.processes[52].threads[53]; 1727 assert.isDefined(t); 1728 // Unmatched END should produce a warning. 1729 assert.isTrue(m.hasImportWarnings); 1730 assert.equal(t.asyncSliceGroup.slices.length, 2); 1731 var unmatchedSlice = t.asyncSliceGroup.slices[0]; 1732 var slice = t.asyncSliceGroup.slices[1]; 1733 assert.equal(unmatchedSlice.title, 'a'); 1734 assert.closeTo(0, unmatchedSlice.start, 1e-5); 1735 assert.isTrue(unmatchedSlice.isTopLevel); 1736 // Unmatched END event begins at the first event of that ID. In this 1737 // case, the first event happens to be the same unmatched event. 1738 assert.closeTo(0 / 1000, unmatchedSlice.duration, 1e-5); 1739 assert.isUndefined(unmatchedSlice.args['x']); 1740 assert.isUndefined(unmatchedSlice.args['y']); 1741 assert.equal(unmatchedSlice.args['z'], 3); 1742 assert.isDefined(unmatchedSlice.error); 1743 assert.sameMembers(unmatchedSlice.subSlices, []); 1744 1745 assert.equal(slice.title, 'b'); 1746 assert.isTrue(slice.isTopLevel); 1747 assert.closeTo(1 / 1000, slice.start, 1e-5); 1748 assert.closeTo(35 / 1000, slice.duration, 1e-5); 1749 // Arguments should include both BEGIN and END event. 1750 assert.equal(slice.args['x'], 1); 1751 assert.equal(slice.args['y'], 2); 1752 assert.sameMembers(slice.subSlices, []); 1753 }); 1754 1755 test('nestableAsyncUnmatchedInnerEndEvent', function() { 1756 var events = [ 1757 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, 1758 ph: 'b', id: 72}, 1759 {name: 'c', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1760 ph: 'n', id: 72}, 1761 {name: 'b', args: {z: 3}, pid: 52, ts: 525, cat: 'foo', tid: 53, 1762 ph: 'e', id: 72}, 1763 {name: 'a', args: {y: 2}, pid: 52, ts: 565, cat: 'foo', tid: 53, 1764 ph: 'e', id: 72} 1765 ]; 1766 1767 var m = makeModel(events); 1768 var t = m.processes[52].threads[53]; 1769 assert.isDefined(t); 1770 // Unmatched END should produce a warning. 1771 assert.isTrue(m.hasImportWarnings); 1772 assert.equal(t.asyncSliceGroup.slices.length, 1); 1773 var parentSlice = t.asyncSliceGroup.slices[0]; 1774 assert.equal(parentSlice.title, 'a'); 1775 assert.isTrue(parentSlice.isTopLevel); 1776 assert.closeTo(0, parentSlice.start, 1e-5); 1777 assert.closeTo(41 / 1000, parentSlice.duration, 1e-5); 1778 // Arguments should include both BEGIN and END event. 1779 assert.equal(parentSlice.args['x'], 1); 1780 assert.equal(parentSlice.args['y'], 2); 1781 1782 assert.isDefined(parentSlice.subSlices); 1783 assert.equal(parentSlice.subSlices.length, 2); 1784 var subSliceInstant = parentSlice.subSlices[0]; 1785 var subSliceUnmatched = parentSlice.subSlices[1]; 1786 assert.equal(subSliceInstant.title, 'c'); 1787 assert.isFalse(subSliceInstant.isTopLevel); 1788 assert.equal(subSliceUnmatched.title, 'b'); 1789 assert.isFalse(subSliceUnmatched.isTopLevel); 1790 // Unmatched END begins at the first event of that ID. 1791 assert.closeTo(0 / 1000, subSliceUnmatched.start, 1e-5); 1792 assert.closeTo(1 / 1000, subSliceUnmatched.duration, 1e-5); 1793 // Arguments should include both BEGIN and END event. 1794 assert.isUndefined(subSliceUnmatched.args['x']); 1795 assert.isUndefined(subSliceUnmatched.args['y']); 1796 assert.equal(subSliceUnmatched.args['z'], 3); 1797 assert.isDefined(subSliceUnmatched.error); 1798 1799 assert.sameMembers(subSliceUnmatched.subSlices, []); 1800 assert.closeTo(1 / 1000, subSliceInstant.start, 1e-5); 1801 assert.closeTo(0, subSliceInstant.duration, 1e-5); 1802 assert.sameMembers(subSliceInstant.subSlices, []); 1803 }); 1804 1805 test('nestableAsyncSameIDDifferentCategory', function() { 1806 // Events with the same ID, but different categories should not be 1807 // considered as nested. 1808 var events = [ 1809 {name: 'EVENT_A', args: {}, pid: 52, ts: 500, cat: 'foo', tid: 53, 1810 ph: 'b', id: 72}, 1811 {name: 'EVENT_B', args: {y: 2}, pid: 52, ts: 550, cat: 'bar', tid: 53, 1812 ph: 'b', id: 72}, 1813 {name: 'EVENT_B', args: {}, pid: 52, ts: 600, cat: 'bar', tid: 53, 1814 ph: 'e', id: 72}, 1815 {name: 'EVENT_A', args: {x: 1}, pid: 52, ts: 650, cat: 'foo', tid: 53, 1816 ph: 'e', id: 72} 1817 ]; 1818 1819 var m = makeModel(events); 1820 var t = m.processes[52].threads[53]; 1821 assert.isDefined(t); 1822 assert.equal(t.asyncSliceGroup.slices.length, 2); 1823 var eventASlice = t.asyncSliceGroup.slices[0]; 1824 assert.equal(eventASlice.title, 'EVENT_A'); 1825 assert.equal(eventASlice.category, 'foo'); 1826 assert.equal(eventASlice.id, 'foo:72'); 1827 assert.isTrue(eventASlice.isTopLevel); 1828 assert.equal(eventASlice.args['x'], 1); 1829 assert.sameMembers(eventASlice.subSlices, []); 1830 1831 var eventBSlice = t.asyncSliceGroup.slices[1]; 1832 assert.equal(eventBSlice.title, 'EVENT_B'); 1833 assert.equal(eventBSlice.category, 'bar'); 1834 assert.equal(eventBSlice.id, 'bar:72'); 1835 assert.isTrue(eventBSlice.isTopLevel); 1836 assert.equal(eventBSlice.args['y'], 2); 1837 assert.sameMembers(eventBSlice.subSlices, []); 1838 }); 1839 1840 test('nestableAsyncStackFrame', function() { 1841 var events = { 1842 traceEvents: [ 1843 {name: 'name', pid: 52, ts: 525, cat: 'foo', tid: 53, 1844 ph: 'b', id: 72, sf: 1}, 1845 {name: 'name', pid: 52, ts: 560, cat: 'foo', tid: 53, 1846 ph: 'e', id: 72, sf: 7} 1847 ], 1848 stackFrames: { 1849 '1': { 1850 category: 'm1', 1851 name: 'main' 1852 }, 1853 '7': { 1854 category: 'm2', 1855 name: 'frame7', 1856 parent: '1' 1857 } 1858 } 1859 }; 1860 1861 var m = makeModel(events); 1862 var t = m.processes[52].threads[53]; 1863 assert.isDefined(t); 1864 assert.equal(t.asyncSliceGroup.slices.length, 1); 1865 var slice = t.asyncSliceGroup.slices[0]; 1866 1867 assert.equal(slice.startStackFrame.title, 'main'); 1868 assert.equal(slice.endStackFrame.title, 'frame7'); 1869 }); 1870 1871 test('importSamples', function() { 1872 var events = [ 1873 {name: 'a', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'}, 1874 {name: 'b', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'}, 1875 {name: 'c', args: {}, pid: 52, ts: 558, cat: 'test', tid: 53, ph: 'P'}, 1876 {name: 'a', args: {}, pid: 52, ts: 568, cat: 'test', tid: 53, ph: 'P'} 1877 ]; 1878 var m = makeModel(events); 1879 var p = m.processes[52]; 1880 assert.isDefined(p); 1881 var t = p.threads[53]; 1882 assert.isDefined(t); 1883 assert.equal(t.samples_.length, 4); 1884 assert.equal(t.samples_[0].start, 0.0); 1885 assert.equal(t.samples_[1].start, 0.0); 1886 assert.closeTo(0.01, t.samples_[2].start, 1e-5); 1887 assert.equal(t.samples_[0].leafStackFrame.title, 'a'); 1888 assert.equal(t.samples_[1].leafStackFrame.title, 'b'); 1889 assert.equal(t.samples_[2].leafStackFrame.title, 'c'); 1890 assert.equal(t.samples_[3].leafStackFrame, t.samples[0].leafStackFrame); 1891 assert.isFalse(m.hasImportWarnings); 1892 }); 1893 1894 test('importSamplesWithStackFrames', function() { 1895 var eventData = { 1896 traceEvents: [ 1897 { name: 'a', args: {}, pid: 1, ts: 0, cat: 'test', tid: 2, ph: 'P', sf: 7 } // @suppress longLineCheck 1898 ], 1899 stackFrames: { 1900 '1': { 1901 category: 'm1', 1902 name: 'main' 1903 }, 1904 '7': { 1905 category: 'm2', 1906 name: 'frame7', 1907 parent: '1' 1908 } 1909 } 1910 }; 1911 1912 var m = makeModel(eventData); 1913 1914 var p = m.processes[1]; 1915 var t = p.threads[2]; 1916 1917 assert.equal(t.samples.length, 1); 1918 assert.equal(t.samples_[0].start, 0.0); 1919 assert.equal(t.samples_[0].leafStackFrame.title, 'frame7'); 1920 assert.isFalse(m.hasImportWarnings); 1921 }); 1922 1923 test('importSamplesMissingArgs', function() { 1924 var events = [ 1925 {name: 'a', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'}, 1926 {name: 'b', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'}, 1927 {name: 'c', pid: 52, ts: 549, cat: 'test', tid: 53, ph: 'P'} 1928 ]; 1929 var m = makeModel(events); 1930 var p = m.processes[52]; 1931 assert.isDefined(p); 1932 var t = p.threads[53]; 1933 assert.isDefined(t); 1934 assert.isDefined(t); 1935 assert.equal(t.samples_.length, 3); 1936 assert.isFalse(m.hasImportWarnings); 1937 }); 1938 1939 test('importV8Samples', function() { 1940 var eventData = { 1941 traceEvents: [ 1942 { name: 'V8Sample', args: {data: {stack: ['0x2a574306061', '0x2a574306224'], vm_state: 'js'}}, pid: 1, ts: 4, cat: 'test', tid: 2, ph: 'P' }, // @suppress longLineCheck 1943 { name: 'V8Sample', args: {data: {stack: [], vm_state: 'gc'}}, pid: 1, ts: 6, cat: 'test', tid: 2, ph: 'P' }, // @suppress longLineCheck 1944 { name: 'JitCodeAdded', args: {data: {code_len: 2, name: 'LazyCompile:~foo http://example.com/bar.js:23', code_start: '0x2a574306060'}}, pid: 1, ts: 1, cat: 'test', tid: 2, ph: 'M' }, // @suppress longLineCheck 1945 { name: 'JitCodeAdded', args: {data: {code_len: 20, name: 'bar', code_start: '0x2a574306220'}}, pid: 1, ts: 2, cat: 'test', tid: 2, ph: 'M' }, // @suppress longLineCheck 1946 { name: 'JitCodeMoved', args: {data: {code_len: 2, old_code_start: '0x2a574306220', code_start: '0x2a574306222'}}, pid: 1, ts: 3, cat: 'test', tid: 2, ph: 'M' }, // @suppress longLineCheck 1947 { name: 'JitCodeAdded', args: {data: {code_len: 20, name: 'baz', code_start: '0xffffffff9f90a1a0'}}, pid: 1, ts: 4, cat: 'test', tid: 2, ph: 'M' } // @suppress longLineCheck 1948 ] 1949 }; 1950 1951 var m = makeModel(eventData); 1952 var p = m.processes[1]; 1953 var t = p.threads[2]; 1954 1955 assert.isFalse(m.hasImportWarnings); 1956 assert.equal(t.samples.length, 2); 1957 1958 var sample = t.samples_[0]; 1959 assert.equal(sample.leafStackFrame.title, 1960 'foo http://example.com/bar.js:22'); 1961 assert.equal(sample.leafStackFrame.parentFrame.title, 'bar'); 1962 1963 var sample = t.samples_[1]; 1964 assert.equal(sample.leafStackFrame.title, 'gc'); 1965 }); 1966 1967 test('importOldFormatV8Samples', function() { 1968 var eventData = { 1969 traceEvents: [ 1970 { name: 'JitCodeAdded', args: {data: {code_len: 2, name: 'LazyCompile:~foo http://example.com/bar.js:23', code_start: '0x2a574306060'}}, pid: 1, ts: 0, cat: 'test', tid: 2, ph: 'I' }, // @suppress longLineCheck 1971 { name: 'JitCodeAdded', args: {data: {code_len: 20, name: 'bar', code_start: '0x2a574306220'}}, pid: 1, ts: 0, cat: 'test', tid: 2, ph: 'I' }, // @suppress longLineCheck 1972 { name: 'JitCodeMoved', args: {data: {code_len: 2, old_code_start: '0x2a574306220', code_start: '0x2a574306222'}}, pid: 1, ts: 0, cat: 'test', tid: 2, ph: 'I' }, // @suppress longLineCheck 1973 { name: 'JitCodeAdded', args: {data: {code_len: 20, name: 'baz', code_start: '0xffffffff9f90a1a0'}}, pid: 1, ts: 0, cat: 'test', tid: 2, ph: 'I' }, // @suppress longLineCheck 1974 { name: 'V8Sample', args: {data: {stack: ['0x2a574306061', '0x2a574306224']}}, pid: 1, ts: 0, cat: 'test', tid: 2, ph: 'P' }, // @suppress longLineCheck 1975 { name: 'V8Sample', args: {data: {stack: [], vm_state: 'gc'}}, pid: 1, ts: 10, cat: 'test', tid: 2, ph: 'P' } // @suppress longLineCheck 1976 ] 1977 }; 1978 1979 var m = makeModel(eventData); 1980 var p = m.processes[1]; 1981 var t = p.threads[2]; 1982 1983 assert.isFalse(m.hasImportWarnings); 1984 assert.equal(t.samples.length, 2); 1985 1986 var sample = t.samples_[0]; 1987 assert.equal(sample.leafStackFrame.title, 1988 'foo http://example.com/bar.js:22'); 1989 assert.equal(sample.leafStackFrame.parentFrame.title, 'bar'); 1990 1991 var sample = t.samples_[1]; 1992 assert.equal(sample.leafStackFrame.title, 'gc'); 1993 }); 1994 1995 test('importSimpleObject', function() { 1996 var events = [ 1997 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 1998 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 15}}, // @suppress longLineCheck 1999 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 20}}, // @suppress longLineCheck 2000 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}} // @suppress longLineCheck 2001 ]; 2002 var m = makeModel(events, false); 2003 assert.equal(m.bounds.min, 10); 2004 assert.equal(m.bounds.max, 50); 2005 assert.isFalse(m.hasImportWarnings); 2006 2007 var p = m.processes[1]; 2008 assert.isDefined(p); 2009 2010 var i10 = p.objects.getObjectInstanceAt(new ScopedId('ptr', '0x1000'), 10); 2011 assert.equal(i10.category, 'c'); 2012 assert.equal(i10.creationTs, 10); 2013 assert.equal(i10.deletionTs, 50); 2014 assert.equal(i10.snapshots.length, 2); 2015 2016 var s15 = i10.snapshots[0]; 2017 assert.equal(s15.ts, 15); 2018 assert.equal(s15.args, 15); 2019 2020 var s20 = i10.snapshots[1]; 2021 assert.equal(s20.ts, 20); 2022 assert.equal(s20.args, 20); 2023 }); 2024 2025 test('importImplicitObjects', function() { 2026 var events = [ 2027 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 2028 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', 2029 args: { snapshot: [ 2030 { id: 'subObject/0x1', 2031 foo: 1 2032 } 2033 ]}}, 2034 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', 2035 args: { snapshot: [ 2036 { id: 'subObject/0x1', 2037 foo: 2 2038 }, 2039 { id: 'subObject/0x2', 2040 foo: 1 2041 } 2042 ]}} 2043 ]; 2044 2045 var m = makeModel(events, false); 2046 var p1 = m.processes[1]; 2047 2048 var iA = p1.objects.getObjectInstanceAt(new ScopedId('ptr', '0x1000'), 10); 2049 var subObjectInstances = p1.objects.getAllInstancesByTypeName()[ 2050 'subObject']; 2051 2052 assert.equal(subObjectInstances.length, 2); 2053 var subObject1 = p1.objects.getObjectInstanceAt( 2054 new ScopedId('ptr', '0x1'), 15); 2055 assert.equal(subObject1.name, 'subObject'); 2056 assert.equal(subObject1.creationTs, 15); 2057 2058 assert.equal(subObject1.snapshots.length, 2); 2059 assert.equal(subObject1.snapshots[0].ts, 15); 2060 assert.equal(subObject1.snapshots[0].args.foo, 1); 2061 assert.equal(subObject1.snapshots[1].ts, 20); 2062 assert.equal(subObject1.snapshots[1].args.foo, 2); 2063 2064 var subObject2 = p1.objects.getObjectInstanceAt( 2065 new ScopedId('ptr', '0x2'), 20); 2066 assert.equal(subObject2.name, 'subObject'); 2067 assert.equal(subObject2.creationTs, 20); 2068 assert.equal(subObject2.snapshots.length, 1); 2069 assert.equal(subObject2.snapshots[0].ts, 20); 2070 }); 2071 2072 test('importImplicitObjectWithCategoryOverride', function() { 2073 var events = [ 2074 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'cat', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 2075 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'otherCat', id: '0x1000', name: 'a', // @suppress longLineCheck 2076 args: { snapshot: [ 2077 { id: 'subObject/0x1', 2078 cat: 'cat', 2079 foo: 1 2080 } 2081 ]}} 2082 ]; 2083 2084 var m = makeModel(events); 2085 var p1 = m.processes[1]; 2086 2087 var iA = p1.objects.getObjectInstanceAt(new ScopedId('ptr', '0x1000'), 10); 2088 var subObjectInstances = p1.objects.getAllInstancesByTypeName()[ 2089 'subObject']; 2090 2091 assert.equal(subObjectInstances.length, 1); 2092 }); 2093 2094 test('importImplicitObjectWithBaseTypeOverride', function() { 2095 var events = [ 2096 {ts: 10000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'PictureLayerImpl', args: { // @suppress longLineCheck 2097 snapshot: { 2098 base_type: 'LayerImpl' 2099 } 2100 }}, 2101 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'LayerImpl', args: {}} // @suppress longLineCheck 2102 ]; 2103 2104 var m = makeModel(events); 2105 var p1 = m.processes[1]; 2106 assert.equal(m.importWarnings.length, 0); 2107 2108 var iA = p1.objects.getObjectInstanceAt(new ScopedId('ptr', '0x1000'), 10); 2109 assert.equal(iA.snapshots.length, 1); 2110 }); 2111 2112 test('importIDRefs', function() { 2113 var events = [ 2114 // An object with two snapshots. 2115 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 2116 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 15}}, // @suppress longLineCheck 2117 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 20}}, // @suppress longLineCheck 2118 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 2119 2120 // A slice that references the object. 2121 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {my_object: {id_ref: '0x1000'}}}, // @suppress longLineCheck 2122 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck 2123 ]; 2124 2125 var m = makeModel(events, false); 2126 var p1 = m.processes[1]; 2127 2128 var iA = p1.objects.getObjectInstanceAt(new ScopedId('ptr', '0x1000'), 10); 2129 var s15 = iA.getSnapshotAt(15); 2130 2131 var taskSlice = p1.threads[1].sliceGroup.slices[0]; 2132 assert.equal(taskSlice.args.my_object, s15); 2133 }); 2134 2135 test('importIDRefsThatPointAtEachOther', function() { 2136 var events = [ 2137 // An object. 2138 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 2139 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck 2140 snapshot: { x: { 2141 id: 'foo/0x1001', 2142 value: 'bar' 2143 }}}}, 2144 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 2145 2146 // A slice that references the object. 2147 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {my_object: {id_ref: '0x1001'}}}, // @suppress longLineCheck 2148 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck 2149 ]; 2150 2151 var m = makeModel(events); 2152 var p1 = m.processes[1]; 2153 2154 var iA = p1.objects.getObjectInstanceAt(new ScopedId('ptr', '0x1000'), 15); 2155 var iFoo = p1.objects.getObjectInstanceAt( 2156 new ScopedId('ptr', '0x1001'), 15); 2157 assert.isDefined(iA); 2158 assert.isDefined(iFoo); 2159 2160 var a15 = iA.getSnapshotAt(15); 2161 var foo15 = iFoo.getSnapshotAt(15); 2162 2163 var taskSlice = p1.threads[1].sliceGroup.slices[0]; 2164 assert.equal(taskSlice.args.my_object, foo15); 2165 }); 2166 2167 test('importArrayWithIDs', function() { 2168 var events = [ 2169 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck 2170 snapshot: { x: [ 2171 {id: 'foo/0x1001', value: 'bar1'}, 2172 {id: 'foo/0x1002', value: 'bar2'}, 2173 {id: 'foo/0x1003', value: 'bar3'} 2174 ]}}} 2175 ]; 2176 2177 var m = makeModel(events, false); 2178 var p1 = m.processes[1]; 2179 2180 var sA = p1.objects.getSnapshotAt(new ScopedId('ptr', '0x1000'), 15); 2181 assert.isTrue(sA.args.x instanceof Array); 2182 assert.equal(sA.args.x.length, 3); 2183 assert.isTrue(sA.args.x[0] instanceof tr.model.ObjectSnapshot); 2184 assert.isTrue(sA.args.x[1] instanceof tr.model.ObjectSnapshot); 2185 assert.isTrue(sA.args.x[2] instanceof tr.model.ObjectSnapshot); 2186 }); 2187 2188 test('importDoesNotMutateEventList', function() { 2189 var events = [ 2190 // An object. 2191 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 2192 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck 2193 snapshot: {foo: 15}}}, 2194 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck 2195 2196 // A slice that references the object. 2197 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: { 2198 my_object: {id_ref: '0x1000'}} 2199 }, 2200 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck 2201 ]; 2202 2203 // The A type family exists to mutate the args list provided to 2204 // snapshots. 2205 function ASnapshot() { 2206 tr.model.ObjectSnapshot.apply(this, arguments); 2207 this.args.foo = 7; 2208 } 2209 ASnapshot.prototype = { 2210 __proto__: tr.model.ObjectSnapshot.prototype 2211 }; 2212 2213 // Import event while the A types are registered, causing the 2214 // arguments of the snapshots to be mutated. 2215 var m; 2216 try { 2217 tr.model.ObjectSnapshot.register(ASnapshot, {typeName: 'a'}); 2218 m = makeModel(events); 2219 } finally { 2220 tr.model.ObjectSnapshot.unregister(ASnapshot); 2221 } 2222 assert.isFalse(m.hasImportWarnings); 2223 2224 // Verify that the events array wasn't modified. 2225 assert.deepEqual( 2226 events[1].args, 2227 {snapshot: {foo: 15}}); 2228 assert.deepEqual( 2229 events[3].args, 2230 {my_object: {id_ref: '0x1000'}}); 2231 }); 2232 2233 test('importFlowEvent', function() { 2234 var events = [ 2235 { name: 'aSlice', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 547, ph: 'B', args: {} }, // @suppress longLineCheck 2236 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {} }, // @suppress longLineCheck 2237 { id: 72, pid: 52, tid: 53, ts: 549, ph: 'E', args: {} }, // @suppress longLineCheck 2238 2239 { name: 'bSlice', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 559, ph: 'B', args: {} }, // @suppress longLineCheck 2240 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {} }, // @suppress longLineCheck 2241 { id: 72, pid: 52, tid: 53, ts: 561, ph: 'E', args: {} }, // @suppress longLineCheck 2242 2243 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {} }, // @suppress longLineCheck 2244 { name: 'cSlice', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 581, ph: 'B', args: {} }, // @suppress longLineCheck 2245 { id: 72, pid: 52, tid: 53, ts: 582, ph: 'E', args: {} } // @suppress longLineCheck 2246 ]; 2247 2248 var m = makeModel(events); 2249 var t = m.processes[52].threads[53]; 2250 2251 assert.isDefined(t); 2252 assert.equal(m.flowEvents.length, 2); 2253 assert.equal(m.flowIntervalTree.size, 2); 2254 2255 var f0 = m.flowEvents[0]; 2256 assert.equal(f0.title, 'a'); 2257 assert.equal(f0.category, 'foo'); 2258 assert.equal(f0.id, 72); 2259 assert.closeTo(f0.start, 0.001, 1e-5); 2260 assert.closeTo(12 / 1000, f0.duration, 1e-5); 2261 assert.equal(f0.startSlice.title, 'aSlice'); 2262 assert.equal(f0.endSlice.title, 'bSlice'); 2263 2264 // TODO(nduca): Replace this assertion with something better when 2265 // flow events don't create synthetic slices on their own. 2266 assert.isDefined(f0.startSlice); 2267 assert.isDefined(f0.endSlice); 2268 2269 var f1 = m.flowEvents[1]; 2270 assert.equal(f1.title, f0.title); 2271 assert.equal(f1.category, f0.category); 2272 assert.equal(f1.id, f0.id); 2273 assert.closeTo(20 / 1000, f1.duration, 1e-5); 2274 2275 assert.equal(f1.startSlice.title, 'bSlice'); 2276 assert.equal(f1.endSlice.title, 'cSlice'); 2277 2278 assert.deepEqual(f0.startSlice.outFlowEvents, [f0]); 2279 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2280 assert.deepEqual(f1.startSlice.outFlowEvents, [f1]); 2281 assert.deepEqual(f1.endSlice.inFlowEvents, [f1]); 2282 }); 2283 2284 test('importOldFlowEventBindtoNext', function() { 2285 // Old trace format without event.bp, and event.cat doesn't contain input 2286 var events = [ 2287 { name: 'slice1', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100}, // @suppress longLineCheck 2288 { name: 'flow', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {}}, // @suppress longLineCheck 2289 2290 { name: 'flow', cat: 'foo', id: 72, pid: 70, tid: 71, ts: 580, ph: 'f', args: {}}, // @suppress longLineCheck 2291 { name: 'slice2', cat: 'foo', pid: 70, tid: 71, ts: 570, ph: 'X', args: {}, 'dur': 100}, // @suppress longLineCheck 2292 { name: 'slice3', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', args: {}, 'dur': 1000} // @suppress longLineCheck 2293 2294 ]; 2295 2296 var m = makeModel(events, false, false); 2297 assert.equal(m.flowEvents.length, 1); 2298 2299 var f0 = m.flowEvents[0]; 2300 2301 assert.equal(f0.title, 'flow'); 2302 assert.equal(f0.category, 'foo'); 2303 assert.equal(f0.id, 72); 2304 assert.equal(f0.start, .548); 2305 assert.closeTo(32 / 1000, f0.duration, 1e-5); 2306 assert.equal(f0.startSlice.title, 'slice1'); 2307 assert.deepEqual(f0.startSlice.outFlowEvents, [f0]); 2308 assert.equal(f0.endSlice.title, 'slice3'); 2309 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2310 }); 2311 2312 test('importOldInputFlowEventBindtoParent', function() { 2313 // Old trace format without event.bp, but event.cat contains input 2314 var events = [ 2315 { name: 'slice1', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100}, // @suppress longLineCheck 2316 { name: 'flow', cat: 'input', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {}}, // @suppress longLineCheck 2317 2318 { name: 'flow', cat: 'input', id: 72, pid: 70, tid: 71, ts: 580, ph: 'f', args: {}}, // @suppress longLineCheck 2319 { name: 'slice2', cat: 'foo', pid: 70, tid: 71, ts: 570, ph: 'X', args: {}, 'dur': 100}, // @suppress longLineCheck 2320 { name: 'slice3', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', args: {}, 'dur': 1000} // @suppress longLineCheck 2321 2322 ]; 2323 2324 var m = makeModel(events, false, false); 2325 assert.equal(m.flowEvents.length, 1); 2326 2327 var f0 = m.flowEvents[0]; 2328 2329 assert.equal(f0.title, 'flow'); 2330 assert.equal(f0.category, 'input'); 2331 assert.equal(f0.id, 72); 2332 assert.equal(f0.start, .548); 2333 assert.closeTo(32 / 1000, f0.duration, 1e-5); 2334 assert.equal(f0.startSlice.title, 'slice1'); 2335 assert.deepEqual(f0.startSlice.outFlowEvents, [f0]); 2336 assert.equal(f0.endSlice.title, 'slice2'); 2337 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2338 }); 2339 2340 test('importOldIPCFlowEventBindtoParent', function() { 2341 // Old trace format without event.bp, but event.cat contains ipc.flow 2342 var events = [ 2343 { name: 'slice1', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100}, // @suppress longLineCheck 2344 { name: 'flow', cat: 'disabled-by-default-ipc.flow', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {}}, // @suppress longLineCheck 2345 2346 { name: 'flow', cat: 'disabled-by-default-ipc.flow', id: 72, pid: 70, tid: 71, ts: 580, ph: 'f', args: {}}, // @suppress longLineCheck 2347 { name: 'slice2', cat: 'foo', pid: 70, tid: 71, ts: 570, ph: 'X', args: {}, 'dur': 100}, // @suppress longLineCheck 2348 { name: 'slice3', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', args: {}, 'dur': 1000} // @suppress longLineCheck 2349 2350 ]; 2351 2352 var m = makeModel(events, false, false); 2353 assert.equal(m.flowEvents.length, 1); 2354 2355 var f0 = m.flowEvents[0]; 2356 2357 assert.equal(f0.title, 'flow'); 2358 assert.equal(f0.category, 'disabled-by-default-ipc.flow'); 2359 assert.equal(f0.id, 72); 2360 assert.equal(f0.start, .548); 2361 assert.closeTo(32 / 1000, f0.duration, 1e-5); 2362 assert.equal(f0.startSlice.title, 'slice1'); 2363 assert.deepEqual(f0.startSlice.outFlowEvents, [f0]); 2364 assert.equal(f0.endSlice.title, 'slice2'); 2365 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2366 }); 2367 2368 test('importNewFlowEventBindtoParent', function() { 2369 // New trace format with event.bp 2370 var events = [ 2371 { name: 'slice1', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100}, // @suppress longLineCheck 2372 { name: 'flow', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', bp: 'e', args: {}}, // @suppress longLineCheck 2373 2374 { name: 'flow', cat: 'foo', id: 72, pid: 70, tid: 71, ts: 580, ph: 'f', bp: 'e', args: {}}, // @suppress longLineCheck 2375 { name: 'slice2', cat: 'foo', pid: 70, tid: 71, ts: 570, ph: 'X', args: {}, 'dur': 100}, // @suppress longLineCheck 2376 { name: 'slice3', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', args: {}, 'dur': 1000} // @suppress longLineCheck 2377 2378 ]; 2379 2380 var m = makeModel(events, false, false); 2381 assert.equal(m.flowEvents.length, 1); 2382 2383 var f0 = m.flowEvents[0]; 2384 2385 assert.equal(f0.title, 'flow'); 2386 assert.equal(f0.category, 'foo'); 2387 assert.equal(f0.id, 72); 2388 assert.equal(f0.start, .548); 2389 assert.closeTo(32 / 1000, f0.duration, 1e-5); 2390 assert.equal(f0.startSlice.title, 'slice1'); 2391 assert.deepEqual(f0.startSlice.outFlowEvents, [f0]); 2392 assert.equal(f0.endSlice.title, 'slice2'); 2393 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2394 }); 2395 2396 test('importNewFlowEventWithInvalidBindingPoint', function() { 2397 // New trace format with event.bp, which however !== 'e' 2398 var events = [ 2399 { name: 'slice1', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100}, // @suppress longLineCheck 2400 { name: 'flow', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', bp: 'z', args: {}}, // @suppress longLineCheck 2401 2402 { name: 'flow', cat: 'foo', id: 72, pid: 70, tid: 71, ts: 580, ph: 'f', bp: 'z', args: {}}, // @suppress longLineCheck 2403 { name: 'slice2', cat: 'foo', pid: 70, tid: 71, ts: 570, ph: 'X', args: {}, 'dur': 100}, // @suppress longLineCheck 2404 { name: 'slice3', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', args: {}, 'dur': 1000} // @suppress longLineCheck 2405 2406 ]; 2407 2408 var m = makeModel(events); 2409 2410 assert.equal(m.flowEvents.length, 0); 2411 }); 2412 2413 test('importFlowV2OnePair', function() { 2414 // Flow V2: one flow producer one flow consumer 2415 var events = [ 2416 { name: 'producer', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100, bind_id: '0xaaa', flow_out: true}, // @suppress longLineCheck 2417 { name: 'consumer', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', 'dur': 1000, bind_id: '0xaaa', flow_in: true} // @suppress longLineCheck 2418 ]; 2419 2420 var m = makeModel(events); 2421 2422 assert.equal(m.flowEvents.length, 1); 2423 2424 var f0 = m.flowEvents[0]; 2425 2426 assert.equal(f0.startSlice.title, 'producer'); 2427 assert.deepEqual(f0.startSlice.outFlowEvents, [f0]); 2428 assert.equal(f0.endSlice.title, 'consumer'); 2429 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2430 }); 2431 2432 test('importFlowV2OneFlowStep', function() { 2433 // Flow V2: one flow producer one flow consumer 2434 var events = [ 2435 { name: 'producer', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100, bind_id: '0xaaa', flow_out: true}, // @suppress longLineCheck 2436 { name: 'step', cat: 'foo', pid: 62, tid: 63, ts: 647, ph: 'X', 'dur': 100, bind_id: '0xaaa', flow_out: true, flow_in: true}, // @suppress longLineCheck 2437 { name: 'consumer', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', 'dur': 1000, bind_id: '0xaaa', args: { 'queue_duration': 0}, flow_in: true} // @suppress longLineCheck 2438 ]; 2439 2440 var m = makeModel(events); 2441 2442 assert.equal(m.flowEvents.length, 2); 2443 2444 var f0 = m.flowEvents[0]; 2445 var f1 = m.flowEvents[1]; 2446 2447 assert.equal(f0.startSlice.title, 'producer'); 2448 assert.deepEqual(f0.startSlice.outFlowEvents, [f0]); 2449 assert.equal(f0.endSlice.title, 'step'); 2450 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2451 2452 assert.equal(f1.startSlice.title, 'step'); 2453 assert.deepEqual(f1.startSlice.outFlowEvents, [f1]); 2454 assert.equal(f1.endSlice.title, 'consumer'); 2455 assert.deepEqual(f1.endSlice.inFlowEvents, [f1]); 2456 }); 2457 2458 test('importFlowV2MultipleConsumers', function() { 2459 // Flow V2: one flow producer multiple flow consumers 2460 var events = [ 2461 { name: 'producer', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100, bind_id: '0xaaa', flow_out: true}, // @suppress longLineCheck 2462 { name: 'consumer1', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', 'dur': 1000, bind_id: '0xaaa', flow_in: true}, // @suppress longLineCheck 2463 { name: 'consumer2', cat: 'foo', pid: 70, tid: 72, ts: 870, ph: 'X', 'dur': 1000, bind_id: '0xaaa', flow_in: true} // @suppress longLineCheck 2464 ]; 2465 2466 var m = makeModel(events); 2467 2468 assert.equal(m.flowEvents.length, 2); 2469 2470 var f0 = m.flowEvents[0]; 2471 var f1 = m.flowEvents[1]; 2472 2473 assert.equal(f0.startSlice.title, 'producer'); 2474 assert.equal(f1.startSlice.title, 'producer'); 2475 2476 assert.equal(f0.startSlice.outFlowEvents.length, 2); 2477 assert.deepEqual(f0.startSlice.outFlowEvents, [f0, f1]); 2478 assert.deepEqual(f1.startSlice.outFlowEvents, [f0, f1]); 2479 2480 assert.equal(f0.endSlice.title, 'consumer1'); 2481 assert.equal(f1.endSlice.title, 'consumer2'); 2482 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2483 assert.deepEqual(f1.endSlice.inFlowEvents, [f1]); 2484 }); 2485 2486 test('importFlowV2MultipleProducers', function() { 2487 // Flow V2: multiple flow producers, which is not allowed 2488 var events = [ 2489 { name: 'producer1', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100, bind_id: '0xaaa', flow_out: true}, // @suppress longLineCheck 2490 { name: 'producer2', cat: 'foo', pid: 52, tid: 54, ts: 567, ph: 'X', 'dur': 100, bind_id: '0xaaa', flow_out: true}, // @suppress longLineCheck 2491 { name: 'consumer', cat: 'foo', pid: 70, tid: 71, ts: 770, ph: 'X', 'dur': 1000, bind_id: '0xaaa', flow_in: true} // @suppress longLineCheck 2492 ]; 2493 2494 var m = makeModel(events); 2495 2496 assert.equal(m.flowEvents.length, 1); 2497 }); 2498 2499 // This test creates a flow event that stops on the same timestamp that 2500 // the 'X' event which it triggers begins. 2501 test('importFlowEventOverlaps', function() { 2502 var events = [ 2503 { name: 'SomeTask', cat: 'foo', pid: 52, tid: 53, ts: 547, ph: 'X', 'dur': 100}, // @suppress longLineCheck 2504 { name: 'PostTask', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {}}, // @suppress longLineCheck 2505 2506 { name: 'PostTask', cat: 'foo', id: 72, pid: 70, tid: 71, ts: 580, ph: 'f', args: { 'queue_duration': 0}}, // @suppress longLineCheck 2507 // Note that RunTask has the same time-stamp as PostTask 'f' 2508 { name: 'RunTask', cat: 'foo', pid: 70, tid: 71, ts: 580, ph: 'X', args: {'src_func': 'PostRunTask'}, 'dur': 1000} // @suppress longLineCheck 2509 ]; 2510 2511 var m = makeModel(events, false); 2512 var startT = m.processes[52].threads[53]; 2513 var endT = m.processes[70].threads[71]; 2514 2515 assert.isDefined(startT); 2516 assert.equal(startT.sliceGroup.slices.length, 1); 2517 2518 assert.isDefined(endT); 2519 assert.equal(endT.sliceGroup.slices.length, 1); 2520 2521 assert.equal(m.flowEvents.length, 1); 2522 2523 // f0 represents 's' to 'f' 2524 var f0 = m.flowEvents[0]; 2525 2526 assert.equal(f0.title, 'PostTask'); 2527 assert.equal(f0.category, 'foo'); 2528 assert.equal(f0.id, 72); 2529 assert.equal(f0.start, .548); 2530 assert.closeTo(32 / 1000, f0.duration, 1e-5); 2531 assert.equal(f0.startSlice.title, 'SomeTask'); 2532 assert.deepEqual(f0.startSlice.outFlowEvents, [f0]); 2533 assert.equal(f0.endSlice.title, 'RunTask'); 2534 assert.deepEqual(f0.endSlice.inFlowEvents, [f0]); 2535 2536 // TODO(nduca): Add assertions about the flow slices, esp that they were 2537 // found correctly. 2538 }); 2539 2540 test('importOutOfOrderFlowEvent', function() { 2541 var events = [ 2542 { name: 'SomeTask', cat: 'foo', pid: 52, tid: 53, ts: 548, ph: 'X', 'dur': 10}, // @suppress longLineCheck 2543 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {} }, // @suppress longLineCheck 2544 2545 { name: 'SomeTask', cat: 'foo', pid: 52, tid: 53, ts: 148, ph: 'X', 'dur': 10}, // @suppress longLineCheck 2546 { name: 'b', cat: 'foo', id: 73, pid: 52, tid: 53, ts: 148, ph: 's', args: {} }, // @suppress longLineCheck 2547 2548 { name: 'b', cat: 'foo', id: 73, pid: 52, tid: 53, ts: 570, ph: 'f', args: {} }, // @suppress longLineCheck 2549 { name: 'SomeTask', cat: 'foo', pid: 52, tid: 53, ts: 571, ph: 'X', 'dur': 10}, // @suppress longLineCheck 2550 2551 { name: 'SomeTask', cat: 'foo', pid: 52, tid: 53, ts: 560, ph: 'X', 'dur': 10}, // @suppress longLineCheck 2552 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {} }, // @suppress longLineCheck 2553 2554 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {} }, // @suppress longLineCheck 2555 { name: 'SomeTask', cat: 'foo', pid: 52, tid: 53, ts: 581, ph: 'X', 'dur': 10} // @suppress longLineCheck 2556 ]; 2557 2558 var expected = [0.4, 0.0, 0.412]; 2559 var m = makeModel(events); 2560 assert.equal(m.flowIntervalTree.size, 3); 2561 2562 var order = m.flowEvents.map(function(x) { return x.start }); 2563 for (var i = 0; i < expected.length; ++i) 2564 assert.closeTo(expected[i], order[i], 1e-5); 2565 }); 2566 2567 test('importCompleteEvent', function() { 2568 var events = [ 2569 { name: 'a', args: {}, pid: 52, ts: 629, dur: 1, cat: 'baz', tid: 53, ph: 'X' }, // @suppress longLineCheck 2570 { name: 'b', args: {}, pid: 52, ts: 730, dur: 20, cat: 'foo', tid: 53, ph: 'X' }, // @suppress longLineCheck 2571 { name: 'c', args: {}, pid: 52, ts: 740, cat: 'baz', tid: 53, ph: 'X' } 2572 ]; 2573 2574 var m = makeModel(events); 2575 assert.equal(m.numProcesses, 1); 2576 var p = m.processes[52]; 2577 assert.isDefined(p); 2578 2579 assert.equal(p.numThreads, 1); 2580 var t = p.threads[53]; 2581 assert.isDefined(t); 2582 assert.equal(t.sliceGroup.slices.length, 3); 2583 assert.equal(t.tid, 53); 2584 2585 var slice = t.sliceGroup.slices[0]; 2586 assert.equal(slice.title, 'a'); 2587 assert.equal(slice.category, 'baz'); 2588 assert.closeTo(0, slice.start, 1e-5); 2589 assert.closeTo(1 / 1000, slice.duration, 1e-5); 2590 assert.equal(slice.subSlices.length, 0); 2591 2592 slice = t.sliceGroup.slices[1]; 2593 assert.equal(slice.title, 'b'); 2594 assert.equal(slice.category, 'foo'); 2595 assert.closeTo((730 - 629) / 1000, slice.start, 1e-5); 2596 assert.closeTo(20 / 1000, slice.duration, 1e-5); 2597 assert.equal(slice.subSlices.length, 1); 2598 2599 slice = t.sliceGroup.slices[2]; 2600 assert.equal(slice.title, 'c'); 2601 assert.isTrue(slice.didNotFinish); 2602 assert.closeTo(10 / 1000, slice.duration, 1e-5); 2603 }); 2604 2605 test('importFlowEventsWithStackFrame', function() { 2606 var eventData = { 2607 traceEvents: [ 2608 { name: 'aSlice', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 547, ph: 'B', args: {} }, // @suppress longLineCheck 2609 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {}, sf: 1 }, // @suppress longLineCheck 2610 { id: 72, pid: 52, tid: 53, ts: 549, ph: 'E', args: {} }, // @suppress longLineCheck 2611 2612 { name: 'bSlice', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 559, ph: 'B', args: {} }, // @suppress longLineCheck 2613 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {}, sf: 2 }, // @suppress longLineCheck 2614 { id: 72, pid: 52, tid: 53, ts: 561, ph: 'E', args: {} }, // @suppress longLineCheck 2615 2616 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {}, sf: 3 }, // @suppress longLineCheck 2617 { name: 'cSlice', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 581, ph: 'B', args: {} }, // @suppress longLineCheck 2618 { id: 72, pid: 52, tid: 53, ts: 582, ph: 'E', args: {} } // @suppress longLineCheck 2619 ], 2620 stackFrames: { 2621 '1': { 2622 category: 'm1', 2623 name: 'fn1' 2624 }, 2625 '2': { 2626 category: 'm2', 2627 name: 'fn2' 2628 }, 2629 '3': { 2630 category: 'm3', 2631 name: 'fn3' 2632 } 2633 } 2634 }; 2635 2636 var m = makeModel(eventData); 2637 2638 assert.equal(m.flowEvents.length, 2); 2639 2640 var f0 = m.flowEvents[0]; 2641 assert.equal(f0.startStackFrame.title, 'fn1'); 2642 assert.equal(f0.endStackFrame.title, 'fn2'); 2643 2644 var f1 = m.flowEvents[1]; 2645 assert.equal(f1.startStackFrame.title, 'fn2'); 2646 assert.equal(f1.endStackFrame.title, 'fn3'); 2647 }); 2648 2649 test('importCompleteEventWithCpuDuration', function() { 2650 var events = [ 2651 { name: 'a', args: {}, pid: 52, ts: 629, dur: 1, cat: 'baz', tid: 53, ph: 'X', tts: 12, tdur: 1 }, // @suppress longLineCheck 2652 { name: 'b', args: {}, pid: 52, ts: 730, dur: 20, cat: 'foo', tid: 53, ph: 'X', tts: 110, tdur: 16 }, // @suppress longLineCheck 2653 { name: 'c', args: {}, pid: 52, ts: 740, cat: 'baz', tid: 53, ph: 'X', tts: 115 } // @suppress longLineCheck 2654 ]; 2655 2656 var m = makeModel(events); 2657 assert.equal(m.numProcesses, 1); 2658 var p = m.processes[52]; 2659 assert.isDefined(p); 2660 2661 assert.equal(p.numThreads, 1); 2662 var t = p.threads[53]; 2663 assert.isDefined(t); 2664 assert.equal(t.sliceGroup.slices.length, 3); 2665 assert.equal(t.tid, 53); 2666 2667 var slice = t.sliceGroup.slices[0]; 2668 assert.equal(slice.title, 'a'); 2669 assert.equal(slice.category, 'baz'); 2670 assert.closeTo(0, slice.start, 1e-5); 2671 assert.closeTo(1 / 1000, slice.duration, 1e-5); 2672 assert.closeTo(12 / 1000, slice.cpuStart, 1e-5); 2673 assert.closeTo(1 / 1000, slice.cpuDuration, 1e-5); 2674 assert.equal(slice.subSlices.length, 0); 2675 2676 slice = t.sliceGroup.slices[1]; 2677 assert.equal(slice.title, 'b'); 2678 assert.equal(slice.category, 'foo'); 2679 assert.closeTo((730 - 629) / 1000, slice.start, 1e-5); 2680 assert.closeTo(20 / 1000, slice.duration, 1e-5); 2681 assert.closeTo(110 / 1000, slice.cpuStart, 1e-5); 2682 assert.closeTo(16 / 1000, slice.cpuDuration, 1e-5); 2683 assert.equal(slice.subSlices.length, 1); 2684 2685 slice = t.sliceGroup.slices[2]; 2686 assert.equal(slice.title, 'c'); 2687 assert.isTrue(slice.didNotFinish); 2688 assert.closeTo(10 / 1000, slice.duration, 1e-5); 2689 }); 2690 2691 test('importNestedCompleteEventWithTightBounds', function() { 2692 var events = [ 2693 { name: 'a', args: {}, pid: 52, ts: 244654227065, dur: 36075, cat: 'baz', tid: 53, ph: 'X' }, // @suppress longLineCheck 2694 { name: 'b', args: {}, pid: 52, ts: 244654227095, dur: 36045, cat: 'foo', tid: 53, ph: 'X' } // @suppress longLineCheck 2695 ]; 2696 2697 var m = makeModel(events, false); 2698 var t = m.processes[52].threads[53]; 2699 2700 var sA = findSliceNamed(t.sliceGroup, 'a'); 2701 var sB = findSliceNamed(t.sliceGroup, 'b'); 2702 2703 assert.equal(sA.title, 'a'); 2704 assert.equal(sA.category, 'baz'); 2705 assert.equal(sA.start, 244654227.065); 2706 assert.equal(sA.duration, 36.075); 2707 assert.closeTo(0.03, sA.selfTime, 1e-5); 2708 2709 assert.equal(sB.title, 'b'); 2710 assert.equal(sB.category, 'foo'); 2711 assert.equal(sB.start, 244654227.095); 2712 assert.equal(sB.duration, 36.045); 2713 2714 assert.equal(sA.subSlices.length, 1); 2715 assert.equal(sA.subSlices[0], sB); 2716 assert.equal(sB.parentSlice, sA); 2717 }); 2718 2719 2720 test('importCompleteEventWithStackFrame', function() { 2721 var eventData = { 2722 traceEvents: [ 2723 { name: 'a', args: {}, pid: 1, ts: 0, dur: 1, cat: 'baz', tid: 2, ph: 'X', sf: 7 }, // @suppress longLineCheck 2724 { name: 'b', args: {}, pid: 1, ts: 5, dur: 1, cat: 'baz', tid: 2, ph: 'X', sf: 8, esf: 9 } // @suppress longLineCheck 2725 ], 2726 stackFrames: { 2727 '1': { 2728 category: 'm1', 2729 name: 'main' 2730 }, 2731 '7': { 2732 category: 'm2', 2733 name: 'frame7', 2734 parent: '1' 2735 }, 2736 '8': { 2737 category: 'm2', 2738 name: 'frame8', 2739 parent: '1' 2740 }, 2741 '9': { 2742 category: 'm2', 2743 name: 'frame9', 2744 parent: '1' 2745 } 2746 } 2747 }; 2748 2749 var m = makeModel(eventData); 2750 2751 var p = m.processes[1]; 2752 var t = p.threads[2]; 2753 assert.isDefined(t); 2754 assert.equal(t.sliceGroup.slices.length, 2); 2755 2756 var s0 = t.sliceGroup.slices[0]; 2757 assert.equal(s0.startStackFrame.title, 'frame7'); 2758 assert.isUndefined(s0.endStackFrame); 2759 2760 var s1 = t.sliceGroup.slices[1]; 2761 assert.equal(s1.startStackFrame.title, 'frame8'); 2762 assert.equal(s1.endStackFrame.title, 'frame9'); 2763 }); 2764 2765 test('importAsyncEventWithSameTimestamp', function() { 2766 var events = []; 2767 // Events are added with ts 0, 1, 1, 2, 2, 3, 3 ...500, 500, 1000 2768 // and use 'seq' to track the order of when the event is recorded. 2769 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 0, ph: 'S', args: {'seq': 0}}); // @suppress longLineCheck 2770 2771 for (var i = 1; i <= 1000; i++) 2772 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: Math.round(i / 2) , ph: 'T', args: {'seq': i}}); // @suppress longLineCheck 2773 2774 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 1000, ph: 'F', args: {'seq': 1001}}); // @suppress longLineCheck 2775 2776 var m = makeModel(events); 2777 var t = m.processes[52].threads[53]; 2778 2779 assert.equal(t.asyncSliceGroup.slices.length, 1); 2780 var parentSlice = t.asyncSliceGroup.slices[0]; 2781 assert.equal(parentSlice.title, 'a'); 2782 assert.equal(parentSlice.category, 'foo'); 2783 assert.isTrue(parentSlice.isTopLevel); 2784 2785 assert.isDefined(parentSlice.subSlices); 2786 var subSlices = parentSlice.subSlices; 2787 assert.equal(subSlices.length, 1000); 2788 // Slices should be sorted according to 'ts'. And if 'ts' is the same, 2789 // slices should keep the order that they were recorded. 2790 for (var i = 0; i < 1000; i++) { 2791 assert.equal(i + 1, subSlices[i].args['seq']); 2792 assert.isFalse(subSlices[i].isTopLevel); 2793 } 2794 }); 2795 2796 test('sampleDataSimple', function() { 2797 var events = { 2798 'traceEvents': [], 2799 'stackFrames': { 2800 '1': { 2801 'category': 'mod', 2802 'name': 'main' 2803 }, 2804 '2': { 2805 'category': 'mod', 2806 'name': 'a', 2807 'parent': 1 2808 }, 2809 '3': { 2810 'category': 'mod', 2811 'name': 'a_sub', 2812 'parent': 2 2813 }, 2814 '4': { 2815 'category': 'mod', 2816 'name': 'b', 2817 'parent': 1 2818 } 2819 }, 2820 'samples': [ 2821 { 2822 'cpu': 0, 'tid': 1, 'ts': 1000.0, 2823 'name': 'cycles:HG', 'sf': 3, 'weight': 1 2824 }, 2825 { 2826 'cpu': 0, 'tid': 1, 'ts': 2000.0, 2827 'name': 'cycles:HG', 'sf': 2, 'weight': 1 2828 }, 2829 { 2830 'cpu': 1, 'tid': 1, 'ts': 3000.0, 2831 'name': 'cycles:HG', 'sf': 3, 'weight': 1 2832 } 2833 ] 2834 }; 2835 var m = makeModel(events, false); 2836 assert.isDefined(m.kernel.cpus[0]); 2837 assert.equal(m.getAllThreads().length, 1); 2838 2839 assert.equal(tr.b.dictionaryKeys(m.stackFrames).length, 4); 2840 assert.equal(m.samples.length, 3); 2841 2842 var t1 = m.processes[1].threads[1]; 2843 assert.equal(t1.samples.length, 3); 2844 2845 var c0 = m.kernel.cpus[0]; 2846 var c1 = m.kernel.cpus[1]; 2847 assert.equal(c0.samples.length, 2); 2848 assert.equal(c1.samples.length, 1); 2849 2850 assert.equal(m.samples[0].cpu, c0); 2851 assert.equal(m.samples[0].thread, t1); 2852 assert.equal(m.samples[0].title, 'cycles:HG'); 2853 assert.equal(m.samples[0].start, 1); 2854 assert.deepEqual( 2855 ['a_sub', 'a', 'main'], 2856 m.samples[0].stackTrace.map(function(x) { return x.title; })); 2857 assert.equal(m.samples[0].weight, 1); 2858 }); 2859 2860 test('importMemoryDumps_verifyProcessAndGlobalMemoryDumpLinks', function() { 2861 var events = [ 2862 // 2 process memory dump events. 2863 { 2864 name: 'a', 2865 pid: 42, 2866 ts: 10000, 2867 cat: 'test', 2868 tid: 53, 2869 ph: 'v', 2870 id: '0x0001', 2871 args: { 2872 dumps: { 2873 process_totals: { 2874 resident_set_bytes: '100' 2875 } 2876 } 2877 } 2878 }, 2879 { 2880 name: 'b', 2881 pid: 43, 2882 ts: 11000, 2883 cat: 'test', 2884 tid: 54, 2885 ph: 'v', 2886 id: '0x0001', 2887 args: { 2888 dumps: { 2889 process_totals: { 2890 resident_set_bytes: '200' 2891 } 2892 } 2893 } 2894 }, 2895 // 1 process memory dump event. 2896 { 2897 name: 'd', 2898 pid: 42, 2899 ts: 13000, 2900 cat: 'test', 2901 tid: 56, 2902 ph: 'v', 2903 id: '0xfffffff12345678', 2904 args: { 2905 dumps: { 2906 process_totals: { 2907 resident_set_bytes: '300' 2908 } 2909 } 2910 } 2911 } 2912 ]; 2913 var m = makeModel(events, false); 2914 var p1 = m.getProcess(42); 2915 var p2 = m.getProcess(43); 2916 assert.isDefined(p1); 2917 assert.isDefined(p2); 2918 2919 // Check that Model and Process objects contain the right dumps. 2920 assert.equal(m.globalMemoryDumps.length, 2); 2921 assert.equal(p1.memoryDumps.length, 2); 2922 assert.equal(p2.memoryDumps.length, 1); 2923 2924 assert.equal(m.globalMemoryDumps[0].start, 10); 2925 assert.equal(p1.memoryDumps[0].start, 10); 2926 assert.equal(p2.memoryDumps[0].start, 11); 2927 assert.equal(m.globalMemoryDumps[0].duration, 1); 2928 assert.equal(p1.memoryDumps[0].duration, 0); 2929 assert.equal(p2.memoryDumps[0].duration, 0); 2930 2931 assert.equal(m.globalMemoryDumps[1].start, 13); 2932 assert.equal(p1.memoryDumps[1].start, 13); 2933 assert.equal(m.globalMemoryDumps[1].duration, 0); 2934 assert.equal(p1.memoryDumps[1].duration, 0); 2935 2936 // Check that GlobalMemoryDump and ProcessMemoryDump objects are 2937 // interconnected correctly. 2938 assert.equal(p1.memoryDumps[0], 2939 m.globalMemoryDumps[0].processMemoryDumps[42]); 2940 assert.equal(p2.memoryDumps[0], 2941 m.globalMemoryDumps[0].processMemoryDumps[43]); 2942 assert.equal(p1.memoryDumps[0].globalMemoryDump, m.globalMemoryDumps[0]); 2943 assert.equal(p2.memoryDumps[0].globalMemoryDump, m.globalMemoryDumps[0]); 2944 2945 assert.equal(p1.memoryDumps[1], 2946 m.globalMemoryDumps[1].processMemoryDumps[42]); 2947 assert.equal(p1.memoryDumps[1].globalMemoryDump, m.globalMemoryDumps[1]); 2948 }); 2949 2950 test('importMemoryDumps_totalResidentBytesOnly', function() { 2951 var events = [ 2952 { 2953 pid: 42, 2954 ts: 10, 2955 ph: 'v', 2956 id: '0x01', 2957 args: { 2958 dumps: { 2959 process_totals: { 2960 resident_set_bytes: '1fffffffffffff' 2961 } 2962 } 2963 } 2964 } 2965 ]; 2966 var m = makeModel(events); 2967 var p = m.getProcess(42); 2968 var d = p.memoryDumps[0]; 2969 2970 assert.equal(d.totals.residentBytes, 9007199254740991); 2971 assert.isUndefined(d.totals.peakResidentBytes); 2972 assert.isUndefined(d.totals.arePeakResidentBytesResettable); 2973 assert.isUndefined(d.totals.platformSpecific); 2974 assert.isUndefined(d.mostRecentVmRegions); 2975 assert.lengthOf(d.memoryAllocatorDumps, 0); 2976 }); 2977 2978 test('importMemoryDumps_withPeakResidentBytes', function() { 2979 var events = [ 2980 { 2981 pid: 42, 2982 ts: 10, 2983 ph: 'v', 2984 id: '0x01', 2985 args: { 2986 dumps: { 2987 process_totals: { 2988 resident_set_bytes: '1fffffffffffff', 2989 peak_resident_set_bytes: '2fffffffffffff', 2990 is_peak_rss_resetable: true 2991 } 2992 } 2993 } 2994 } 2995 ]; 2996 var m = makeModel(events); 2997 var p = m.getProcess(42); 2998 var d = p.memoryDumps[0]; 2999 3000 assert.equal(d.totals.residentBytes, 9007199254740991); 3001 assert.equal(d.totals.peakResidentBytes, 13510798882111488); 3002 assert.isTrue(d.totals.arePeakResidentBytesResettable); 3003 assert.isUndefined(d.totals.platformSpecific); 3004 assert.isUndefined(d.mostRecentVmRegions); 3005 assert.lengthOf(d.memoryAllocatorDumps, 0); 3006 }); 3007 3008 test('importMemoryDumps_platformSpecificTotals', function() { 3009 var events = [ 3010 { 3011 pid: 42, 3012 ts: 10, 3013 ph: 'v', 3014 id: '0x01', 3015 args: { 3016 dumps: { 3017 process_totals: { 3018 resident_set_bytes: '1fffffffffffff', 3019 private_bytes: 'fffffffffffff', 3020 shared_bytes: '10000000000000' 3021 } 3022 } 3023 } 3024 } 3025 ]; 3026 var m = makeModel(events); 3027 var p = m.getProcess(42); 3028 var d = p.memoryDumps[0]; 3029 3030 assert.equal(d.totals.residentBytes, 9007199254740991); 3031 assert.isUndefined(d.totals.peakResidentBytes); 3032 assert.isUndefined(d.totals.arePeakResidentBytesResettable); 3033 assert.deepEqual(d.totals.platformSpecific, 3034 {private_bytes: 4503599627370495, shared_bytes: 4503599627370496}); 3035 assert.isUndefined(d.mostRecentVmRegions); 3036 assert.lengthOf(d.memoryAllocatorDumps, 0); 3037 }); 3038 3039 test('importMemoryDumps_vmRegions', function() { 3040 var events = [ 3041 { 3042 name: 'some_dump_name', 3043 pid: 42, 3044 ts: 10, 3045 cat: 'test', 3046 tid: 53, 3047 ph: 'v', 3048 id: '000', 3049 args: { 3050 dumps: { 3051 process_totals: { 3052 resident_set_bytes: '0' 3053 }, 3054 process_mmaps: { 3055 vm_regions: [ 3056 { 3057 sa: 'f0', 3058 sz: '150', 3059 pf: 6, 3060 mf: '[stack:20310]', 3061 bs: { 3062 pss: '9e', 3063 pc: '40', 3064 pd: '20', 3065 sc: '100', 3066 sd: '0', 3067 sw: '50' 3068 } 3069 }, 3070 { 3071 sa: '350', 3072 sz: '250', 3073 pf: 5, 3074 mf: '/dev/ashmem/dalvik', 3075 bs: { 3076 pss: 'cd', 3077 pd: 'cd', 3078 sc: undefined, 3079 sw: '0' 3080 } 3081 }, 3082 { 3083 sa: '7ff10ff4b000', 3084 sz: '40000', 3085 pf: 134, 3086 mf: '/run/shm/.org.chromium.Chromium.sqqN11 (deleted)', 3087 bs: { 3088 pss: '40000', 3089 pc: '0', 3090 pd: '40000', 3091 sc: '0', 3092 sd: '0', 3093 sw: '0' 3094 } 3095 } 3096 ] 3097 } 3098 } 3099 } 3100 } 3101 ]; 3102 var m = makeModel(events); 3103 var p = m.getProcess(42); 3104 var d = p.memoryDumps[0]; 3105 3106 checkVMRegions(d.vmRegions, [ 3107 { 3108 startAddress: 240, 3109 sizeInBytes: 336, 3110 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 3111 VMRegion.PROTECTION_FLAG_WRITE, 3112 mappedFile: '[stack:20310]', 3113 byteStats: { 3114 privateCleanResident: 64, 3115 privateDirtyResident: 32, 3116 sharedCleanResident: 256, 3117 sharedDirtyResident: 0, 3118 proportionalResident: 158, 3119 swapped: 80 3120 } 3121 }, 3122 { 3123 startAddress: 848, 3124 sizeInBytes: 592, 3125 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 3126 VMRegion.PROTECTION_FLAG_EXECUTE, 3127 mappedFile: '/dev/ashmem/dalvik', 3128 byteStats: { 3129 proportionalResident: 205, 3130 privateDirtyResident: 205, 3131 swapped: 0 3132 } 3133 }, 3134 { 3135 startAddress: 140673331539968, 3136 sizeInBytes: 262144, 3137 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 3138 VMRegion.PROTECTION_FLAG_WRITE | VMRegion.PROTECTION_FLAG_MAYSHARE, 3139 mappedFile: '/run/shm/.org.chromium.Chromium.sqqN11 (deleted)', 3140 byteStats: { 3141 privateCleanResident: 0, 3142 privateDirtyResident: 262144, 3143 sharedCleanResident: 0, 3144 sharedDirtyResident: 0, 3145 proportionalResident: 262144, 3146 swapped: 0 3147 } 3148 } 3149 ]); 3150 3151 assert.equal(d.totals.residentBytes, 0); 3152 assert.isUndefined(d.totals.peakResidentBytes); 3153 assert.isUndefined(d.totals.arePeakResidentBytesResettable); 3154 assert.isUndefined(d.totals.platformSpecific); 3155 assert.lengthOf(d.memoryAllocatorDumps, 0); 3156 }); 3157 3158 test('importMemoryDumps_explicitMemoryAllocatorDumps', function() { 3159 var events = [ 3160 { 3161 name: 'a', 3162 pid: 42, 3163 ts: 10, 3164 cat: 'test', 3165 tid: 53, 3166 ph: 'v', 3167 id: '0x0001', 3168 args: { 3169 dumps: { 3170 process_totals: { 3171 resident_set_bytes: '100' 3172 }, 3173 allocators: { 3174 'oilpan': { 3175 guid: '1a', 3176 attrs: { 3177 objects_count: { 3178 type: 'scalar', units: 'objects', value: '2f' 3179 }, 3180 inner_size: {type: 'scalar', units: 'bytes', value: '1000'}, 3181 size: {type: 'scalar', units: 'bytes', value: '8000'} 3182 } 3183 }, 3184 'oilpan/heap1': { 3185 guid: '2b', 3186 attrs: { 3187 objects_count: { 3188 type: 'scalar', units: 'objects', value: '3f' 3189 }, 3190 inner_size: {type: 'scalar', units: 'bytes', value: '3000'}, 3191 size: {type: 'scalar', units: 'bytes', value: '4000'} 3192 } 3193 }, 3194 'oilpan/heap2': { 3195 guid: '3c', 3196 attrs: { 3197 objects_count: { 3198 type: 'scalar', units: 'objects', value: '4f' 3199 }, 3200 inner_size: {type: 'scalar', units: 'bytes', value: '4000'}, 3201 size: {type: 'scalar', units: 'bytes', value: '4000'} 3202 } 3203 }, 3204 'oilpan/heap2/bucket1': { 3205 // Deliberately missing GUID (to check that the importer does 3206 // not skip memory allocator dump without GUID). 3207 attrs: { 3208 objects_count: { 3209 type: 'scalar', units: 'objects', value: '1f' 3210 }, 3211 inner_size: {type: 'scalar', units: 'bytes', value: '2000'}, 3212 size: {type: 'scalar', units: 'bytes', value: '2000'} 3213 } 3214 }, 3215 'v8': { 3216 guid: '5e', 3217 attrs: { 3218 objects_count: { 3219 type: 'scalar', units: 'objects', value: '5f' 3220 }, 3221 inner_size: {type: 'scalar', units: 'bytes', value: '5000'}, 3222 size: {type: 'scalar', units: 'bytes', value: '6000'} 3223 } 3224 } 3225 } 3226 } 3227 } 3228 } 3229 ]; 3230 var m = makeModel(events); 3231 var p = m.getProcess(42); 3232 var d = p.memoryDumps[0]; 3233 3234 assert.equal(d.memoryAllocatorDumps.length, 2); 3235 3236 var oilpanRoot = d.getMemoryAllocatorDumpByFullName('oilpan'); 3237 var v8Root = d.getMemoryAllocatorDumpByFullName('v8'); 3238 assert.isDefined(oilpanRoot); 3239 assert.isDefined(v8Root); 3240 assert.include(d.memoryAllocatorDumps, oilpanRoot); 3241 assert.include(d.memoryAllocatorDumps, v8Root); 3242 3243 checkDumpNumericsAndDiagnostics(oilpanRoot, { 3244 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 47), 3245 'size': 32768, 3246 'effective_size': 32768, 3247 'inner_size': 4096 3248 }, {}); 3249 assert.equal(oilpanRoot.children.length, 2); 3250 3251 var oilpanBucket1 = d.getMemoryAllocatorDumpByFullName( 3252 'oilpan/heap2/bucket1'); 3253 assert.isDefined(oilpanBucket1); 3254 assert.equal(oilpanBucket1.fullName, 'oilpan/heap2/bucket1'); 3255 assert.equal(oilpanBucket1.name, 'bucket1'); 3256 checkDumpNumericsAndDiagnostics(oilpanBucket1, { 3257 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 31), 3258 'size': 8192, 3259 'effective_size': 8192, 3260 'inner_size': 8192 3261 }, {}); 3262 assert.equal(oilpanBucket1.children.length, 0); 3263 3264 assert.isDefined(oilpanBucket1.parent); 3265 assert.equal(oilpanBucket1.parent.fullName, 'oilpan/heap2'); 3266 assert.equal(oilpanBucket1.parent.name, 'heap2'); 3267 assert.include(oilpanBucket1.parent.children, oilpanBucket1); 3268 3269 assert.isDefined(oilpanBucket1.parent.parent); 3270 assert.strictEqual(oilpanBucket1.parent.parent, oilpanRoot); 3271 3272 assert.equal(d.totals.residentBytes, 256); 3273 assert.isUndefined(d.totals.peakResidentBytes); 3274 assert.isUndefined(d.totals.arePeakResidentBytesResettable); 3275 assert.isUndefined(d.totals.platformSpecific); 3276 assert.isUndefined(d.mostRecentVmRegions); 3277 }); 3278 3279 test('importMemoryDumps_implicitMemoryAllocatorDumps', function() { 3280 var events = [ 3281 { 3282 name: 'a', 3283 pid: 42, 3284 ts: 10, 3285 cat: 'test', 3286 tid: 53, 3287 ph: 'v', 3288 id: '0x0001', 3289 args: { 3290 dumps: { 3291 process_totals: { 3292 resident_set_bytes: '100' 3293 }, 3294 allocators: { 3295 'oilpan/heap1': { 3296 guid: '999', 3297 attrs: { 3298 objects_count: { 3299 type: 'scalar', units: 'objects', value: '3f' 3300 }, 3301 inner_size: {type: 'scalar', units: 'bytes', value: '3000'}, 3302 size: {type: 'scalar', units: 'bytes', value: '4000'} 3303 } 3304 }, 3305 'oilpan/heap2/bucket1': { 3306 guid: '888', 3307 attrs: { 3308 objects_count: { 3309 type: 'scalar', units: 'objects', value: '1f' 3310 }, 3311 inner_size: {type: 'scalar', units: 'bytes', value: '2000'}, 3312 size: {type: 'scalar', units: 'bytes', value: '2000'} 3313 } 3314 }, 3315 'v8': { 3316 guid: '777', 3317 attrs: { 3318 objects_count: { 3319 type: 'scalar', units: 'objects', value: '5f' 3320 }, 3321 inner_size: {type: 'scalar', units: 'bytes', value: '5000'}, 3322 size: {type: 'scalar', units: 'bytes', value: '6000'} 3323 } 3324 } 3325 } 3326 } 3327 } 3328 } 3329 ]; 3330 var m = makeModel(events); 3331 var p = m.getProcess(42); 3332 var d = p.memoryDumps[0]; 3333 3334 assert.equal(d.memoryAllocatorDumps.length, 2); 3335 3336 var oilpanRoot = d.getMemoryAllocatorDumpByFullName('oilpan'); 3337 var v8Root = d.getMemoryAllocatorDumpByFullName('v8'); 3338 assert.isDefined(oilpanRoot); 3339 assert.isDefined(v8Root); 3340 assert.include(d.memoryAllocatorDumps, oilpanRoot); 3341 assert.include(d.memoryAllocatorDumps, v8Root); 3342 3343 checkDumpNumericsAndDiagnostics(oilpanRoot, { 3344 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 94), 3345 'size': 24576, 3346 'effective_size': 24576, 3347 'inner_size': 20480 3348 }, {}); 3349 assert.equal(oilpanRoot.children.length, 2); 3350 3351 var oilpanBucket1 = d.getMemoryAllocatorDumpByFullName( 3352 'oilpan/heap2/bucket1'); 3353 assert.isDefined(oilpanBucket1); 3354 assert.equal(oilpanBucket1.fullName, 'oilpan/heap2/bucket1'); 3355 assert.equal(oilpanBucket1.name, 'bucket1'); 3356 checkDumpNumericsAndDiagnostics(oilpanBucket1, { 3357 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 31), 3358 'size': 8192, 3359 'effective_size': 8192, 3360 'inner_size': 8192 3361 }, {}); 3362 assert.equal(oilpanBucket1.children.length, 0); 3363 3364 assert.isDefined(oilpanBucket1.parent); 3365 assert.equal(oilpanBucket1.parent.fullName, 'oilpan/heap2'); 3366 assert.equal(oilpanBucket1.parent.name, 'heap2'); 3367 assert.include(oilpanBucket1.parent.children, oilpanBucket1); 3368 3369 assert.isDefined(oilpanBucket1.parent.parent); 3370 assert.strictEqual(oilpanBucket1.parent.parent, oilpanRoot); 3371 3372 assert.equal(d.totals.residentBytes, 256); 3373 assert.isUndefined(d.totals.peakResidentBytes); 3374 assert.isUndefined(d.totals.arePeakResidentBytesResettable); 3375 assert.isUndefined(d.totals.platformSpecific); 3376 assert.isUndefined(d.mostRecentVmRegions); 3377 }); 3378 3379 test('importMemoryDumps_globalMemoryAllocatorDumps', function() { 3380 var events = [ 3381 { 3382 name: 'a', 3383 pid: 42, 3384 ts: 10, 3385 cat: 'test', 3386 tid: 53, 3387 ph: 'v', 3388 id: '0x0001', 3389 args: { 3390 dumps: { 3391 process_totals: { 3392 resident_set_bytes: '100' 3393 }, 3394 allocators: { 3395 'tile_manager/tile1': { 3396 guid: '21', 3397 attrs: { 3398 objects_count: { 3399 type: 'scalar', units: 'objects', value: '3f' 3400 }, 3401 inner_size: {type: 'scalar', units: 'bytes', value: '3000'}, 3402 size: {type: 'scalar', units: 'bytes', value: '4000'}, 3403 weather: {type: 'string', units: '', value: 'rainy'} 3404 } 3405 }, 3406 'global/shared_bitmap_manager/bitmap2': { 3407 guid: '42', 3408 attrs: { 3409 objects_count: { 3410 type: 'scalar', units: 'objects', value: '1f' 3411 }, 3412 inner_size: {type: 'scalar', units: 'bytes', value: '2000'}, 3413 size: {type: 'scalar', units: 'bytes', value: '2000'}, 3414 weather: {type: 'string', units: '', value: 'sunny'} 3415 } 3416 } 3417 } 3418 } 3419 } 3420 } 3421 ]; 3422 var m = makeModel(events); 3423 var p = m.getProcess(42); 3424 var gmd = m.globalMemoryDumps[0]; 3425 var pmd = p.memoryDumps[0]; 3426 3427 assert.isUndefined(gmd.totals); 3428 assert.equal(pmd.totals.residentBytes, 256); 3429 assert.isUndefined(pmd.totals.peakResidentBytes); 3430 assert.isUndefined(pmd.totals.arePeakResidentBytesResettable); 3431 assert.isUndefined(pmd.totals.platformSpecific); 3432 3433 assert.isUndefined(gmd.mostRecentVmRegions); 3434 assert.isUndefined(pmd.mostRecentVmRegions); 3435 3436 assert.equal(gmd.memoryAllocatorDumps.length, 1); 3437 assert.equal(pmd.memoryAllocatorDumps.length, 1); 3438 3439 // Global memory allocator dumps. 3440 var sharedBitmapManager = gmd.getMemoryAllocatorDumpByFullName( 3441 'shared_bitmap_manager'); 3442 assert.isDefined(sharedBitmapManager); 3443 assert.include(gmd.memoryAllocatorDumps, sharedBitmapManager); 3444 3445 checkDumpNumericsAndDiagnostics(sharedBitmapManager, { 3446 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 31), 3447 'size': 8192, 3448 'effective_size': 8192, 3449 'inner_size': 8192 3450 }, {}); 3451 assert.lengthOf(sharedBitmapManager.children, 1); 3452 3453 var bitmap2 = gmd.getMemoryAllocatorDumpByFullName( 3454 'shared_bitmap_manager/bitmap2'); 3455 assert.isDefined(bitmap2); 3456 assert.include(sharedBitmapManager.children, bitmap2); 3457 assert.strictEqual(bitmap2.parent, sharedBitmapManager); 3458 3459 checkDumpNumericsAndDiagnostics(bitmap2, { 3460 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 31), 3461 'size': 8192, 3462 'effective_size': 8192, 3463 'inner_size': 8192 3464 }, { 'weather': 'sunny' }); 3465 assert.lengthOf(bitmap2.children, 0); 3466 3467 assert.isUndefined(gmd.getMemoryAllocatorDumpByFullName('tile_manager')); 3468 assert.isUndefined( 3469 gmd.getMemoryAllocatorDumpByFullName('tile_manager/tile1')); 3470 3471 // Process memory allocator dumps. 3472 var tileManagerRoot = pmd.getMemoryAllocatorDumpByFullName('tile_manager'); 3473 assert.isDefined(tileManagerRoot); 3474 assert.include(pmd.memoryAllocatorDumps, tileManagerRoot); 3475 assert.isUndefined(tileManagerRoot.parent); 3476 3477 checkDumpNumericsAndDiagnostics(tileManagerRoot, { 3478 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 63), 3479 'size': 16384, 3480 'effective_size': 16384, 3481 'inner_size': 12288 3482 }, {}); 3483 assert.lengthOf(tileManagerRoot.children, 1); 3484 3485 var tile1 = pmd.getMemoryAllocatorDumpByFullName( 3486 'tile_manager/tile1'); 3487 assert.isDefined(tile1); 3488 assert.include(tileManagerRoot.children, tile1); 3489 assert.strictEqual(tile1.parent, tileManagerRoot); 3490 3491 checkDumpNumericsAndDiagnostics(tile1, { 3492 'objects_count': new ScalarNumeric(unitlessNumber_smallerIsBetter, 63), 3493 'size': 16384, 3494 'effective_size': 16384, 3495 'inner_size': 12288 3496 }, { 'weather': 'rainy' }); 3497 assert.lengthOf(tile1.children, 0); 3498 3499 assert.isUndefined( 3500 pmd.getMemoryAllocatorDumpByFullName('shared_bitmap_manager')); 3501 assert.isUndefined( 3502 pmd.getMemoryAllocatorDumpByFullName('shared_bitmap_manager/bitmap2')); 3503 }); 3504 3505 test('importMemoryDumps_memoryAllocatorDumpEdges', function() { 3506 var events = [ 3507 { 3508 name: 'browser', 3509 pid: 42, 3510 ts: 10, 3511 cat: 'test', 3512 tid: 53, 3513 ph: 'v', 3514 id: '0x0001', 3515 args: { 3516 dumps: { 3517 process_totals: { 3518 resident_set_bytes: '100' 3519 }, 3520 allocators: { 3521 'local': { 3522 guid: '3', 3523 attrs: { 3524 mood: {type: 'string', units: '', value: 'very good'} 3525 } 3526 }, 3527 'global/shared': { 3528 guid: '7', 3529 attrs: { 3530 color: {type: 'string', units: '', value: 'blue'} 3531 } 3532 } 3533 }, 3534 allocators_graph: [ 3535 { 3536 source: '3', 3537 target: '7', 3538 type: 'ownership', 3539 importance: 0 3540 } 3541 ] 3542 } 3543 } 3544 }, 3545 { 3546 name: 'renderer', 3547 pid: 43, 3548 ts: 11, 3549 cat: 'test', 3550 tid: 53, 3551 ph: 'v', 3552 id: '0x0001', 3553 args: { 3554 dumps: { 3555 process_totals: { 3556 resident_set_bytes: '200' 3557 }, 3558 allocators: { 3559 'local': { 3560 guid: '4', 3561 attrs: { 3562 length: {type: 'scalar', units: 'bytes', value: '3'} 3563 } 3564 }, 3565 'global/shared': { 3566 guid: '7', 3567 attrs: { 3568 area: {type: 'scalar', units: 'sq ft', value: '9'} 3569 } 3570 } 3571 }, 3572 allocators_graph: [ 3573 { 3574 source: '4', 3575 target: '7', 3576 type: 'ownership', 3577 importance: 1 3578 } 3579 ] 3580 } 3581 } 3582 }, 3583 { 3584 name: 'gpu', 3585 pid: 44, 3586 ts: 10.5, 3587 cat: 'test', 3588 tid: 53, 3589 ph: 'v', 3590 id: '0x0001', 3591 args: { 3592 dumps: { 3593 process_totals: { 3594 resident_set_bytes: '300' 3595 }, 3596 allocators: { 3597 'local1': { 3598 guid: '5', 3599 attrs: { 3600 state: {type: 'string', units: '', value: 'ON'} 3601 } 3602 }, 3603 'local2': { 3604 guid: '6', 3605 attrs: { 3606 temperature: {type: 'scalar', units: 'C', value: '64'} 3607 } 3608 } 3609 }, 3610 allocators_graph: [ 3611 { 3612 source: '5', 3613 target: '7', 3614 type: 'ownership', 3615 importance: -1 3616 }, 3617 { 3618 source: '6', 3619 target: '5', 3620 type: 'ownership', 3621 importance: 1 3622 }, 3623 { 3624 source: '5', 3625 target: '4', 3626 type: 'retention' 3627 } 3628 ] 3629 } 3630 } 3631 } 3632 ]; 3633 var model = makeModel(events); 3634 var browserProcess = model.getProcess(42); 3635 var rendererProcess = model.getProcess(43); 3636 var gpuProcess = model.getProcess(44); 3637 3638 assert.lengthOf(model.globalMemoryDumps, 1); 3639 assert.lengthOf(browserProcess.memoryDumps, 1); 3640 assert.lengthOf(rendererProcess.memoryDumps, 1); 3641 assert.lengthOf(gpuProcess.memoryDumps, 1); 3642 3643 var globalDump = model.globalMemoryDumps[0]; 3644 var browserDump = browserProcess.memoryDumps[0]; 3645 var rendererDump = rendererProcess.memoryDumps[0]; 3646 var gpuDump = gpuProcess.memoryDumps[0]; 3647 3648 // Global memory allocator dump. 3649 assert.lengthOf(globalDump.memoryAllocatorDumps, 1); 3650 3651 var globalDumpShared = globalDump.getMemoryAllocatorDumpByFullName( 3652 'shared'); 3653 assert.isDefined(globalDumpShared); 3654 assert.include(globalDump.memoryAllocatorDumps, globalDumpShared); 3655 checkDumpNumericsAndDiagnostics(globalDumpShared, { 3656 'area': new ScalarNumeric(unitlessNumber_smallerIsBetter, 9) 3657 }, { 'color': 'blue' }); 3658 assert.lengthOf(globalDumpShared.children, 0); 3659 assert.isUndefined(globalDumpShared.parent); 3660 3661 assert.isUndefined(globalDumpShared.owns); 3662 assert.lengthOf(globalDumpShared.ownedBy, 3); 3663 assert.lengthOf(globalDumpShared.retains, 0); 3664 assert.lengthOf(globalDumpShared.retainedBy, 0); 3665 3666 // Browser memory allocator dump. 3667 assert.lengthOf(browserDump.memoryAllocatorDumps, 1); 3668 3669 var browserDumpLocal = browserDump.getMemoryAllocatorDumpByFullName( 3670 'local'); 3671 assert.isDefined(browserDumpLocal); 3672 assert.include(browserDump.memoryAllocatorDumps, browserDumpLocal); 3673 checkDumpNumericsAndDiagnostics(browserDumpLocal, { 3674 'area': new ScalarNumeric(unitlessNumber_smallerIsBetter, 9) 3675 }, { 'color': 'blue', 'mood': 'very good' }); 3676 assert.lengthOf(browserDumpLocal.children, 0); 3677 assert.isUndefined(browserDumpLocal.parent); 3678 3679 assert.isDefined(browserDumpLocal.owns); 3680 assert.lengthOf(browserDumpLocal.ownedBy, 0); 3681 assert.lengthOf(browserDumpLocal.retains, 0); 3682 assert.lengthOf(browserDumpLocal.retainedBy, 0); 3683 3684 var browserDumpLocalOwnsLink = browserDumpLocal.owns; 3685 assert.include(globalDumpShared.ownedBy, browserDumpLocalOwnsLink); 3686 assert.strictEqual(browserDumpLocalOwnsLink.source, browserDumpLocal); 3687 assert.strictEqual(browserDumpLocalOwnsLink.target, globalDumpShared); 3688 assert.equal(browserDumpLocalOwnsLink.importance, 0); 3689 3690 // Renderer memory allocator dump. 3691 assert.lengthOf(rendererDump.memoryAllocatorDumps, 1); 3692 3693 var rendererDumpLocal = rendererDump.getMemoryAllocatorDumpByFullName( 3694 'local'); 3695 assert.isDefined(rendererDumpLocal); 3696 assert.include(rendererDump.memoryAllocatorDumps, rendererDumpLocal); 3697 checkDumpNumericsAndDiagnostics(rendererDumpLocal, { 3698 'area': new ScalarNumeric(unitlessNumber_smallerIsBetter, 9), 3699 'length': 3 3700 }, { 'color': 'blue' }); 3701 assert.lengthOf(rendererDumpLocal.children, 0); 3702 assert.isUndefined(rendererDumpLocal.parent); 3703 3704 assert.isDefined(rendererDumpLocal.owns); 3705 assert.lengthOf(rendererDumpLocal.ownedBy, 0); 3706 assert.lengthOf(rendererDumpLocal.retains, 0); 3707 assert.lengthOf(rendererDumpLocal.retainedBy, 1); 3708 3709 var rendererDumpLocalOwnsLink = rendererDumpLocal.owns; 3710 assert.include(globalDumpShared.ownedBy, rendererDumpLocalOwnsLink); 3711 assert.strictEqual(rendererDumpLocalOwnsLink.source, rendererDumpLocal); 3712 assert.strictEqual(rendererDumpLocalOwnsLink.target, globalDumpShared); 3713 assert.equal(rendererDumpLocalOwnsLink.importance, 1); 3714 3715 // GPU memory allocator dumps. 3716 assert.lengthOf(gpuDump.memoryAllocatorDumps, 2); 3717 3718 var gpuDumpLocal1 = gpuDump.getMemoryAllocatorDumpByFullName('local1'); 3719 assert.isDefined(gpuDumpLocal1); 3720 assert.include(gpuDump.memoryAllocatorDumps, gpuDumpLocal1); 3721 checkDumpNumericsAndDiagnostics(gpuDumpLocal1, { 3722 'area': new ScalarNumeric(unitlessNumber_smallerIsBetter, 9) 3723 }, { 'state': 'ON', 'color': 'blue' }); 3724 assert.lengthOf(gpuDumpLocal1.children, 0); 3725 assert.isUndefined(gpuDumpLocal1.parent); 3726 3727 assert.isDefined(gpuDumpLocal1.owns); 3728 assert.lengthOf(gpuDumpLocal1.ownedBy, 1); 3729 assert.lengthOf(gpuDumpLocal1.retains, 1); 3730 assert.lengthOf(gpuDumpLocal1.retainedBy, 0); 3731 3732 var gpuDumpLocal1OwnsLink = gpuDumpLocal1.owns; 3733 assert.include(globalDumpShared.ownedBy, gpuDumpLocal1OwnsLink); 3734 assert.strictEqual(gpuDumpLocal1OwnsLink.source, gpuDumpLocal1); 3735 assert.strictEqual(gpuDumpLocal1OwnsLink.target, globalDumpShared); 3736 assert.equal(gpuDumpLocal1OwnsLink.importance, -1); 3737 3738 var gpuDumpLocal1RetainsLink = gpuDumpLocal1.retains[0]; 3739 assert.include(rendererDumpLocal.retainedBy, gpuDumpLocal1RetainsLink); 3740 assert.strictEqual(gpuDumpLocal1RetainsLink.source, gpuDumpLocal1); 3741 assert.strictEqual(gpuDumpLocal1RetainsLink.target, rendererDumpLocal); 3742 assert.isUndefined(gpuDumpLocal1RetainsLink.importance); 3743 3744 var gpuDumpLocal2 = gpuDump.getMemoryAllocatorDumpByFullName('local2'); 3745 assert.isDefined(gpuDumpLocal2); 3746 assert.include(gpuDump.memoryAllocatorDumps, gpuDumpLocal2); 3747 checkDumpNumericsAndDiagnostics(gpuDumpLocal2, { 3748 'temperature': new ScalarNumeric(unitlessNumber_smallerIsBetter, 100) 3749 }, {}); 3750 assert.lengthOf(gpuDumpLocal2.children, 0); 3751 assert.isUndefined(gpuDumpLocal2.parent); 3752 3753 assert.isDefined(gpuDumpLocal2.owns); 3754 assert.lengthOf(gpuDumpLocal2.ownedBy, 0); 3755 assert.lengthOf(gpuDumpLocal2.retains, 0); 3756 assert.lengthOf(gpuDumpLocal2.retainedBy, 0); 3757 3758 var gpuDumpLocal2OwnsLink = gpuDumpLocal2.owns; 3759 assert.include(gpuDumpLocal1.ownedBy, gpuDumpLocal2OwnsLink); 3760 assert.strictEqual(gpuDumpLocal2OwnsLink.source, gpuDumpLocal2); 3761 assert.strictEqual(gpuDumpLocal2OwnsLink.target, gpuDumpLocal1); 3762 assert.equal(gpuDumpLocal2OwnsLink.importance, 1); 3763 }); 3764 3765 test('importMemoryDumps_memoryAllocatorDumpsMissingFields', function() { 3766 var events = [ 3767 { 3768 name: 'a', 3769 pid: 42, 3770 ts: 10, 3771 ph: 'v', 3772 id: '0x0001', 3773 args: { 3774 dumps: { 3775 allocators: { 3776 'no_crash': { 3777 /* Missing GUID and attributes. */ 3778 } 3779 } 3780 } 3781 } 3782 } 3783 ]; 3784 var m = makeModel(events); 3785 var p = m.getProcess(42); 3786 var d = p.memoryDumps[0]; 3787 3788 assert.equal(d.memoryAllocatorDumps.length, 1); 3789 var noCrashRoot = d.getMemoryAllocatorDumpByFullName('no_crash'); 3790 assert.lengthOf(noCrashRoot.children, 0); 3791 checkDumpNumericsAndDiagnostics(noCrashRoot, {}, {}); 3792 assert.isUndefined(noCrashRoot.parent); 3793 assert.isUndefined(noCrashRoot.guid); 3794 }); 3795 3796 test('importMemoryDumps_weakMemoryAllocatorDumps', function() { 3797 var events = [ 3798 { 3799 pid: 42, 3800 ts: 10, 3801 ph: 'v', 3802 id: '0x0001', 3803 args: { 3804 dumps: { 3805 allocators: { 3806 // Sinks for ownership edges (to check that the correct ownership 3807 // edges are removed). 3808 'root_sink': { guid: '100', attrs: {} }, 3809 'root_sink/child_sink': { guid: '200', attrs: {} }, 3810 'root_sink/child_sink/descendant_sink': { 3811 guid: '300', attrs: {} 3812 }, 3813 3814 // Note: 'removed' in the name of a dump means that the dump will 3815 // be removed despite being non-weak (strong), e.g. due to one of 3816 // its ancestors being weak. 3817 3818 // All descendants of a weak root dump should be removed. 3819 'weak_root': { guid: '1', attrs: {}, flags: 1 }, 3820 'weak_root/removed_child': { guid: '2', attrs: {} }, 3821 'weak_root/inferred_removed_child/removed_descendant': { 3822 guid: '3', attrs: {}, flags: 0 3823 }, 3824 3825 // A strong root should be kept even if all its descendants are 3826 // weak. 3827 'strong_root': { guid: '4', attrs: {}, flags: 0 }, 3828 'strong_root/weak_child': { guid: '5', attrs: {}, flags: 1 }, 3829 'strong_root/inferred_weak_child/weak_descendant': { 3830 guid: '6', attrs: {}, flags: 1 3831 }, 3832 3833 // All inferred ancestors of a weak descendant should be marked 3834 // weak and, consequently, removed (provided that they don't have 3835 // any non-weak descendants). 3836 'inferred_weak_root/inferred_weak_child/weak_descendant': { 3837 guid: '7', attrs: {}, flags: 1 3838 }, 3839 3840 // An inferred dump should be marked non-weak if it has at least 3841 // one strong descendant. 3842 'inferred_strong_root/child1_weak': { 3843 guid: '8', attrs: {}, flags: 1 3844 }, 3845 'inferred_strong_root/child2_strong': { 3846 guid: '9', attrs: {} 3847 }, 3848 'inferred_strong_root/child3_weak': { 3849 guid: '10', attrs: {}, flags: 1 3850 }, 3851 'inferred_strong_root2/inferred_strong_child/desc1_strong': { 3852 guid: '11', attrs: {} 3853 }, 3854 'inferred_strong_root2/inferred_strong_child/desc2_weak': { 3855 guid: '12', attrs: {}, flags: 1 3856 }, 3857 'inferred_strong_root2/inferred_strong_child/desc3_strong': { 3858 guid: '13', attrs: {} 3859 }, 3860 'inferred_strong_root2/weak_child': { 3861 guid: '14', attrs: {}, flags: 1 3862 }, 3863 3864 // A desdendant dump should be removed if it has a weak ancestor. 3865 'strong_root2': { guid: '15', attrs: {} }, 3866 'strong_root2/weak_child': { guid: '16', attrs: {}, flags: 1 }, 3867 'strong_root2/weak_child/removed_descendant': { 3868 guid: '17', attrs: {} 3869 }, 3870 3871 // Check that "weakness" also propagates across ownership edges. 3872 'removed_root': { guid: '18', attrs: {} }, 3873 'removed_root/removed_child': { 3874 guid: '19', attrs: {} 3875 }, 3876 'inferred_strong_root3/removed_child': { 3877 guid: '20', attrs: {} 3878 }, 3879 }, 3880 allocators_graph: [ 3881 { source: '1', target: '100', type: 'ownership' }, 3882 { source: '2', target: '200', type: 'ownership' }, 3883 { source: '3', target: '300', type: 'ownership' }, 3884 3885 { source: '4', target: '100', type: 'ownership' }, // Kept. 3886 { source: '5', target: '200', type: 'ownership' }, 3887 { source: '6', target: '300', type: 'ownership' }, 3888 3889 { source: '7', target: '300', type: 'ownership' }, 3890 3891 { source: '8', target: '200', type: 'ownership' }, 3892 { source: '9', target: '200', type: 'ownership' }, // Kept. 3893 { source: '10', target: '200', type: 'ownership' }, 3894 { source: '11', target: '300', type: 'ownership' }, // Kept. 3895 { source: '12', target: '300', type: 'ownership' }, 3896 { source: '13', target: '300', type: 'ownership' }, // Kept. 3897 { source: '14', target: '200', type: 'ownership' }, 3898 3899 { source: '15', target: '100', type: 'ownership' }, // Kept. 3900 { source: '16', target: '200', type: 'ownership' }, 3901 { source: '17', target: '300', type: 'ownership' }, 3902 3903 { source: '18', target: '3' /* not a sink */, type: 'ownership' }, 3904 { source: '19', target: '200', type: 'ownership' }, 3905 { source: '20', target: '19' /* not a sink */, type: 'ownership' } 3906 ] 3907 } 3908 } 3909 } 3910 ]; 3911 var m = makeModel(events); 3912 var p = m.getProcess(42); 3913 var d = p.memoryDumps[0]; 3914 var memoryAllocatorDumps = d.memoryAllocatorDumps; 3915 assert.lengthOf(memoryAllocatorDumps, 6); 3916 3917 function checkDump(dump, expectedFullName, expectedGuid, expectedParent, 3918 expectedChildCount, expectedOwnsLink, expectedOwnedByLinkCount) { 3919 assert.strictEqual(dump.fullName, expectedFullName); 3920 assert.strictEqual(dump.guid, expectedGuid); 3921 assert.strictEqual(dump.parent, expectedParent); 3922 assert.lengthOf(dump.children, expectedChildCount); 3923 assert.strictEqual(dump.owns, expectedOwnsLink); 3924 assert.lengthOf(dump.ownedBy, expectedOwnedByLinkCount); 3925 assert.strictEqual( 3926 d.getMemoryAllocatorDumpByFullName(expectedFullName), dump); 3927 } 3928 3929 function checkOwnsLink(ownerDump, expectedTarget) { 3930 assert.strictEqual(ownerDump.owns.source, ownerDump); 3931 assert.strictEqual(ownerDump.owns.target, expectedTarget); 3932 } 3933 3934 // Check root_sink/* dumps. 3935 var rootSink = d.memoryAllocatorDumps[3]; 3936 checkDump(rootSink, 'root_sink', '100', undefined, 1, undefined, 2); 3937 var childSink = rootSink.children[0]; 3938 checkDump(childSink, 'root_sink/child_sink', '200', rootSink, 1, undefined, 3939 1); 3940 var descendantSink = childSink.children[0]; 3941 checkDump(descendantSink, 'root_sink/child_sink/descendant_sink', '300', 3942 childSink, 0, undefined, 2); 3943 3944 // Check strong_root/* dumps. 3945 var strongRoot = d.memoryAllocatorDumps[4]; 3946 checkDump(strongRoot, 'strong_root', '4', undefined, 0, rootSink.ownedBy[0], 3947 0); 3948 3949 // Check inferred_strong_root/* dumps. 3950 var inferredStrongRoot = d.memoryAllocatorDumps[0]; 3951 checkDump(inferredStrongRoot, 'inferred_strong_root', undefined, undefined, 3952 1, undefined, 0); 3953 var child2Strong = inferredStrongRoot.children[0]; 3954 checkDump(child2Strong, 'inferred_strong_root/child2_strong', '9', 3955 inferredStrongRoot, 0, childSink.ownedBy[0], 0); 3956 3957 // Check inferred_strong_root2/* dumps. 3958 var inferredStrongRoot2 = d.memoryAllocatorDumps[1]; 3959 checkDump(inferredStrongRoot2, 'inferred_strong_root2', undefined, 3960 undefined, 1, undefined, 0); 3961 var inferredStrongChild = inferredStrongRoot2.children[0]; 3962 checkDump(inferredStrongChild, 3963 'inferred_strong_root2/inferred_strong_child', undefined, 3964 inferredStrongRoot2, 2, undefined, 0); 3965 var desc1Strong = inferredStrongChild.children[0]; 3966 checkDump(desc1Strong, 3967 'inferred_strong_root2/inferred_strong_child/desc1_strong', '11', 3968 inferredStrongChild, 0, descendantSink.ownedBy[0], 0); 3969 var desc3Strong = inferredStrongChild.children[1]; 3970 checkDump(desc3Strong, 3971 'inferred_strong_root2/inferred_strong_child/desc3_strong', '13', 3972 inferredStrongChild, 0, descendantSink.ownedBy[1], 0); 3973 3974 // Check strong_root2/* dumps. 3975 var strongRoot2 = d.memoryAllocatorDumps[5]; 3976 checkDump(strongRoot2, 'strong_root2', '15', undefined, 0, 3977 rootSink.ownedBy[1], 0); 3978 3979 // Check inferred_strong_root3/* dumps. 3980 var inferredStrongRoot3 = d.memoryAllocatorDumps[2]; 3981 checkDump(inferredStrongRoot3, 'inferred_strong_root3', undefined, 3982 undefined, 0, undefined, 0); 3983 3984 // Check the links. 3985 checkOwnsLink(strongRoot, rootSink); 3986 checkOwnsLink(child2Strong, childSink); 3987 checkOwnsLink(desc1Strong, descendantSink); 3988 checkOwnsLink(desc3Strong, descendantSink); 3989 checkOwnsLink(strongRoot2, rootSink); 3990 3991 // Check that the removed weak dumps are not indexed. 3992 [ 3993 'weak_root', 3994 'weak_root/removed_child', 3995 'weak_root/inferred_removed_child', 3996 'weak_root/inferred_removed_child/removed_descendant', 3997 'strong_root/weak_child', 3998 'strong_root/inferred_weak_child/weak_descendant', 3999 'inferred_weak_root', 4000 'inferred_weak_root/inferred_weak_child', 4001 'inferred_weak_root/inferred_weak_child/weak_descendant', 4002 'inferred_strong_root/child1_weak', 4003 'inferred_strong_root/child3_weak', 4004 'inferred_strong_root2/inferred_strong_child/desc2_weak', 4005 'inferred_strong_root2/weak_child', 4006 'strong_root2/weak_child', 4007 'strong_root2/removed_descendant', 4008 'removed_root', 4009 'removed_root/removed_child', 4010 'inferred_strong_root3/removed_child' 4011 ].forEach(function(fullName) { 4012 assert.isUndefined(d.getMemoryAllocatorDumpByFullName(fullName)); 4013 }); 4014 }); 4015 4016 test('importMemoryDumps_levelsOfDetail', function() { 4017 function checkLevelsOfDetail(rawLevelsOfDetail, expectedGlobalLevelOfDetail, 4018 expectedProcessLevelsOfDetail) { 4019 var events = []; 4020 rawLevelsOfDetail.forEach(function(rawProcessLevelsOfDetail, pid) { 4021 rawProcessLevelsOfDetail.forEach(function(rawComposableLevelOfDetail) { 4022 var dumps = {}; 4023 if (rawComposableLevelOfDetail !== undefined) 4024 dumps.level_of_detail = rawComposableLevelOfDetail; 4025 events.push({ 4026 name: 'process_' + pid, 4027 pid: pid, 4028 ts: 10, 4029 ph: 'v', 4030 id: '0x0001', 4031 args: { 4032 dumps: dumps 4033 } 4034 }); 4035 }); 4036 }); 4037 var model = makeModel(events); 4038 4039 // Check GlobalMemoryDump level of detail. 4040 assert.lengthOf(model.globalMemoryDumps, 1); 4041 assert.strictEqual(model.globalMemoryDumps[0].levelOfDetail, 4042 expectedGlobalLevelOfDetail); 4043 4044 // Check ProcessMemoryDumps levels of detail. 4045 assert.lengthOf(Object.keys(model.processes), 4046 expectedProcessLevelsOfDetail.length); 4047 for (var i = 0; i < expectedProcessLevelsOfDetail.length; i++) { 4048 var process = model.getProcess(i); 4049 assert.lengthOf(process.memoryDumps, 1); 4050 assert.strictEqual(process.memoryDumps[0].levelOfDetail, 4051 expectedProcessLevelsOfDetail[i]); 4052 } 4053 } 4054 4055 // Well-formed trace events. 4056 checkLevelsOfDetail([[undefined]], undefined, [undefined]); 4057 checkLevelsOfDetail([['light'], ['light']], 'light', ['light', 'light']); 4058 checkLevelsOfDetail( 4059 [ 4060 ['detailed', 'detailed'], 4061 ['detailed'], 4062 ['detailed', 'detailed', 'detailed'] 4063 ], 4064 'detailed', 4065 ['detailed', 'detailed', 'detailed']); 4066 4067 // Not so well-formed trace events. 4068 checkLevelsOfDetail( 4069 [['light'], [undefined], ['detailed'], ['light']], 4070 'detailed', 4071 ['light', undefined, 'detailed', 'light']); 4072 checkLevelsOfDetail( 4073 [['light', 'detailed'], [undefined], ['light', undefined]], 4074 'detailed', 4075 ['detailed', undefined, 'light']); 4076 checkLevelsOfDetail( 4077 [['invalid', 'light'], ['invalid']], 4078 'light', 4079 ['light', undefined]); 4080 }); 4081 4082 test('importMemoryDumps_heapDumps_oldFormat', function() { 4083 var events = [ // Intentionally shuffled. 4084 { 4085 pid: 21, 4086 ts: 9, 4087 ph: 'v', 4088 id: '0123', 4089 args: { 4090 dumps: { 4091 heaps: { 4092 partition_alloc: { 4093 entries: [ 4094 { size: '1000' }, 4095 { bt: '0', size: 'abc' } 4096 ] 4097 } 4098 } 4099 } 4100 } 4101 }, 4102 { 4103 pid: 42, 4104 ph: 'M', 4105 name: 'stackFrames', 4106 args: { 4107 stackFrames: { 4108 '0': { name: 'MessageLoop::RunTask' }, 4109 '1': { name: 'TimerBase::run', parent: '0' }, 4110 'TWO': { name: 'ScheduledAction::execute', 'parent': '1' }, 4111 '3': { name: 'FunctionCall', parent: 'TWO' }, 4112 '4': { name: 'UpdateLayoutTree', parent: '1' }, 4113 '5': { name: 'MessageLoop::JogTask' } 4114 } 4115 } 4116 }, 4117 { 4118 pid: 42, 4119 ph: 'M', 4120 name: 'typeNames', 4121 args: { 4122 typeNames: { 4123 // GCC. 4124 '22': '[unknown]', 4125 '23': 'testing::ManuallyAnnotatedMockClass', 4126 '24': 'const char* WTF::getStringWithTypeName() [with T = ' + 4127 'blink::Event]', 4128 '25': 'blink::ContextLifecycleObserver*', 4129 '26': 'const char* WTF::getStringWithTypeName() [with T = ' + 4130 'blink::WebFrame*]' 4131 } 4132 } 4133 }, 4134 { 4135 pid: 42, 4136 ts: 10, 4137 ph: 'v', 4138 id: '0123', 4139 args: { 4140 dumps: { 4141 process_totals: { 4142 resident_set_bytes: '0' 4143 }, 4144 heaps: { 4145 partition_alloc: { 4146 entries: [ 4147 { type: '24', size: '2e6fc8' }, 4148 { size: '5cdf91' }, 4149 { type: '25', size: '1737e4' }, 4150 { bt: '', size: '5b6cd6' }, 4151 { bt: '4', size: '18f0' }, 4152 { bt: '3', size: 'e3a8' } 4153 ] 4154 }, 4155 malloc: { 4156 entries: [ 4157 { size: '789' }, 4158 { bt: '0', size: '123' }, 4159 { bt: '5', size: '456' }, 4160 { type: '25', size: 'cd' } 4161 ] 4162 } 4163 } 4164 } 4165 } 4166 }, 4167 { 4168 pid: 21, 4169 ph: 'M', 4170 name: 'stackFrames', 4171 args: { 4172 stackFrames: { 4173 // Intentionally in reverse order. 4174 '0': { name: 'FrameView::layout', parent: '1' }, 4175 '1': { name: 'MessageLoop::RunTask' } 4176 } 4177 } 4178 }, 4179 { 4180 pid: 21, 4181 ts: 12, 4182 ph: 'v', 4183 id: '0987', 4184 args: { 4185 dumps: { 4186 heaps: { 4187 partition_alloc: { 4188 entries: [ 4189 { size: '2000' }, 4190 { bt: '0', size: 'def' } 4191 ] 4192 } 4193 } 4194 } 4195 } 4196 } 4197 ]; 4198 var m = makeModel(events); 4199 var p1 = m.getProcess(21); 4200 var p2 = m.getProcess(42); 4201 assert.lengthOf(m.globalMemoryDumps, 2); 4202 assert.lengthOf(p1.memoryDumps, 2); 4203 assert.lengthOf(p2.memoryDumps, 1); 4204 4205 // Stack frames. 4206 assert.deepEqual( 4207 tr.b.mapItems(m.stackFrames, function(id, f) { return f.title }), 4208 { 4209 'p21:0': 'FrameView::layout', 4210 'p21:0:self': '<self>', 4211 'p21:1': 'MessageLoop::RunTask', 4212 'p42::self': '<self>', 4213 'p42:0': 'MessageLoop::RunTask', 4214 'p42:0:self': '<self>', 4215 'p42:1': 'TimerBase::run', 4216 'p42:TWO': 'ScheduledAction::execute', 4217 'p42:3': 'FunctionCall', 4218 'p42:3:self': '<self>', 4219 'p42:4': 'UpdateLayoutTree', 4220 'p42:4:self': '<self>', 4221 'p42:5': 'MessageLoop::JogTask', 4222 'p42:5:self': '<self>' 4223 }); 4224 4225 // 1. Process 21, first dump. 4226 var pmd1 = p1.memoryDumps[0]; 4227 var hds1 = pmd1.heapDumps; 4228 assert.sameMembers(Object.keys(hds1), ['partition_alloc']); 4229 4230 var partitionAllocDump1 = hds1['partition_alloc']; 4231 assert.strictEqual(partitionAllocDump1.processMemoryDump, pmd1); 4232 assert.equal(partitionAllocDump1.allocatorName, 'partition_alloc'); 4233 var partitionAllocEntries1 = partitionAllocDump1.entries; 4234 assert.lengthOf(partitionAllocEntries1, 2); 4235 checkHeapEntry(partitionAllocEntries1[0], partitionAllocDump1, 4096, 4236 undefined /* root */, undefined /* sum over all types */); 4237 checkHeapEntry(partitionAllocEntries1[1], partitionAllocDump1, 2748, 4238 ['<self>', 'FrameView::layout', 'MessageLoop::RunTask']); 4239 4240 // 2. Process 21, second dump. 4241 var pmd2 = p1.memoryDumps[1]; 4242 var hds2 = pmd2.heapDumps; 4243 assert.sameMembers(Object.keys(hds2), ['partition_alloc']); 4244 4245 var partitionAllocDump2 = hds2['partition_alloc']; 4246 assert.strictEqual(partitionAllocDump2.processMemoryDump, pmd2); 4247 assert.equal(partitionAllocDump2.allocatorName, 'partition_alloc'); 4248 var partitionAllocEntries2 = partitionAllocDump2.entries; 4249 assert.lengthOf(partitionAllocEntries2, 2); 4250 checkHeapEntry(partitionAllocEntries2[0], partitionAllocDump2, 8192, 4251 undefined /* root */, undefined /* sum over all types */); 4252 checkHeapEntry(partitionAllocEntries2[1], partitionAllocDump2, 3567, 4253 ['<self>', 'FrameView::layout', 'MessageLoop::RunTask'], 4254 undefined /* sum over all types */); 4255 4256 // All heap dumps in Process 21 should use the same stack frames. 4257 assert.strictEqual( 4258 getFrame(partitionAllocEntries1[1], 0), 4259 getFrame(partitionAllocEntries2[1], 0)); 4260 4261 // 3. Process 42. 4262 var pmd3 = p2.memoryDumps[0]; 4263 var hds3 = pmd3.heapDumps; 4264 assert.sameMembers(Object.keys(hds3), ['partition_alloc', 'malloc']); 4265 4266 var partitionAllocDump3 = hds3['partition_alloc']; 4267 assert.strictEqual(partitionAllocDump3.processMemoryDump, pmd3); 4268 assert.equal(partitionAllocDump3.allocatorName, 'partition_alloc'); 4269 var partitionAllocEntries3 = partitionAllocDump3.entries; 4270 assert.lengthOf(partitionAllocEntries3, 6); 4271 checkHeapEntry(partitionAllocEntries3[0], partitionAllocDump3, 3043272, 4272 undefined /* root */, 'blink::Event'); 4273 checkHeapEntry(partitionAllocEntries3[1], partitionAllocDump3, 6086545, 4274 undefined /* root */, undefined /* sum over all types */); 4275 checkHeapEntry(partitionAllocEntries3[2], partitionAllocDump3, 1521636, 4276 undefined /* root */, 'blink::ContextLifecycleObserver*'); 4277 checkHeapEntry(partitionAllocEntries3[3], partitionAllocDump3, 5991638, 4278 ['<self>'], undefined /* sum over all types */); 4279 checkHeapEntry(partitionAllocEntries3[4], partitionAllocDump3, 6384, 4280 ['<self>', 'UpdateLayoutTree', 'TimerBase::run', 4281 'MessageLoop::RunTask'], undefined /* sum over all types */); 4282 checkHeapEntry(partitionAllocEntries3[5], partitionAllocDump3, 58280, 4283 ['<self>', 'FunctionCall', 'ScheduledAction::execute', 'TimerBase::run', 4284 'MessageLoop::RunTask'], undefined /* sum over all types */); 4285 4286 var mallocDump3 = hds3['malloc']; 4287 assert.strictEqual(mallocDump3.processMemoryDump, pmd3); 4288 assert.equal(mallocDump3.allocatorName, 'malloc'); 4289 var mallocEntries3 = mallocDump3.entries; 4290 assert.lengthOf(mallocEntries3, 4); 4291 checkHeapEntry(mallocEntries3[0], mallocDump3, 1929, undefined /* root */, 4292 undefined /* sum over all types */); 4293 checkHeapEntry(mallocEntries3[1], mallocDump3, 291, 4294 ['<self>', 'MessageLoop::RunTask'], undefined /* sum over all types */); 4295 checkHeapEntry(mallocEntries3[2], mallocDump3, 1110, 4296 ['<self>', 'MessageLoop::JogTask'], undefined /* sum over all types */); 4297 checkHeapEntry(mallocEntries3[3], mallocDump3, 205, undefined /* root */, 4298 'blink::ContextLifecycleObserver*'); 4299 4300 // All heap dumps in Process 42 should use the same stack frames. 4301 assert.strictEqual( 4302 getFrame(partitionAllocEntries3[5], 3), 4303 getFrame(partitionAllocEntries3[4], 2)); 4304 assert.strictEqual( 4305 getFrame(mallocEntries3[1], 1), 4306 getFrame(partitionAllocEntries3[4], 3)); 4307 }); 4308 4309 test('importMemoryDumps_heapDumps_newFormat', function() { 4310 var events = [ // Intentionally shuffled. 4311 { 4312 pid: 21, 4313 ts: 9, 4314 ph: 'v', 4315 id: '0123', 4316 args: { 4317 dumps: { 4318 heaps: { 4319 partition_alloc: { 4320 entries: [ 4321 { bt: '', type: '25', size: '1000' }, 4322 { bt: 'A', size: 'abc' } 4323 ] 4324 } 4325 } 4326 } 4327 } 4328 }, 4329 { 4330 pid: 42, 4331 ph: 'M', 4332 name: 'stackFrames', 4333 args: { 4334 stackFrames: { 4335 '-1': { name: '<self>' }, 4336 '0': { name: 'MessageLoop::RunTask' }, 4337 '0.5': { name: '<self>', parent: '0' }, 4338 '1': { name: 'TimerBase::run', parent: '0' }, 4339 'TWO': { name: 'ScheduledAction::execute', 'parent': '1' }, 4340 '2.72': { name: '<self>', 'parent': 'TWO' }, 4341 '3': { name: 'FunctionCall', parent: 'TWO' }, 4342 '\u03C0': { name: '<self>', parent: '3' }, 4343 '4': { name: 'UpdateLayoutTree', parent: '1' }, 4344 'FOUR-AND-A-BIT': { name: '<self>', parent: '4' }, 4345 '5': { name: 'MessageLoop::JogTask' }, 4346 'NaN': { name: '<self>', parent: '5' } 4347 } 4348 } 4349 }, 4350 { 4351 pid: 42, 4352 ph: 'M', 4353 name: 'typeNames', 4354 args: { 4355 typeNames: { 4356 // Clang. 4357 '22': '[unknown]', 4358 '23': 'testing::ManuallyAnnotatedMockClass', 4359 '24': 'const char *WTF::getStringWithTypeName() [T = ' + 4360 'blink::Event]', 4361 '25': 'blink::ContextLifecycleObserver *', 4362 '26': 'const char *WTF::getStringWithTypeName() [T = ' + 4363 'blink::WebFrame *]' 4364 } 4365 } 4366 }, 4367 { 4368 pid: 42, 4369 ts: 10, 4370 ph: 'v', 4371 id: '0123', 4372 args: { 4373 dumps: { 4374 process_totals: { 4375 resident_set_bytes: '0' 4376 }, 4377 heaps: { 4378 partition_alloc: { 4379 entries: [ 4380 { bt: '' /* root */, size: '5cdf91' }, 4381 { bt: '' /* root */, type: '24', size: '2e6fc8' }, 4382 { bt: '' /* root */, type: '25', size: '1737e4' }, 4383 { bt: '-1', type: '22', size: '5b6cd6' }, 4384 { bt: 'FOUR-AND-A-BIT', size: '18f0' }, 4385 { bt: 'FOUR-AND-A-BIT', type: '26', size: 'c78' }, 4386 { bt: '\u03C0', size: 'e3a8' } 4387 ] 4388 }, 4389 malloc: { 4390 entries: [ 4391 { bt: '', size: '789' }, 4392 { bt: '0.5', size: '123' }, 4393 { bt: 'NaN', size: '456' }, 4394 { bt: '3', type: '25', size: 'cd' } 4395 ] 4396 } 4397 } 4398 } 4399 } 4400 }, 4401 { 4402 pid: 21, 4403 ph: 'M', 4404 name: 'stackFrames', 4405 args: { 4406 stackFrames: { 4407 // Intentionally in reverse order. 4408 'A': { name: '<self>', parent: '0' }, 4409 '0': { name: 'FrameView::layout', parent: '1' }, 4410 '1': { name: 'MessageLoop::RunTask' } 4411 } 4412 } 4413 }, 4414 { 4415 pid: 21, 4416 ts: 12, 4417 ph: 'v', 4418 id: '0987', 4419 args: { 4420 dumps: { 4421 heaps: { 4422 winheap: { 4423 entries: [] // Intentionally empty. 4424 }, 4425 partition_alloc: { 4426 entries: [ 4427 { bt: '', size: '2000' }, 4428 { bt: 'A', type: '25', size: 'def' }, 4429 { bt: '3' /* invalid */, size: 'aaa' }, 4430 { bt: 'A', type: '24' /* invalid */, size: 'bbb' }, 4431 { bt: '0', size: 'fff' } 4432 ] 4433 } 4434 } 4435 } 4436 } 4437 }, 4438 { 4439 pid: 21, 4440 ph: 'M', 4441 name: 'typeNames', 4442 args: { 4443 typeNames: { 4444 // Microsoft Visual C++. 4445 '25': 'const char *__cdecl WTF::getStringWithTypeName<class ' + 4446 'v8::FunctionCallbackInfo<class v8::Value>>(void)' 4447 } 4448 } 4449 }, 4450 { 4451 pid: 63, 4452 ph: 'M', 4453 name: 'stackFrames', 4454 args: { 4455 stackFrames: {} // Intentionally empty. 4456 } 4457 }, 4458 { 4459 pid: 63, 4460 ph: 'M', 4461 name: 'typeNames', 4462 args: { 4463 typeNames: {} // Intentionally empty. 4464 } 4465 }, 4466 { 4467 pid: 63, 4468 ts: 13, 4469 ph: 'v', 4470 id: '0987', 4471 args: { 4472 dumps: { 4473 heaps: { 4474 winheap: { 4475 entries: [ 4476 { bt: '', size: '10000' } 4477 ] 4478 } 4479 } 4480 } 4481 } 4482 }, 4483 { 4484 pid: 84, 4485 ph: 'M', 4486 name: 'stackFrames', 4487 args: { 4488 stackFrames: { 4489 '5': { name: 'MessageLoop::WalkTask' } 4490 } 4491 } 4492 }, 4493 { 4494 pid: 84, 4495 ph: 'M', 4496 name: 'typeNames', 4497 args: { 4498 typeNames: { 4499 '0': '[unknown]', 4500 '1': 'base::All', 4501 '3': 'content::Manually', 4502 '4': 'net::Annotated' 4503 } 4504 } 4505 }, 4506 { 4507 pid: 84, 4508 ts: 14, 4509 ph: 'v', 4510 id: '0987', 4511 args: { 4512 dumps: { 4513 heaps: { 4514 malloc: { 4515 entries: [ 4516 { bt: '5', type: '3', size: 'abcd' } 4517 ] 4518 } 4519 } 4520 } 4521 } 4522 } 4523 ]; 4524 var m = makeModel(events); 4525 var p1 = m.getProcess(21); 4526 var p2 = m.getProcess(42); 4527 var p3 = m.getProcess(63); 4528 var p4 = m.getProcess(84); 4529 assert.lengthOf(m.globalMemoryDumps, 2); 4530 assert.lengthOf(p1.memoryDumps, 2); 4531 assert.lengthOf(p2.memoryDumps, 1); 4532 assert.lengthOf(p3.memoryDumps, 1); 4533 assert.lengthOf(p4.memoryDumps, 1); 4534 4535 // Stack frames. 4536 assert.deepEqual( 4537 tr.b.mapItems(m.stackFrames, function(id, f) { return f.title }), 4538 { 4539 'p21:0': 'FrameView::layout', 4540 'p21:A': '<self>', 4541 'p21:1': 'MessageLoop::RunTask', 4542 'p42:-1': '<self>', 4543 'p42:0': 'MessageLoop::RunTask', 4544 'p42:0.5': '<self>', 4545 'p42:1': 'TimerBase::run', 4546 'p42:TWO': 'ScheduledAction::execute', 4547 'p42:2.72': '<self>', 4548 'p42:3': 'FunctionCall', 4549 'p42:\u03C0': '<self>', 4550 'p42:4': 'UpdateLayoutTree', 4551 'p42:FOUR-AND-A-BIT': '<self>', 4552 'p42:5': 'MessageLoop::JogTask', 4553 'p42:NaN': '<self>', 4554 'p84:5': 'MessageLoop::WalkTask' 4555 }); 4556 4557 // 1. Process 21, first dump. 4558 var pmd1 = p1.memoryDumps[0]; 4559 var hds1 = pmd1.heapDumps; 4560 assert.sameMembers(Object.keys(hds1), ['partition_alloc']); 4561 4562 var partitionAllocDump1 = hds1['partition_alloc']; 4563 assert.strictEqual(partitionAllocDump1.processMemoryDump, pmd1); 4564 assert.equal(partitionAllocDump1.allocatorName, 'partition_alloc'); 4565 var partitionAllocEntries1 = partitionAllocDump1.entries; 4566 assert.lengthOf(partitionAllocEntries1, 2); 4567 checkHeapEntry(partitionAllocEntries1[0], partitionAllocDump1, 4096, 4568 undefined /* root */, 4569 'class v8::FunctionCallbackInfo<class v8::Value>'); 4570 checkHeapEntry(partitionAllocEntries1[1], partitionAllocDump1, 2748, 4571 ['<self>', 'FrameView::layout', 'MessageLoop::RunTask'], 4572 undefined /* sum over all types */); 4573 4574 // 2. Process 21, second dump. 4575 var pmd2 = p1.memoryDumps[1]; 4576 var hds2 = pmd2.heapDumps; 4577 assert.sameMembers(Object.keys(hds2), ['partition_alloc']); 4578 4579 var partitionAllocDump2 = hds2['partition_alloc']; 4580 assert.strictEqual(partitionAllocDump2.processMemoryDump, pmd2); 4581 assert.equal(partitionAllocDump2.allocatorName, 'partition_alloc'); 4582 var partitionAllocEntries2 = partitionAllocDump2.entries; 4583 assert.lengthOf(partitionAllocEntries2, 3); 4584 checkHeapEntry(partitionAllocEntries2[0], partitionAllocDump2, 8192, 4585 undefined /* root */, undefined /* sum over all types */); 4586 checkHeapEntry(partitionAllocEntries2[1], partitionAllocDump2, 3567, 4587 ['<self>', 'FrameView::layout', 'MessageLoop::RunTask'], 4588 'class v8::FunctionCallbackInfo<class v8::Value>'); 4589 checkHeapEntry(partitionAllocEntries2[2], partitionAllocDump2, 4095, 4590 ['FrameView::layout', 'MessageLoop::RunTask'], 4591 undefined /* sum over all types */); 4592 4593 // All heap dumps in Process 21 should use the same stack frames. 4594 assert.strictEqual( 4595 getFrame(partitionAllocEntries1[1], 0), 4596 getFrame(partitionAllocEntries2[1], 0)); 4597 assert.strictEqual( 4598 getFrame(partitionAllocEntries2[2], 0), 4599 getFrame(partitionAllocEntries2[1], 1)); 4600 4601 // 3. Process 42. 4602 var pmd3 = p2.memoryDumps[0]; 4603 var hds3 = pmd3.heapDumps; 4604 assert.sameMembers(Object.keys(hds3), ['partition_alloc', 'malloc']); 4605 4606 var partitionAllocDump3 = hds3['partition_alloc']; 4607 assert.strictEqual(partitionAllocDump3.processMemoryDump, pmd3); 4608 assert.equal(partitionAllocDump3.allocatorName, 'partition_alloc'); 4609 var partitionAllocEntries3 = partitionAllocDump3.entries; 4610 assert.lengthOf(partitionAllocEntries3, 7); 4611 checkHeapEntry(partitionAllocEntries3[0], partitionAllocDump3, 6086545, 4612 undefined /* root */, undefined /* sum over all types */); 4613 checkHeapEntry(partitionAllocEntries3[1], partitionAllocDump3, 3043272, 4614 undefined /* root */, 'blink::Event'); 4615 checkHeapEntry(partitionAllocEntries3[2], partitionAllocDump3, 1521636, 4616 undefined /* root */, 'blink::ContextLifecycleObserver *'); 4617 checkHeapEntry(partitionAllocEntries3[3], partitionAllocDump3, 5991638, 4618 ['<self>'], '[unknown]'); 4619 checkHeapEntry(partitionAllocEntries3[4], partitionAllocDump3, 6384, 4620 ['<self>', 'UpdateLayoutTree', 'TimerBase::run', 4621 'MessageLoop::RunTask'], undefined /* sum over all types */); 4622 checkHeapEntry(partitionAllocEntries3[5], partitionAllocDump3, 3192, 4623 ['<self>', 'UpdateLayoutTree', 'TimerBase::run', 4624 'MessageLoop::RunTask'], 'blink::WebFrame *'); 4625 checkHeapEntry(partitionAllocEntries3[6], partitionAllocDump3, 58280, 4626 ['<self>', 'FunctionCall', 'ScheduledAction::execute', 'TimerBase::run', 4627 'MessageLoop::RunTask'], undefined /* sum over all types */); 4628 4629 var mallocDump3 = hds3['malloc']; 4630 assert.strictEqual(mallocDump3.processMemoryDump, pmd3); 4631 assert.equal(mallocDump3.allocatorName, 'malloc'); 4632 var mallocEntries3 = mallocDump3.entries; 4633 assert.lengthOf(mallocEntries3, 4); 4634 checkHeapEntry(mallocEntries3[0], mallocDump3, 1929, undefined /* root */, 4635 undefined /* sum over all types */); 4636 checkHeapEntry(mallocEntries3[1], mallocDump3, 291, 4637 ['<self>', 'MessageLoop::RunTask'], undefined /* sum over all types */); 4638 checkHeapEntry(mallocEntries3[2], mallocDump3, 1110, 4639 ['<self>', 'MessageLoop::JogTask'], undefined /* sum over all types */); 4640 checkHeapEntry(mallocEntries3[3], mallocDump3, 205, 4641 ['FunctionCall', 'ScheduledAction::execute', 'TimerBase::run', 4642 'MessageLoop::RunTask'], 'blink::ContextLifecycleObserver *'); 4643 4644 // All heap dumps in Process 42 should use the same stack frames. 4645 assert.strictEqual( 4646 getFrame(partitionAllocEntries3[5], 0), 4647 getFrame(partitionAllocEntries3[4], 0)); 4648 assert.strictEqual( 4649 getFrame(partitionAllocEntries3[6], 3), 4650 getFrame(partitionAllocEntries3[4], 2)); 4651 assert.strictEqual( 4652 getFrame(mallocEntries3[1], 1), 4653 getFrame(partitionAllocEntries3[4], 3)); 4654 assert.strictEqual( 4655 getFrame(mallocEntries3[3], 0), 4656 getFrame(partitionAllocEntries3[6], 1)); 4657 4658 // 4. Process 63. 4659 var pmd4 = p3.memoryDumps[0]; 4660 var hds4 = pmd4.heapDumps; 4661 assert.sameMembers(Object.keys(hds4), ['winheap']); 4662 4663 var winheapDump = hds4['winheap']; 4664 assert.strictEqual(winheapDump.processMemoryDump, pmd4); 4665 assert.equal(winheapDump.allocatorName, 'winheap'); 4666 var winheapEntries = winheapDump.entries; 4667 assert.lengthOf(winheapEntries, 1); 4668 checkHeapEntry(winheapEntries[0], winheapDump, 65536, 4669 undefined /* root */, undefined /* sum over all types */); 4670 4671 // 5. Process 84. 4672 var pmd5 = p4.memoryDumps[0]; 4673 var hds5 = pmd5.heapDumps; 4674 assert.sameMembers(Object.keys(hds5), ['malloc']); 4675 4676 var mallocDump4 = hds5['malloc']; 4677 assert.strictEqual(mallocDump4.processMemoryDump, pmd5); 4678 assert.equal(mallocDump4.allocatorName, 'malloc'); 4679 var mallocEntries4 = mallocDump4.entries; 4680 assert.lengthOf(mallocEntries4, 1); 4681 checkHeapEntry(mallocEntries4[0], mallocDump4, 43981, 4682 ['MessageLoop::WalkTask'], 'content::Manually'); 4683 }); 4684 4685 test('importMemoryDumps_composableDumps', function() { 4686 // Split PMD1 over multiple PMD trace events, all of which should be merged 4687 // by the importer. Also inject some PMD trace events with different PIDs 4688 // or dump IDs, which should *not* be merged with the rest. 4689 var events = [ 4690 { // Heap dumps. 4691 pid: 42, 4692 ts: 10000, 4693 ph: 'v', 4694 id: '0x0001', 4695 args: { 4696 dumps: { 4697 level_of_detail: 'light', 4698 heaps: { 4699 partition_alloc: { 4700 entries: [ 4701 { bt: '99', type: '888', size: '500' } 4702 ] 4703 } 4704 } 4705 } 4706 } 4707 }, 4708 { // PMD2 with a different dump id (should not be merged). 4709 pid: 42, 4710 ts: 10003, // Same PID, so it will end up in the same process. 4711 ph: 'v', 4712 id: '0x0002', 4713 args: { 4714 dumps: { 4715 level_of_detail: 'detailed', 4716 allocators: { 4717 'local1': { 4718 guid: '3', 4719 attrs: { 4720 A: {type: 'scalar', units: 'bytes', value: '0xBAD'} 4721 } 4722 }, 4723 'global/shared1': { 4724 guid: '4', 4725 attrs: { 4726 A: {type: 'string', units: '', value: 'brown'} 4727 } 4728 } 4729 }, 4730 allocators_graph: [ 4731 { 4732 source: '4', 4733 target: '3', 4734 type: 'ownership' 4735 } 4736 ] 4737 } 4738 } 4739 }, 4740 { // Stack frames (required for heap dumps). 4741 pid: 42, 4742 ph: 'M', 4743 name: 'stackFrames', 4744 args: { 4745 stackFrames: { 4746 '99': { name: 'MessageLoop::RunTask' } 4747 } 4748 } 4749 }, 4750 { // Allocator dumps. 4751 pid: 42, 4752 ts: 10001, 4753 ph: 'v', 4754 id: '0x0001', 4755 args: { 4756 dumps: { 4757 level_of_detail: 'light', 4758 allocators: { 4759 'local1': { 4760 guid: '3', 4761 attrs: { 4762 A: {type: 'string', units: '', value: 'blue'} 4763 } 4764 }, 4765 'global/shared1': { 4766 guid: '7', 4767 attrs: { 4768 A: {type: 'string', units: '', value: 'purple'} 4769 } 4770 }, 4771 'global/shared2': { 4772 guid: '8', 4773 attrs: { 4774 A: {type: 'string', units: '', value: 'cyan'} 4775 } 4776 } 4777 } 4778 } 4779 } 4780 }, 4781 { // PMD3 with a different PID (should not be merged). 4782 pid: 68, 4783 ts: 9999, 4784 ph: 'v', 4785 id: '0x0001', // Same dump ID, so it will end up in the same GMD. 4786 args: { 4787 dumps: { 4788 process_mmaps: { 4789 vm_regions: [ 4790 { 4791 sa: '350', 4792 sz: '250', 4793 pf: 5, 4794 mf: '/dev/ashmem/dalvik', 4795 bs: { 4796 pd: 'cd' 4797 } 4798 } 4799 ] 4800 } 4801 } 4802 } 4803 }, 4804 { // VM regions. 4805 pid: 42, 4806 ts: 10005, 4807 ph: 'v', 4808 id: '0x0001', 4809 args: { 4810 dumps: { 4811 level_of_detail: 'light', 4812 process_mmaps: { 4813 vm_regions: [ 4814 { 4815 sa: 'f0', 4816 sz: '150', 4817 pf: 6, 4818 mf: '[stack:20310]', 4819 bs: { 4820 pss: '9e' 4821 } 4822 } 4823 ] 4824 } 4825 } 4826 } 4827 }, 4828 { // Totals. 4829 pid: 42, 4830 ts: 10003, 4831 ph: 'v', 4832 id: '0x0001', 4833 args: { 4834 dumps: { 4835 level_of_detail: 'light', 4836 process_totals: { 4837 resident_set_bytes: '100', 4838 private_bytes: '80' // OS-specific total. 4839 } 4840 } 4841 } 4842 }, 4843 { // Allocator dump edges. 4844 pid: 42, 4845 ts: 10004, 4846 ph: 'v', 4847 id: '0x0001', 4848 args: { 4849 dumps: { 4850 level_of_detail: 'light', 4851 allocators_graph: [ 4852 { 4853 source: '4', 4854 target: '8', 4855 type: 'retention' 4856 } 4857 ] 4858 } 4859 } 4860 }, 4861 { // Object type names (required for heap dumps). 4862 pid: 42, 4863 ph: 'M', 4864 name: 'typeNames', 4865 args: { 4866 typeNames: { 4867 // GCC. 4868 '888': 'const char* WTF::getStringWithTypeName() [with T = ' + 4869 'cc::SurfaceFactory]' 4870 } 4871 } 4872 }, 4873 { // Allocator dumps and dump edges (should be merged). 4874 pid: 42, 4875 ts: 10002, 4876 ph: 'v', 4877 id: '0x0001', 4878 args: { 4879 dumps: { 4880 level_of_detail: 'light', 4881 allocators: { 4882 'local1': { 4883 guid: '3', 4884 attrs: { 4885 B: {type: 'string', units: '', value: 'red'} 4886 } 4887 }, 4888 'local2': { 4889 guid: '4', 4890 attrs: { 4891 B: {type: 'string', units: '', value: 'yellow'} 4892 } 4893 }, 4894 'global/shared1': { 4895 guid: '7', 4896 attrs: { 4897 B: {type: 'string', units: '', value: 'green'} 4898 } 4899 } 4900 }, 4901 allocators_graph: [ 4902 { 4903 source: '3', 4904 target: '7', 4905 type: 'ownership', 4906 importance: 1 4907 } 4908 ] 4909 } 4910 } 4911 } 4912 ]; 4913 var m = makeModel(events, false); 4914 4915 function checkDumpTime(dump, expectedStart, expectedDuration) { 4916 assert.closeTo(dump.start, expectedStart / 1000, 1e-5); 4917 assert.closeTo(dump.duration, expectedDuration / 1000, 1e-5); 4918 } 4919 4920 function checkLinkCounts(allocatorDump, expectedHasOwns, 4921 expectedOwnedByCount, expectedRetainsCount, expectedRetainedByCount) { 4922 assert.strictEqual(allocatorDump.owns !== undefined, expectedHasOwns); 4923 assert.lengthOf(allocatorDump.ownedBy, expectedOwnedByCount); 4924 assert.lengthOf(allocatorDump.retains, expectedRetainsCount); 4925 assert.lengthOf(allocatorDump.retainedBy, expectedRetainedByCount); 4926 } 4927 4928 // Check the overall structure of the model and memory dumps. 4929 assert.sameMembers(Object.keys(m.processes), ['42', '68']); 4930 assert.lengthOf(m.globalMemoryDumps, 2); 4931 var gmd1 = m.globalMemoryDumps[0]; 4932 assert.strictEqual(gmd1.model, m); 4933 checkDumpTime(gmd1, 9999, 6); 4934 var gmd2 = m.globalMemoryDumps[1]; 4935 assert.strictEqual(gmd2.model, m); 4936 checkDumpTime(gmd2, 10003, 0); 4937 4938 var p1 = m.getProcess(42); 4939 assert.lengthOf(p1.memoryDumps, 2); 4940 var pmd1 = p1.memoryDumps[0]; 4941 checkDumpTime(pmd1, 10000, 5); 4942 assert.strictEqual(pmd1.globalMemoryDump, gmd1); 4943 assert.strictEqual(pmd1.process, p1); 4944 var pmd2 = p1.memoryDumps[1]; 4945 checkDumpTime(pmd2, 10003, 0); 4946 assert.strictEqual(pmd2.globalMemoryDump, gmd2); 4947 assert.strictEqual(pmd2.process, p1); 4948 4949 var p2 = m.getProcess(68); 4950 assert.lengthOf(p2.memoryDumps, 1); 4951 var pmd3 = p2.memoryDumps[0]; 4952 checkDumpTime(pmd3, 9999, 0); 4953 assert.strictEqual(pmd3.globalMemoryDump, gmd1); 4954 assert.strictEqual(pmd3.process, p2); 4955 4956 assert.deepEqual(gmd1.processMemoryDumps, {42: pmd1, 68: pmd3}); 4957 assert.deepEqual(gmd2.processMemoryDumps, {42: pmd2}); 4958 4959 // Check the composed dump. 4960 assert.strictEqual(pmd1.levelOfDetail, 'light'); 4961 4962 var totals = pmd1.totals; 4963 assert.strictEqual(totals.residentBytes, 256); 4964 assert.isUndefined(totals.peakResidentBytes); 4965 assert.isUndefined(totals.arePeakResidentBytesResettable); 4966 assert.deepEqual(totals.platformSpecific, {private_bytes: 128}); 4967 4968 var vmRegions = pmd1.vmRegions; 4969 checkVMRegions(vmRegions, [ 4970 { 4971 mappedFile: '[stack:20310]', 4972 startAddress: 240, 4973 sizeInBytes: 336, 4974 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 4975 VMRegion.PROTECTION_FLAG_WRITE, 4976 byteStats: { 4977 proportionalResident: 158 4978 } 4979 } 4980 ]); 4981 4982 var memoryAllocatorDumps = pmd1.memoryAllocatorDumps; 4983 assert.lengthOf(memoryAllocatorDumps, 2); 4984 4985 var local1Dump = pmd1.getMemoryAllocatorDumpByFullName('local1'); 4986 assert.strictEqual(memoryAllocatorDumps[0], local1Dump); 4987 assert.strictEqual(local1Dump.fullName, 'local1'); 4988 assert.isUndefined(local1Dump.parent); 4989 assert.lengthOf(local1Dump.children, 0); 4990 checkDumpNumericsAndDiagnostics(local1Dump, {}, 4991 { 'A': 'blue', 'B': 'red' }); 4992 checkLinkCounts(local1Dump, true /* owns */, 0 /* owned by */, 4993 0 /* retains */, 0 /* retained by */); 4994 4995 var local2Dump = pmd1.getMemoryAllocatorDumpByFullName('local2'); 4996 assert.strictEqual(memoryAllocatorDumps[1], local2Dump); 4997 assert.strictEqual(local2Dump.fullName, 'local2'); 4998 assert.isUndefined(local2Dump.parent); 4999 assert.lengthOf(local2Dump.children, 0); 5000 checkDumpNumericsAndDiagnostics(local2Dump, {}, { 'B': 'yellow' }); 5001 checkLinkCounts(local2Dump, false /* owns */, 0 /* owned by */, 5002 1 /* retains */, 0 /* retained by */); 5003 5004 var heapDumps = pmd1.heapDumps; 5005 assert.sameMembers(Object.keys(heapDumps), ['partition_alloc']); 5006 var heapDump = heapDumps['partition_alloc']; 5007 assert.strictEqual(heapDump.processMemoryDump, pmd1); 5008 assert.strictEqual(heapDump.allocatorName, 'partition_alloc'); 5009 var entries = heapDump.entries; 5010 assert.lengthOf(entries, 1); 5011 assert.strictEqual(entries[0].heapDump, heapDump); 5012 assert.strictEqual(entries[0].leafStackFrame.title, 'MessageLoop::RunTask'); 5013 assert.strictEqual(entries[0].objectTypeName, 'cc::SurfaceFactory'); 5014 assert.strictEqual(entries[0].size, 1280); 5015 5016 // Check the other dumps. 5017 assert.strictEqual(pmd2.levelOfDetail, 'detailed'); 5018 assert.isUndefined(pmd2.vmRegions); 5019 assert.lengthOf(pmd2.memoryAllocatorDumps, 1); 5020 var otherLocal1Dump = pmd2.getMemoryAllocatorDumpByFullName('local1'); 5021 assert.strictEqual(otherLocal1Dump, pmd2.memoryAllocatorDumps[0]); 5022 assert.strictEqual(otherLocal1Dump.fullName, 'local1'); 5023 assert.isUndefined(otherLocal1Dump.parent); 5024 checkDumpNumericsAndDiagnostics(otherLocal1Dump, { 'A': 2989 }, {}); 5025 assert.isUndefined(pmd2.heapDumps); 5026 checkLinkCounts(otherLocal1Dump, false /* owns */, 1 /* owned by */, 5027 0 /* retains */, 0 /* retained by */); 5028 5029 assert.isUndefined(pmd3.levelOfDetail); 5030 var otherVmRegions = pmd3.vmRegions; 5031 checkVMRegions(otherVmRegions, [ 5032 { 5033 mappedFile: '/dev/ashmem/dalvik', 5034 startAddress: 848, 5035 sizeInBytes: 592, 5036 protectionFlags: VMRegion.PROTECTION_FLAG_READ | 5037 VMRegion.PROTECTION_FLAG_EXECUTE, 5038 byteStats: { 5039 privateDirtyResident: 205 5040 } 5041 } 5042 ]); 5043 assert.lengthOf(pmd3.memoryAllocatorDumps, 0); 5044 assert.isUndefined(pmd3.heapDumps); 5045 5046 // Check the global dumps. 5047 assert.lengthOf(gmd1.memoryAllocatorDumps, 2); 5048 var shared1Dump = gmd1.getMemoryAllocatorDumpByFullName('shared1'); 5049 assert.strictEqual(shared1Dump, gmd1.memoryAllocatorDumps[0]); 5050 assert.strictEqual(shared1Dump.fullName, 'shared1'); 5051 assert.isUndefined(shared1Dump.parent); 5052 checkDumpNumericsAndDiagnostics(shared1Dump, {}, 5053 { 'A': 'purple', 'B': 'green' }); 5054 checkLinkCounts(shared1Dump, false /* owns */, 1 /* owned by */, 5055 0 /* retains */, 0 /* retained by */); 5056 var shared2Dump = gmd1.getMemoryAllocatorDumpByFullName('shared2'); 5057 assert.strictEqual(shared2Dump, gmd1.memoryAllocatorDumps[1]); 5058 assert.strictEqual(shared2Dump.fullName, 'shared2'); 5059 assert.isUndefined(shared2Dump.parent); 5060 checkDumpNumericsAndDiagnostics(shared2Dump, {}, { 'A': 'cyan' }); 5061 checkLinkCounts(shared2Dump, false /* owns */, 0 /* owned by */, 5062 0 /* retains */, 1 /* retained by */); 5063 5064 assert.lengthOf(gmd2.memoryAllocatorDumps, 1); 5065 var otherShared1Dump = gmd2.getMemoryAllocatorDumpByFullName('shared1'); 5066 assert.strictEqual(otherShared1Dump, gmd2.memoryAllocatorDumps[0]); 5067 assert.strictEqual(otherShared1Dump.fullName, 'shared1'); 5068 assert.isUndefined(otherShared1Dump.parent); 5069 checkDumpNumericsAndDiagnostics(otherShared1Dump, {}, { 'A': 'brown' }); 5070 checkLinkCounts(otherShared1Dump, true /* owns */, 0 /* owned by */, 5071 0 /* retains */, 0 /* retained by */); 5072 5073 // Check the edges. 5074 var ownershipLink = local1Dump.owns; 5075 assert.strictEqual(shared1Dump.ownedBy[0], ownershipLink); 5076 assert.strictEqual(ownershipLink.source, local1Dump); 5077 assert.strictEqual(ownershipLink.target, shared1Dump); 5078 assert.strictEqual(ownershipLink.importance, 1); 5079 5080 var retentionLink = local2Dump.retains[0]; 5081 assert.strictEqual(shared2Dump.retainedBy[0], retentionLink); 5082 assert.strictEqual(retentionLink.source, local2Dump); 5083 assert.strictEqual(retentionLink.target, shared2Dump); 5084 assert.isUndefined(retentionLink.importance); 5085 5086 var otherOwnershipLink = otherShared1Dump.owns; 5087 assert.strictEqual(otherLocal1Dump.ownedBy[0], otherOwnershipLink); 5088 assert.strictEqual(otherOwnershipLink.source, otherShared1Dump); 5089 assert.strictEqual(otherOwnershipLink.target, otherLocal1Dump); 5090 assert.isUndefined(otherOwnershipLink.importance); 5091 }); 5092 5093 test('importThreadInstantSliceWithStackFrame', function() { 5094 var eventData = { 5095 traceEvents: [ 5096 { name: 'a', args: {}, pid: 1, ts: 0, cat: 'baz', tid: 2, ph: 'I', s: 't', sf: 7 } // @suppress longLineCheck 5097 ], 5098 stackFrames: { 5099 '1': { 5100 category: 'm1', 5101 name: 'main' 5102 }, 5103 '7': { 5104 category: 'm2', 5105 name: 'frame7', 5106 parent: '1' 5107 } 5108 } 5109 }; 5110 5111 var m = makeModel(eventData); 5112 5113 var p = m.processes[1]; 5114 var t = p.threads[2]; 5115 assert.isDefined(t); 5116 assert.equal(t.sliceGroup.slices.length, 1); 5117 5118 var s0 = t.sliceGroup.slices[0]; 5119 assert.equal(s0.startStackFrame.title, 'frame7'); 5120 assert.isUndefined(s0.endStackFrame); 5121 }); 5122 5123 test('importDurationEventsWithStackFrames', function() { 5124 var eventData = { 5125 traceEvents: [ 5126 { name: 'a', args: {}, pid: 1, ts: 0, cat: 'baz', tid: 2, ph: 'B', sf: 7 }, // @suppress longLineCheck 5127 { name: 'b', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 2, ph: 'E', sf: 8 } // @suppress longLineCheck 5128 ], 5129 stackFrames: { 5130 '1': { 5131 category: 'm1', 5132 name: 'main' 5133 }, 5134 '7': { 5135 category: 'm2', 5136 name: 'frame7', 5137 parent: '1' 5138 }, 5139 '8': { 5140 category: 'm2', 5141 name: 'frame8', 5142 parent: '1' 5143 } 5144 } 5145 }; 5146 5147 var m = makeModel(eventData); 5148 5149 var p = m.processes[1]; 5150 var t = p.threads[2]; 5151 assert.isDefined(t); 5152 assert.equal(t.sliceGroup.slices.length, 1); 5153 5154 var s0 = t.sliceGroup.slices[0]; 5155 assert.equal(s0.startStackFrame.title, 'frame7'); 5156 assert.equal(s0.endStackFrame.title, 'frame8'); 5157 }); 5158 5159 test('annotationParsing', function() { 5160 var yComponents1 = [{stableId: '52.53', yPercentOffset: 0.5}, 5161 {stableId: '52', yPercentOffset: 0.3}]; 5162 var yComponents2 = [{stableId: '52.53', yPercentOffset: 0.7}, 5163 {stableId: '52', yPercentOffset: 0.4}]; 5164 var location1 = new tr.model.Location(0.1, yComponents1); 5165 var location2 = new tr.model.Location(0.2, yComponents2); 5166 5167 var eventData = { traceEvents: [ 5168 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}], 5169 traceAnnotations: [ 5170 {typeName: 'xmarker', args: {timestamp: 12}}, 5171 {typeName: 'rect', args: { 5172 start: location1.toDict(), end: location2.toDict()}}, 5173 {typeName: 'comment_box', args: {text: 'test', 5174 location: location1.toDict()}} 5175 ]}; 5176 5177 var m = makeModel(eventData); 5178 var annotations = m.getAllAnnotations(); 5179 assert.equal(annotations.length, 3); 5180 5181 assert.isTrue(annotations[0] instanceof tr.model.XMarkerAnnotation); 5182 assert.equal(annotations[0].timestamp, 12); 5183 5184 assert.isTrue(annotations[1] instanceof tr.model.RectAnnotation); 5185 assert.deepEqual(annotations[1].startLocation, location1); 5186 assert.deepEqual(annotations[1].endLocation, location2); 5187 5188 assert.isTrue( 5189 annotations[2] instanceof tr.model.CommentBoxAnnotation); 5190 assert.equal(annotations[2].text, 'test'); 5191 assert.deepEqual(annotations[2].location, location1); 5192 }); 5193 5194 test('importDisplayTimeUnit', function() { 5195 var eventData = { 5196 traceEvents: [], 5197 displayTimeUnit: 'ns' 5198 }; 5199 var m = makeModel(JSON.stringify(eventData)); 5200 assert.equal(m.intrinsicTimeUnit, tr.v.TimeDisplayModes.ns); 5201 }); 5202 5203 test('extractBattorSubTraces', function() { 5204 var battorLog = '# BattOr\n# voltage range [0.000000, 7196.484161] mV\n' + 5205 '#current range [11.898481, 2110.900916] mA\n' + 5206 '# sample_rate=10000Hz, gain=30.257143x\n' + 5207 '# filpot_pos=3, amppot_pos=35, timer_ovf=399, timer_div=4 ovs_bits=0\n' + // @suppress longLineCheck 5208 '0.0 1040.3 3984.2\n' + 5209 '0.1 1081.3 3987.8\n' + 5210 '0.2 1092.6 3987.8\n' + 5211 '0.3 1070.0 3987.8\n' + 5212 '0.4 1017.7 3994.8\n'; 5213 5214 var eventData = { 5215 traceEvents: [ 5216 { name: 'a', args: {}, pid: 1, ts: 0, cat: 'baz', tid: 2, ph: 'B', sf: 7 }, // @suppress longLineCheck 5217 { name: 'b', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 2, ph: 'E', sf: 8 } // @suppress longLineCheck 5218 ], 5219 powerTraceAsString: battorLog 5220 }; 5221 5222 var m = makeModel(eventData); 5223 var importer = new tr.e.importer.TraceEventImporter(m, eventData); 5224 var subTraces = importer.extractSubtraces(); 5225 assert.isTrue(subTraces instanceof Array); 5226 assert.equal(subTraces.length, 1); 5227 assert.equal(subTraces[0], battorLog); 5228 }); 5229 5230 test('metadataParsing', function() { 5231 var metadataValue = {value: {}}; 5232 var eventData = { 5233 traceEvents: [ 5234 { name: 'a', args: {}, pid: 1, ts: 0, cat: 'baz', tid: 2, ph: 'B', sf: 7 }, // @suppress longLineCheck 5235 { name: 'b', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 2, ph: 'E', sf: 8 } // @suppress longLineCheck 5236 ], 5237 metadata: metadataValue 5238 }; 5239 5240 var m = makeModel(eventData); 5241 assert.isTrue(m.metadata instanceof Array); 5242 assert.equal(m.metadata.length, 1); 5243 assert.equal(m.metadata[0].name, 'metadata'); 5244 assert.equal(m.metadata[0].value, metadataValue); 5245 }); 5246 5247 test('importMarks', function() { 5248 var eventData = { 5249 traceEvents: [ 5250 { name: 'mark1', args: {}, pid: 1, tid: 2, ts: 0, tts: 0, cat: 'blink.user_timing', ph: 'R' }, // @suppress longLineCheck 5251 { name: 'mark2', args: {}, pid: 1, tid: 2, ts: 10, tts: 10, cat: 'blink.user_timing', ph: 'R' } // @suppress longLineCheck 5252 ] 5253 }; 5254 5255 var m = makeModel(eventData); 5256 5257 var p = m.processes[1]; 5258 var t = p.threads[2]; 5259 assert.lengthOf(t.sliceGroup.slices, 2); 5260 5261 var s0 = t.sliceGroup.slices[0]; 5262 assert.equal(s0.title, 'mark1'); 5263 assert.equal(s0.start, 0); 5264 5265 var s1 = t.sliceGroup.slices[1]; 5266 assert.equal(s1.title, 'mark2'); 5267 assert.equal(s1.start, .01); 5268 }); 5269 5270 test('createNestableAsyncSlicesForUserTimingWithoutArgs', function() { 5271 /** 5272 * Structure of this async slices 5273 * 5274 * Group A: 5275 * 5276 * |__________| 5277 * a1 5278 * 5279 * Group B: 5280 * 5281 * |______________________________| 5282 * b1 5283 * |__________||_| 5284 * b2 b4 5285 * |_| 5286 * b3 5287 **/ 5288 var events = [ 5289 { 5290 name: 'A:a1', 5291 args: {params: ''}, 5292 pid: 1, 5293 ts: 100, 5294 cat: 'blink.user_timing', 5295 tid: 2, 5296 id: 3, 5297 ph: 'b' 5298 }, 5299 { 5300 name: 'A:a1', 5301 args: {params: ''}, 5302 pid: 1, 5303 ts: 110, 5304 cat: 'blink.user_timing', 5305 tid: 2, 5306 id: 3, 5307 ph: 'e' 5308 }, 5309 { 5310 name: 'B:b1', 5311 args: {params: ''}, 5312 pid: 1, 5313 ts: 120, 5314 cat: 'blink.user_timing', 5315 tid: 2, 5316 id: 4, 5317 ph: 'b' 5318 }, 5319 { 5320 name: 'B:b2', 5321 args: {params: ''}, 5322 pid: 1, 5323 ts: 130, 5324 cat: 'blink.user_timing', 5325 tid: 2, 5326 id: 5, 5327 ph: 'b' 5328 }, 5329 { 5330 name: 'B:b3', 5331 args: {params: ''}, 5332 pid: 1, 5333 ts: 131, 5334 cat: 'blink.user_timing', 5335 tid: 2, 5336 id: 5, 5337 ph: 'b' 5338 }, 5339 { 5340 name: 'B:b3', 5341 args: {params: ''}, 5342 pid: 1, 5343 ts: 132, 5344 cat: 'blink.user_timing', 5345 tid: 2, 5346 id: 5, 5347 ph: 'e' 5348 }, 5349 { 5350 name: 'B:b2', 5351 args: {params: ''}, 5352 pid: 1, 5353 ts: 140, 5354 cat: 'blink.user_timing', 5355 tid: 2, 5356 id: 5, 5357 ph: 'e' 5358 }, 5359 { 5360 name: 'B:b4', 5361 args: {params: ''}, 5362 pid: 1, 5363 ts: 141, 5364 cat: 'blink.user_timing', 5365 tid: 2, 5366 id: 5, 5367 ph: 'b' 5368 }, 5369 { 5370 name: 'B:b4', 5371 args: {params: ''}, 5372 pid: 1, 5373 ts: 142, 5374 cat: 'blink.user_timing', 5375 tid: 2, 5376 id: 5, 5377 ph: 'e' 5378 }, 5379 { 5380 name: 'B:b1', 5381 args: {params: ''}, 5382 pid: 1, 5383 ts: 150, 5384 cat: 'blink.user_timing', 5385 tid: 2, 5386 id: 4, 5387 ph: 'e' 5388 } 5389 ]; 5390 5391 var m = makeModel(events); 5392 assert(m.numProcesses, 1); 5393 var p = m.processes[1]; 5394 assert.isDefined(p); 5395 assert.equal(p.numThreads, 1); 5396 var t = p.threads[2]; 5397 var asyncSliceGroup = t.asyncSliceGroup; 5398 assert.equal(asyncSliceGroup.length, 2); 5399 for (var i = 0; i < asyncSliceGroup.length; ++i) { 5400 assert.isTrue(asyncSliceGroup.slices[i] instanceof MeasureAsyncSlice); 5401 } 5402 5403 var groupA = asyncSliceGroup.slices[0]; 5404 assert.equal(groupA.viewSubGroupTitle, 'A'); 5405 assert.equal(groupA.title, 'a1'); 5406 assert.equal(groupA.subSlices.length, 0); 5407 var groupB = asyncSliceGroup.slices[1]; 5408 assert.equal(groupB.viewSubGroupTitle, 'B'); 5409 assert.equal(groupB.title, 'b1'); 5410 assert.equal(groupB.subSlices.length, 2); 5411 var groupBSubSlice1 = groupB.subSlices[0]; 5412 assert.equal(groupBSubSlice1.viewSubGroupTitle, 'B'); 5413 assert.equal(groupBSubSlice1.title, 'b2'); 5414 assert.equal(groupBSubSlice1.subSlices.length, 1); 5415 assert.equal(groupBSubSlice1.subSlices[0].viewSubGroupTitle, 'B'); 5416 assert.equal(groupBSubSlice1.subSlices[0].title, 'b3'); 5417 assert.equal(groupBSubSlice1.subSlices[0].subSlices.length, 0); 5418 var groupBSubSlice2 = groupB.subSlices[1]; 5419 assert.equal(groupBSubSlice2.viewSubGroupTitle, 'B'); 5420 assert.equal(groupBSubSlice2.title, 'b4'); 5421 assert.equal(groupBSubSlice2.subSlices.length, 0); 5422 }); 5423 5424 test('createNestableAsyncSlicesForUserTimingWithArgs', function() { 5425 /** 5426 * Structure of this async slices 5427 * 5428 * Group A: 5429 * 5430 * |__________| |__________| 5431 * a1 a2 5432 * 5433 * a1.args = {a: 1} 5434 * a2.args = {a: 2, b: 2} 5435 **/ 5436 var events = [ 5437 { 5438 name: 'A:a1/eyJhIjoxfQ==', 5439 args: {params: ''}, 5440 pid: 1, 5441 ts: 100, 5442 cat: 'blink.user_timing', 5443 tid: 2, 5444 id: 3, 5445 ph: 'b' 5446 }, 5447 { 5448 name: 'A:a1/eyJhIjoxfQ==', 5449 args: {params: ''}, 5450 pid: 1, 5451 ts: 110, 5452 cat: 'blink.user_timing', 5453 tid: 2, 5454 id: 3, 5455 ph: 'e' 5456 }, 5457 { 5458 name: 'A:a2/eyJhIjoyLCJiIjoyfQ==', 5459 args: {params: ''}, 5460 pid: 1, 5461 ts: 120, 5462 cat: 'blink.user_timing', 5463 tid: 2, 5464 id: 4, 5465 ph: 'b' 5466 }, 5467 { 5468 name: 'A:a2/eyJhIjoyLCJiIjoyfQ==', 5469 args: {params: ''}, 5470 pid: 1, 5471 ts: 130, 5472 cat: 'blink.user_timing', 5473 tid: 2, 5474 id: 4, 5475 ph: 'e' 5476 } 5477 ]; 5478 5479 var m = makeModel(events); 5480 assert(m.numProcesses, 1); 5481 var p = m.processes[1]; 5482 assert.isDefined(p); 5483 assert.equal(p.numThreads, 1); 5484 var t = p.threads[2]; 5485 var asyncSliceGroup = t.asyncSliceGroup; 5486 assert.equal(asyncSliceGroup.length, 2); 5487 for (var i = 0; i < asyncSliceGroup.length; ++i) { 5488 assert.isTrue(asyncSliceGroup.slices[i] instanceof MeasureAsyncSlice); 5489 } 5490 5491 var a1 = asyncSliceGroup.slices[0]; 5492 assert.equal(a1.viewSubGroupTitle, 'A'); 5493 assert.equal(a1.title, 'a1'); 5494 assert.equal(a1.subSlices.length, 0); 5495 assert.deepEqual(a1.args, {a: 1}); 5496 var a2 = asyncSliceGroup.slices[1]; 5497 assert.equal(a2.viewSubGroupTitle, 'A'); 5498 assert.equal(a2.title, 'a2'); 5499 assert.equal(a2.subSlices.length, 0); 5500 assert.deepEqual(a2.args, {a: 2, b: 2}); 5501 }); 5502 5503 test('UserTimingAsyncSlicesWithNormalAsyncSlices', function() { 5504 /** 5505 * Structure of user timing async slices 5506 * 5507 * Group A: 5508 * 5509 * |__________| 5510 * a1 5511 * |__| 5512 * a2 5513 * 5514 * B 5515 * |__| 5516 * B 5517 * C 5518 * |_| 5519 * C 5520 **/ 5521 var events = [ 5522 { 5523 name: 'A:a1', args: {params: ''}, pid: 1, ts: 1, 5524 cat: 'blink.user_timing', tid: 2, id: 3, ph: 'b' 5525 }, 5526 { 5527 name: 'A:a1', args: {params: ''}, pid: 1, ts: 11, 5528 cat: 'blink.user_timing', tid: 2, id: 3, ph: 'e' 5529 }, 5530 { 5531 name: 'A:a2', args: {params: ''}, pid: 1, ts: 2, 5532 cat: 'blink.user_timing', tid: 2, id: 4, ph: 'b' 5533 }, 5534 { 5535 name: 'A:a2', args: {params: ''}, pid: 1, ts: 4, 5536 cat: 'blink.user_timing', tid: 2, id: 4, ph: 'e' 5537 }, 5538 { 5539 name: 'B', args: {}, pid: 1, ts: 9, cat: 'foo', 5540 tid: 2, ph: 'b', id: 5 5541 }, 5542 { 5543 name: 'B', args: {}, pid: 1, ts: 11, cat: 'foo', 5544 tid: 2, ph: 'e', id: 5 5545 }, 5546 { 5547 name: 'C', args: {}, pid: 1, ts: 12, cat: 'foo', 5548 tid: 2, ph: 'b', id: 6 5549 }, 5550 { 5551 name: 'C', args: {}, pid: 1, ts: 13, cat: 'foo', 5552 tid: 2, ph: 'e', id: 6 5553 } 5554 ]; 5555 5556 var m = makeModel(events); 5557 assert(m.numProcesses, 1); 5558 var p = m.processes[1]; 5559 assert.isDefined(p); 5560 assert.equal(p.numThreads, 1); 5561 var t = p.threads[2]; 5562 var asyncSliceGroup = t.asyncSliceGroup; 5563 assert.equal(asyncSliceGroup.length, 3); 5564 assert.isTrue(asyncSliceGroup.slices[0] instanceof MeasureAsyncSlice); 5565 assert.isFalse(asyncSliceGroup.slices[1] instanceof MeasureAsyncSlice); 5566 assert.isFalse(asyncSliceGroup.slices[2] instanceof MeasureAsyncSlice); 5567 5568 var a1 = asyncSliceGroup.slices[0]; 5569 assert.equal(a1.viewSubGroupTitle, 'A'); 5570 assert.equal(a1.title, 'a1'); 5571 assert.equal(a1.subSlices.length, 1); 5572 var a2 = a1.subSlices[0]; 5573 assert.equal(a2.viewSubGroupTitle, 'A'); 5574 assert.equal(a2.title, 'a2'); 5575 assert.equal(a2.subSlices.length, 0); 5576 var B = asyncSliceGroup.slices[1]; 5577 assert.equal(B.viewSubGroupTitle, 'B'); 5578 assert.equal(B.title, 'B'); 5579 assert.equal(B.subSlices.length, 0); 5580 var C = asyncSliceGroup.slices[2]; 5581 assert.equal(C.viewSubGroupTitle, 'C'); 5582 assert.equal(C.title, 'C'); 5583 assert.equal(C.subSlices.length, 0); 5584 }); 5585 5586 test('clockSync', function() { 5587 var events = [{ 5588 name: 'clock_sync', args: {sync_id: 'abc', issue_ts: 5}, 5589 pid: 1, ts: 15, cat: '__metadata', tid: 2, ph: 'c' 5590 }]; 5591 5592 var m = makeModel(events); 5593 5594 var foundClockSync = false; 5595 for (var i = 0; i < m.clockSyncRecords.length; i++) { 5596 var clockSync = m.clockSyncRecords[i]; 5597 if (clockSync.syncId !== 'abc') 5598 continue; 5599 5600 foundClockSync = true; 5601 assert.equal(clockSync.start, .005); 5602 assert.equal(clockSync.duration, .010); 5603 } 5604 5605 assert.isTrue(foundClockSync); 5606 assert.isFalse(m.hasImportWarnings); 5607 }); 5608 5609 test('clockSync_missingSyncId', function() { 5610 var events = [{ 5611 name: 'clock_sync', args: {issue_ts: 5}, 5612 pid: 1, ts: 15, cat: '__metadata', tid: 2, ph: 'c' 5613 }]; 5614 5615 var m = makeModel(events); 5616 assert.isTrue(m.hasImportWarnings); 5617 }); 5618 5619 test('clockSync_missingStartTs', function() { 5620 var events = [{ 5621 name: 'clock_sync', args: {sync_id: 'abc'}, 5622 pid: 1, ts: 15, cat: '__metadata', tid: 2, ph: 'c' 5623 }]; 5624 5625 var m = makeModel(events); 5626 5627 var foundClockSync = false; 5628 for (var i = 0; i < m.clockSyncRecords.length; i++) { 5629 var clockSync = m.clockSyncRecords[i]; 5630 if (clockSync.syncId !== 'abc') 5631 continue; 5632 5633 foundClockSync = true; 5634 } 5635 5636 assert.isFalse(foundClockSync); 5637 assert.isTrue(m.hasImportWarnings); 5638 }); 5639 5640 // TODO(nduca): one slice, two threads 5641 // TODO(nduca): one slice, two pids 5642 5643}); 5644</script> 5645