1 <!DOCTYPE html> 2 <html> 3 <!-- 4 Copyright (c) 2012 The Chromium Authors. All rights reserved. 5 Use of this source code is governed by a BSD-style license that can be 6 found in the LICENSE file. 7 --> 8 <head> 9 <title>TraceEventImporter tests</title> 10 <script src="base.js"></script> 11 <script> 12 base.require('unittest'); 13 base.require('test_utils'); 14 base.require('trace_event_importer'); 15 </script> 16 </head> 17 <body> 18 <script> 19 'use strict'; 20 21 var findSliceNamed = test_utils.findSliceNamed; 22 23 function testCanImportEmpty() { 24 self.assertFalse(tracing.TraceEventImporter.canImport([])); 25 self.assertFalse(tracing.TraceEventImporter.canImport('')); 26 } 27 28 function testBasicSingleThreadNonnestedParsing() { 29 var events = [ 30 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, 31 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}, 32 {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B'}, 33 {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E'} 34 ]; 35 36 var m = new tracing.TimelineModel(events); 37 assertEquals(1, m.numProcesses); 38 var p = m.processes[52]; 39 assertNotUndefined(p); 40 41 assertEquals(1, p.numThreads); 42 var t = p.threads[53]; 43 assertNotUndefined(t); 44 assertEquals(2, t.slices.length); 45 assertEquals(53, t.tid); 46 var slice = t.slices[0]; 47 assertEquals('a', slice.title); 48 assertEquals('foo', slice.category); 49 assertEquals(0, slice.start); 50 assertAlmostEquals((560 - 520) / 1000, slice.duration); 51 assertEquals(0, slice.subSlices.length); 52 53 slice = t.slices[1]; 54 assertEquals('b', slice.title); 55 assertEquals('bar', slice.category); 56 assertAlmostEquals((629 - 520) / 1000, slice.start); 57 assertAlmostEquals((631 - 629) / 1000, slice.duration); 58 assertEquals(0, slice.subSlices.length); 59 } 60 61 function testArgumentDupeCreatesNonFailingImportError() { 62 var events = [ 63 {name: 'a', args: {'x': 1}, pid: 1, ts: 520, cat: 'foo', tid: 1, ph: 'B'}, 64 {name: 'a', args: {'x': 2}, pid: 1, ts: 560, cat: 'foo', tid: 1, ph: 'E'} 65 ]; 66 67 var m = new tracing.TimelineModel(events); 68 var t = m.processes[1].threads[1]; 69 var sA = findSliceNamed(t.slices, 'a'); 70 71 assertEquals(2, sA.args.x); 72 assertEquals(m.importErrors.length, 1); 73 } 74 75 function testCategoryBeginEndMismatchPrefersBegin() { 76 var events = [ 77 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, 78 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'bar', tid: 53, ph: 'E'} 79 ]; 80 81 var m = new tracing.TimelineModel(events); 82 assertEquals(1, m.numProcesses); 83 var p = m.processes[52]; 84 assertNotUndefined(p); 85 86 assertEquals(1, p.numThreads); 87 var t = p.threads[53]; 88 assertNotUndefined(t); 89 assertEquals(1, t.slices.length); 90 assertEquals(53, t.tid); 91 var slice = t.slices[0]; 92 assertEquals('a', slice.title); 93 assertEquals('foo', slice.category); 94 } 95 96 function testNestedParsing() { 97 var events = [ 98 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 99 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'B'}, 100 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 1, ph: 'E'}, 101 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'} 102 ]; 103 var m = new tracing.TimelineModel(events, false); 104 var t = m.processes[1].threads[1]; 105 106 var sA = findSliceNamed(t.slices, 'a'); 107 var sB = findSliceNamed(t.slices, 'b'); 108 109 assertEquals('a', sA.title); 110 assertEquals('foo', sA.category); 111 assertEquals(0.001, sA.start); 112 assertEquals(0.003, sA.duration); 113 114 assertEquals('b', sB.title); 115 assertEquals('bar', sB.category); 116 assertEquals(0.002, sB.start); 117 assertEquals(0.001, sB.duration); 118 } 119 120 function testAutoclosing() { 121 var events = [ 122 // Slice that doesn't finish. 123 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 124 125 // Slice that does finish to give an 'end time' to make autoclosing work. 126 {name: 'b', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'}, 127 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'} 128 ]; 129 var m = new tracing.TimelineModel(events); 130 var p = m.processes[1]; 131 var t = p.threads[1]; 132 var slice = t.slices[0]; 133 assertEquals('a', slice.title); 134 assertEquals('foo', slice.category); 135 assertTrue(slice.didNotFinish); 136 assertEquals(0, slice.start); 137 assertEquals((2 - 1) / 1000, slice.duration); 138 } 139 140 function testAutoclosingLoneBegin() { 141 var events = [ 142 // Slice that doesn't finish. 143 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'} 144 ]; 145 var m = new tracing.TimelineModel(events); 146 var p = m.processes[1]; 147 var t = p.threads[1]; 148 var slice = t.slices[0]; 149 assertEquals('a', slice.title); 150 assertEquals('foo', slice.category); 151 assertTrue(slice.didNotFinish); 152 assertEquals(0, slice.start); 153 assertEquals(0, slice.duration); 154 } 155 156 function testAutoclosingWithSubTasks() { 157 var events = [ 158 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 159 {name: 'b1', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'}, 160 {name: 'b1', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'}, 161 {name: 'b2', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'} 162 ]; 163 var m = new tracing.TimelineModel(events, false); 164 var t = m.processes[1].threads[1]; 165 166 var sA = findSliceNamed(t.slices, 'a'); 167 var sB1 = findSliceNamed(t.slices, 'b1'); 168 var sB2 = findSliceNamed(t.slices, 'b2'); 169 170 assertEquals(0.003, sA.end); 171 assertEquals(0.003, sB1.end); 172 assertEquals(0.003, sB2.end); 173 } 174 175 function testAutoclosingWithEventsOutsideRange() { 176 var events = [ 177 // Slice that begins before min and ends after max of the other threads. 178 {name: 'a', args: {}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'B'}, 179 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'}, 180 181 // Slice that does finish to give an 'end time' to establish a basis 182 {name: 'c', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'}, 183 {name: 'c', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'} 184 ]; 185 var m = new tracing.TimelineModel(events, false); 186 var p = m.processes[1]; 187 var t = p.threads[1]; 188 assertEquals(2, t.slices.length); 189 190 var slice = findSliceNamed(t.slices, 'a'); 191 assertEquals('a', slice.title); 192 assertEquals('foo', slice.category); 193 assertEquals(0, slice.start); 194 assertEquals(0.003, slice.duration); 195 196 var t2 = p.threads[2]; 197 var slice2 = findSliceNamed(t2.slices, 'c'); 198 assertEquals('c', slice2.title); 199 assertEquals('bar', slice2.category); 200 assertEquals(0.001, slice2.start); 201 assertEquals(0.001, slice2.duration); 202 203 assertEquals(0.000, m.minTimestamp); 204 assertEquals(0.003, m.maxTimestamp); 205 } 206 207 function testNestedAutoclosing() { 208 var events = [ 209 // Tasks that don't finish. 210 {name: 'a1', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 211 {name: 'a2', args: {}, pid: 1, ts: 1.5, cat: 'foo', tid: 1, ph: 'B'}, 212 213 // Slice that does finish to give an 'end time' to make autoclosing work. 214 {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'}, 215 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'} 216 ]; 217 var m = new tracing.TimelineModel(events, false); 218 var t1 = m.processes[1].threads[1]; 219 var t2 = m.processes[1].threads[2]; 220 221 var sA1 = findSliceNamed(t1.slices, 'a1'); 222 var sA2 = findSliceNamed(t1.slices, 'a2'); 223 var sB = findSliceNamed(t2.slices, 'b'); 224 225 assertEquals(0.002, sA1.end); 226 assertEquals(0.002, sA2.end); 227 } 228 229 function testTaskColoring() { 230 // The test below depends on hashing of 'a' != 'b'. Fail early if that 231 // assumption is incorrect. 232 assertNotEquals(tracing.getStringHash('a'), tracing.getStringHash('b')); 233 234 var events = [ 235 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 236 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, 237 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 1, ph: 'B'}, 238 {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 1, ph: 'E'}, 239 {name: 'a', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'B'}, 240 {name: 'a', args: {}, pid: 1, ts: 6, cat: 'baz', tid: 1, ph: 'E'} 241 ]; 242 var m = new tracing.TimelineModel(events); 243 var p = m.processes[1]; 244 var t = p.threads[1]; 245 var a1 = t.slices[0]; 246 assertEquals('a', a1.title); 247 assertEquals('foo', a1.category); 248 var b = t.slices[1]; 249 assertEquals('b', b.title); 250 assertEquals('bar', b.category); 251 assertNotEquals(a1.colorId, b.colorId); 252 var a2 = t.slices[2]; 253 assertEquals('a', a2.title); 254 assertEquals('baz', a2.category); 255 assertEquals(a1.colorId, a2.colorId); 256 } 257 258 function testMultipleThreadParsing() { 259 var events = [ 260 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 261 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, 262 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 2, ph: 'B'}, 263 {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 2, ph: 'E'} 264 ]; 265 var m = new tracing.TimelineModel(events); 266 assertEquals(1, m.numProcesses); 267 var p = m.processes[1]; 268 assertNotUndefined(p); 269 270 assertEquals(2, p.numThreads); 271 272 // Check thread 1. 273 var t = p.threads[1]; 274 assertNotUndefined(t); 275 assertEquals(1, t.slices.length); 276 assertEquals(1, t.tid); 277 278 var slice = t.slices[0]; 279 assertEquals('a', slice.title); 280 assertEquals('foo', slice.category); 281 assertEquals(0, slice.start); 282 assertEquals((2 - 1) / 1000, slice.duration); 283 assertEquals(0, slice.subSlices.length); 284 285 // Check thread 2. 286 var t = p.threads[2]; 287 assertNotUndefined(t); 288 assertEquals(1, t.slices.length); 289 assertEquals(2, t.tid); 290 291 slice = t.slices[0]; 292 assertEquals('b', slice.title); 293 assertEquals('bar', slice.category); 294 assertEquals((3 - 1) / 1000, slice.start); 295 assertEquals((4 - 3) / 1000, slice.duration); 296 assertEquals(0, slice.subSlices.length); 297 } 298 299 function testMultiplePidParsing() { 300 var events = [ 301 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 302 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, 303 {name: 'b', args: {}, pid: 2, ts: 3, cat: 'bar', tid: 2, ph: 'B'}, 304 {name: 'b', args: {}, pid: 2, ts: 4, cat: 'bar', tid: 2, ph: 'E'} 305 ]; 306 var m = new tracing.TimelineModel(events); 307 assertEquals(2, m.numProcesses); 308 var p = m.processes[1]; 309 assertNotUndefined(p); 310 311 assertEquals(1, p.numThreads); 312 313 // Check process 1 thread 1. 314 var t = p.threads[1]; 315 assertNotUndefined(t); 316 assertEquals(1, t.slices.length); 317 assertEquals(1, t.tid); 318 319 var slice = t.slices[0]; 320 assertEquals('a', slice.title); 321 assertEquals('foo', slice.category); 322 assertEquals(0, slice.start); 323 assertEquals((2 - 1) / 1000, slice.duration); 324 assertEquals(0, slice.subSlices.length); 325 326 // Check process 2 thread 2. 327 var p = m.processes[2]; 328 assertNotUndefined(p); 329 assertEquals(1, p.numThreads); 330 var t = p.threads[2]; 331 assertNotUndefined(t); 332 assertEquals(1, t.slices.length); 333 assertEquals(2, t.tid); 334 335 slice = t.slices[0]; 336 assertEquals('b', slice.title); 337 assertEquals('bar', slice.category); 338 assertEquals((3 - 1) / 1000, slice.start); 339 assertEquals((4 - 3) / 1000, slice.duration); 340 assertEquals(0, slice.subSlices.length); 341 342 // Check getAllThreads. 343 assertArrayEquals([m.processes[1].threads[1], m.processes[2].threads[2]], 344 m.getAllThreads()); 345 } 346 347 // Thread names. 348 function testThreadNames() { 349 var events = [ 350 {name: 'thread_name', args: {name: 'Thread 1'}, 351 pid: 1, ts: 0, tid: 1, ph: 'M'}, 352 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 353 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, 354 {name: 'b', args: {}, pid: 2, ts: 3, cat: 'foo', tid: 2, ph: 'B'}, 355 {name: 'b', args: {}, pid: 2, ts: 4, cat: 'foo', tid: 2, ph: 'E'}, 356 {name: 'thread_name', args: {name: 'Thread 2'}, 357 pid: 2, ts: 0, tid: 2, ph: 'M'} 358 ]; 359 var m = new tracing.TimelineModel(events); 360 assertEquals('Thread 1', m.processes[1].threads[1].name); 361 assertEquals('Thread 2', m.processes[2].threads[2].name); 362 } 363 364 function testParsingWhenEndComesFirst() { 365 var events = [ 366 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'E'}, 367 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'B'}, 368 {name: 'a', args: {}, pid: 1, ts: 5, cat: 'foo', tid: 1, ph: 'E'} 369 ]; 370 var m = new tracing.TimelineModel(events, false); 371 var p = m.processes[1]; 372 var t = p.threads[1]; 373 assertEquals(1, t.slices.length); 374 assertEquals('a', t.slices[0].title); 375 assertEquals('foo', t.slices[0].category); 376 assertEquals(0.004, t.slices[0].start); 377 assertEquals(0.001, t.slices[0].duration); 378 assertEquals(1, m.importErrors.length); 379 } 380 381 function testImmediateParsing() { 382 var events = [ 383 // Need to include immediates inside a task so the timeline 384 // recentering/zeroing doesn't clobber their timestamp. 385 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, 386 {name: 'immediate', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'I'}, 387 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'} 388 ]; 389 var m = new tracing.TimelineModel(events, false); 390 var p = m.processes[1]; 391 var t = p.threads[1]; 392 assertEquals(2, t.slices.length); 393 assertEquals(0.002, t.slices[0].start); 394 assertEquals(0, t.slices[0].duration); 395 assertEquals(0.001, t.slices[1].start); 396 assertEquals(0.003, t.slices[1].duration); 397 398 assertEquals(2, t.slices.length); 399 var slice = findSliceNamed(t.slices, 'a'); 400 assertEquals('a', slice.title); 401 assertEquals('foo', slice.category); 402 assertEquals(0.003, slice.duration); 403 404 var immed = findSliceNamed(t.slices, 'immediate'); 405 assertEquals('immediate', immed.title); 406 assertEquals('bar', immed.category); 407 assertEquals(0.002, immed.start); 408 assertEquals(0, immed.duration); 409 assertEquals(0, immed.subSlices.length); 410 } 411 412 function testSimpleCounter() { 413 var events = [ 414 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1, 415 ph: 'C'}, 416 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, 417 ph: 'C'}, 418 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 20, cat: 'foo', tid: 1, 419 ph: 'C'} 420 421 ]; 422 var m = new tracing.TimelineModel(events); 423 var p = m.processes[1]; 424 var ctr = m.processes[1].counters['foo.ctr']; 425 426 assertEquals('ctr', ctr.name); 427 assertEquals('foo', ctr.category); 428 assertEquals(3, ctr.numSamples); 429 assertEquals(1, ctr.numSeries); 430 431 assertArrayEquals(['value'], ctr.seriesNames); 432 assertArrayEquals([tracing.getStringColorId('ctr.value')], ctr.seriesColors); 433 assertArrayEquals([0, 0.01, 0.02], ctr.timestamps); 434 assertArrayEquals([0, 10, 0], ctr.samples); 435 assertArrayEquals([0, 10, 0], ctr.totals); 436 assertEquals(10, ctr.maxTotal); 437 } 438 439 function testInstanceCounter() { 440 var events = [ 441 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1, 442 ph: 'C', id: 0}, 443 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, 444 ph: 'C', id: 0}, 445 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, 446 ph: 'C', id: 1}, 447 {name: 'ctr', args: {'value': 20}, pid: 1, ts: 15, cat: 'foo', tid: 1, 448 ph: 'C', id: 1}, 449 {name: 'ctr', args: {'value': 30}, pid: 1, ts: 18, cat: 'foo', tid: 1, 450 ph: 'C', id: 1}, 451 {name: 'ctr', args: {'value': 40}, pid: 1, ts: 20, cat: 'bar', tid: 1, 452 ph: 'C', id: 2} 453 ]; 454 var m = new tracing.TimelineModel(events); 455 var p = m.processes[1]; 456 var ctr = m.processes[1].counters['foo.ctr[0]']; 457 assertEquals('ctr[0]', ctr.name); 458 assertEquals('foo', ctr.category); 459 assertEquals(2, ctr.numSamples); 460 assertEquals(1, ctr.numSeries); 461 assertArrayEquals([0, 0.01], ctr.timestamps); 462 assertArrayEquals([0, 10], ctr.samples); 463 464 var ctr = m.processes[1].counters['foo.ctr[1]']; 465 assertEquals('ctr[1]', ctr.name); 466 assertEquals('foo', ctr.category); 467 assertEquals(3, ctr.numSamples); 468 assertEquals(1, ctr.numSeries); 469 assertArrayEquals([0.01, 0.015, 0.018], ctr.timestamps); 470 assertArrayEquals([10, 20, 30], ctr.samples); 471 472 var ctr = m.processes[1].counters['bar.ctr[2]']; 473 assertEquals('ctr[2]', ctr.name); 474 assertEquals('bar', ctr.category); 475 assertEquals(1, ctr.numSamples); 476 assertEquals(1, ctr.numSeries); 477 assertArrayEquals([0.02], ctr.timestamps); 478 assertArrayEquals([40], ctr.samples); 479 } 480 481 function testMultiCounterUpdateBounds() { 482 var ctr = new tracing.TimelineCounter(undefined, 'testBasicCounter', 483 '', 'testBasicCounter'); 484 ctr.seriesNames = ['value1', 'value2']; 485 ctr.seriesColors = ['testBasicCounter.value1', 'testBasicCounter.value2']; 486 ctr.timestamps = [0, 1, 2, 3, 4, 5, 6, 7]; 487 ctr.samples = [0, 0, 488 1, 0, 489 1, 1, 490 2, 1.1, 491 3, 0, 492 1, 7, 493 3, 0, 494 3.1, 0.5]; 495 ctr.updateBounds(); 496 assertEquals(0, ctr.minTimestamp); 497 assertEquals(7, ctr.maxTimestamp); 498 assertEquals(8, ctr.maxTotal); 499 assertArrayEquals([0, 0, 500 1, 1, 501 1, 2, 502 2, 3.1, 503 3, 3, 504 1, 8, 505 3, 3, 506 3.1, 3.6], ctr.totals); 507 } 508 509 function testMultiCounter() { 510 var events = [ 511 {name: 'ctr', args: {'value1': 0, 'value2': 7}, pid: 1, ts: 0, cat: 'foo', 512 tid: 1, ph: 'C'}, 513 {name: 'ctr', args: {'value1': 10, 'value2': 4}, pid: 1, ts: 10, cat: 'foo', 514 tid: 1, ph: 'C'}, 515 {name: 'ctr', args: {'value1': 0, 'value2': 1 }, pid: 1, ts: 20, cat: 'foo', 516 tid: 1, ph: 'C'} 517 ]; 518 var m = new tracing.TimelineModel(events); 519 var p = m.processes[1]; 520 var ctr = m.processes[1].counters['foo.ctr']; 521 assertEquals('ctr', ctr.name); 522 523 assertEquals('ctr', ctr.name); 524 assertEquals('foo', ctr.category); 525 assertEquals(3, ctr.numSamples); 526 assertEquals(2, ctr.numSeries); 527 528 assertArrayEquals(['value1', 'value2'], ctr.seriesNames); 529 assertArrayEquals([tracing.getStringColorId('ctr.value1'), 530 tracing.getStringColorId('ctr.value2')], 531 ctr.seriesColors); 532 assertArrayEquals([0, 0.01, 0.02], ctr.timestamps); 533 assertArrayEquals([0, 7, 534 10, 4, 535 0, 1], ctr.samples); 536 assertArrayEquals([0, 7, 537 10, 14, 538 0, 1], ctr.totals); 539 assertEquals(14, ctr.maxTotal); 540 } 541 542 function testImportObjectInsteadOfArray() { 543 var events = { traceEvents: [ 544 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 545 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 546 ] }; 547 548 var m = new tracing.TimelineModel(events); 549 assertEquals(1, m.numProcesses); 550 } 551 552 function testImportString() { 553 var events = [ 554 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 555 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 556 ]; 557 558 var m = new tracing.TimelineModel(JSON.stringify(events)); 559 assertEquals(1, m.numProcesses); 560 } 561 562 function testImportStringWithTrailingNewLine() { 563 var events = [ 564 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 565 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 566 ]; 567 568 var m = new tracing.TimelineModel(JSON.stringify(events) + '\n'); 569 assertEquals(1, m.numProcesses); 570 } 571 572 function testImportStringWithMissingCloseSquareBracket() { 573 var events = [ 574 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 575 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 576 ]; 577 578 var tmp = JSON.stringify(events); 579 assertEquals(']', tmp[tmp.length - 1]); 580 581 // Drop off the trailing ] 582 var dropped = tmp.substring(0, tmp.length - 1); 583 var m = new tracing.TimelineModel(dropped); 584 assertEquals(1, m.numProcesses); 585 } 586 587 function testImportStringWithEndingCommaButMissingCloseSquareBracket() { 588 var lines = [ 589 '[', 590 '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', 591 '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' 592 ] 593 var text = lines.join('\n'); 594 595 var m = new tracing.TimelineModel(text); 596 assertEquals(1, m.numProcesses); 597 assertEquals(1, m.processes[52].threads[53].slices.length); 598 } 599 600 function testImportStringWithMissingCloseSquareBracketAndNewline() { 601 var events = [ 602 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, 603 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 604 ]; 605 606 var tmp = JSON.stringify(events); 607 assertEquals(']', tmp[tmp.length - 1]); 608 609 // Drop off the trailing ] and add a newline 610 var dropped = tmp.substring(0, tmp.length - 1); 611 var m = new tracing.TimelineModel(dropped + '\n'); 612 assertEquals(1, m.numProcesses); 613 } 614 615 function testImportStringWithEndingCommaButMissingCloseSquareBracketCRLF() { 616 var lines = [ 617 '[', 618 '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', 619 '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' 620 ] 621 var text = lines.join('\r\n'); 622 623 var m = new tracing.TimelineModel(text); 624 assertEquals(1, m.numProcesses); 625 assertEquals(1, m.processes[52].threads[53].slices.length); 626 } 627 628 function testStartFinishOneSliceOneThread() { 629 var events = [ 630 // Time is intentionally out of order. 631 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'cat', tid: 53, 632 ph: 'F', id: 72}, 633 {name: 'a', pid: 52, ts: 524, cat: 'cat', tid: 53, 634 ph: 'S', id: 72, args: {'foo': 'bar'}} 635 ]; 636 637 var m = new tracing.TimelineModel(events); 638 var t = m.processes[52].threads[53]; 639 assertNotUndefined(t); 640 assertEquals(1, t.asyncSlices.slices.length); 641 assertEquals('a', t.asyncSlices.slices[0].title); 642 assertEquals('cat', t.asyncSlices.slices[0].category); 643 assertEquals(72, t.asyncSlices.slices[0].id); 644 assertEquals('bar', t.asyncSlices.slices[0].args.foo); 645 assertEquals(0, t.asyncSlices.slices[0].start); 646 assertAlmostEquals((60 - 24) / 1000, t.asyncSlices.slices[0].duration); 647 assertEquals(t, t.asyncSlices.slices[0].startThread); 648 assertEquals(t, t.asyncSlices.slices[0].endThread); 649 } 650 651 function testEndArgsAddedToSlice() { 652 var events = [ 653 {name: 'a', args: {x: 1}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, 654 {name: 'a', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} 655 ]; 656 657 var m = new tracing.TimelineModel(events); 658 assertEquals(1, m.numProcesses); 659 var p = m.processes[52]; 660 assertNotUndefined(p); 661 662 assertEquals(1, p.numThreads); 663 var t = p.threads[53]; 664 assertNotUndefined(t); 665 assertEquals(1, t.slices.length); 666 assertEquals(53, t.tid); 667 var slice = t.slices[0]; 668 assertEquals('a', slice.title); 669 assertEquals('foo', slice.category); 670 assertEquals(0, slice.start); 671 assertEquals(0, slice.subSlices.length); 672 assertEquals(1, slice.args['x']); 673 assertEquals(2, slice.args['y']); 674 } 675 676 function testEndArgOverrwritesOriginalArgValueIfDuplicated() { 677 var events = [ 678 {name: 'b', args: {z: 3}, pid: 52, ts: 629, cat: 'foo', tid: 53, ph: 'B'}, 679 {name: 'b', args: {z: 4}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'} 680 ]; 681 682 var m = new tracing.TimelineModel(events); 683 assertEquals(1, m.numProcesses); 684 var p = m.processes[52]; 685 assertNotUndefined(p); 686 687 assertEquals(1, p.numThreads); 688 var t = p.threads[53]; 689 assertNotUndefined(t); 690 var slice = t.slices[0]; 691 assertEquals('b', slice.title); 692 assertEquals('foo', slice.category); 693 assertEquals(0, slice.start); 694 assertEquals(0, slice.subSlices.length); 695 assertEquals(4, slice.args['z']); 696 } 697 698 function testAsyncEndArgsAddedToSlice() { 699 var events = [ 700 // Time is intentionally out of order. 701 {name: 'c', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, 702 ph: 'F', id: 72}, 703 {name: 'c', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, 704 ph: 'S', id: 72} 705 ]; 706 707 var m = new tracing.TimelineModel(events); 708 var t = m.processes[52].threads[53]; 709 assertNotUndefined(t); 710 assertEquals(1, t.asyncSlices.slices.length); 711 var parentSlice = t.asyncSlices.slices[0]; 712 assertEquals('c', parentSlice.title); 713 assertEquals('foo', parentSlice.category); 714 715 assertNotUndefined(parentSlice.subSlices); 716 assertEquals(1, parentSlice.subSlices.length); 717 var subSlice = parentSlice.subSlices[0]; 718 assertEquals(1, subSlice.args['x']); 719 assertEquals(2, subSlice.args['y']); 720 } 721 722 function testAsyncEndArgOverrwritesOriginalArgValueIfDuplicated() { 723 var events = [ 724 // Time is intentionally out of order. 725 {name: 'd', args: {z: 4}, pid: 52, ts: 560, cat: 'foo', tid: 53, 726 ph: 'F', id: 72}, 727 {name: 'd', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53, 728 ph: 'S', id: 72} 729 ]; 730 731 var m = new tracing.TimelineModel(events); 732 var t = m.processes[52].threads[53]; 733 assertNotUndefined(t); 734 assertEquals(1, t.asyncSlices.slices.length); 735 var parentSlice = t.asyncSlices.slices[0]; 736 assertEquals('d', parentSlice.title); 737 assertEquals('foo', parentSlice.category); 738 739 assertNotUndefined(parentSlice.subSlices); 740 assertEquals(1, parentSlice.subSlices.length); 741 var subSlice = parentSlice.subSlices[0]; 742 assertEquals(4, subSlice.args['z']); 743 } 744 745 function testAsyncStepsInOneThread() { 746 var events = [ 747 // Time is intentionally out of order. 748 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, 749 ph: 'F', id: 72}, 750 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53, 751 ph: 'T', id: 72}, 752 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, 753 ph: 'S', id: 72} 754 ]; 755 756 var m = new tracing.TimelineModel(events); 757 var t = m.processes[52].threads[53]; 758 assertNotUndefined(t); 759 assertEquals(1, t.asyncSlices.slices.length); 760 var parentSlice = t.asyncSlices.slices[0]; 761 assertEquals('a', parentSlice.title); 762 assertEquals('foo', parentSlice.category); 763 assertEquals(0, parentSlice.start); 764 765 assertNotUndefined(parentSlice.subSlices); 766 assertEquals(2, parentSlice.subSlices.length); 767 var subSlice = parentSlice.subSlices[0]; 768 assertEquals('a', subSlice.title); 769 assertEquals('foo', subSlice.category); 770 assertEquals(0, subSlice.start); 771 assertAlmostEquals((548 - 524) / 1000, subSlice.duration); 772 assertEquals(1, subSlice.args['x']); 773 774 var subSlice = parentSlice.subSlices[1]; 775 assertEquals('a:s1', subSlice.title); 776 assertEquals('foo', subSlice.category); 777 assertAlmostEquals((548 - 524) / 1000, subSlice.start); 778 assertAlmostEquals((560 - 548) / 1000, subSlice.duration); 779 assertEquals(2, subSlice.args['y']); 780 assertEquals(3, subSlice.args['z']); 781 } 782 783 function testAsyncStepsMissingStart() { 784 var events = [ 785 // Time is intentionally out of order. 786 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, 787 ph: 'F', id: 72}, 788 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53, 789 ph: 'T', id: 72} 790 ]; 791 792 var m = new tracing.TimelineModel(events); 793 var t = m.processes[52].threads[53]; 794 assertUndefined(t); 795 } 796 797 function testAsyncStepsMissingFinish() { 798 var events = [ 799 // Time is intentionally out of order. 800 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53, 801 ph: 'T', id: 72}, 802 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, 803 ph: 'S', id: 72} 804 ]; 805 806 var m = new tracing.TimelineModel(events); 807 var t = m.processes[52].threads[53]; 808 assertUndefined(t); 809 } 810 811 // TODO(nduca): one slice, two threads 812 // TODO(nduca): one slice, two pids 813 </script> 814 </body> 815 </html> 816