blob: 23905e17cee4ee64f5bd92c4eec78d8f6894d6e3 [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="/tracing/core/auditor.html">
<script>
'use strict';
tr.exportTo('tr.e.audits', function() {
var VSYNC_COUNTER_PRECISIONS = {
// Android. Some versions have VSYNC split out into VSYNC-app and VSYNC-sf.
// Requires "gfx" systrace category to be enabled.
'android.VSYNC-app': 15,
'android.VSYNC': 15
};
var VSYNC_SLICE_PRECISIONS = {
// Android.
'RenderWidgetHostViewAndroid::OnVSync': 5,
// Android. Very precise. Requires "gfx" systrace category to be enabled.
'VSYNC': 10,
// Linux. Very precise. Requires "gpu" tracing category to be enabled.
'vblank': 10,
// Mac. Derived from a Mac callback (CVDisplayLinkSetOutputCallback).
'DisplayLinkMac::GetVSyncParameters': 5
};
var BEGIN_FRAME_SLICE_PRECISION = {
'Scheduler::BeginFrame': 10
};
/**
* Auditor that analyzes the model and, if possible, adds data to it
* indicating when vertical sync events took place.
*
* @constructor
* @extends {tr.c.Auditor}
*/
function VSyncAuditor(model) {
tr.c.Auditor.call(this, model);
};
VSyncAuditor.prototype = {
__proto__: tr.c.Auditor.prototype,
runAnnotate: function() {
this.model.device.vSyncTimestamps = this.findVSyncTimestamps(this.model);
},
/**
* Returns an array of the most accurate VSync times available in the model.
*/
findVSyncTimestamps: function(model) {
var times = [];
// Only keep the most precise VSync data.
var maxPrecision = Number.NEGATIVE_INFINITY;
var maxTitle = undefined;
function useInstead(title, precisions) {
var precision = precisions[title];
if (precision === undefined)
return false;
if (title === maxTitle)
return true;
if (precision <= maxPrecision) {
if (precision === maxPrecision) {
console.warn('Encountered two different VSync events (' +
maxTitle + ', ' + title + ') with the same precision, ' +
'ignoring the newer one (' + title + ')');
}
return false;
}
maxPrecision = precision;
maxTitle = title;
times = [];
return true;
}
for (var pid in model.processes) {
var process = model.processes[pid];
// Traverse process counters.
for (var cid in process.counters) {
if (useInstead(cid, VSYNC_COUNTER_PRECISIONS)) {
var counter = process.counters[cid];
for (var i = 0; i < counter.series.length; i++) {
var series = counter.series[i];
Array.prototype.push.apply(times, series.timestamps);
}
}
}
// Traverse thread slices.
for (var tid in process.threads) {
var thread = process.threads[tid];
for (var i = 0; i < thread.sliceGroup.slices.length; i++) {
var slice = thread.sliceGroup.slices[i];
if (useInstead(slice.title, VSYNC_SLICE_PRECISIONS))
times.push(slice.start);
// We need to check not only that we have a Scheduler::BeginFrame
// event, but also that we have one that has a frame time associated
// with it. Older versions of Scheduler::BeginFrame don't have one.
else if (useInstead(slice.title, BEGIN_FRAME_SLICE_PRECISION) &&
slice.args.args && slice.args.args.frame_time_us)
times.push(slice.args.args.frame_time_us / 1000.0);
}
}
}
times.sort(function(x, y) { return x - y; });
return times;
}
};
tr.c.Auditor.register(VSyncAuditor);
return {
VSyncAuditor: VSyncAuditor
};
});
</script>