blob: 737e9b89e5b7ea31d66d6f47ea623ecd38f0b61e [file] [log] [blame]
/*
* Copyright (C) 2011 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 com.android.graphics.tests;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log;
import com.android.ddmlib.NullOutputReceiver;
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.result.FileInputStreamSource;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.RunUtil;
import com.android.tradefed.util.StreamUtil;
import com.android.tradefed.util.proto.TfMetricProtoUtil;
import org.junit.Assert;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Runs the user action framerate benchmark test. This test capture use the scripted monkey to
* inject the keyevent to mimic the real user action, capture the average framerate and save the
* result file to the sdcard.
*
* <p>Note that this test will not run properly unless /sdcard is mounted and writable.
*/
public class UserActionBenchmark implements IDeviceTest, IRemoteTest {
private static final String LOG_TAG = "UserActionBenchmark";
ITestDevice mTestDevice = null;
private static final long START_TIMER = 2 * 60 * 1000; // 2 minutes
@Option(name = "test-output-filename", description = "The test output filename.")
private String mDeviceTestOutputFilename = "avgFrameRateOut.txt";
// The time in ms to wait the scripted monkey finish.
private static final int CMD_TIMEOUT = 60 * 60 * 1000;
private static final Pattern AVERAGE_FPS = Pattern.compile("(.*):(\\d+.\\d+)");
@Option(name = "test-case", description = "The name of test-cases to run. May be repeated.")
private Collection<String> mTestCases = new ArrayList<>();
@Option(name = "iteration", description = "Test run iteration")
private int mIteration = 1;
@Option(name = "throttle", description = "Scripted monkey throttle time")
private int mThrottle = 500; // in milliseconds
@Option(name = "script-path", description = "Test script path")
private String mScriptPath = "userActionFPSScript";
@Option(name = "test-label", description = "Test label")
private String mTestLabel = "UserActionFramerateBenchmark";
@Override
public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
Assert.assertNotNull(mTestDevice);
// Start the test after device is fully booted and stable
// FIXME: add option in TF to wait until device is booted and stable
RunUtil.getDefault().sleep(START_TIMER);
String extStore = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
String scriptFullPath =
String.format("%s/%s/%s", extStore, mScriptPath, mTestDevice.getProductType());
for (String testCase : mTestCases) {
// Start the scripted monkey command
mTestDevice.executeShellCommand(
String.format(
"monkey -f /%s/%s.txt --throttle %d %d",
scriptFullPath, testCase, mThrottle, mIteration),
new NullOutputReceiver(),
CMD_TIMEOUT,
TimeUnit.MILLISECONDS,
2);
logOutputFiles(listener);
cleanResultFile();
}
}
/** Clean up the test result file from test run */
private void cleanResultFile() throws DeviceNotAvailableException {
String extStore = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
mTestDevice.executeShellCommand(
String.format("rm %s/%s", extStore, mDeviceTestOutputFilename));
}
/**
* Pull the output files from the device, add it to the logs, and also parse out the relevant
* test metrics and report them.
*/
private void logOutputFiles(ITestInvocationListener listener)
throws DeviceNotAvailableException {
File outputFile = null;
InputStreamSource outputSource = null;
try {
outputFile = mTestDevice.pullFileFromExternal(mDeviceTestOutputFilename);
if (outputFile == null) {
return;
}
// Upload a verbatim copy of the output file
Log.d(
LOG_TAG,
String.format(
"Sending %d byte file %s into the logosphere!",
outputFile.length(), outputFile));
outputSource = new FileInputStreamSource(outputFile);
listener.testLog(mDeviceTestOutputFilename, LogDataType.TEXT, outputSource);
// Parse the output file to upload aggregated metrics
parseOutputFile(new FileInputStream(outputFile), listener);
} catch (IOException e) {
Log.e(
LOG_TAG,
String.format("IOException while reading or parsing output file: %s", e));
} finally {
FileUtil.deleteFile(outputFile);
StreamUtil.cancel(outputSource);
}
}
/**
* Parse the test result, calculate the average and parse the metrics from the scripted monkey
* test output file
*/
private void parseOutputFile(InputStream dataStream, ITestInvocationListener listener) {
Map<String, String> runMetrics = new HashMap<>();
// try to parse it
String contents;
try {
contents = StreamUtil.getStringFromStream(dataStream);
} catch (IOException e) {
Log.e(LOG_TAG, String.format("Got IOException during test processing: %s", e));
return;
}
List<String> lines = Arrays.asList(contents.split("\n"));
String key = null;
float averageResult;
float totalResult = 0;
int counter = 0;
// collect the result and calculate the average
for (String line : lines) {
Matcher m = AVERAGE_FPS.matcher(line);
if (m.matches()) {
key = m.group(1);
totalResult += Float.parseFloat(m.group(2));
counter++;
}
}
averageResult = totalResult / counter;
Log.i(LOG_TAG, String.format("averageResult = %s\n", averageResult));
runMetrics.put(key, Float.toString(averageResult));
reportMetrics(listener, runMetrics);
}
/**
* Report run metrics by creating an empty test run to stick them in
*
* <p>Exposed for unit testing
*/
void reportMetrics(ITestInvocationListener listener, Map<String, String> metrics) {
Log.d(LOG_TAG, String.format("About to report metrics: %s", metrics));
listener.testRunStarted(mTestLabel, 0);
listener.testRunEnded(0, TfMetricProtoUtil.upgradeConvert(metrics));
}
@Override
public void setDevice(ITestDevice device) {
mTestDevice = device;
}
@Override
public ITestDevice getDevice() {
return mTestDevice;
}
}