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