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