/*
* Copyright (C) 2014 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.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.util.AbiFormatter;
import com.android.tradefed.util.RunUtil;
import com.android.tradefed.util.proto.TfMetricProtoUtil;
import org.junit.Assert;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Test Runner for graphics Flatland Benchmark test.
*
*
Flatland test is a benchmark for measuring GPU performance in various 2D UI rendering and
* window composition scenarios.
*
*
Since it is measuring the hardware performance, the test should be executed in as consistent
* and static an environment as possible.
*
*
* - The display should be turned off and background service should be stopped before running
* the benchmark. Running 'adb shell stop' is probably sufficient for this, but if there are
* device specific background services that consume much CPU cycles, memory bandwidth, or
* might otherwise interfere with GPU rendering, those should be stopped as well
*
- All relevant hardware clocks should be locked at particular frequency when running the
* test.
*
*
* If running the benchmark with clocks locked causes thermal throttling, set option
* "--sleep-time" to 10 to 50 (ms) to insert sleep between each benchmark sample run.
*
*
Output interpretation: For each test case, the expected time in milliseconds that a single
* frame of the scenario takes to complete will be printed out. Four types of values could
* displayed:
*
*
* - fast - frames of the scenarios are completed too fast to be reliably benchmarked. This
* corresponds to frame time less than 3 ms. The scenario was skipped. "0" will be posted into
* the dashboard.
*
- slow - frame time is too long, normally orver 50 ms. The scenario was skipped. "1000" will
* be posted into the dashboard.
*
- varies - frame time was not stable. rerun the test to get a stable results. If that results
* show repeatedly, something is wrong with the environment, signal to file a bug.
*
- decimal number - frame time for the scenarios are measured.
*
*/
public class FlatlandTest implements IDeviceTest, IRemoteTest {
private static final long SHELL_TIMEOUT = 30 * 60 * 1000;
private static final String COMMAND = "flatland|#ABI32#|";
private static final String FIRST_LINE = "cmdline:";
private static final String TITLE = "Scenario";
private static final long START_TIMER = 2 * 60 * 1000; // 2 minutes
private static final String RESULT_FAST = "fast";
private static final String RESULT_SLOW = "slow";
private static final String RESULT_VARIES = "varies";
private ITestDevice mTestDevice = null;
// HashMap to store results for
public Map mResultMap = new HashMap();
@Option(name = "ru-key", description = "Reporting unit key to use when posting results")
private String mRuKey = "flatland";
@Option(name = "run-path", description = "path for the binary")
private String mRunPath = "/data/local/tmp/";
@Option(
name = "sleep-time",
description =
"sleep for N ms between samples, set to 10 - 50 ms if the locked CPU"
+ " frequency causes thermal throttle.")
private int mSleepTime = 50;
@Option(name = "schema-map", description = "map a test case name to a schema key")
private Map mSchemaMap = new HashMap();
@Option(
name = AbiFormatter.FORCE_ABI_STRING,
description = AbiFormatter.FORCE_ABI_DESCRIPTION,
importance = Importance.IF_UNSET)
private String mForceAbi = null;
@Override
public void setDevice(ITestDevice testDevice) {
mTestDevice = testDevice;
}
@Override
public ITestDevice getDevice() {
return mTestDevice;
}
@Override
public void run(ITestInvocationListener standardListener) throws DeviceNotAvailableException {
Assert.assertNotNull(mRunPath);
RunUtil.getDefault().sleep(START_TIMER);
// execute test
StringBuilder cmd = new StringBuilder();
cmd.append(mRunPath);
cmd.append(COMMAND);
if (mSleepTime > 0) {
cmd.append(" -s ");
cmd.append(mSleepTime);
}
standardListener.testRunStarted(mRuKey, 1);
long start = System.currentTimeMillis();
CollectingOutputReceiver receiver = new CollectingOutputReceiver();
mTestDevice.executeShellCommand(
AbiFormatter.formatCmdForAbi(cmd.toString(), mForceAbi),
receiver,
SHELL_TIMEOUT,
TimeUnit.MILLISECONDS,
2);
String result = receiver.getOutput();
if (result == null) {
CLog.v("no test results returned. Test failed?");
return;
}
// parse results and report metrics
parseResult(result);
standardListener.testRunEnded(
(System.currentTimeMillis() - start), TfMetricProtoUtil.upgradeConvert(mResultMap));
}
/** Parse results returned from running the benchmark */
public void parseResult(String result) {
String[] lines = result.split(System.getProperty("line.separator"));
if (lines.length <= 0) {
return;
}
for (int i = 0; i < lines.length; i++) {
if (!lines[i].contains(FIRST_LINE) && !lines[i].contains(TITLE)) {
// skip the first two lines
String[] items = lines[i].trim().split("\\|");
if (items.length == 3) {
String schemaKey = String.format("%s %s", items[0].trim(), items[1].trim());
if (mSchemaMap.get(schemaKey) != null) {
// get the mapped schema key if there is any
schemaKey = mSchemaMap.get(schemaKey);
}
String renderTime = items[2].trim();
if (renderTime != null) {
if (renderTime.equals(RESULT_FAST)) {
mResultMap.put(schemaKey, "0");
} else if (renderTime.equals(RESULT_SLOW)) {
mResultMap.put(schemaKey, "1000");
} else if (renderTime.equals(RESULT_VARIES)) {
mResultMap.put(schemaKey, "-1");
} else {
mResultMap.put(schemaKey, renderTime);
}
}
}
}
}
}
}