diff options
author | Teng-Hui Zhu <ztenghui@google.com> | 2016-06-20 14:42:35 -0700 |
---|---|---|
committer | Teng-Hui Zhu <ztenghui@google.com> | 2016-06-21 16:11:31 -0700 |
commit | 23d1fdded5fe78024927137ddfb82401fd9e3344 (patch) | |
tree | 00cd4dd6b1b4a739849d85d7799bde3c0f295645 /apct-tests/perftests/utils | |
parent | afcde2d13268bee17f648a237fcf388a9c86b05d (diff) |
Refactor the java side APCT perf test
Relocate everything into apct-tests/
Setup the share static java lib for the common code and use it.
b/28980976
Change-Id: I74c80c0b54ad18ee5fc44da43249d3c88fb926e2
Diffstat (limited to 'apct-tests/perftests/utils')
-rw-r--r-- | apct-tests/perftests/utils/Android.mk | 14 | ||||
-rw-r--r-- | apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java | 163 |
2 files changed, 177 insertions, 0 deletions
diff --git a/apct-tests/perftests/utils/Android.mk b/apct-tests/perftests/utils/Android.mk new file mode 100644 index 000000000000..2dc7d4c7915b --- /dev/null +++ b/apct-tests/perftests/utils/Android.mk @@ -0,0 +1,14 @@ + LOCAL_PATH := $(call my-dir) + include $(CLEAR_VARS) + + # Build all java files in the java subdirectory + LOCAL_SRC_FILES := $(call all-subdir-java-files) + + # Any libraries that this library depends on + LOCAL_JAVA_LIBRARIES := android.test.runner + + # The name of the jar file to create + LOCAL_MODULE := apct-perftests-utils + + # Build a static jar file. + include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java new file mode 100644 index 000000000000..8e1674abae08 --- /dev/null +++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.perftests.utils; + +import android.app.Activity; +import android.app.Instrumentation; +import android.os.Bundle; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; + +/** + * Provides a benchmark framework. + * + * Example usage: + * // Executes the code while keepRunning returning true. + * + * public void sampleMethod() { + * BenchmarkState state = new BenchmarkState(); + * + * int[] src = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + * while (state.keepRunning()) { + * int[] dest = new int[src.length]; + * System.arraycopy(src, 0, dest, 0, src.length); + * } + * System.out.println(state.summaryLine()); + * } + */ +public class BenchmarkState { + private static final String TAG = "BenchmarkState"; + + private static final int NOT_STARTED = 1; // The benchmark has not started yet. + private static final int RUNNING = 2; // The benchmark is running. + private static final int FINISHED = 3; // The benchmark has stopped. + private static final int MIN_REPEAT_TIMES = 16; + + private int mState = NOT_STARTED; // Current benchmark state. + + private long mNanoPreviousTime = 0; // Previously captured System.nanoTime(). + private long mNanoFinishTime = 0; // Finish if System.nanoTime() returns after than this value. + private long mNanoTimeLimit = 1 * 1000 * 1000 * 1000; // 1 sec. Default time limit. + + // Statistics. These values will be filled when the benchmark has finished. + // The computation needs double precision, but long int is fine for final reporting. + private long mMedian = 0; + private double mMean = 0.0; + private double mStandardDeviation = 0.0; + + // Individual duration in nano seconds. + private ArrayList<Long> mResults = new ArrayList<>(); + + /** + * Calculates statistics. + */ + private void calculateSatistics() { + final int size = mResults.size(); + if (size <= 1) { + throw new IllegalStateException("At least two results are necessary."); + } + + Collections.sort(mResults); + mMedian = size % 2 == 0 ? (mResults.get(size / 2) + mResults.get(size / 2 + 1)) / 2 : + mResults.get(size / 2); + + for (int i = 0; i < size; ++i) { + mMean += mResults.get(i); + } + mMean /= (double) size; + + for (int i = 0; i < size; ++i) { + final double tmp = mResults.get(i) - mMean; + mStandardDeviation += tmp * tmp; + } + mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1)); + } + + /** + * Judges whether the benchmark needs more samples. + * + * For the usage, see class comment. + */ + public boolean keepRunning() { + switch (mState) { + case NOT_STARTED: + mNanoPreviousTime = System.nanoTime(); + mNanoFinishTime = mNanoPreviousTime + mNanoTimeLimit; + mState = RUNNING; + return true; + case RUNNING: + final long currentTime = System.nanoTime(); + mResults.add(currentTime - mNanoPreviousTime); + + // To calculate statistics, needs two or more samples. + if (mResults.size() > MIN_REPEAT_TIMES && currentTime > mNanoFinishTime) { + calculateSatistics(); + mState = FINISHED; + return false; + } + + mNanoPreviousTime = currentTime; + return true; + case FINISHED: + throw new IllegalStateException("The benchmark has finished."); + default: + throw new IllegalStateException("The benchmark is in unknown state."); + } + } + + public long mean() { + if (mState != FINISHED) { + throw new IllegalStateException("The benchmark hasn't finished"); + } + return (long) mMean; + } + + public long median() { + if (mState != FINISHED) { + throw new IllegalStateException("The benchmark hasn't finished"); + } + return mMedian; + } + + public long standardDeviation() { + if (mState != FINISHED) { + throw new IllegalStateException("The benchmark hasn't finished"); + } + return (long) mStandardDeviation; + } + + private String summaryLine() { + StringBuilder sb = new StringBuilder(); + sb.append("Summary: "); + sb.append("median=" + median() + "ns, "); + sb.append("mean=" + mean() + "ns, "); + sb.append("sigma=" + standardDeviation() + ", "); + sb.append("iteration=" + mResults.size()); + return sb.toString(); + } + + public void sendFullStatusReport(Instrumentation instrumentation, String key) { + Log.i(TAG, key + summaryLine()); + Bundle status = new Bundle(); + status.putLong(key + "_median", median()); + status.putLong(key + "_mean", mean()); + status.putLong(key + "_standardDeviation", standardDeviation()); + instrumentation.sendStatus(Activity.RESULT_OK, status); + } +} |