Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Unified Diff: perf_insights/perf_insights/timeline_based_measurement/rendering_stats_test.html

Issue 1336373002: Port rendering_stats' implementation to javascript (Closed) Base URL: https://github.com/catapult-project/catapult@master
Patch Set: Address some of Nat's comments Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: perf_insights/perf_insights/timeline_based_measurement/rendering_stats_test.html
diff --git a/perf_insights/perf_insights/timeline_based_measurement/rendering_stats_test.html b/perf_insights/perf_insights/timeline_based_measurement/rendering_stats_test.html
new file mode 100644
index 0000000000000000000000000000000000000000..e1a6a39651aaa96222b64a0fc83059dfc7fb96c1
--- /dev/null
+++ b/perf_insights/perf_insights/timeline_based_measurement/rendering_stats_test.html
@@ -0,0 +1,734 @@
+<!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/base/math.html">
+<link rel="import" href="/tracing/base/range.html">
+<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/utils.html">
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/extras/chrome/cc/constants.html">
+<link rel="import" href="/tracing/extras/chrome/chrome_test_utils.html">
+<link rel="import" href="/tracing/model/model.html">
+
+<link rel="import"
+ href="/perf_insights/timeline_based_measurement/rendering_stats.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+
+ var RenderingStatsHelpers = pi.tbm.RenderingStatsHelpers;
+ var RenderingStats = pi.tbm.RenderingStats;
+ var Range = tr.b.Range;
+ var constants = tr.e.cc.constants;
+ var round = tr.b.round;
+ var flattenArray = tr.b.flattenArray;
+
+ var test_utils = tr.c.TestUtils;
+ var ThreadSlice = tr.model.ThreadSlice;
+
+
dsinclair 2015/09/22 16:08:32 nit: remove blank line
+ /**
+ * A mock timer class.
+ *
+ * An instance of this class is used as a global timer for stats and
+ * consistent timestamps for all mock trace events.
+ * The unit of time is milliseconds.
+ **/
+ function MockTimer() {
+ this.milliseconds = 0;
+ }
+
+ MockTimer.prototype = {
+ advance: function(low, high, delta) {
+ this.milliseconds += delta;
+ return delta;
+ },
+
+ advanceAndGet(opt_low, opt_high, opt_delta) {
+ if (opt_low === undefined)
+ opt_low = 0.1;
dsinclair 2015/09/22 16:08:32 opt_low = opt_low || 0.1; (although this doesn't
+ if (opt_high === undefined)
+ opt_high = 1.0;
+ if (opt_delta === undefined)
+ opt_delta = 0.4;
+ this.advance(opt_low, opt_high, opt_delta);
+ return this.milliseconds;
+ }
+ };
+
+ /* Stores expected data for comparison with actual RenderingStats */
+ function ReferenceRenderingStats() {
+ this.frameTimestamps = [];
+ this.frameTimes = [];
+ this.approximatedPixelPercentages = [];
+ this.checkerboardedPixelPercentages = [];
+ }
+
+ ReferenceRenderingStats.prototype = {
+ pushNewRange: function() {
+ this.frameTimestamps.push([]);
+ this.frameTimes.push([]);
+ this.approximatedPixelPercentages.push([]);
+ this.checkerboardedPixelPercentages.push([]);
+ }
+ };
+
+ /* Stores expected data for comparison with actual input latency stats */
+ function ReferenceInputLatencyStats() {
+ this.inputEventLatency = [];
+ this.input_event = [];
+ }
+
+ /**
+ * Adds a random surface flinger stats event.
+ *
+ * thread: The timeline model thread to which the event will be added.
+ * first_frame: Is this the first frame within the bounds of an action?
+ * opt_ref_stats: A ReferenceRenderingStats object to record expected
+ * values.
+ **/
+ function addSurfaceFlingerStats(
+ mock_timer, thread, first_frame, opt_ref_stats) {
+
+ // Create randonm data and timestap for impl thread rendering stats.
dsinclair 2015/09/22 16:08:32 nit: s/randonm/random nit: s/timestap/timestamp
+ var data = {
+ 'frame_count': 1,
+ 'refresh_period': 16.6666
+ };
+ var timestamp = mock_timer.advanceAndGet();
+
dsinclair 2015/09/22 16:08:32 nit: remove blank line
+
+ // Add a slice with the event data to the given thread.
+ thread.sliceGroup.pushSlice(test_utils.newSliceEx({
+ type: ThreadSlice,
+ cat: 'SurfaceFlinger',
+ title: 'vsync_before',
+ start: timestamp,
+ duration: 0.0,
+ args: {
+ 'data': data
+ }
+ }));
+
+
+ if (opt_ref_stats === undefined)
+ return;
+
+ // Add timestamp only if a frame was output
+ if (data['frame_count'] === 1) {
dsinclair 2015/09/22 16:08:32 if (data.frame_count !== 1) return;
+ var frameTimes = opt_ref_stats.frameTimes;
+ var frameTimestamps = opt_ref_stats.frameTimestamps;
+ if (!first_frame) {
+ // Add frame_time if this is not the first frame in within the bounds
+ // of an action.
+ var prev_timestamps_group =
+ frameTimestamps[frameTimestamps.length - 1];
+ var prev_timestamp =
+ prev_timestamps_group[prev_timestamps_group.length - 1];
+ frameTimes[frameTimes.length - 1].push(timestamp - prev_timestamp);
+ }
+ frameTimestamps[frameTimestamps.length - 1].push(timestamp);
+
+ }
+ }
+
+ /**
+ * Adds a random display rendering stats event.
+ *
+ * thread: The timeline model thread to which the event will be added.
+ * first_frame: Is this the first frame within the bounds of an action?
dsinclair 2015/09/22 16:08:32 Do we know the answer to this?
+ * ref_stats: A ReferenceRenderingStats object to record expected values.
+ **/
+ function addDisplayRenderingStats(
+ mock_timer, thread, first_frame, opt_ref_stats) {
+
+ // Create randonm data and timestap for main thread rendering stats.
+ var data = {
+ 'frame_count': 1
+ };
+ var timestamp = mock_timer.advanceAndGet();
+
+ // Add a slice with the event data to the given thread.
+ thread.sliceGroup.pushSlice(test_utils.newSliceEx({
+ type: ThreadSlice,
+ cat: 'benchmark',
+ title: 'BenchmarkInstrumentation::DisplayRenderingStats',
+ start: timestamp,
+ duration: 0.0,
+ args: {
+ 'data': data
+ }
+ }));
+
+ if (opt_ref_stats === undefined)
+ return;
+ var frameTimes = opt_ref_stats.frameTimes;
+ var frameTimestamps = opt_ref_stats.frameTimestamps;
+ // Add timestamp only if a frame was output
+ if (!first_frame) {
+ // Add frame_time if this is not the first frame in within the bounds of
+ // an action.
+ var prev_timestamps_group =
+ frameTimestamps[frameTimestamps.length - 1];
+ var prev_timestamp =
+ prev_timestamps_group[prev_timestamps_group.length - 1];
+ frameTimes[frameTimes.length - 1].push(timestamp - prev_timestamp);
+ }
+ frameTimestamps[frameTimestamps.length - 1].push(timestamp);
+ }
+
+ /**
+ * Adds a random impl thread rendering stats event.
+ *
+ * thread: The model thread to which the event will be added.
+ * first_frame: Is this the first frame within the bounds of an action?
+ * opt_ref_stats: A ReferenceRenderingStats object to record expected
+ * values.
+ **/
+ function addImplThreadRenderingStats(
+ mock_timer, thread, first_frame, opt_ref_stats) {
+
+ // Create randonm data and timestap for impl thread rendering stats.
+ var data = {
+ 'frame_count': 1,
+ 'visible_content_area': 95,
+ 'approximated_visible_content_area': 3,
+ 'checkerboarded_visible_content_area': 4
+ };
+ var timestamp = mock_timer.advanceAndGet();
+
+ // Add a slice with the event data to the given thread.
+ thread.sliceGroup.pushSlice(test_utils.newSliceEx({
+ type: ThreadSlice,
+ cat: 'benchmark',
+ title: 'BenchmarkInstrumentation::ImplThreadRenderingStats',
+ start: timestamp,
+ duration: 0.0,
+ args: {
+ 'data': data
+ }
+ }));
+
+ if (!opt_ref_stats)
+ return;
+
+ // Add timestamp only if a frame was output
+ if (data['frame_count'] === 1) {
+ if (!first_frame) {
+ // Add frame_time if this is not the first frame in within the bounds
+ // of an action.
+ var lastFrameTimestamps = opt_ref_stats.frameTimestamps[
+ opt_ref_stats.frameTimestamps.length - 1];
+ var prev_timestamp = lastFrameTimestamps[
+ lastFrameTimestamps.length - 1];
+ opt_ref_stats.frameTimes[opt_ref_stats.frameTimes.length - 1].push(
+ timestamp - prev_timestamp);
+ }
+ opt_ref_stats.frameTimestamps[
+ opt_ref_stats.frameTimestamps.length - 1].push(timestamp);
+
+ opt_ref_stats.approximatedPixelPercentages[
+ opt_ref_stats.approximatedPixelPercentages.length - 1].push(
+ round(tr.b.Statistics.divideIfPossibleOrZero(
+ data['approximated_visible_content_area'],
+ data['visible_content_area']) * 100.0, 3));
+
+ opt_ref_stats.checkerboardedPixelPercentages[
+ opt_ref_stats.checkerboardedPixelPercentages.length - 1].push(
+ round(tr.b.Statistics.divideIfPossibleOrZero(
+ data['checkerboarded_visible_content_area'],
+ data['visible_content_area']) * 100.0, 3));
+ }
+ }
+
+ /**
+ * Adds a random input latency stats event.
+ *
+ * start_thread: The start thread on which the async slice is added.
+ * end_thread: The end thread on which the async slice is ended.
+ * opt_ref_latency_stats: A ReferenceInputLatencyStats object for expected
+ * values.
+ **/
+ function addInputLatencyStats(
+ mock_timer, start_thread, end_thread, opt_ref_latency_stats) {
+
+ var original_comp_time = mock_timer.advanceAndGet(2, 4) * 1000.0;
+ var ui_comp_time = mock_timer.advanceAndGet(2, 4) * 1000.0;
+ var begin_comp_time = mock_timer.advanceAndGet(2, 4) * 1000.0;
+ var forward_comp_time = mock_timer.advanceAndGet(2, 4) * 1000.0;
+ var end_comp_time = mock_timer.advanceAndGet(10, 20) * 1000.0;
+
+ var data = {};
+ data[constants.ORIGINAL_COMP_NAME] = {
+ 'time': original_comp_time
+ };
+ data[constants.UI_COMP_NAME] = {
+ 'time': ui_comp_time
+ };
+ data[constants.BEGIN_COMP_NAME] = {
+ 'time': begin_comp_time
+ };
+ data[constants.END_COMP_NAME] = {
+ 'time': end_comp_time
+ };
+
+ var timestamp = mock_timer.advanceAndGet(2, 4);
+
+ var tracing_async_slice = test_utils.newAsyncSliceEx({
+ cat: 'benchmark',
+ title: 'InputLatency',
+ start: timestamp,
+ duration: 0
+ });
+
+ var async_sub_slice = test_utils.newAsyncSliceEx({
+ cat: 'benchmark',
+ title: constants.GESTURE_SCROLL_UPDATE_EVENT_NAME,
+ start: timestamp,
+ args: {
+ 'data': data
+ },
+ duration: 0
+ });
+ async_sub_slice.parentContainer = tracing_async_slice;
+ async_sub_slice.startThread = start_thread;
+ async_sub_slice.endThread = end_thread;
+
+ tracing_async_slice.subSlices.push(async_sub_slice);
+ tracing_async_slice.startThread = start_thread;
+ tracing_async_slice.endThread = end_thread;
+ start_thread.sliceGroup.pushSlice(tracing_async_slice);
+
+ // Add scroll update latency info.
+ var scroll_update_data = {};
+ scroll_update_data[
+ constants.BEGIN_SCROLL_UPDATE_COMP_NAME] = {
+ 'time': begin_comp_time
+ };
+ scroll_update_data[
+ constants.FORWARD_SCROLL_UPDATE_COMP_NAME] = {
+ 'time': forward_comp_time
+ };
+ scroll_update_data[constants.END_COMP_NAME] = {
+ 'time': end_comp_time
+ };
+
+ var scroll_async_slice = test_utils.newAsyncSliceEx({
+ cat: 'benchmark',
+ title: 'InputLatency',
+ start: timestamp,
+ duration: 0
+ });
+
+ var scroll_async_sub_slice = test_utils.newAsyncSliceEx({
+ cat: 'benchmark',
+ title: constants.SCROLL_UPDATE_EVENT_NAME,
+ start: timestamp,
+ args: {
+ 'data': scroll_update_data
+ },
+ duration: 0
+ });
+ scroll_async_sub_slice.parentContainer = scroll_async_slice;
+ scroll_async_sub_slice.startThread = start_thread;
+ scroll_async_sub_slice.endThread = end_thread;
+
+ scroll_async_slice.subSlices.push(scroll_async_sub_slice);
+ scroll_async_slice.startThread = start_thread;
+ scroll_async_slice.endThread = end_thread;
+ start_thread.sliceGroup.pushSlice(scroll_async_slice);
+
+ // Also add some dummy frame statistics so we can feed the resulting
+ // timeline to RenderingStats.
+ addImplThreadRenderingStats(mock_timer, end_thread, false);
+
+ if (opt_ref_latency_stats === undefined)
+ return;
+
+ opt_ref_latency_stats.input_event.push(async_sub_slice);
+ opt_ref_latency_stats.input_event.push(
+ scroll_async_sub_slice);
+ opt_ref_latency_stats.inputEventLatency.push({
+ eventTitle: constants.GESTURE_SCROLL_UPDATE_EVENT_NAME,
+ latency: (data[constants.END_COMP_NAME]['time'] -
+ data[constants.ORIGINAL_COMP_NAME]['time']) / 1000.0
+ });
+ var scroll_update_time = (
+ scroll_update_data[constants.END_COMP_NAME].time -
+ scroll_update_data[
+ constants.BEGIN_SCROLL_UPDATE_COMP_NAME].time);
+ opt_ref_latency_stats.inputEventLatency.push({
+ eventTitle: constants.SCROLL_UPDATE_EVENT_NAME,
+ latency: scroll_update_time / 1000.0
+ });
+ };
+
+ test('hasRenderingStats', function() {
+ var model = new tr.Model();
+ var timer = new MockTimer();
+
+ // A process without rendering stats
+ var process_without_stats = model.getOrCreateProcess(1);
+ var thread_without_stats = process_without_stats.getOrCreateThread(
+ 11);
+ model.updateBounds();
+ assert.equal(
+ RenderingStatsHelpers.hasRenderingStats(thread_without_stats),
+ false);
+
+ // A process with rendering stats, but no frames in them
+ var process_without_frames = model.getOrCreateProcess(2);
+ var thread_without_frames = process_without_frames.getOrCreateThread(
+ 21);
+ process_without_frames.updateBounds();
+ assert.equal(
+ RenderingStatsHelpers.hasRenderingStats(thread_without_frames),
+ false);
+
+ // A process with rendering stats and frames in them
+ var process_with_frames = model.getOrCreateProcess(3);
+ var thread_with_frames = process_with_frames.getOrCreateThread(31);
+ addImplThreadRenderingStats(timer, thread_with_frames, true);
+ process_with_frames.updateBounds();
+ assert.equal(
+ RenderingStatsHelpers.hasRenderingStats(thread_with_frames),
+ true);
+
+ });
+
+ test('bothSurfaceFlingerAndDisplayStats', function() {
+ var model = new tr.Model();
+ var timer = new MockTimer();
+
+ var ref_stats = new ReferenceRenderingStats();
+ ref_stats.pushNewRange();
+ var surface_flinger = model.getOrCreateProcess(4);
+ surface_flinger.title = 'SurfaceFlinger';
+ var surface_flinger_thread = surface_flinger.getOrCreateThread(41);
+ var renderer = model.getOrCreateProcess(2);
+ var browser = model.getOrCreateProcess(3);
+ var browser_main = browser.getOrCreateThread(31);
+ browser_main.sliceGroup.beginSlice('webkit.console', 'ActionA',
+ timer.advanceAndGet(2, 4), '');
+
+ // Create SurfaceFlinger stats and display rendering stats.
+ for (var i = 0; i < 10; i++) {
+ var first = i === 0;
+ addSurfaceFlingerStats(timer, surface_flinger_thread, first,
+ ref_stats);
+ timer.advance(2, 4, 0.5);
+ }
+
+ for (var i = 0; i < 10; i++) {
+ var first = i === 0;
+ addDisplayRenderingStats(timer, browser_main, first);
+ timer.advance(5, 10, 0.1);
+ }
+
+ browser_main.sliceGroup.endSlice(timer.advanceAndGet());
+ timer.advance(2, 4, 0.2);
+
+ browser.updateBounds();
+ renderer.updateBounds();
+ var timelineRanges = [];
+ model.iterateAllEvents(function(event) {
+ if (event.title === 'ActionA') {
+ timelineRanges.push(Range.fromExplicitRange(event.start, event.end));
+ }
+ });
+ var stats = new RenderingStats(
+ renderer, browser, surface_flinger, timelineRanges);
+
+ // Compare rendering stats to reference - Only SurfaceFlinger stats should
+ // count
+ assert.deepEqual(stats.frameTimestamps, ref_stats.frameTimestamps);
+ assert.deepEqual(stats.frameTimes, ref_stats.frameTimes);
+ });
+
+ test('bothDisplayAndImplStats', function() {
+ var model = new tr.Model();
+ var timer = new MockTimer();
+
+ var ref_stats = new ReferenceRenderingStats();
+ ref_stats.pushNewRange();
+ var renderer = model.getOrCreateProcess(2);
+ var browser = model.getOrCreateProcess(3);
+ var browser_main = browser.getOrCreateThread(31);
+ browser_main.sliceGroup.beginSlice('webkit.console', 'ActionA',
+ timer.advanceAndGet(2, 4), '');
+
+ // Create SurfaceFlinger stats and display rendering stats.
+ for (var i = 0; i < 10; i++) {
+ var first = i === 0;
+ addImplThreadRenderingStats(timer, browser_main, first);
+ timer.advance(2, 4, 0.4);
+ }
+
+ for (var i = 0; i < 10; i++) {
+ var first = i === 0;
+ addDisplayRenderingStats(timer, browser_main, first, ref_stats);
+ timer.advance(5, 10, 0.3);
+ }
+
+ browser_main.sliceGroup.endSlice(timer.advanceAndGet());
+ timer.advance(2, 4, 0.9);
+
+ browser.updateBounds();
+ renderer.updateBounds();
+ var timelineRanges = [];
+ model.iterateAllEvents(function(event) {
+ if (event.title === 'ActionA') {
+ timelineRanges.push(Range.fromExplicitRange(event.start, event.end));
+ }
+ });
+ var stats = new RenderingStats(renderer, browser, null, timelineRanges);
+
+ // Compare rendering stats to reference - Only SurfaceFlinger stats should
+ // count
+ assert.deepEqual(stats.frameTimestamps, ref_stats.frameTimestamps);
+ assert.deepEqual(stats.frameTimes, ref_stats.frameTimes);
+ });
+
+
+ test('rangeWithoutFrames', function() {
+ var model = new tr.Model();
+ var timer = new MockTimer();
+
+ // Create a renderer process, with a main thread and impl thread.
+ var renderer = model.getOrCreateProcess(2);
+ var renderer_main = renderer.getOrCreateThread(21);
+ var renderer_compositor = renderer.getOrCreateThread(22);
+
+ // Create 10 main and impl rendering stats events for Action A.
+ renderer_main.sliceGroup.beginSlice('webkit.console', 'ActionA',
+ timer.advanceAndGet(2, 4), '');
+ for (var i = 0; i < 10; i++) {
+ var first = i === 0;
+ addImplThreadRenderingStats(timer, renderer_compositor, first);
+ }
+ renderer_main.sliceGroup.endSlice(timer.advanceAndGet(2, 4));
+ timer.advance(2, 4, 0.7);
+
+ // Create 5 main and impl rendering stats events not within any action.
+ for (var i = 0; i < 5; i++) {
+ var first = i === 0;
+ addImplThreadRenderingStats(timer, renderer_compositor, first);
+ }
+
+ // Create Action B without any frames. This should trigger
+ // NotEnoughFramesError when the RenderingStats object is created.
+ renderer_main.sliceGroup.beginSlice('webkit.console', 'ActionB',
+ timer.advanceAndGet(2, 4), '');
+
+ renderer_main.sliceGroup.endSlice(timer.advanceAndGet(2, 4));
+
+ renderer.updateBounds();
+ var timelineRanges = [];
+ model.iterateAllEvents(function(event) {
+ if (event.title === 'ActionA' || event.title === 'ActionB') {
+ timelineRanges.push(Range.fromExplicitRange(event.start, event.end));
+ }
+ });
+ var stats = new RenderingStats(
+ renderer, null, null, timelineRanges);
+
+ assert.equal(0, stats.frameTimestamps[1].length);
+ });
+
+ test('fromTimeline', function() {
+ var model = new tr.Model();
+
+ // Create a browser process and a renderer process, and a main thread and
+ // impl thread for each.
+ var browser = model.getOrCreateProcess(1);
+ var browser_compositor = browser.getOrCreateThread(12);
+ var renderer = model.getOrCreateProcess(2);
+ var renderer_main = renderer.getOrCreateThread(21);
+ var renderer_compositor = renderer.getOrCreateThread(22);
+
+ var timer = new MockTimer();
+ var renderer_ref_stats = new ReferenceRenderingStats();
+ var browser_ref_stats = new ReferenceRenderingStats();
+
+ // Create 10 main and impl rendering stats events for Action A.
+ renderer_main.sliceGroup.beginSlice('webkit.console', 'ActionA',
+ timer.advanceAndGet(2, 4), '');
+ renderer_ref_stats.pushNewRange();
+ browser_ref_stats.pushNewRange();
+ for (var i = 0; i < 10; i++) {
+ var first = i === 0;
+ addImplThreadRenderingStats(
+ timer, renderer_compositor, first, renderer_ref_stats);
+ addImplThreadRenderingStats(
+ timer, browser_compositor, first, browser_ref_stats);
+ }
+ renderer_main.sliceGroup.endSlice(timer.advanceAndGet(2, 4));
+
+ // Create 5 main and impl rendering stats events not within any action.
+ for (var i = 0; i < 5; i++) {
+ var first = i === 0;
+ addImplThreadRenderingStats(timer, renderer_compositor, first);
+ addImplThreadRenderingStats(timer, browser_compositor, first);
+ }
+
+ // Create 10 main and impl rendering stats events for Action B.
+ renderer_main.sliceGroup.beginSlice('webkit.console', 'ActionB',
+ timer.advanceAndGet(2, 4), '');
+ renderer_ref_stats.pushNewRange();
+ browser_ref_stats.pushNewRange();
+ for (var i = 0; i < 10; i++) {
+ var first = i === 0;
+ addImplThreadRenderingStats(
+ timer, renderer_compositor, first, renderer_ref_stats);
+ addImplThreadRenderingStats(
+ timer, browser_compositor, first, browser_ref_stats);
+ }
+ renderer_main.sliceGroup.endSlice(timer.advanceAndGet(2, 4));
+
+ // Create 10 main and impl rendering stats events for Action A.
+ renderer_main.sliceGroup.beginSlice('webkit.console', 'ActionA',
+ timer.advanceAndGet(2, 4), '');
+ renderer_ref_stats.pushNewRange();
+ browser_ref_stats.pushNewRange();
+ for (var i = 0; i < 10; i++) {
+ var first = i === 0;
+ addImplThreadRenderingStats(
+ timer, renderer_compositor, first, renderer_ref_stats);
+ addImplThreadRenderingStats(
+ timer, browser_compositor, first, browser_ref_stats);
+ }
+ renderer_main.sliceGroup.endSlice(timer.advanceAndGet(2, 4));
+ timer.advance(2, 4, 0.1);
+
+ browser.updateBounds();
+ renderer.updateBounds();
+ var timelineRanges = [];
+ model.iterateAllEvents(function(event) {
+ if (event.title === 'ActionA' || event.title === 'ActionB') {
+ timelineRanges.push(Range.fromExplicitRange(event.start, event.end));
+ }
+ });
+ var stats = new RenderingStats(
+ renderer, browser, null, timelineRanges);
+
+ // Compare rendering stats to reference.
+ assert.deepEqual(stats.frameTimestamps,
+ browser_ref_stats.frameTimestamps);
+ assert.deepEqual(stats.frameTimes,
+ browser_ref_stats.frameTimes);
+ assert.deepEqual(stats.approximatedPixelPercentages,
+ renderer_ref_stats.approximatedPixelPercentages);
+ assert.deepEqual(stats.checkerboardedPixelPercentages,
+ renderer_ref_stats.checkerboardedPixelPercentages);
+ });
+
+ test('inputLatencyFromTimeline', function() {
+ var model = new tr.Model();
+
+ // Create a browser process and a renderer process.
+ var browser = model.getOrCreateProcess(1);
+ var browser_main = browser.getOrCreateThread(11);
+ var renderer = model.getOrCreateProcess(2);
+ var renderer_main = renderer.getOrCreateThread(21);
+
+ var timer = new MockTimer();
+ var ref_latency = new ReferenceInputLatencyStats();
+
+ // Create 10 input latency stats events for Action A.
+ renderer_main.sliceGroup.beginSlice('webkit.console', 'ActionA',
+ timer.advanceAndGet(2, 4), '');
+ for (var i = 0; i < 10; i++) {
+ addInputLatencyStats(timer, browser_main, renderer_main, ref_latency);
+ }
+ renderer_main.sliceGroup.endSlice(timer.advanceAndGet(2, 4));
+
+ // Create 5 input latency stats events not within any action.
+ timer.advance(2, 4, 0.3);
+ for (var i = 0; i < 5; i++) {
+ addInputLatencyStats(timer, browser_main, renderer_main);
+ }
+
+ // Create 10 input latency stats events for Action B.
+ renderer_main.sliceGroup.beginSlice('webkit.console', 'ActionB',
+ timer.advanceAndGet(2, 4), '');
+ for (var i = 0; i < 10; i++) {
+ addInputLatencyStats(timer, browser_main, renderer_main, ref_latency);
+ }
+ renderer_main.sliceGroup.endSlice(timer.advanceAndGet(2, 4));
+
+ // Create 10 input latency stats events for Action A.
+ renderer_main.sliceGroup.beginSlice('webkit.console', 'ActionA',
+ timer.advanceAndGet(2, 4), '');
+ for (var i = 0; i < 10; i++) {
+ addInputLatencyStats(timer, browser_main, renderer_main, ref_latency);
+ }
+ renderer_main.sliceGroup.endSlice(timer.advanceAndGet(2, 4));
+
+ browser.updateBounds();
+ renderer.updateBounds();
+
+ var latencyEvents = [];
+ var timelineRanges = [];
+ model.iterateAllEvents(function(event) {
+ if (event.title === 'ActionA' || event.title === 'ActionB') {
+ var range = Range.fromExplicitRange(event.start, event.end);
+ timelineRanges.push(range);
+ latencyEvents.push.apply(
+ latencyEvents,
+ RenderingStatsHelpers.getLatencyEvents(browser, range));
+ }
+ });
+ assert.deepEqual(latencyEvents, ref_latency.input_event);
+
+ var stats = new RenderingStats(renderer, browser, null, timelineRanges);
+
+ var expected_input_latency = ref_latency.inputEventLatency.filter(
+ function(e) {
+ return (e.eventTitle !==
+ constants.SCROLL_UPDATE_EVENT_NAME);
+ }).map(
+ function(e) {
+ return e.latency;
+ }
+ );
+ assert.deepEqual(
+ flattenArray(stats.inputEventLatency),
+ expected_input_latency);
+ var expected_scroll_latency = ref_latency.inputEventLatency.filter(
+ function(e) {
+ return (e.eventTitle ===
+ constants.SCROLL_UPDATE_EVENT_NAME);
+ }).map(
+ function(e) {
+ return e.latency;
+ }
+ );
+
+ assert.deepEqual(
+ flattenArray(stats.scrollUpdateLatency),
+ expected_scroll_latency);
+
+ var expected_gestureScrollUpdateLatency =
+ ref_latency.inputEventLatency.filter(
+ function(e) {
+ return (e.eventTitle ===
+ constants.GESTURE_SCROLL_UPDATE_EVENT_NAME);
+ }).map(
+ function(e) {
+ return e.latency;
+ }
+ );
+
+ assert.deepEqual(
+ flattenArray(stats.gestureScrollUpdateLatency),
+ expected_gestureScrollUpdateLatency);
+ });
+
+});
+</script>

Powered by Google App Engine
This is Rietveld 408576698