blob: d97d13647464c3aa15c1e880f367db272d16ae47 [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/base/base.html">
<link rel="import" href="/core/test_utils.html">
<link rel="import" href="/core/trace_model/frame.html">
<link rel="import" href="/extras/audits/android_auditor.html">
<link rel="import" href="/extras/importer/linux_perf/linux_perf_importer.html">
<script>
'use strict';
tv.b.unittest.testSuite(function() {
var SCHEDULING_STATE = tv.c.trace_model.SCHEDULING_STATE;
var newSliceNamed = tv.c.test_utils.newSliceNamed;
var FRAME_PERF_CLASS = tv.c.trace_model.FRAME_PERF_CLASS;
var newThreadSlice = tv.c.test_utils.newThreadSlice;
test('scheduleAlerts', function() {
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 0, 10));
uiThread.timeSlices = [
newThreadSlice(uiThread, SCHEDULING_STATE.RUNNING, 0, 3, 0),
newThreadSlice(uiThread, SCHEDULING_STATE.RUNNABLE, 3, 5, 0),
newThreadSlice(uiThread, SCHEDULING_STATE.RUNNING, 8, 2, 0)];
}, tv.e.audits.AndroidAuditor);
assert.equal(model.alerts.length, 1);
var alert = model.alerts[0];
assert.equal(alert.type.title, 'Scheduling delay');
assert.closeTo(alert.args.delay, 5, 1e-5);
model = tv.c.test_utils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 0, 15));
uiThread.timeSlices = [
newThreadSlice(uiThread, SCHEDULING_STATE.RUNNING, 0, 5, 0),
newThreadSlice(uiThread, SCHEDULING_STATE.UNINTR_SLEEP, 5, 9, 0),
newThreadSlice(uiThread, SCHEDULING_STATE.RUNNING, 14, 1, 0)];
}, tv.e.audits.AndroidAuditor);
assert.equal(model.alerts.length, 1);
var alert = model.alerts[0];
assert.equal(alert.type.title, 'Blocking I/O delay');
assert.closeTo(alert.args.delay, 9, 1e-5);
});
test('saveLayerAlert', function() {
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
var renderThread = model.getOrCreateProcess(1).getOrCreateThread(2);
renderThread.name = 'RenderThread';
renderThread.sliceGroup.pushSlice(newSliceNamed('DrawFrame', 200, 5));
renderThread.sliceGroup.pushSlice(newSliceNamed(
'BadAlphaView alpha caused saveLayer 480x320', 203, 1));
}, tv.e.audits.AndroidAuditor);
assert.equal(model.alerts.length, 1);
var alert = model.alerts[0];
assert.equal(alert.args['view name'], 'BadAlphaView');
assert.equal(alert.args.width, 480);
assert.equal(alert.args.height, 320);
});
test('uploadAlert', function() {
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
var renderThread = model.getOrCreateProcess(1).getOrCreateThread(2);
renderThread.name = 'RenderThread';
renderThread.sliceGroup.pushSlice(newSliceNamed('doFrame', 0, 20));
renderThread.sliceGroup.pushSlice(newSliceNamed(
'Upload 1000x1000 Texture', 0, 15));
}, tv.e.audits.AndroidAuditor);
assert.equal(model.alerts.length, 1);
var alert = model.alerts[0];
assert.closeTo(alert.args['pixels uploaded (millions)'], 1, 1e-5);
assert.equal(alert.args['time spent'], 15);
});
test('listViewAlert', function() {
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceNamed('obtainView', 0, 5));
uiThread.sliceGroup.pushSlice(newSliceNamed('setupListItem', 5, 5));
uiThread.sliceGroup.pushSlice(newSliceNamed('obtainView', 10, 5));
uiThread.sliceGroup.pushSlice(newSliceNamed('setupListItem', 15, 5));
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 20, 10));
// short frame, so no alert should be generated
uiThread.sliceGroup.pushSlice(newSliceNamed('obtainView', 50, 5));
uiThread.sliceGroup.pushSlice(newSliceNamed('setupListItem', 55, 5));
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 60, 1));
}, tv.e.audits.AndroidAuditor);
assert.equal(model.alerts.length, 1);
var alert = model.alerts[0];
assert.equal(alert.args['items inflated'], 2);
assert.closeTo(alert.args['time spent'], 20, 1e-5);
});
test('measureLayoutAlert', function() {
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 0, 20));
uiThread.sliceGroup.pushSlice(newSliceNamed('measure', 0, 5));
uiThread.sliceGroup.pushSlice(newSliceNamed('layout', 10, 5));
}, tv.e.audits.AndroidAuditor);
assert.equal(model.alerts.length, 1);
assert.closeTo(model.alerts[0].args['time spent'], 10, 1e-5);
});
test('viewDrawAlert', function() {
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
// modern naming
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 0, 20));
uiThread.sliceGroup.pushSlice(newSliceNamed('Record View#draw()', 0, 10));
// legacy naming
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 40, 20));
uiThread.sliceGroup.pushSlice(newSliceNamed('getDisplayList', 40, 10));
}, tv.e.audits.AndroidAuditor);
assert.equal(model.alerts.length, 2);
assert.closeTo(model.alerts[0].args['time spent'], 10, 1e-5);
assert.closeTo(model.alerts[1].args['time spent'], 10, 1e-5);
});
test('addFrameToModel', function() {
var process;
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
process = model.getOrCreateProcess(1);
var uiThread = process.getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 0, 8));
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 16, 20));
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 40, 90));
}, tv.e.audits.AndroidAuditor);
assert.equal(process.frames.length, 3);
assert.closeTo(process.frames[0].totalDuration, 8, 1e-5);
assert.closeTo(process.frames[1].totalDuration, 20, 1e-5);
assert.closeTo(process.frames[2].totalDuration, 90, 1e-5);
assert.equal(process.frames[0].perfClass,
FRAME_PERF_CLASS.GOOD);
assert.equal(process.frames[1].perfClass,
FRAME_PERF_CLASS.BAD);
assert.equal(process.frames[2].perfClass,
FRAME_PERF_CLASS.TERRIBLE);
});
test('processRenameAndSort', function() {
var appProcess;
var sfProcess;
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
appProcess = model.getOrCreateProcess(1);
var uiThread = appProcess.getOrCreateThread(1);
uiThread.name = 'ndroid.systemui';
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 0, 8));
sfProcess = model.getOrCreateProcess(2);
var sfThread = sfProcess.getOrCreateThread(2);
sfThread.name = '/system/bin/surfaceflinger';
sfThread.sliceGroup.pushSlice(newSliceNamed('doComposition', 8, 2));
}, tv.e.audits.AndroidAuditor);
// both processes should be renamed
assert.equal(appProcess.name, 'android.systemui');
assert.equal(sfProcess.name, 'SurfaceFlinger');
assert.isTrue(sfProcess.sortIndex < appProcess.sortIndex);
});
test('drawingThreadPriorities', function() {
var uiThread;
var renderThread;
var workerThread;
var otherThread;
var model = tv.c.test_utils.newModelWithAuditor(function(model) {
var appProcess = model.getOrCreateProcess(1);
uiThread = appProcess.getOrCreateThread(1);
uiThread.name = 'ndroid.systemui';
uiThread.sliceGroup.pushSlice(newSliceNamed('performTraversals', 0, 4));
renderThread = appProcess.getOrCreateThread(2);
renderThread.name = 'RenderThread';
renderThread.sliceGroup.pushSlice(newSliceNamed('DrawFrame', 3, 4));
workerThread = appProcess.getOrCreateThread(3);
workerThread.name = 'hwuiTask1';
workerThread.sliceGroup.pushSlice(newSliceNamed('work', 4, 1));
otherThread = appProcess.getOrCreateThread(4);
otherThread.name = 'other';
otherThread.sliceGroup.pushSlice(newSliceNamed('otherWork', 0, 2));
}, tv.e.audits.AndroidAuditor);
assert.isTrue(uiThread.sortIndex < renderThread.sortIndex);
assert.isTrue(renderThread.sortIndex < workerThread.sortIndex);
assert.isTrue(workerThread.sortIndex < otherThread.sortIndex);
});
test('favicon', function() {
var createTraceModelWithJank = function(percentageJank) {
return tv.c.test_utils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
for (var i = 0; i < 100; i++) {
var slice = newSliceNamed('performTraversals',
30 * i,
i <= percentageJank ? 24 : 8);
uiThread.sliceGroup.pushSlice(slice);
}
}, tv.e.audits.AndroidAuditor);
};
assert.equal(createTraceModelWithJank(3).faviconHue, 'green');
assert.equal(createTraceModelWithJank(10).faviconHue, 'yellow');
assert.equal(createTraceModelWithJank(50).faviconHue, 'red');
});
});
</script>