Merge "Refactor the java side APCT perf test"
This commit is contained in:
@@ -5,7 +5,7 @@ LOCAL_MODULE_TAGS := tests
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test apct-perftests-utils
|
||||
|
||||
LOCAL_PACKAGE_NAME := CorePerfTests
|
||||
|
||||
@@ -20,8 +20,7 @@ import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import android.perftest.BenchmarkState;
|
||||
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
@@ -74,9 +73,6 @@ public class TextViewSetTextLocalePerfTest {
|
||||
textView.setTextLocale(mSecondLocale);
|
||||
}
|
||||
|
||||
Log.i("TextViewSetTextLocalePerfTest", mMetricKey + ": " + state.summaryLine());
|
||||
final Bundle status = new Bundle();
|
||||
status.putLong(mMetricKey, state.median());
|
||||
InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
|
||||
state.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(), mMetricKey);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := apct-perftests-utils
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
package android.graphics.perftests;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.VectorDrawable;
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
import android.util.Log;
|
||||
@@ -37,19 +37,19 @@ import java.io.IOException;
|
||||
public class VectorDrawablePerfTest extends ActivityInstrumentationTestCase2<StubActivity> {
|
||||
|
||||
private static final String TAG = "PathPerfTest";
|
||||
private static final int REPEAT_TIMES = 200;
|
||||
private static final boolean DBG_PERF = false;
|
||||
|
||||
private int[] mTestWidths = {1024, 512};
|
||||
private int[] mTestHeights = {512, 1024};
|
||||
|
||||
private String KEY_VECTORDRAWABLE_DRAW_TIME = "VectorDrawable_Draw_Time_MicroSec";
|
||||
private String KEY_VECTORDRAWABLE_DRAW_TIME = "VectorDrawable_Draw_Time_NanoSec";
|
||||
|
||||
public VectorDrawablePerfTest() {
|
||||
super(StubActivity.class);
|
||||
}
|
||||
|
||||
// Save a bitmap into a PNG, only for debugging purpose.
|
||||
// TODO: move into utility class.
|
||||
private void saveBitmapIntoPNG(Bitmap bitmap, int resId) throws IOException {
|
||||
// Save the image to the disk.
|
||||
FileOutputStream out = null;
|
||||
@@ -87,14 +87,14 @@ public class VectorDrawablePerfTest extends ActivityInstrumentationTestCase2<Stu
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, conf);
|
||||
Canvas canvas = new Canvas(bmp);
|
||||
|
||||
long startTime = System.nanoTime();
|
||||
for (int i = 0; i < REPEAT_TIMES; i++) {
|
||||
BenchmarkState state = new BenchmarkState();
|
||||
int i = 0;
|
||||
while (state.keepRunning()) {
|
||||
// Use different width / height each to force the vectorDrawable abandon the cache.
|
||||
vd.setBounds(0, 0, mTestWidths[i % 2], mTestHeights[i % 2]);
|
||||
i++;
|
||||
vd.draw(canvas);
|
||||
}
|
||||
long duration = System.nanoTime() - startTime;
|
||||
long avgDurationMicroSecond = duration / REPEAT_TIMES / 1000;
|
||||
|
||||
// Double check the bitmap pixels to make sure we draw correct content.
|
||||
int backgroundColor = bmp.getPixel(w / 4, h / 2);
|
||||
@@ -102,13 +102,6 @@ public class VectorDrawablePerfTest extends ActivityInstrumentationTestCase2<Stu
|
||||
assertTrue("The background should be white", backgroundColor == 0xFFFFFFFF);
|
||||
assertTrue("The object should be black", objColor == 0xFF000000);
|
||||
|
||||
if (DBG_PERF) {
|
||||
Log.v(TAG, "avg drawing vector drawable in bitmap size " + w + "x" + h + ":"
|
||||
+ avgDurationMicroSecond + "micro seconds");
|
||||
}
|
||||
|
||||
final Bundle status = new Bundle();
|
||||
status.putLong(KEY_VECTORDRAWABLE_DRAW_TIME, avgDurationMicroSecond);
|
||||
getInstrumentation().sendStatus(Activity.RESULT_OK, status);
|
||||
state.sendFullStatusReport(getInstrumentation(), KEY_VECTORDRAWABLE_DRAW_TIME);
|
||||
}
|
||||
}
|
||||
14
apct-tests/perftests/utils/Android.mk
Normal file
14
apct-tests/perftests/utils/Android.mk
Normal file
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* 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.perftest;
|
||||
|
||||
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 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 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.
|
||||
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() > 2 && 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 double mean() {
|
||||
if (mState != FINISHED) {
|
||||
throw new IllegalStateException("The benchmark hasn't finished");
|
||||
}
|
||||
return mMean;
|
||||
}
|
||||
|
||||
public long median() {
|
||||
if (mState != FINISHED) {
|
||||
throw new IllegalStateException("The benchmark hasn't finished");
|
||||
}
|
||||
return mMedian;
|
||||
}
|
||||
|
||||
public double standardDeviation() {
|
||||
if (mState != FINISHED) {
|
||||
throw new IllegalStateException("The benchmark hasn't finished");
|
||||
}
|
||||
return mStandardDeviation;
|
||||
}
|
||||
|
||||
public 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();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user