153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan/* 253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * Copyright (C) 2009 The Android Open Source Project 353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * 453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * Licensed under the Apache License, Version 2.0 (the "License"); 553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * you may not use this file except in compliance with the License. 653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * You may obtain a copy of the License at 753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * 853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * http://www.apache.org/licenses/LICENSE-2.0 953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * 1053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * Unless required by applicable law or agreed to in writing, software 1153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * distributed under the License is distributed on an "AS IS" BASIS, 1253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * See the License for the specific language governing permissions and 1453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * limitations under the License. 1553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan */ 1653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan 1753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chanpackage android.os; 1853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan 1953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chanimport android.util.Log; 2053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan 2153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chanimport java.util.HashMap; 2253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan 2353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan/** 2453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * A class to help with measuring latency in your code. 2553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * 2653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * Suggested usage: 2753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * 1) Instanciate a LatencyTimer as a class field. 2853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * private [static] LatencyTimer mLt = new LatencyTimer(100, 1000); 2953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * 2) At various points in the code call sample with a string and the time delta to some fixed time. 3053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * The string should be unique at each point of the code you are measuring. 3153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * mLt.sample("before processing event", System.nanoTime() - event.getEventTimeNano()); 3253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * processEvent(event); 3353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * mLt.sample("after processing event ", System.nanoTime() - event.getEventTimeNano()); 3453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * 3553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * @hide 3653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan */ 3753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chanpublic final class LatencyTimer 3853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan{ 3953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan final String TAG = "LatencyTimer"; 4053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan final int mSampleSize; 4153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan final int mScaleFactor; 4253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan volatile HashMap<String, long[]> store = new HashMap<String, long[]>(); 4353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan 4453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan /** 4553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * Creates a LatencyTimer object 4653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * @param sampleSize number of samples to collect before printing out the average 4753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * @param scaleFactor divisor used to make each sample smaller to prevent overflow when 4853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * (sampleSize * average sample value)/scaleFactor > Long.MAX_VALUE 4953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan */ 5053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan public LatencyTimer(int sampleSize, int scaleFactor) { 5153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan if (scaleFactor == 0) { 5253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan scaleFactor = 1; 5353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 5453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan mScaleFactor = scaleFactor; 5553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan mSampleSize = sampleSize; 5653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 5753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan 5853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan /** 5953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * Add a sample delay for averaging. 6053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * @param tag string used for printing out the result. This should be unique at each point of 6153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * this called. 6253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan * @param delta time difference from an unique point of reference for a particular iteration 6353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan */ 6453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan public void sample(String tag, long delta) { 6553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan long[] array = getArray(tag); 6653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan 6753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan // array[mSampleSize] holds the number of used entries 6853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan final int index = (int) array[mSampleSize]++; 6953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan array[index] = delta; 7053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan if (array[mSampleSize] == mSampleSize) { 7153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan long totalDelta = 0; 7253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan for (long d : array) { 7353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan totalDelta += d/mScaleFactor; 7453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 7553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan array[mSampleSize] = 0; 7653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan Log.i(TAG, tag + " average = " + totalDelta / mSampleSize); 7753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 7853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 7953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan 8053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan private long[] getArray(String tag) { 8153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan long[] data = store.get(tag); 8253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan if (data == null) { 8353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan synchronized(store) { 8453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan data = store.get(tag); 8553071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan if (data == null) { 8653071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan data = new long[mSampleSize + 1]; 8753071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan store.put(tag, data); 8853071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan data[mSampleSize] = 0; 8953071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 9053071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 9153071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 9253071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan return data; 9353071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan } 9453071d6d159f6dfd6fe0328a39bcf967ef308a64Michael Chan} 95