Merge "Add some options to macrobench"

This commit is contained in:
John Reck
2016-01-04 15:26:18 +00:00
committed by Android (Google) Code Review
8 changed files with 212 additions and 36 deletions

View File

@ -243,6 +243,7 @@ void JankTracker::dumpData(const ProfileData* data, int fd) {
dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
(float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
dprintf(fd, "\n50th percentile: %ums", findPercentile(data, 50));
dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));

View File

@ -53,6 +53,8 @@ int Properties::overrideSpotShadowStrength = -1;
ProfileType Properties::sProfileType = ProfileType::None;
bool Properties::sDisableProfileBars = false;
bool Properties::waitForGpuCompletion = false;
static int property_get_int(const char* key, int defaultValue) {
char buf[PROPERTY_VALUE_MAX] = {'\0',};

View File

@ -285,6 +285,9 @@ public:
static ProfileType getProfileType();
// Should be used only by test apps
static bool waitForGpuCompletion;
private:
static ProfileType sProfileType;
static bool sDisableProfileBars;

View File

@ -29,8 +29,6 @@
#define GLES_VERSION 2
#define WAIT_FOR_GPU_COMPLETION 0
// Android-specific addition that is used to show when frames began in systrace
EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
@ -179,7 +177,10 @@ void EglManager::loadConfig() {
}
void EglManager::createContext() {
EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
EGLint attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
EGL_NONE
};
mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
"Failed to create context, error = %s", egl_error_str());
@ -318,12 +319,10 @@ void EglManager::damageFrame(const Frame& frame, const SkRect& dirty) {
bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
#if WAIT_FOR_GPU_COMPLETION
{
if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
ATRACE_NAME("Finishing GPU work");
fence();
}
#endif
EGLint rects[4];
frame.map(screenDirty, rects);

View File

@ -37,6 +37,7 @@ class TestScene {
public:
struct Options {
int count = 0;
int reportFrametimeWeight = 0;
};
template <class T>

View File

@ -38,6 +38,30 @@ public:
}
};
template<class T>
class ModifiedMovingAverage {
public:
ModifiedMovingAverage(int weight) : mWeight(weight) {}
T add(T today) {
if (!mHasValue) {
mAverage = today;
} else {
mAverage = (((mWeight - 1) * mAverage) + today) / mWeight;
}
return mAverage;
}
T average() {
return mAverage;
}
private:
bool mHasValue = false;
int mWeight;
T mAverage;
};
void run(const TestScene::Info& info, const TestScene::Options& opts) {
// Switch to the real display
gDisplay = getBuiltInDisplay();
@ -67,22 +91,35 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) {
proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
// Do a few cold runs then reset the stats so that the caches are all hot
for (int i = 0; i < 3; i++) {
for (int i = 0; i < 5; i++) {
testContext.waitForVsync();
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
proxy->syncAndDrawFrame();
}
proxy->resetProfileInfo();
proxy->fence();
ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
for (int i = 0; i < opts.count; i++) {
testContext.waitForVsync();
ATRACE_NAME("UI-Draw Frame");
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
scene->doFrame(i);
proxy->syncAndDrawFrame();
{
ATRACE_NAME("UI-Draw Frame");
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
scene->doFrame(i);
proxy->syncAndDrawFrame();
}
proxy->fence();
nsecs_t done = systemTime(CLOCK_MONOTONIC);
if (opts.reportFrametimeWeight) {
avgMs.add((done - vsync) / 1000000.0);
if (i % 10 == 9) {
printf("Average frametime %.3fms\n", avgMs.average());
}
}
}
proxy->dumpProfileInfo(STDOUT_FILENO, 0);

View File

@ -17,6 +17,7 @@
#include "tests/common/TestScene.h"
#include "protos/hwui.pb.h"
#include "Properties.h"
#include <getopt.h>
#include <stdio.h>
@ -25,26 +26,38 @@
#include <unordered_map>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::test;
static int gFrameCount = 150;
static int gRepeatCount = 1;
static std::vector<TestScene::Info> gRunTests;
static TestScene::Options gOpts;
void run(const TestScene::Info& info, const TestScene::Options& opts);
static void printHelp() {
printf("\
USAGE: hwuitest [OPTIONS] <TESTNAME>\n\
\n\
OPTIONS:\n\
-c, --count=NUM NUM loops a test should run (example, number of frames)\n\
-r, --runs=NUM Repeat the test(s) NUM times\n\
-h, --help Display this help\n\
--list List all tests\n\
\n");
printf(R"(
USAGE: hwuitest [OPTIONS] <TESTNAME>
OPTIONS:
-c, --count=NUM NUM loops a test should run (example, number of frames)
-r, --runs=NUM Repeat the test(s) NUM times
-h, --help Display this help
--list List all tests
--wait-for-gpu Set this to wait for the GPU before producing the
next frame. Note that without locked clocks this will
pathologically bad performance due to large idle time
--report-frametime[=weight] If set, the test will print to stdout the
moving average frametime. Weight is optional, default is 10
--cpuset=name Adds the test to the specified cpuset before running
Not supported on all devices and needs root
)");
}
static void listTests() {
@ -77,11 +90,56 @@ static void listTests() {
}
}
static void moveToCpuSet(const char* cpusetName) {
if (access("/dev/cpuset/tasks", F_OK)) {
fprintf(stderr, "don't have access to cpusets, skipping...\n");
return;
}
static const int BUF_SIZE = 100;
char buffer[BUF_SIZE];
if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
return;
}
int fd = open(buffer, O_WRONLY | O_CLOEXEC);
if (fd == -1) {
fprintf(stderr, "Error opening file %d\n", errno);
return;
}
pid_t pid = getpid();
int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
if (towrite >= BUF_SIZE) {
fprintf(stderr, "Buffer wasn't large enough?\n");
} else {
if (write(fd, buffer, towrite) != towrite) {
fprintf(stderr, "Failed to write, errno=%d", errno);
}
}
close(fd);
}
// For options that only exist in long-form. Anything in the
// 0-255 range is reserved for short options (which just use their ASCII value)
namespace LongOpts {
enum {
Reserved = 255,
List,
WaitForGpu,
ReportFrametime,
CpuSet,
};
}
static const struct option LONG_OPTIONS[] = {
{ "frames", required_argument, nullptr, 'f' },
{ "repeat", required_argument, nullptr, 'r' },
{ "help", no_argument, nullptr, 'h' },
{ "list", no_argument, nullptr, 'l' },
{ "list", no_argument, nullptr, LongOpts::List },
{ "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
{ "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
{ "cpuset", required_argument, nullptr, LongOpts::CpuSet },
{ 0, 0, 0, 0 }
};
@ -89,8 +147,6 @@ static const char* SHORT_OPTIONS = "c:r:h";
void parseOptions(int argc, char* argv[]) {
int c;
// temporary variable
int count;
bool error = false;
opterr = 0;
@ -110,31 +166,53 @@ void parseOptions(int argc, char* argv[]) {
// (although none of the current LONG_OPTIONS do this...)
break;
case 'l':
case LongOpts::List:
listTests();
exit(EXIT_SUCCESS);
break;
case 'c':
count = atoi(optarg);
if (!count) {
gOpts.count = atoi(optarg);
if (!gOpts.count) {
fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
error = true;
} else {
gFrameCount = (count > 0 ? count : INT_MAX);
}
break;
case 'r':
count = atoi(optarg);
if (!count) {
gRepeatCount = atoi(optarg);
if (!gRepeatCount) {
fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
error = true;
} else {
gRepeatCount = (count > 0 ? count : INT_MAX);
gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
}
break;
case LongOpts::ReportFrametime:
if (optarg) {
gOpts.reportFrametimeWeight = atoi(optarg);
if (!gOpts.reportFrametimeWeight) {
fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
error = true;
}
} else {
gOpts.reportFrametimeWeight = 10;
}
break;
case LongOpts::WaitForGpu:
Properties::waitForGpuCompletion = true;
break;
case LongOpts::CpuSet:
if (!optarg) {
error = true;
break;
}
moveToCpuSet(optarg);
break;
case 'h':
printHelp();
exit(EXIT_SUCCESS);
@ -172,13 +250,14 @@ void parseOptions(int argc, char* argv[]) {
}
int main(int argc, char* argv[]) {
// set defaults
gOpts.count = 150;
parseOptions(argc, argv);
TestScene::Options opts;
opts.count = gFrameCount;
for (int i = 0; i < gRepeatCount; i++) {
for (auto&& test : gRunTests) {
run(test, opts);
run(test, gOpts);
}
}
printf("Success!\n");

View File

@ -0,0 +1,54 @@
#!/bin/bash
# Copyright (C) 2015 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.
adb root
adb wait-for-device
adb shell stop mpdecision
adb shell stop perfd
adb shell stop
for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do
adb shell kill $pid
done
adb shell setprop debug.egl.traceGpuCompletion 1
adb shell daemonize surfaceflinger
sleep 3
adb shell setprop service.bootanim.exit 1
# cpu possible frequencies
# 204000 229500 255000 280500 306000 331500 357000 382500 408000 433500 459000
# 484500 510000 535500 561000 586500 612000 637500 663000 688500 714000 739500
# 765000 790500 816000 841500 867000 892500 918000 943500 969000 994500 1020000
# 1122000 1224000 1326000 1428000 1530000 1632000 1734000 1836000 1938000
# 2014500 2091000 2193000 2295000 2397000 2499000
S=1326000
echo "set cpu $cpu to $S hz";
adb shell "echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"
#disable hotplug
adb shell "echo 0 > /sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable"
# gbus possible rates
# 72000 108000 180000 252000 324000 396000 468000 540000 612000 648000
# 684000 708000 756000 804000 852000 (kHz)
S=324000000
echo "set gpu to $s hz"
adb shell "echo 1 > /d/clock/override.gbus/state"
adb shell "echo $S > /d/clock/override.gbus/rate"