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/base/sorted_array_utils.html">
9
10<script>
11'use strict';
12
13/**
14 * @fileoverview Class for representing SurfaceFlinger process and its Vsyncs.
15 */
16tr.exportTo('tr.model.helpers', function() {
17  var findLowIndexInSortedArray = tr.b.findLowIndexInSortedArray;
18
19  var VSYNC_SF_NAME = 'android.VSYNC-sf';
20  var VSYNC_APP_NAME = 'android.VSYNC-app';
21  var VSYNC_FALLBACK_NAME = 'android.VSYNC';
22
23  // when sampling vsync, push samples back by this much to ensure
24  // frame start samples *between* vsyncs
25  var TIMESTAMP_FUDGE_MS = 0.01;
26
27  function getVsyncTimestamps(process, counterName) {
28
29    var vsync = process.counters[counterName];
30    if (!vsync)
31      vsync = process.counters[VSYNC_FALLBACK_NAME];
32
33    if (vsync && vsync.numSeries == 1 && vsync.numSamples > 1)
34      return vsync.series[0].timestamps;
35    return undefined;
36  }
37
38  /**
39   * Model for SurfaceFlinger specific data.
40   * @constructor
41   */
42  function AndroidSurfaceFlinger(process, thread) {
43    this.process = process;
44    this.thread = thread;
45
46    this.appVsync_ = undefined;
47    this.sfVsync_ = undefined;
48
49    this.appVsyncTimestamps_ = getVsyncTimestamps(process, VSYNC_APP_NAME);
50    this.sfVsyncTimestamps_ = getVsyncTimestamps(process, VSYNC_SF_NAME);
51  };
52
53  AndroidSurfaceFlinger.createForProcessIfPossible = function(process) {
54    var mainThread = process.getThread(process.pid);
55
56    // newer versions - main thread, lowercase name, preceeding forward slash
57    if (mainThread && mainThread.name &&
58        /surfaceflinger/.test(mainThread.name))
59      return new AndroidSurfaceFlinger(process, mainThread);
60
61    // older versions - another thread is named SurfaceFlinger
62    var primaryThreads = process.findAllThreadsNamed('SurfaceFlinger');
63    if (primaryThreads.length == 1)
64      return new AndroidSurfaceFlinger(process, primaryThreads[0]);
65    return undefined;
66  };
67
68  AndroidSurfaceFlinger.prototype = {
69    get hasVsyncs() {
70      return !!this.appVsyncTimestamps_ && !!this.sfVsyncTimestamps_;
71    },
72
73    getFrameKickoff: function(timestamp) {
74      if (!this.hasVsyncs)
75        throw new Error('cannot query vsync info without vsyncs');
76
77      var firstGreaterIndex =
78          findLowIndexInSortedArray(this.appVsyncTimestamps_,
79                                    function(x) { return x; },
80                                    timestamp + TIMESTAMP_FUDGE_MS);
81
82      if (firstGreaterIndex < 1)
83        return undefined;
84      return this.appVsyncTimestamps_[firstGreaterIndex - 1];
85    },
86
87    getFrameDeadline: function(timestamp) {
88      if (!this.hasVsyncs)
89        throw new Error('cannot query vsync info without vsyncs');
90
91      var firstGreaterIndex =
92          findLowIndexInSortedArray(this.sfVsyncTimestamps_,
93                                    function(x) { return x; },
94                                    timestamp + TIMESTAMP_FUDGE_MS);
95      if (firstGreaterIndex >= this.sfVsyncTimestamps_.length)
96        return undefined;
97      return this.sfVsyncTimestamps_[firstGreaterIndex];
98    }
99  };
100
101  return {
102    AndroidSurfaceFlinger: AndroidSurfaceFlinger
103  };
104});
105</script>
106