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