mobile/android/base/gfx/DrawTimingQueue.java

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 package org.mozilla.gecko.gfx;
     8 import android.os.SystemClock;
    10 /**
    11  * A custom-built data structure to assist with measuring draw times.
    12  *
    13  * This class maintains a fixed-size circular buffer of DisplayPortMetrics
    14  * objects and associated timestamps. It provides only three operations, which
    15  * is all we require for our purposes of measuring draw times. Note
    16  * in particular that the class is designed so that even though it is
    17  * accessed from multiple threads, it does not require synchronization;
    18  * any concurrency errors that result from this are handled gracefully.
    19  *
    20  * Assuming an unrolled buffer so that mTail is greater than mHead, the data
    21  * stored in the buffer at entries [mHead, mTail) will never be modified, and
    22  * so are "safe" to read. If this reading is done on the same thread that
    23  * owns mHead, then reading the range [mHead, mTail) is guaranteed to be safe
    24  * since the range itself will not shrink.
    25  */
    26 final class DrawTimingQueue {
    27     private static final String LOGTAG = "GeckoDrawTimingQueue";
    28     private static final int BUFFER_SIZE = 16;
    30     private final DisplayPortMetrics[] mMetrics;
    31     private final long[] mTimestamps;
    33     private int mHead;
    34     private int mTail;
    36     DrawTimingQueue() {
    37         mMetrics = new DisplayPortMetrics[BUFFER_SIZE];
    38         mTimestamps = new long[BUFFER_SIZE];
    39         mHead = BUFFER_SIZE - 1;
    40         mTail = 0;
    41     }
    43     /**
    44      * Add a new entry to the tail of the queue. If the buffer is full,
    45      * do nothing. This must only be called from the Java UI thread.
    46      */
    47     boolean add(DisplayPortMetrics metrics) {
    48         if (mHead == mTail) {
    49             return false;
    50         }
    51         mMetrics[mTail] = metrics;
    52         mTimestamps[mTail] = SystemClock.uptimeMillis();
    53         mTail = (mTail + 1) % BUFFER_SIZE;
    54         return true;
    55     }
    57     /**
    58      * Find the timestamp associated with the given metrics, AND remove
    59      * all metrics objects from the start of the queue up to and including
    60      * the one provided. Note that because of draw coalescing, the metrics
    61      * object passed in here may not be the one at the head of the queue,
    62      * and so we must iterate our way through the list to find it.
    63      * This must only be called from the compositor thread.
    64      */
    65     long findTimeFor(DisplayPortMetrics metrics) {
    66         // keep a copy of the tail pointer so that we ignore new items
    67         // added to the queue while we are searching. this is fine because
    68         // the one we are looking for will either have been added already
    69         // or will not be in the queue at all.
    70         int tail = mTail;
    71         // walk through the "safe" range from mHead to tail; these entries
    72         // will not be modified unless we change mHead.
    73         int i = (mHead + 1) % BUFFER_SIZE;
    74         while (i != tail) {
    75             if (mMetrics[i].fuzzyEquals(metrics)) {
    76                 // found it, copy out the timestamp to a local var BEFORE
    77                 // changing mHead or add could clobber the timestamp.
    78                 long timestamp = mTimestamps[i];
    79                 mHead = i;
    80                 return timestamp;
    81             }
    82             i = (i + 1) % BUFFER_SIZE;
    83         }
    84         return -1;
    85     }
    87     /**
    88      * Reset the buffer to empty.
    89      * This must only be called from the compositor thread.
    90      */
    91     void reset() {
    92         // we can only modify mHead on this thread.
    93         mHead = (mTail + BUFFER_SIZE - 1) % BUFFER_SIZE;
    94     }
    95 }

mercurial