blob: ffeef45997747dd49bdaf182a08b32700e33be06 [file] [log] [blame]
John Reck94c40fe2014-10-08 09:28:43 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
sergeyv7dc370b2016-06-17 11:21:11 -070017#include "tests/common/LeakChecker.h"
Chris Craik27e58b42015-12-07 10:01:38 -080018#include "tests/common/TestScene.h"
John Reck94c40fe2014-10-08 09:28:43 -070019
John Recke248bd12015-08-05 13:53:53 -070020#include "protos/hwui.pb.h"
John Reck682573c2015-10-30 10:37:35 -070021#include "Properties.h"
John Recke248bd12015-08-05 13:53:53 -070022
John Reckf1480762016-07-03 18:28:25 -070023#include <benchmark/benchmark.h>
24#include <../src/sysinfo.h>
John Reckb7dd29e2015-10-06 13:28:17 -070025#include <getopt.h>
John Recke702c9c2015-10-07 10:26:02 -070026#include <stdio.h>
27#include <string>
28#include <unistd.h>
29#include <unordered_map>
John Reckb7dd29e2015-10-06 13:28:17 -070030#include <vector>
John Reck38e0c322015-11-10 12:19:17 -080031#include <pthread.h>
John Reck7f2e5e32015-05-05 11:00:53 -070032
John Reck682573c2015-10-30 10:37:35 -070033#include <sys/types.h>
34#include <sys/stat.h>
35#include <fcntl.h>
36#include <errno.h>
37
John Reck94c40fe2014-10-08 09:28:43 -070038using namespace android;
39using namespace android::uirenderer;
Chris Craik27e58b42015-12-07 10:01:38 -080040using namespace android::uirenderer::test;
John Reck94c40fe2014-10-08 09:28:43 -070041
John Reckb7dd29e2015-10-06 13:28:17 -070042static int gRepeatCount = 1;
Chris Craik27e58b42015-12-07 10:01:38 -080043static std::vector<TestScene::Info> gRunTests;
John Reck682573c2015-10-30 10:37:35 -070044static TestScene::Options gOpts;
John Reckf1480762016-07-03 18:28:25 -070045std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
John Reckb7dd29e2015-10-06 13:28:17 -070046
John Reckf1480762016-07-03 18:28:25 -070047void run(const TestScene::Info& info, const TestScene::Options& opts,
48 benchmark::BenchmarkReporter* reporter);
John Reck16c9d6a2015-11-17 15:51:08 -080049
John Reckb7dd29e2015-10-06 13:28:17 -070050static void printHelp() {
John Reck682573c2015-10-30 10:37:35 -070051 printf(R"(
52USAGE: hwuitest [OPTIONS] <TESTNAME>
53
54OPTIONS:
55 -c, --count=NUM NUM loops a test should run (example, number of frames)
56 -r, --runs=NUM Repeat the test(s) NUM times
57 -h, --help Display this help
58 --list List all tests
59 --wait-for-gpu Set this to wait for the GPU before producing the
60 next frame. Note that without locked clocks this will
61 pathologically bad performance due to large idle time
62 --report-frametime[=weight] If set, the test will print to stdout the
63 moving average frametime. Weight is optional, default is 10
64 --cpuset=name Adds the test to the specified cpuset before running
65 Not supported on all devices and needs root
66)");
John Reckb7dd29e2015-10-06 13:28:17 -070067}
68
69static void listTests() {
70 printf("Tests: \n");
Chris Craik27e58b42015-12-07 10:01:38 -080071 for (auto&& test : TestScene::testMap()) {
John Recke702c9c2015-10-07 10:26:02 -070072 auto&& info = test.second;
73 const char* col1 = info.name.c_str();
74 int dlen = info.description.length();
75 const char* col2 = info.description.c_str();
76 // World's best line breaking algorithm.
77 do {
78 int toPrint = dlen;
79 if (toPrint > 50) {
80 char* found = (char*) memrchr(col2, ' ', 50);
81 if (found) {
82 toPrint = found - col2;
83 } else {
84 toPrint = 50;
85 }
86 }
87 printf("%-20s %.*s\n", col1, toPrint, col2);
88 col1 = "";
89 col2 += toPrint;
90 dlen -= toPrint;
91 while (*col2 == ' ') {
92 col2++; dlen--;
93 }
94 } while (dlen > 0);
95 printf("\n");
John Reckb7dd29e2015-10-06 13:28:17 -070096 }
97}
98
John Reck682573c2015-10-30 10:37:35 -070099static void moveToCpuSet(const char* cpusetName) {
100 if (access("/dev/cpuset/tasks", F_OK)) {
101 fprintf(stderr, "don't have access to cpusets, skipping...\n");
102 return;
103 }
104 static const int BUF_SIZE = 100;
105 char buffer[BUF_SIZE];
106
107 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
108 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
109 return;
110 }
111 int fd = open(buffer, O_WRONLY | O_CLOEXEC);
112 if (fd == -1) {
113 fprintf(stderr, "Error opening file %d\n", errno);
114 return;
115 }
116 pid_t pid = getpid();
117
118 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
119 if (towrite >= BUF_SIZE) {
120 fprintf(stderr, "Buffer wasn't large enough?\n");
121 } else {
122 if (write(fd, buffer, towrite) != towrite) {
123 fprintf(stderr, "Failed to write, errno=%d", errno);
124 }
125 }
126 close(fd);
127}
128
John Reckf1480762016-07-03 18:28:25 -0700129static bool setBenchmarkFormat(const char* format) {
130 if (!strcmp(format, "tabular")) {
131 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
132 } else if (!strcmp(format, "json")) {
133 gBenchmarkReporter.reset(new benchmark::JSONReporter());
134 } else if (!strcmp(format, "csv")) {
135 gBenchmarkReporter.reset(new benchmark::CSVReporter());
136 } else {
137 fprintf(stderr, "Unknown format '%s'", format);
138 return false;
139 }
140 return true;
141}
142
John Reck682573c2015-10-30 10:37:35 -0700143// For options that only exist in long-form. Anything in the
144// 0-255 range is reserved for short options (which just use their ASCII value)
145namespace LongOpts {
146enum {
147 Reserved = 255,
148 List,
149 WaitForGpu,
150 ReportFrametime,
151 CpuSet,
John Reckf1480762016-07-03 18:28:25 -0700152 BenchmarkFormat,
153 Offscreen,
John Reck682573c2015-10-30 10:37:35 -0700154};
155}
156
John Reckb7dd29e2015-10-06 13:28:17 -0700157static const struct option LONG_OPTIONS[] = {
158 { "frames", required_argument, nullptr, 'f' },
159 { "repeat", required_argument, nullptr, 'r' },
160 { "help", no_argument, nullptr, 'h' },
John Reck682573c2015-10-30 10:37:35 -0700161 { "list", no_argument, nullptr, LongOpts::List },
162 { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
163 { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
164 { "cpuset", required_argument, nullptr, LongOpts::CpuSet },
John Reckf1480762016-07-03 18:28:25 -0700165 { "benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat },
166 { "offscreen", no_argument, nullptr, LongOpts::Offscreen },
John Reckb7dd29e2015-10-06 13:28:17 -0700167 { 0, 0, 0, 0 }
168};
169
170static const char* SHORT_OPTIONS = "c:r:h";
171
172void parseOptions(int argc, char* argv[]) {
173 int c;
John Reckb7dd29e2015-10-06 13:28:17 -0700174 bool error = false;
175 opterr = 0;
176
177 while (true) {
178
179 /* getopt_long stores the option index here. */
180 int option_index = 0;
181
182 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
183
184 if (c == -1)
185 break;
186
187 switch (c) {
188 case 0:
189 // Option set a flag, don't need to do anything
190 // (although none of the current LONG_OPTIONS do this...)
191 break;
192
John Reck682573c2015-10-30 10:37:35 -0700193 case LongOpts::List:
John Reckb7dd29e2015-10-06 13:28:17 -0700194 listTests();
195 exit(EXIT_SUCCESS);
196 break;
197
198 case 'c':
John Reck682573c2015-10-30 10:37:35 -0700199 gOpts.count = atoi(optarg);
200 if (!gOpts.count) {
John Reckb7dd29e2015-10-06 13:28:17 -0700201 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
202 error = true;
John Reckb7dd29e2015-10-06 13:28:17 -0700203 }
204 break;
205
206 case 'r':
John Reck682573c2015-10-30 10:37:35 -0700207 gRepeatCount = atoi(optarg);
208 if (!gRepeatCount) {
John Reckb7dd29e2015-10-06 13:28:17 -0700209 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
210 error = true;
211 } else {
John Reck682573c2015-10-30 10:37:35 -0700212 gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
John Reckb7dd29e2015-10-06 13:28:17 -0700213 }
214 break;
215
John Reck682573c2015-10-30 10:37:35 -0700216 case LongOpts::ReportFrametime:
217 if (optarg) {
218 gOpts.reportFrametimeWeight = atoi(optarg);
219 if (!gOpts.reportFrametimeWeight) {
220 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
221 error = true;
222 }
223 } else {
224 gOpts.reportFrametimeWeight = 10;
225 }
226 break;
227
228 case LongOpts::WaitForGpu:
229 Properties::waitForGpuCompletion = true;
230 break;
231
232 case LongOpts::CpuSet:
233 if (!optarg) {
234 error = true;
235 break;
236 }
237 moveToCpuSet(optarg);
238 break;
239
John Reckf1480762016-07-03 18:28:25 -0700240 case LongOpts::BenchmarkFormat:
241 if (!optarg) {
242 error = true;
243 break;
244 }
245 if (!setBenchmarkFormat(optarg)) {
246 error = true;
247 }
248 break;
249
250 case LongOpts::Offscreen:
251 gOpts.renderOffscreen = true;
252 break;
253
John Reckb7dd29e2015-10-06 13:28:17 -0700254 case 'h':
255 printHelp();
256 exit(EXIT_SUCCESS);
257 break;
258
259 case '?':
260 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
261 // fall-through
262 default:
263 error = true;
264 break;
265 }
266 }
267
268 if (error) {
269 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
270 exit(EXIT_FAILURE);
271 }
272
273 /* Print any remaining command line arguments (not options). */
274 if (optind < argc) {
275 do {
276 const char* test = argv[optind++];
John Reckf1480762016-07-03 18:28:25 -0700277 if (!strcmp(test, "all")) {
278 for (auto& iter : TestScene::testMap()) {
279 gRunTests.push_back(iter.second);
280 }
John Reckb7dd29e2015-10-06 13:28:17 -0700281 } else {
John Reckf1480762016-07-03 18:28:25 -0700282 auto pos = TestScene::testMap().find(test);
283 if (pos == TestScene::testMap().end()) {
284 fprintf(stderr, "Unknown test '%s'\n", test);
285 exit(EXIT_FAILURE);
286 } else {
287 gRunTests.push_back(pos->second);
288 }
John Reckb7dd29e2015-10-06 13:28:17 -0700289 }
290 } while (optind < argc);
291 } else {
Chris Craik27e58b42015-12-07 10:01:38 -0800292 gRunTests.push_back(TestScene::testMap()["shadowgrid"]);
John Reckb7dd29e2015-10-06 13:28:17 -0700293 }
294}
295
Chris Craik03188872015-02-02 18:39:33 -0800296int main(int argc, char* argv[]) {
John Reck682573c2015-10-30 10:37:35 -0700297 // set defaults
298 gOpts.count = 150;
299
John Reckb7dd29e2015-10-06 13:28:17 -0700300 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700301 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
302 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
303 }
304
305 if (gBenchmarkReporter) {
306 size_t name_field_width = 10;
307 for (auto&& test : gRunTests) {
308 name_field_width = std::max<size_t>(name_field_width, test.name.size());
309 }
310 // _50th, _90th, etc...
311 name_field_width += 5;
312
313 benchmark::BenchmarkReporter::Context context;
314 context.num_cpus = benchmark::NumCPUs();
315 context.mhz_per_cpu = benchmark::CyclesPerSecond() / 1000000.0f;
316 context.cpu_scaling_enabled = benchmark::CpuScalingEnabled();
317 context.name_field_width = name_field_width;
318 gBenchmarkReporter->ReportContext(context);
319 }
John Reckb7dd29e2015-10-06 13:28:17 -0700320
321 for (int i = 0; i < gRepeatCount; i++) {
322 for (auto&& test : gRunTests) {
John Reckf1480762016-07-03 18:28:25 -0700323 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700324 }
325 }
John Reckf1480762016-07-03 18:28:25 -0700326
327 if (gBenchmarkReporter) {
328 gBenchmarkReporter->Finalize();
329 }
330
sergeyv7dc370b2016-06-17 11:21:11 -0700331 LeakChecker::checkForLeaks();
John Reck94c40fe2014-10-08 09:28:43 -0700332 return 0;
333}