OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.base; |
| 6 |
| 7 import android.animation.Animator; |
| 8 import android.animation.Animator.AnimatorListener; |
| 9 import android.animation.AnimatorListenerAdapter; |
| 10 import android.animation.TimeAnimator; |
| 11 import android.animation.TimeAnimator.TimeListener; |
| 12 import android.util.Log; |
| 13 |
| 14 /** |
| 15 * Record Android animation frame rate and save it to UMA histogram. This is mai
nly for monitoring |
| 16 * any jankiness of short Chrome Android animations. It is limited to few second
s of recording. |
| 17 */ |
| 18 public class AnimationFrameTimeHistogram { |
| 19 private static final String TAG = "AnimationFrameTimeHistogram"; |
| 20 private static final int MAX_FRAME_TIME_NUM = 600; // 10 sec on 60 fps. |
| 21 |
| 22 private final Recorder mRecorder = new Recorder(); |
| 23 private final String mHistogramName; |
| 24 |
| 25 /** |
| 26 * @param histogramName The histogram name that the recorded frame times wil
l be saved. |
| 27 * This must be also defined in histograms.xml |
| 28 * @return An AnimatorListener instance that records frame time histogram on
start and end |
| 29 * automatically. |
| 30 */ |
| 31 public static AnimatorListener getAnimatorRecorder(final String histogramNam
e) { |
| 32 return new AnimatorListenerAdapter() { |
| 33 private final AnimationFrameTimeHistogram mAnimationFrameTimeHistogr
am = |
| 34 new AnimationFrameTimeHistogram(histogramName); |
| 35 |
| 36 @Override |
| 37 public void onAnimationStart(Animator animation) { |
| 38 mAnimationFrameTimeHistogram.startRecording(); |
| 39 } |
| 40 |
| 41 @Override |
| 42 public void onAnimationEnd(Animator animation) { |
| 43 mAnimationFrameTimeHistogram.endRecording(); |
| 44 } |
| 45 |
| 46 @Override |
| 47 public void onAnimationCancel(Animator animation) { |
| 48 mAnimationFrameTimeHistogram.endRecording(); |
| 49 } |
| 50 }; |
| 51 } |
| 52 |
| 53 /** |
| 54 * @param histogramName The histogram name that the recorded frame times wil
l be saved. |
| 55 * This must be also defined in histograms.xml |
| 56 */ |
| 57 public AnimationFrameTimeHistogram(String histogramName) { |
| 58 mHistogramName = histogramName; |
| 59 } |
| 60 |
| 61 /** |
| 62 * Start recording frame times. The recording can fail if it exceeds a few s
econds. |
| 63 */ |
| 64 public void startRecording() { |
| 65 mRecorder.startRecording(); |
| 66 } |
| 67 |
| 68 /** |
| 69 * End recording and save it to histogram. It won't save histogram if the re
cording wasn't |
| 70 * successful. |
| 71 */ |
| 72 public void endRecording() { |
| 73 if (mRecorder.endRecording()) { |
| 74 nativeSaveHistogram(mHistogramName, |
| 75 mRecorder.getFrameTimesMs(), mRecorder.getFrameTimesCount())
; |
| 76 } |
| 77 mRecorder.cleanUp(); |
| 78 } |
| 79 |
| 80 /** |
| 81 * Record Android animation frame rate and return the result. |
| 82 */ |
| 83 private static class Recorder implements TimeListener { |
| 84 // TODO(kkimlabs): If we can use in the future, migrate to Choreographer
for minimal |
| 85 // workload. |
| 86 private final TimeAnimator mAnimator = new TimeAnimator(); |
| 87 private long[] mFrameTimesMs; |
| 88 private int mFrameTimesCount; |
| 89 |
| 90 private Recorder() { |
| 91 mAnimator.setTimeListener(this); |
| 92 } |
| 93 |
| 94 private void startRecording() { |
| 95 assert !mAnimator.isRunning(); |
| 96 mFrameTimesCount = 0; |
| 97 mFrameTimesMs = new long[MAX_FRAME_TIME_NUM]; |
| 98 mAnimator.start(); |
| 99 } |
| 100 |
| 101 /** |
| 102 * @return Whether the recording was successful. If successful, the resu
lt is available via |
| 103 * getFrameTimesNs and getFrameTimesCount. |
| 104 */ |
| 105 private boolean endRecording() { |
| 106 boolean succeeded = mAnimator.isStarted(); |
| 107 mAnimator.end(); |
| 108 return succeeded; |
| 109 } |
| 110 |
| 111 private long[] getFrameTimesMs() { |
| 112 return mFrameTimesMs; |
| 113 } |
| 114 |
| 115 private int getFrameTimesCount() { |
| 116 return mFrameTimesCount; |
| 117 } |
| 118 |
| 119 /** |
| 120 * Deallocates the temporary buffer to record frame times. Must be calle
d after ending |
| 121 * the recording and getting the result. |
| 122 */ |
| 123 private void cleanUp() { |
| 124 mFrameTimesMs = null; |
| 125 } |
| 126 |
| 127 @Override |
| 128 public void onTimeUpdate(TimeAnimator animation, long totalTime, long de
ltaTime) { |
| 129 if (mFrameTimesCount == mFrameTimesMs.length) { |
| 130 mAnimator.end(); |
| 131 cleanUp(); |
| 132 Log.w(TAG, "Animation frame time recording reached the maximum n
umber. It's either" |
| 133 + "the animation took too long or recording end is not c
alled."); |
| 134 return; |
| 135 } |
| 136 |
| 137 // deltaTime is 0 for the first frame. |
| 138 if (deltaTime > 0) { |
| 139 mFrameTimesMs[mFrameTimesCount++] = deltaTime; |
| 140 } |
| 141 } |
| 142 } |
| 143 |
| 144 private native void nativeSaveHistogram(String histogramName, long[] frameTi
mesMs, int count); |
| 145 } |
OLD | NEW |