• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html>
2<!--
3Copyright (c) 2015 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/android/android_auditor.html">
10<link rel="import" href="/tracing/extras/importer/linux_perf/ftrace_importer.html">
11
12<script>
13'use strict';
14
15tr.b.unittest.testSuite(function() {
16  var AndroidModelHelper = tr.model.helpers.AndroidModelHelper;
17  var newAsyncSliceNamed = tr.c.TestUtils.newAsyncSliceNamed;
18  var newSliceEx = tr.c.TestUtils.newSliceEx;
19  var newCounterNamed = tr.c.TestUtils.newCounterNamed;
20  var newCounterSeries = tr.c.TestUtils.newCounterSeries;
21
22  function createSurfaceFlingerWithVsyncs(model) {
23      if (model.getProcess(2))
24        throw new Error('process already exists');
25
26      var sfProcess = model.getOrCreateProcess(2);
27      var sfThread = sfProcess.getOrCreateThread(2); // main thread, tid = pid
28      sfThread.name = '/system/bin/surfaceflinger';
29
30      // ensure slicegroup has data
31      sfThread.sliceGroup.pushSlice(newSliceEx({
32        title: 'doComposition',
33        start: 8,
34        duration: 2
35      }));
36
37      var counter = sfProcess.getOrCreateCounter('android', 'VSYNC');
38      var series = newCounterSeries();
39      for (var i = 0; i <= 10; i++) {
40        series.addCounterSample(i * 10, i % 2);
41      }
42      counter.addSeries(series);
43  }
44
45  /*
46   * List of customizeModelCallbacks which produce different 80ms frames,
47   * each starting at 10ms, and with a single important slice
48   */
49  var SINGLE_FRAME_CUSTOM_MODELS = [
50    function(model) {
51      // UI thread only
52      var uiThread = model.getOrCreateProcess(120).getOrCreateThread(120);
53      uiThread.sliceGroup.pushSlice(newSliceEx(
54          {title: 'performTraversals', start: 10, duration: 80}));
55
56      model.uiThread = uiThread;
57    },
58
59    function(model) {
60      // RenderThread only
61      var renderThread = model.getOrCreateProcess(120).getOrCreateThread(200);
62      renderThread.name = 'RenderThread';
63      renderThread.sliceGroup.pushSlice(newSliceEx(
64          {title: 'doFrame', start: 10, duration: 80}));
65
66      model.renderThread = renderThread;
67    },
68
69    function(model) {
70      var uiThread = model.getOrCreateProcess(120).getOrCreateThread(120);
71
72      // UI thread time - 19 (from 10 to 29)
73      uiThread.asyncSliceGroup.push(
74        newAsyncSliceNamed('deliverInputEvent', 10, 9, uiThread, uiThread));
75      uiThread.sliceGroup.pushSlice(newSliceEx(
76          {title: 'performTraversals', start: 20, duration: 10}));
77      uiThread.sliceGroup.pushSlice(newSliceEx(
78          {title: 'draw', start: 20, duration: 8}));
79      uiThread.sliceGroup.pushSlice(newSliceEx(
80          {title: 'Record View#draw()', start: 20, duration: 8}));
81
82      // RenderThread time - 61 (from 29 to 90)
83      var renderThread = model.getOrCreateProcess(120).getOrCreateThread(200);
84      renderThread.name = 'RenderThread';
85      renderThread.sliceGroup.pushSlice(newSliceEx(
86          {title: 'DrawFrame', start: 29, duration: 61}));
87      renderThread.sliceGroup.pushSlice(newSliceEx(
88          {title: 'syncFrameState', start: 29, duration: 1}));
89
90      model.uiThread = uiThread;
91      model.renderThread = renderThread;
92    }
93  ];
94
95  test('getThreads', function() {
96    SINGLE_FRAME_CUSTOM_MODELS.forEach(function(customizeModelCallback) {
97      var model = tr.c.TestUtils.newModel(customizeModelCallback);
98      var helper = model.getOrCreateHelper(AndroidModelHelper);
99      assert.equal(helper.apps[0].uiThread, model.uiThread);
100      assert.equal(helper.apps[0].renderThread, model.renderThread);
101    });
102  });
103
104  test('iterateImportantSlices', function() {
105    SINGLE_FRAME_CUSTOM_MODELS.forEach(function(customizeModelCallback) {
106      var model = tr.c.TestUtils.newModel(customizeModelCallback);
107      var helper = model.getOrCreateHelper(AndroidModelHelper);
108
109      var seen = 0;
110      helper.iterateImportantSlices(function(importantSlice) {
111        assert.isTrue(importantSlice instanceof tr.model.Slice);
112        seen++;
113      });
114      assert.equal(seen, 1);
115    });
116  });
117
118  test('getFrames', function() {
119    SINGLE_FRAME_CUSTOM_MODELS.forEach(function(customizeModelCallback) {
120      var model = tr.c.TestUtils.newModel(customizeModelCallback);
121      var helper = model.getOrCreateHelper(AndroidModelHelper);
122      assert.equal(helper.apps.length, 1);
123
124      var frames = helper.apps[0].getFrames();
125      assert.equal(frames.length, 1);
126      assert.closeTo(frames[0].totalDuration, 80, 1e-5);
127
128      assert.closeTo(frames[0].start, 10, 1e-5);
129      assert.closeTo(frames[0].end, 90, 1e-5);
130    });
131  });
132
133  test('surfaceFlingerVsyncs', function() {
134    var model = tr.c.TestUtils.newModel(createSurfaceFlingerWithVsyncs);
135    var helper = model.getOrCreateHelper(AndroidModelHelper);
136    assert.isTrue(helper.surfaceFlinger.hasVsyncs);
137
138    // test querying the vsyncs
139    assert.closeTo(helper.surfaceFlinger.getFrameKickoff(5), 0, 1e-5);
140    assert.closeTo(helper.surfaceFlinger.getFrameDeadline(95), 100, 1e-5);
141
142    assert.closeTo(helper.surfaceFlinger.getFrameKickoff(10), 10, 1e-5);
143    assert.closeTo(helper.surfaceFlinger.getFrameDeadline(90), 100, 1e-5);
144
145    // test undefined behavior outside of vsyncs.
146    assert.isUndefined(helper.surfaceFlinger.getFrameKickoff(-5));
147    assert.isUndefined(helper.surfaceFlinger.getFrameDeadline(105));
148  });
149
150  test('frameVsyncInterop', function() {
151    var model = tr.c.TestUtils.newModel(function(model) {
152      // app - 3 good, 3 bad frames
153      var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
154      uiThread.sliceGroup.pushSlice(newSliceEx(
155          {title: 'performTraversals', start: 1, duration: 8}));
156      uiThread.sliceGroup.pushSlice(newSliceEx(
157          {title: 'performTraversals', start: 10, duration: 8}));
158      uiThread.sliceGroup.pushSlice(newSliceEx(
159          {title: 'performTraversals', start: 20, duration: 8}));
160      uiThread.sliceGroup.pushSlice(newSliceEx(
161          {title: 'performTraversals', start: 31, duration: 11}));
162      uiThread.sliceGroup.pushSlice(newSliceEx(
163          {title: 'performTraversals', start: 45, duration: 6}));
164      uiThread.sliceGroup.pushSlice(newSliceEx(
165          {title: 'performTraversals', start: 60, duration: 20}));
166
167      // surface flinger - vsync every 10ms
168      createSurfaceFlingerWithVsyncs(model);
169    });
170    var helper = model.getOrCreateHelper(AndroidModelHelper);
171
172    var frames = helper.apps[0].getFrames();
173    assert.equal(frames.length, 6);
174    for (var i = 0; i < 6; i++) {
175      var shouldMissDeadline = i >= 3;
176      var missedDeadline = frames[i].args['deadline'] < frames[i].end;
177      assert.equal(shouldMissDeadline, missedDeadline);
178    }
179  });
180
181  test('appInputs', function() {
182    var model = tr.c.TestUtils.newModel(function(model) {
183      var process = model.getOrCreateProcess(120);
184      var uiThread = process.getOrCreateThread(120);
185      uiThread.sliceGroup.pushSlice(newSliceEx(
186          {title: 'performTraversals', start: 20, duration: 4}));
187      uiThread.sliceGroup.pushSlice(newSliceEx(
188          {title: 'performTraversals', start: 40, duration: 4}));
189
190      var counter = process.getOrCreateCounter('android', 'aq:pending:foo');
191      var series = newCounterSeries();
192      series.addCounterSample(10, 1);
193      series.addCounterSample(20, 0);
194      series.addCounterSample(30, 1);
195      series.addCounterSample(40, 2);
196      series.addCounterSample(50, 0);
197      counter.addSeries(series);
198    });
199    var helper = model.getOrCreateHelper(AndroidModelHelper);
200    assert.equal(helper.apps.length, 1);
201
202    var inputSamples = helper.apps[0].getInputSamples();
203    assert.equal(inputSamples.length, 3);
204    assert.equal(inputSamples[0].timestamp, 10);
205    assert.equal(inputSamples[1].timestamp, 30);
206    assert.equal(inputSamples[2].timestamp, 40);
207  });
208
209  test('appAnimations', function() {
210    var model = tr.c.TestUtils.newModel(function(model) {
211      var process = model.getOrCreateProcess(120);
212      var uiThread = process.getOrCreateThread(120);
213      uiThread.sliceGroup.pushSlice(newSliceEx(
214          {title: 'performTraversals', start: 10, duration: 10}));
215      uiThread.asyncSliceGroup.push(newAsyncSliceNamed('animator:foo', 0, 10,
216                                                       uiThread, uiThread));
217    });
218    var helper = model.getOrCreateHelper(AndroidModelHelper);
219    assert.equal(helper.apps.length, 1);
220
221    var animations = helper.apps[0].getAnimationAsyncSlices();
222    assert.equal(animations.length, 1);
223    assert.equal(animations[0].start, 0);
224    assert.equal(animations[0].end, 10);
225  });
226});
227</script>
228