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