blob: dc8e600df6b02666099af79b751f0a1a7c81a913 [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 Reck1bcacfd2017-11-03 10:12:19 -070020#include "Properties.h"
Seigo Nonakab6e20132016-11-14 14:07:41 +090021#include "hwui/Typeface.h"
John Recke248bd12015-08-05 13:53:53 -070022#include "protos/hwui.pb.h"
23
John Reck1bcacfd2017-11-03 10:12:19 -070024#include <benchmark/benchmark.h>
John Reckb7dd29e2015-10-06 13:28:17 -070025#include <getopt.h>
John Reck1bcacfd2017-11-03 10:12:19 -070026#include <pthread.h>
John Recke702c9c2015-10-07 10:26:02 -070027#include <stdio.h>
John Recke702c9c2015-10-07 10:26:02 -070028#include <unistd.h>
John Reck1bcacfd2017-11-03 10:12:19 -070029#include <string>
John Recke702c9c2015-10-07 10:26:02 -070030#include <unordered_map>
John Reckb7dd29e2015-10-06 13:28:17 -070031#include <vector>
John Reck7f2e5e32015-05-05 11:00:53 -070032
John Reck682573c2015-10-30 10:37:35 -070033#include <errno.h>
John Reck1bcacfd2017-11-03 10:12:19 -070034#include <fcntl.h>
35#include <sys/stat.h>
36#include <sys/types.h>
John Reck682573c2015-10-30 10:37:35 -070037
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,
John Reck1bcacfd2017-11-03 10:12:19 -070048 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"(
sergeyv202c10b2016-07-11 17:53:45 -070052USAGE: hwuimacro [OPTIONS] <TESTNAME>
John Reck682573c2015-10-30 10:37:35 -070053
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
sergeyv202c10b2016-07-11 17:53:45 -070066 --offscreen Render tests off device screen. This option is on by default
67 --onscreen Render tests on device screen. By default tests
68 are offscreen rendered
69 --benchmark_format Set output format. Possible values are tabular, json, csv
John Reck18f442e2018-04-09 16:56:34 -070070 --renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
John Reckec100972018-04-05 16:41:41 -070071 --render-ahead=NUM Sets how far to render-ahead. Must be 0 (default), 1, or 2.
John Reck682573c2015-10-30 10:37:35 -070072)");
John Reckb7dd29e2015-10-06 13:28:17 -070073}
74
75static void listTests() {
76 printf("Tests: \n");
Chris Craik27e58b42015-12-07 10:01:38 -080077 for (auto&& test : TestScene::testMap()) {
John Recke702c9c2015-10-07 10:26:02 -070078 auto&& info = test.second;
79 const char* col1 = info.name.c_str();
80 int dlen = info.description.length();
81 const char* col2 = info.description.c_str();
82 // World's best line breaking algorithm.
83 do {
84 int toPrint = dlen;
85 if (toPrint > 50) {
John Reck1bcacfd2017-11-03 10:12:19 -070086 char* found = (char*)memrchr(col2, ' ', 50);
John Recke702c9c2015-10-07 10:26:02 -070087 if (found) {
88 toPrint = found - col2;
89 } else {
90 toPrint = 50;
91 }
92 }
93 printf("%-20s %.*s\n", col1, toPrint, col2);
94 col1 = "";
95 col2 += toPrint;
96 dlen -= toPrint;
97 while (*col2 == ' ') {
John Reck1bcacfd2017-11-03 10:12:19 -070098 col2++;
99 dlen--;
John Recke702c9c2015-10-07 10:26:02 -0700100 }
101 } while (dlen > 0);
102 printf("\n");
John Reckb7dd29e2015-10-06 13:28:17 -0700103 }
104}
105
John Reck682573c2015-10-30 10:37:35 -0700106static void moveToCpuSet(const char* cpusetName) {
107 if (access("/dev/cpuset/tasks", F_OK)) {
108 fprintf(stderr, "don't have access to cpusets, skipping...\n");
109 return;
110 }
111 static const int BUF_SIZE = 100;
112 char buffer[BUF_SIZE];
113
114 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
115 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
116 return;
117 }
118 int fd = open(buffer, O_WRONLY | O_CLOEXEC);
119 if (fd == -1) {
120 fprintf(stderr, "Error opening file %d\n", errno);
121 return;
122 }
123 pid_t pid = getpid();
124
John Reck1bcacfd2017-11-03 10:12:19 -0700125 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
John Reck682573c2015-10-30 10:37:35 -0700126 if (towrite >= BUF_SIZE) {
127 fprintf(stderr, "Buffer wasn't large enough?\n");
128 } else {
129 if (write(fd, buffer, towrite) != towrite) {
130 fprintf(stderr, "Failed to write, errno=%d", errno);
131 }
132 }
133 close(fd);
134}
135
John Reckf1480762016-07-03 18:28:25 -0700136static bool setBenchmarkFormat(const char* format) {
137 if (!strcmp(format, "tabular")) {
138 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
139 } else if (!strcmp(format, "json")) {
140 gBenchmarkReporter.reset(new benchmark::JSONReporter());
141 } else if (!strcmp(format, "csv")) {
142 gBenchmarkReporter.reset(new benchmark::CSVReporter());
143 } else {
144 fprintf(stderr, "Unknown format '%s'", format);
145 return false;
146 }
147 return true;
148}
149
John Reck113ddd92017-11-09 16:21:21 -0800150static bool setRenderer(const char* renderer) {
John Reck18f442e2018-04-09 16:56:34 -0700151 if (!strcmp(renderer, "skiagl")) {
John Reck113ddd92017-11-09 16:21:21 -0800152 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL);
153 } else if (!strcmp(renderer, "skiavk")) {
154 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan);
155 } else {
156 fprintf(stderr, "Unknown format '%s'", renderer);
157 return false;
158 }
159 return true;
160}
161
John Reck682573c2015-10-30 10:37:35 -0700162// For options that only exist in long-form. Anything in the
163// 0-255 range is reserved for short options (which just use their ASCII value)
164namespace LongOpts {
165enum {
166 Reserved = 255,
167 List,
168 WaitForGpu,
169 ReportFrametime,
170 CpuSet,
John Reckf1480762016-07-03 18:28:25 -0700171 BenchmarkFormat,
sergeyv202c10b2016-07-11 17:53:45 -0700172 Onscreen,
John Reckf1480762016-07-03 18:28:25 -0700173 Offscreen,
John Reck113ddd92017-11-09 16:21:21 -0800174 Renderer,
John Reckec100972018-04-05 16:41:41 -0700175 RenderAhead,
John Reck682573c2015-10-30 10:37:35 -0700176};
177}
178
John Reckb7dd29e2015-10-06 13:28:17 -0700179static const struct option LONG_OPTIONS[] = {
John Reck1bcacfd2017-11-03 10:12:19 -0700180 {"frames", required_argument, nullptr, 'f'},
181 {"repeat", required_argument, nullptr, 'r'},
182 {"help", no_argument, nullptr, 'h'},
183 {"list", no_argument, nullptr, LongOpts::List},
184 {"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
185 {"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
186 {"cpuset", required_argument, nullptr, LongOpts::CpuSet},
187 {"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
188 {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
189 {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
John Reck113ddd92017-11-09 16:21:21 -0800190 {"renderer", required_argument, nullptr, LongOpts::Renderer},
John Reckec100972018-04-05 16:41:41 -0700191 {"render-ahead", required_argument, nullptr, LongOpts::RenderAhead},
John Reck1bcacfd2017-11-03 10:12:19 -0700192 {0, 0, 0, 0}};
John Reckb7dd29e2015-10-06 13:28:17 -0700193
194static const char* SHORT_OPTIONS = "c:r:h";
195
196void parseOptions(int argc, char* argv[]) {
197 int c;
John Reckb7dd29e2015-10-06 13:28:17 -0700198 bool error = false;
199 opterr = 0;
200
201 while (true) {
John Reckb7dd29e2015-10-06 13:28:17 -0700202 /* getopt_long stores the option index here. */
203 int option_index = 0;
204
205 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
206
John Reck1bcacfd2017-11-03 10:12:19 -0700207 if (c == -1) break;
John Reckb7dd29e2015-10-06 13:28:17 -0700208
209 switch (c) {
John Reck1bcacfd2017-11-03 10:12:19 -0700210 case 0:
211 // Option set a flag, don't need to do anything
212 // (although none of the current LONG_OPTIONS do this...)
213 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700214
John Reck1bcacfd2017-11-03 10:12:19 -0700215 case LongOpts::List:
216 listTests();
217 exit(EXIT_SUCCESS);
218 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700219
John Reck1bcacfd2017-11-03 10:12:19 -0700220 case 'c':
221 gOpts.count = atoi(optarg);
222 if (!gOpts.count) {
223 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
John Reck682573c2015-10-30 10:37:35 -0700224 error = true;
225 }
John Reck682573c2015-10-30 10:37:35 -0700226 break;
John Reck682573c2015-10-30 10:37:35 -0700227
John Reck1bcacfd2017-11-03 10:12:19 -0700228 case 'r':
229 gRepeatCount = atoi(optarg);
230 if (!gRepeatCount) {
231 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
232 error = true;
233 } else {
234 gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
235 }
John Reckf1480762016-07-03 18:28:25 -0700236 break;
John Reckf1480762016-07-03 18:28:25 -0700237
John Reck1bcacfd2017-11-03 10:12:19 -0700238 case LongOpts::ReportFrametime:
239 if (optarg) {
240 gOpts.reportFrametimeWeight = atoi(optarg);
241 if (!gOpts.reportFrametimeWeight) {
242 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
243 error = true;
244 }
245 } else {
246 gOpts.reportFrametimeWeight = 10;
247 }
248 break;
sergeyv202c10b2016-07-11 17:53:45 -0700249
John Reck1bcacfd2017-11-03 10:12:19 -0700250 case LongOpts::WaitForGpu:
251 Properties::waitForGpuCompletion = true;
252 break;
John Reckf1480762016-07-03 18:28:25 -0700253
John Reck1bcacfd2017-11-03 10:12:19 -0700254 case LongOpts::CpuSet:
255 if (!optarg) {
256 error = true;
257 break;
258 }
259 moveToCpuSet(optarg);
260 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700261
John Reck1bcacfd2017-11-03 10:12:19 -0700262 case LongOpts::BenchmarkFormat:
263 if (!optarg) {
264 error = true;
265 break;
266 }
267 if (!setBenchmarkFormat(optarg)) {
268 error = true;
269 }
270 break;
271
John Reck113ddd92017-11-09 16:21:21 -0800272 case LongOpts::Renderer:
273 if (!optarg) {
274 error = true;
275 break;
276 }
277 if (!setRenderer(optarg)) {
278 error = true;
279 }
280 break;
281
John Reck1bcacfd2017-11-03 10:12:19 -0700282 case LongOpts::Onscreen:
283 gOpts.renderOffscreen = false;
284 break;
285
286 case LongOpts::Offscreen:
287 gOpts.renderOffscreen = true;
288 break;
289
John Reckec100972018-04-05 16:41:41 -0700290 case LongOpts::RenderAhead:
291 if (!optarg) {
292 error = true;
293 }
294 gOpts.renderAhead = atoi(optarg);
295 if (gOpts.renderAhead < 0 || gOpts.renderAhead > 2) {
296 error = true;
297 }
298 break;
299
John Reck1bcacfd2017-11-03 10:12:19 -0700300 case 'h':
301 printHelp();
302 exit(EXIT_SUCCESS);
303 break;
304
305 case '?':
306 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
John Reckb7dd29e2015-10-06 13:28:17 -0700307 // fall-through
John Reck1bcacfd2017-11-03 10:12:19 -0700308 default:
309 error = true;
310 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700311 }
312 }
313
314 if (error) {
315 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
316 exit(EXIT_FAILURE);
317 }
318
319 /* Print any remaining command line arguments (not options). */
320 if (optind < argc) {
321 do {
322 const char* test = argv[optind++];
sergeyv202c10b2016-07-11 17:53:45 -0700323 auto pos = TestScene::testMap().find(test);
324 if (pos == TestScene::testMap().end()) {
325 fprintf(stderr, "Unknown test '%s'\n", test);
326 exit(EXIT_FAILURE);
John Reckb7dd29e2015-10-06 13:28:17 -0700327 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700328 gRunTests.push_back(pos->second);
John Reckb7dd29e2015-10-06 13:28:17 -0700329 }
330 } while (optind < argc);
331 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700332 for (auto& iter : TestScene::testMap()) {
333 gRunTests.push_back(iter.second);
334 }
John Reckb7dd29e2015-10-06 13:28:17 -0700335 }
336}
337
Chris Craik03188872015-02-02 18:39:33 -0800338int main(int argc, char* argv[]) {
John Reck682573c2015-10-30 10:37:35 -0700339 // set defaults
340 gOpts.count = 150;
341
Seigo Nonakab6e20132016-11-14 14:07:41 +0900342 Typeface::setRobotoTypefaceForTest();
343
John Reckb7dd29e2015-10-06 13:28:17 -0700344 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700345 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
346 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
347 }
348
349 if (gBenchmarkReporter) {
350 size_t name_field_width = 10;
351 for (auto&& test : gRunTests) {
352 name_field_width = std::max<size_t>(name_field_width, test.name.size());
353 }
354 // _50th, _90th, etc...
355 name_field_width += 5;
356
357 benchmark::BenchmarkReporter::Context context;
John Reckf1480762016-07-03 18:28:25 -0700358 context.name_field_width = name_field_width;
359 gBenchmarkReporter->ReportContext(context);
360 }
John Reckb7dd29e2015-10-06 13:28:17 -0700361
362 for (int i = 0; i < gRepeatCount; i++) {
363 for (auto&& test : gRunTests) {
John Reckf1480762016-07-03 18:28:25 -0700364 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700365 }
366 }
John Reckf1480762016-07-03 18:28:25 -0700367
368 if (gBenchmarkReporter) {
369 gBenchmarkReporter->Finalize();
370 }
371
sergeyv7dc370b2016-06-17 11:21:11 -0700372 LeakChecker::checkForLeaks();
John Reck94c40fe2014-10-08 09:28:43 -0700373 return 0;
374}