Merge "Refactor the java side APCT perf test"

This commit is contained in:
Tenghui Zhu
2016-06-22 17:04:59 +00:00
committed by Android (Google) Code Review
12 changed files with 190 additions and 169 deletions

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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)

View File

@@ -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);
}
}

View 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)

View File

@@ -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);
}
}

View File

@@ -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();
}
}