BenchmarkState.java revision 23d1fdded5fe78024927137ddfb82401fd9e3344
123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu/* 223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * Copyright (C) 2016 The Android Open Source Project 323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * 423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * Licensed under the Apache License, Version 2.0 (the "License"); 523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * you may not use this file except in compliance with the License. 623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * You may obtain a copy of the License at 723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * 823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * http://www.apache.org/licenses/LICENSE-2.0 923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * 1023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * Unless required by applicable law or agreed to in writing, software 1123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * distributed under the License is distributed on an "AS IS" BASIS, 1223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * See the License for the specific language governing permissions and 1423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * limitations under the License. 1523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu */ 1623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 1723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhupackage android.perftests.utils; 1823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 1923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhuimport android.app.Activity; 2023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhuimport android.app.Instrumentation; 2123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhuimport android.os.Bundle; 2223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhuimport android.util.Log; 2323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 2423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhuimport java.util.ArrayList; 2523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhuimport java.util.Collections; 2623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 2723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu/** 2823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * Provides a benchmark framework. 2923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * 3023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * Example usage: 3123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * // Executes the code while keepRunning returning true. 3223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * 3323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * public void sampleMethod() { 3423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * BenchmarkState state = new BenchmarkState(); 3523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * 3623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * int[] src = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 3723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * while (state.keepRunning()) { 3823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * int[] dest = new int[src.length]; 3923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * System.arraycopy(src, 0, dest, 0, src.length); 4023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * } 4123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * System.out.println(state.summaryLine()); 4223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * } 4323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu */ 4423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhupublic class BenchmarkState { 4523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private static final String TAG = "BenchmarkState"; 4623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 4723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private static final int NOT_STARTED = 1; // The benchmark has not started yet. 4823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private static final int RUNNING = 2; // The benchmark is running. 4923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private static final int FINISHED = 3; // The benchmark has stopped. 5023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private static final int MIN_REPEAT_TIMES = 16; 5123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 5223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private int mState = NOT_STARTED; // Current benchmark state. 5323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 5423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private long mNanoPreviousTime = 0; // Previously captured System.nanoTime(). 5523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private long mNanoFinishTime = 0; // Finish if System.nanoTime() returns after than this value. 5623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private long mNanoTimeLimit = 1 * 1000 * 1000 * 1000; // 1 sec. Default time limit. 5723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 5823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu // Statistics. These values will be filled when the benchmark has finished. 5923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu // The computation needs double precision, but long int is fine for final reporting. 6023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private long mMedian = 0; 6123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private double mMean = 0.0; 6223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private double mStandardDeviation = 0.0; 6323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 6423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu // Individual duration in nano seconds. 6523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private ArrayList<Long> mResults = new ArrayList<>(); 6623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 6723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu /** 6823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * Calculates statistics. 6923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu */ 7023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private void calculateSatistics() { 7123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu final int size = mResults.size(); 7223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu if (size <= 1) { 7323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu throw new IllegalStateException("At least two results are necessary."); 7423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 7523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 7623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu Collections.sort(mResults); 7723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mMedian = size % 2 == 0 ? (mResults.get(size / 2) + mResults.get(size / 2 + 1)) / 2 : 7823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mResults.get(size / 2); 7923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 8023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu for (int i = 0; i < size; ++i) { 8123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mMean += mResults.get(i); 8223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 8323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mMean /= (double) size; 8423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 8523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu for (int i = 0; i < size; ++i) { 8623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu final double tmp = mResults.get(i) - mMean; 8723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mStandardDeviation += tmp * tmp; 8823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 8923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1)); 9023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 9123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 9223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu /** 9323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * Judges whether the benchmark needs more samples. 9423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * 9523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu * For the usage, see class comment. 9623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu */ 9723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu public boolean keepRunning() { 9823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu switch (mState) { 9923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu case NOT_STARTED: 10023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mNanoPreviousTime = System.nanoTime(); 10123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mNanoFinishTime = mNanoPreviousTime + mNanoTimeLimit; 10223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mState = RUNNING; 10323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu return true; 10423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu case RUNNING: 10523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu final long currentTime = System.nanoTime(); 10623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mResults.add(currentTime - mNanoPreviousTime); 10723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 10823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu // To calculate statistics, needs two or more samples. 10923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu if (mResults.size() > MIN_REPEAT_TIMES && currentTime > mNanoFinishTime) { 11023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu calculateSatistics(); 11123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mState = FINISHED; 11223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu return false; 11323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 11423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 11523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu mNanoPreviousTime = currentTime; 11623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu return true; 11723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu case FINISHED: 11823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu throw new IllegalStateException("The benchmark has finished."); 11923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu default: 12023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu throw new IllegalStateException("The benchmark is in unknown state."); 12123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 12223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 12323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 12423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu public long mean() { 12523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu if (mState != FINISHED) { 12623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu throw new IllegalStateException("The benchmark hasn't finished"); 12723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 12823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu return (long) mMean; 12923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 13023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 13123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu public long median() { 13223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu if (mState != FINISHED) { 13323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu throw new IllegalStateException("The benchmark hasn't finished"); 13423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 13523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu return mMedian; 13623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 13723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 13823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu public long standardDeviation() { 13923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu if (mState != FINISHED) { 14023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu throw new IllegalStateException("The benchmark hasn't finished"); 14123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 14223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu return (long) mStandardDeviation; 14323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 14423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 14523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu private String summaryLine() { 14623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu StringBuilder sb = new StringBuilder(); 14723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu sb.append("Summary: "); 14823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu sb.append("median=" + median() + "ns, "); 14923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu sb.append("mean=" + mean() + "ns, "); 15023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu sb.append("sigma=" + standardDeviation() + ", "); 15123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu sb.append("iteration=" + mResults.size()); 15223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu return sb.toString(); 15323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 15423d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu 15523d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu public void sendFullStatusReport(Instrumentation instrumentation, String key) { 15623d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu Log.i(TAG, key + summaryLine()); 15723d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu Bundle status = new Bundle(); 15823d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu status.putLong(key + "_median", median()); 15923d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu status.putLong(key + "_mean", mean()); 16023d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu status.putLong(key + "_standardDeviation", standardDeviation()); 16123d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu instrumentation.sendStatus(Activity.RESULT_OK, status); 16223d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu } 16323d1fdded5fe78024927137ddfb82401fd9e3344Teng-Hui Zhu} 164