input_latency_async_slice_test.html revision 4a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724
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/extras/chrome/cc/input_latency_async_slice.html">
9<link rel="import" href="/tracing/core/test_utils.html">
10<link rel="import" href="/tracing/model/event_set.html">
11<link rel="import" href="/tracing/model/model.html">
12<link rel="import" href="/tracing/model/model_indices.html">
13
14<script>
15'use strict';
16
17tr.b.unittest.testSuite(function() {
18  var newAsyncSliceEx = tr.c.test_utils.newAsyncSliceEx;
19  var newSliceEx = tr.c.test_utils.newSliceEx;
20  var newFlowEventEx = tr.c.test_utils.newFlowEventEx;
21  var newModel = tr.c.test_utils.newModel;
22  var EventSet = tr.model.EventSet;
23
24  test('matchByType_oldStyle', function() {
25    var sOuter = newAsyncSliceEx({
26      title: 'InputLatency',
27      cat: 'benchmark',
28      start: 0,
29      end: 10,
30      id: '0x100',
31      isTopLevel: true,
32      args: {
33        data: {
34          INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT: {'time' : 0},
35          INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT: {time: 10}
36        }
37      }
38    });
39    assert.throws(function() {
40      sOuter.typeName;
41    });
42
43    var sInner = newAsyncSliceEx({
44      title: 'InputLatency:GestureScrollUpdate',
45      cat: 'benchmark',
46      start: 2,
47      end: 10,
48      id: '0x100',
49      args: {
50        'step': 'GestureScrollUpdate'
51      }
52    });
53    sOuter.subSlices.push(sInner);
54    assert.isTrue(sOuter instanceof tr.e.cc.InputLatencyAsyncSlice);
55    assert.isTrue(sInner instanceof tr.e.cc.InputLatencyAsyncSlice);
56    assert.equal(sOuter.inputLatency, 10);
57    assert.equal(tr.e.cc.INPUT_EVENT_TYPE_NAMES.SCROLL_UPDATE, sInner.typeName);
58    assert.equal(tr.e.cc.INPUT_EVENT_TYPE_NAMES.SCROLL_UPDATE, sOuter.typeName);
59  });
60
61  test('matchByType_newStyle', function() {
62    var sInfo = newAsyncSliceEx({
63      title: 'InputLatency::GestureScrollUpdate',
64      cat: 'benchmark',
65      start: 2,
66      end: 10,
67      id: '0x100',
68      isTopLevel: true,
69      args: {
70        data: {
71          INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT: {'time' : 0},
72          INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT: {time: 10}
73        }
74      }
75    });
76
77    assert.isTrue(sInfo instanceof tr.e.cc.InputLatencyAsyncSlice);
78    assert.equal(sInfo.inputLatency, 10);
79    assert.equal(tr.e.cc.INPUT_EVENT_TYPE_NAMES.SCROLL_UPDATE, sInfo.typeName);
80  });
81
82  test('unknownType', function() {
83    var sInfo = newAsyncSliceEx({
84      title: 'InputLatency::BadTypeName',
85      cat: 'benchmark,latencyInfo',
86      start: 2,
87      end: 10,
88      id: '0x100',
89      isTopLevel: true,
90      args: {
91        data: {
92          INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT: {'time' : 0},
93          INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT: {'time' : 0},
94          INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT: {time: 10}
95        }
96      }
97    });
98    assert.equal(tr.e.cc.INPUT_EVENT_TYPE_NAMES.UNKNOWN, sInfo.typeName);
99  });
100
101  test('getAssociatedEventsBypassRendererMain', function() {
102    var m = newModel(function(m) {
103
104      var pb = m.getOrCreateProcess(1);
105      var pr = m.getOrCreateProcess(2);
106      var mainBrowserThread = pb.getOrCreateThread(10);
107      var mainRendererThread = pr.getOrCreateThread(20);
108      var compositorThread = pr.getOrCreateThread(21);
109
110      mainBrowserThread.name = 'CrBrowserMain';
111      mainRendererThread.name = 'CrRendererMain';
112      compositorThread.name = 'Compositor';
113
114      // Expectation: None of s2 and s3 should be included
115      // CrBrowserMain:        [s0]             [s1]
116      //                         |              /|\
117      // CrRendererMain:         |   [s2] [s3]   |
118      //                        \|/              |
119      // Compositor:            [s4]-------------|
120
121      m.s0 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
122          { title: 's0', start: 0.0, duration: 1.0 }));
123      m.s1 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
124          { title: 's1', start: 6.0, duration: 1.0 }));
125      m.s2 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
126          { title: 's2', start: 2.0, duration: 1.0 }));
127      m.s3 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
128          { title: 's3', start: 4.0, duration: 1.0 }));
129      m.s4 = compositorThread.sliceGroup.pushSlice(newSliceEx(
130          { title: 's4', start: 0.5, duration: 1.0 }));
131
132      m.f1 = newFlowEventEx({
133        title: 'test1',
134        start: 0,
135        end: 10,
136        startSlice: m.s0,
137        endSlice: m.s4,
138        id: '0x100'
139      });
140
141      m.f2 = newFlowEventEx({
142        title: 'test2',
143        start: 20,
144        end: 30,
145        startSlice: m.s4,
146        endSlice: m.s1,
147        id: '0x100'
148      });
149
150      m.flowEvents.push(m.f1);
151      m.flowEvents.push(m.f2);
152
153      m.as0 = newAsyncSliceEx({
154        title: 'test1',
155        cat: 'benchmark,latencyInfo',
156        start: 2,
157        end: 10,
158        id: '0x101',
159        isTopLevel: true,
160        startThread: mainBrowserThread
161      });
162
163      m.as1 = newAsyncSliceEx({
164        title: 'test2',
165        cat: 'benchmark,latencyInfo',
166        start: 2,
167        end: 10,
168        id: '0x100',
169        isTopLevel: true,
170        startThread: compositorThread
171      });
172
173    });
174
175    assert.isTrue(m.as0.associatedEvents.length === 0);
176    assert.isTrue(m.as1.associatedEvents.equals(
177        new EventSet([m.f1, m.s0, m.f2, m.s4, m.s1])));
178    assert.equal(m.as1.associatedEvents[0].id, '0x100');
179  });
180
181  test('getAssociatedEventsBypassRendererMainWithOnScroll', function() {
182    var m = newModel(function(m) {
183
184      var pb = m.getOrCreateProcess(1);
185      var pr = m.getOrCreateProcess(2);
186      var mainBrowserThread = pb.getOrCreateThread(10);
187      var mainRendererThread = pr.getOrCreateThread(20);
188      var compositorThread = pr.getOrCreateThread(21);
189
190      mainBrowserThread.name = 'CrBrowserMain';
191      mainRendererThread.name = 'CrRendererMain';
192      compositorThread.name = 'Compositor';
193
194      // Expectation: s2 should be included but not s3
195      // GestureScrollUpdate:  [       as1        ]
196      // CrBrowserMain:        [s0]              [s1]
197      //                         |               /|\
198      // CrRendererMain:         |    [s2] [s3]   |
199      //                        \|/   /|\         |
200      // Compositor:            [s4]___|__________|
201      // ScrollUpdate:               [   as2   ]
202
203      m.s0 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
204          { title: 's0', start: 0.0, duration: 1.0 }));
205      m.s1 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
206          { title: 's1', start: 6.0, duration: 1.0 }));
207      m.s2 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
208          { title: 's2', start: 2.0, duration: 1.0 }));
209      m.s3 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
210          { title: 's3', start: 4.0, duration: 1.0 }));
211      m.s4 = compositorThread.sliceGroup.pushSlice(newSliceEx(
212          { title: 's4', start: 0.5, duration: 1.0 }));
213
214      m.f1 = newFlowEventEx({
215        title: 'f1',
216        start: 0,
217        end: 10,
218        startSlice: m.s0,
219        endSlice: m.s4,
220        id: '0x100'
221      });
222
223      m.f2 = newFlowEventEx({
224        title: 'f2',
225        start: 20,
226        end: 30,
227        startSlice: m.s4,
228        endSlice: m.s1,
229        id: '0x100'
230      });
231
232      m.f3 = newFlowEventEx({
233        title: 'f3',
234        start: 20,
235        end: 30,
236        startSlice: m.s4,
237        endSlice: m.s2,
238        id: '0x800'
239      });
240
241      m.flowEvents.push(m.f1);
242      m.flowEvents.push(m.f2);
243      m.flowEvents.push(m.f3);
244
245      m.as0 = mainBrowserThread.asyncSliceGroup.push(newAsyncSliceEx({
246        title: 'InputLatency::GestureScrollUpdate',
247        cat: 'benchmark,latencyInfo',
248        args: {
249          data: {
250            INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT: 100
251          }
252        },
253        start: 2,
254        end: 10,
255        id: '0x101',
256        isTopLevel: true,
257        startThread: mainBrowserThread
258      }));
259      assert.equal(tr.e.cc.INPUT_EVENT_TYPE_NAMES.SCROLL_UPDATE,
260                   m.as0.typeName);
261
262      m.as1 = mainBrowserThread.asyncSliceGroup.push(newAsyncSliceEx({
263        title: 'InputLatency::GestureScrollUpdate',
264        cat: 'benchmark,latencyInfo',
265        args: {
266          data: {}
267        },
268        start: 0,
269        end: 10,
270        id: '0x100',
271        isTopLevel: true,
272        startThread: mainBrowserThread
273      }));
274      assert.equal(tr.e.cc.INPUT_EVENT_TYPE_NAMES.SCROLL_UPDATE,
275                   m.as1.typeName);
276
277      m.as2 = compositorThread.asyncSliceGroup.push(newAsyncSliceEx({
278        title: 'Latency::ScrollUpdate',
279        cat: 'benchmark,latencyInfo',
280        args: {
281          data: {
282            INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT: 100
283          }
284        },
285        start: 1.5,
286        end: 8,
287        id: '0x800',
288        isTopLevel: true,
289        startThread: compositorThread
290      }));
291      assert.equal(tr.e.cc.INPUT_EVENT_TYPE_NAMES.LATENCY_SCROLL_UPDATE,
292                   m.as2.typeName);
293    });
294
295    assert.isTrue(m.as0.associatedEvents.length === 0);
296    assert.isTrue(m.as1.associatedEvents.equals(
297        new EventSet([m.f1, m.s0, m.f2, m.s4, m.s1, m.f3, m.s2])));
298    assert.equal(m.as1.associatedEvents[0].id, '0x100');
299  });
300
301  test('getAssociatedEventsWithoutCommit', function() {
302    var m = newModel(function(m) {
303
304      var pb = m.getOrCreateProcess(1);
305      var pr = m.getOrCreateProcess(2);
306      var mainBrowserThread = pb.getOrCreateThread(10);
307      var mainRendererThread = pr.getOrCreateThread(20);
308      var compositorThread = pr.getOrCreateThread(21);
309
310      mainBrowserThread.name = 'CrBrowserMain';
311      mainRendererThread.name = 'CrRendererMain';
312      compositorThread.name = 'Compositor';
313
314      // Expectation: none of s3 and s5 should be included
315      // CrBrowserMain:        [s0]             [s1]
316      //                         |              /|\
317      //                         |     __________|
318      //                         |     |
319      // CrRendererMain:         |   [s2] [s3]      [s5]
320      //                        \|/   /|\
321      // Compositor:            [s4]___|
322
323      m.s0 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
324          { title: 's0', start: 0.0, duration: 1.0 }));
325      m.s1 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
326          { title: 's1', start: 6.0, duration: 1.0 }));
327      m.s2 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
328          { title: 's2', start: 2.0, duration: 1.0 }));
329      m.s3 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
330          { title: 's3', start: 4.0, duration: 1.0 }));
331      m.s4 = compositorThread.sliceGroup.pushSlice(newSliceEx(
332          { title: 's4', start: 0.5, duration: 1.0 }));
333      m.s5 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
334          { title: 's5', start: 100.0, duration: 1.0 }));
335
336      m.f1 = newFlowEventEx({
337        title: 'f1',
338        start: 0,
339        end: 10,
340        startSlice: m.s0,
341        endSlice: m.s4,
342        id: '0x100'
343      });
344
345      m.f2 = newFlowEventEx({
346        title: 'f2',
347        start: 20,
348        end: 30,
349        startSlice: m.s4,
350        endSlice: m.s2,
351        id: '0x100'
352      });
353
354      m.f3 = newFlowEventEx({
355        title: 'f3',
356        start: 20,
357        end: 30,
358        startSlice: m.s2,
359        endSlice: m.s1,
360        id: '0x100'
361      });
362
363      m.flowEvents.push(m.f1);
364      m.flowEvents.push(m.f2);
365      m.flowEvents.push(m.f3);
366
367      m.as0 = newAsyncSliceEx({
368        title: 'test1',
369        cat: 'benchmark,latencyInfo',
370        start: 2,
371        end: 10,
372        id: '0x101',
373        isTopLevel: true,
374        startThread: mainBrowserThread
375      });
376
377      m.as1 = newAsyncSliceEx({
378        title: 'test2',
379        cat: 'benchmark,latencyInfo',
380        start: 2,
381        end: 10,
382        id: '0x100',
383        isTopLevel: true,
384        startThread: mainBrowserThread
385      });
386
387    });
388
389    assert.isTrue(m.as0.associatedEvents.length === 0);
390    assert.isTrue(m.as1.associatedEvents.equals(
391        new EventSet([m.f1, m.s0, m.f2, m.s4, m.f3, m.s2, m.s1])));
392    assert.equal(m.as1.associatedEvents[0].id, '0x100');
393  });
394
395  test('getAssociatedEventsWillCommit', function() {
396    var m = newModel(function(m) {
397
398      var pb = m.getOrCreateProcess(1);
399      var pr = m.getOrCreateProcess(2);
400      var mainBrowserThread = pb.getOrCreateThread(10);
401      var mainRendererThread = pr.getOrCreateThread(20);
402      var compositorThread = pr.getOrCreateThread(21);
403
404      mainBrowserThread.name = 'CrBrowserMain';
405      mainRendererThread.name = 'CrRendererMain';
406      compositorThread.name = 'Compositor';
407
408      // Expectation: s3 should be included by getOtherCasuallyRelatedEvents,
409      // because there is a PostTask s7 -> s3, but s6 shouldn't be included.
410      // CrBrowserMain:        [s0]                [ s1 ]
411      //                         |                   /|\
412      //                         |                    |
413      //                         | [    s2   ]____    |
414      // CrRendererMain:         |   /|\ [s7]     |   |     [s6]
415      //                         |    |   |       |   |
416      //                         |    |   |       |   |
417      //                        \|/   |  \|/     \|/  |
418      // Compositor:            [s4]__|  [s3]   [s5]__|
419
420      m.s0 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
421          { title: 's0', start: 0.0, duration: 1.0 }));
422      m.s1 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
423          { title: 's1', start: 6.0, duration: 1.0 }));
424      m.s2 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
425          { title: 's2', start: 2.0, duration: 1.0 }));
426      m.s3 = compositorThread.sliceGroup.pushSlice(newSliceEx(
427          { title: 's3', start: 4.0, duration: 1.0 }));
428      m.s4 = compositorThread.sliceGroup.pushSlice(newSliceEx(
429          { title: 's4', start: 0.5, duration: 1.0 }));
430      m.s5 = compositorThread.sliceGroup.pushSlice(newSliceEx(
431          { title: 's5', start: 5.5, duration: 1.0 }));
432      m.s6 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
433          { title: 's6', start: 1000.0, duration: 1.0 }));
434      m.s7 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
435          { title: 's7', start: 2.5, duration: 0.2 }));
436
437      mainBrowserThread.sliceGroup.createSubSlices();
438      mainRendererThread.sliceGroup.createSubSlices();
439      compositorThread.sliceGroup.createSubSlices();
440
441      m.f1 = newFlowEventEx({
442        title: 'f1',
443        start: 0,
444        end: 10,
445        startSlice: m.s0,
446        endSlice: m.s4,
447        id: '0x100'
448      });
449
450      m.f2 = newFlowEventEx({
451        title: 'f2',
452        start: 20,
453        end: 30,
454        startSlice: m.s4,
455        endSlice: m.s2,
456        id: '0x100'
457      });
458
459      m.f3 = newFlowEventEx({
460        title: 'f3',
461        start: 20,
462        end: 30,
463        startSlice: m.s2,
464        endSlice: m.s5,
465        id: '0x100'
466      });
467
468      m.f4 = newFlowEventEx({
469        title: 'f4',
470        start: 20,
471        end: 30,
472        startSlice: m.s5,
473        endSlice: m.s1,
474        id: '0x100'
475      });
476
477      m.f5 = newFlowEventEx({
478        title: 'f5',
479        cat: 'disabled-by-default-toplevel.flow',
480        start: 20,
481        end: 30,
482        startSlice: m.s7,
483        endSlice: m.s3,
484        id: '0xAAA'
485      });
486
487      m.flowEvents.push(m.f1);
488      m.flowEvents.push(m.f2);
489      m.flowEvents.push(m.f3);
490      m.flowEvents.push(m.f4);
491      m.flowEvents.push(m.f5);
492
493      m.as0 = newAsyncSliceEx({
494        title: 'test1',
495        cat: 'benchmark,latencyInfo',
496        start: 2,
497        end: 10,
498        id: '0x101',
499        isTopLevel: true,
500        startThread: mainBrowserThread
501      });
502
503      m.as1 = newAsyncSliceEx({
504        title: 'test2',
505        cat: 'benchmark,latencyInfo',
506        start: 2,
507        end: 10,
508        id: '0x100',
509        isTopLevel: true,
510        startThread: mainBrowserThread
511      });
512
513    });
514
515    assert.isTrue(m.as0.associatedEvents.length === 0);
516    assert.isTrue(m.as1.associatedEvents.equals(new EventSet(
517        [m.f1, m.f2, m.f3, m.f4, m.f5,
518         m.s0, m.s1, m.s2, m.s3, m.s4, m.s5, m.s7])));
519    assert.equal(m.as1.associatedEvents[0].id, '0x100');
520  });
521
522  test('getAssociatedEventsExcludeOtherInputs', function() {
523    var m = newModel(function(m) {
524
525      var pb = m.getOrCreateProcess(1);
526      var pr = m.getOrCreateProcess(2);
527      var mainBrowserThread = pb.getOrCreateThread(10);
528      var mainRendererThread = pr.getOrCreateThread(20);
529      var compositorThread = pr.getOrCreateThread(21);
530
531      mainBrowserThread.name = 'CrBrowserMain';
532      mainRendererThread.name = 'CrRendererMain';
533      compositorThread.name = 'Compositor';
534
535      // Expectation: s3 should be included by getOtherCasuallyRelatedEvents,
536      // because there is a PostTask s7 -> s3. Even though there is also a
537      // PostTask from s9 to s6, s6 shouldn't be included because it's tracked
538      // by LatencyInfo of another input.
539      // CrBrowserMain:        [s0]                 [ s1 ]   [s8]
540      //                         |                    /|\     |
541      //                         |                     |      |
542      //                         | [    s2   ]____     |     \|/
543      // CrRendererMain:         |   /|\ [s7]     |    |     [s6]
544      //                         |    |   |       |    |     /|\
545      //                         |    |   |       |    |      |
546      //                        \|/   |  \|/     \|/   |      |
547      // Compositor:            [s4]__|  [s3]   [ s5 ]_|      |
548      //                                         [s9]_________|
549
550      m.s0 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
551          { title: 's0', start: 0.0, duration: 1.0 }));
552      m.s1 = mainBrowserThread.sliceGroup.pushSlice(newSliceEx(
553          { title: 's1', start: 6.0, duration: 1.0 }));
554      m.s2 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
555          { title: 's2', start: 2.0, duration: 1.0 }));
556      m.s3 = compositorThread.sliceGroup.pushSlice(newSliceEx(
557          { title: 's3', start: 4.0, duration: 1.0 }));
558      m.s4 = compositorThread.sliceGroup.pushSlice(newSliceEx(
559          { title: 's4', start: 0.5, duration: 1.0 }));
560      m.s5 = compositorThread.sliceGroup.pushSlice(newSliceEx(
561          { title: 's5', start: 5.5, duration: 1.0 }));
562      m.s6 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
563          { title: 's6', start: 10.0, duration: 1.0 }));
564      m.s7 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
565          { title: 's7', start: 2.5, duration: 0.2 }));
566      m.s8 = mainRendererThread.sliceGroup.pushSlice(newSliceEx(
567          { title: 's8', start: 9.5, duration: 1.0 }));
568      m.s9 = compositorThread.sliceGroup.pushSlice(newSliceEx(
569          { title: 'Scheduler::ScheduleBeginImplFrameDeadline',
570            start: 5.7, duration: 0.2 }));
571
572      mainBrowserThread.sliceGroup.createSubSlices();
573      mainRendererThread.sliceGroup.createSubSlices();
574      compositorThread.sliceGroup.createSubSlices();
575
576      m.f1 = newFlowEventEx({
577        title: 'f1',
578        cat: 'input',
579        start: 0,
580        end: 10,
581        startSlice: m.s0,
582        endSlice: m.s4,
583        id: '0x100'
584      });
585
586      m.f2 = newFlowEventEx({
587        title: 'f2',
588        cat: 'input',
589        start: 20,
590        end: 30,
591        startSlice: m.s4,
592        endSlice: m.s2,
593        id: '0x100'
594      });
595
596      m.f3 = newFlowEventEx({
597        title: 'f3',
598        cat: 'input',
599        start: 20,
600        end: 30,
601        startSlice: m.s2,
602        endSlice: m.s5,
603        id: '0x100'
604      });
605
606      m.f4 = newFlowEventEx({
607        title: 'f4',
608        cat: 'input',
609        start: 20,
610        end: 30,
611        startSlice: m.s5,
612        endSlice: m.s1,
613        id: '0x100'
614      });
615
616      m.f5 = newFlowEventEx({
617        title: 'f5',
618        cat: 'disabled-by-default-toplevel.flow',
619        start: 20,
620        end: 30,
621        startSlice: m.s7,
622        endSlice: m.s3,
623        id: '0xAAA'
624      });
625
626      m.f6 = newFlowEventEx({
627        title: 'f6',
628        cat: 'disabled-by-default-toplevel.flow',
629        start: 20,
630        end: 30,
631        startSlice: m.s9,
632        endSlice: m.s6,
633        id: '0xAAB'
634      });
635
636      m.f7 = newFlowEventEx({
637        title: 'f7',
638        cat: 'input',
639        start: 20,
640        end: 30,
641        startSlice: m.s8,
642        endSlice: m.s6,
643        id: '0x102'
644      });
645
646      m.flowEvents.push(m.f1);
647      m.flowEvents.push(m.f2);
648      m.flowEvents.push(m.f3);
649      m.flowEvents.push(m.f4);
650      m.flowEvents.push(m.f5);
651      m.flowEvents.push(m.f6);
652      m.flowEvents.push(m.f7);
653
654      m.as0 = newAsyncSliceEx({
655        title: 'test1',
656        cat: 'benchmark,latencyInfo',
657        start: 2,
658        end: 10,
659        id: '0x101',
660        isTopLevel: true,
661        startThread: mainBrowserThread
662      });
663
664      m.as1 = newAsyncSliceEx({
665        title: 'test2',
666        cat: 'benchmark,latencyInfo',
667        start: 2,
668        end: 10,
669        id: '0x100',
670        isTopLevel: true,
671        startThread: mainBrowserThread
672      });
673
674      m.as2 = newAsyncSliceEx({
675        title: 'test2',
676        cat: 'benchmark,latencyInfo',
677        start: 2,
678        end: 10,
679        id: '0x102',
680        isTopLevel: true,
681        startThread: mainBrowserThread
682      });
683
684    });
685
686    assert.isTrue(m.as0.associatedEvents.length === 0);
687    assert.isTrue(m.as1.associatedEvents.equals(new EventSet(
688        [m.f1, m.f2, m.f3, m.f4, m.f5,
689         m.s0, m.s1, m.s2, m.s3, m.s4, m.s5, m.s7, m.s9])));
690    assert.equal(m.as1.associatedEvents[0].id, '0x100');
691  });
692
693});
694</script>
695