blob: f3f32eb6897cb49b7bcef33fbbf18ce174bf7a27 [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 Reck6104cea2019-01-10 14:37:17 -080022#include "HardwareBitmapUploader.h"
23#include "renderthread/RenderProxy.h"
John Recke248bd12015-08-05 13:53:53 -070024
John Reck1bcacfd2017-11-03 10:12:19 -070025#include <benchmark/benchmark.h>
John Reck66e06d42021-05-11 17:04:54 -040026#include <fnmatch.h>
John Reckb7dd29e2015-10-06 13:28:17 -070027#include <getopt.h>
John Reck1bcacfd2017-11-03 10:12:19 -070028#include <pthread.h>
John Recke702c9c2015-10-07 10:26:02 -070029#include <stdio.h>
John Recke702c9c2015-10-07 10:26:02 -070030#include <unistd.h>
John Reck1bcacfd2017-11-03 10:12:19 -070031#include <string>
John Recke702c9c2015-10-07 10:26:02 -070032#include <unordered_map>
John Reckb7dd29e2015-10-06 13:28:17 -070033#include <vector>
John Reck7f2e5e32015-05-05 11:00:53 -070034
John Reck682573c2015-10-30 10:37:35 -070035#include <errno.h>
John Reck1bcacfd2017-11-03 10:12:19 -070036#include <fcntl.h>
37#include <sys/stat.h>
38#include <sys/types.h>
John Reck682573c2015-10-30 10:37:35 -070039
John Reck94c40fe2014-10-08 09:28:43 -070040using namespace android;
41using namespace android::uirenderer;
Chris Craik27e58b42015-12-07 10:01:38 -080042using namespace android::uirenderer::test;
John Reck94c40fe2014-10-08 09:28:43 -070043
Chris Craik27e58b42015-12-07 10:01:38 -080044static std::vector<TestScene::Info> gRunTests;
John Reck682573c2015-10-30 10:37:35 -070045static TestScene::Options gOpts;
John Recka8427802021-05-10 17:47:50 -040046static bool gRunLeakCheck = true;
John Reckf1480762016-07-03 18:28:25 -070047std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
John Reckb7dd29e2015-10-06 13:28:17 -070048
John Reckf1480762016-07-03 18:28:25 -070049void run(const TestScene::Info& info, const TestScene::Options& opts,
John Reck1bcacfd2017-11-03 10:12:19 -070050 benchmark::BenchmarkReporter* reporter);
John Reck16c9d6a2015-11-17 15:51:08 -080051
John Reckb7dd29e2015-10-06 13:28:17 -070052static void printHelp() {
John Reck682573c2015-10-30 10:37:35 -070053 printf(R"(
sergeyv202c10b2016-07-11 17:53:45 -070054USAGE: hwuimacro [OPTIONS] <TESTNAME>
John Reck682573c2015-10-30 10:37:35 -070055
56OPTIONS:
57 -c, --count=NUM NUM loops a test should run (example, number of frames)
58 -r, --runs=NUM Repeat the test(s) NUM times
59 -h, --help Display this help
60 --list List all tests
61 --wait-for-gpu Set this to wait for the GPU before producing the
62 next frame. Note that without locked clocks this will
63 pathologically bad performance due to large idle time
64 --report-frametime[=weight] If set, the test will print to stdout the
65 moving average frametime. Weight is optional, default is 10
66 --cpuset=name Adds the test to the specified cpuset before running
67 Not supported on all devices and needs root
sergeyv202c10b2016-07-11 17:53:45 -070068 --offscreen Render tests off device screen. This option is on by default
69 --onscreen Render tests on device screen. By default tests
70 are offscreen rendered
71 --benchmark_format Set output format. Possible values are tabular, json, csv
John Reck18f442e2018-04-09 16:56:34 -070072 --renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
John Recka8427802021-05-10 17:47:50 -040073 --skip-leak-check Skips the memory leak check
John Reck39207682021-05-12 19:10:47 -040074 --report-gpu-memory[=verbose] Dumps the GPU memory usage after each test run
John Reck682573c2015-10-30 10:37:35 -070075)");
John Reckb7dd29e2015-10-06 13:28:17 -070076}
77
78static void listTests() {
79 printf("Tests: \n");
Chris Craik27e58b42015-12-07 10:01:38 -080080 for (auto&& test : TestScene::testMap()) {
John Recke702c9c2015-10-07 10:26:02 -070081 auto&& info = test.second;
82 const char* col1 = info.name.c_str();
83 int dlen = info.description.length();
84 const char* col2 = info.description.c_str();
85 // World's best line breaking algorithm.
86 do {
87 int toPrint = dlen;
88 if (toPrint > 50) {
John Reck1bcacfd2017-11-03 10:12:19 -070089 char* found = (char*)memrchr(col2, ' ', 50);
John Recke702c9c2015-10-07 10:26:02 -070090 if (found) {
91 toPrint = found - col2;
92 } else {
93 toPrint = 50;
94 }
95 }
96 printf("%-20s %.*s\n", col1, toPrint, col2);
97 col1 = "";
98 col2 += toPrint;
99 dlen -= toPrint;
100 while (*col2 == ' ') {
John Reck1bcacfd2017-11-03 10:12:19 -0700101 col2++;
102 dlen--;
John Recke702c9c2015-10-07 10:26:02 -0700103 }
104 } while (dlen > 0);
105 printf("\n");
John Reckb7dd29e2015-10-06 13:28:17 -0700106 }
107}
108
John Reck682573c2015-10-30 10:37:35 -0700109static void moveToCpuSet(const char* cpusetName) {
110 if (access("/dev/cpuset/tasks", F_OK)) {
111 fprintf(stderr, "don't have access to cpusets, skipping...\n");
112 return;
113 }
114 static const int BUF_SIZE = 100;
115 char buffer[BUF_SIZE];
116
117 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
118 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
119 return;
120 }
121 int fd = open(buffer, O_WRONLY | O_CLOEXEC);
122 if (fd == -1) {
123 fprintf(stderr, "Error opening file %d\n", errno);
124 return;
125 }
126 pid_t pid = getpid();
127
John Reck1bcacfd2017-11-03 10:12:19 -0700128 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
John Reck682573c2015-10-30 10:37:35 -0700129 if (towrite >= BUF_SIZE) {
130 fprintf(stderr, "Buffer wasn't large enough?\n");
131 } else {
132 if (write(fd, buffer, towrite) != towrite) {
133 fprintf(stderr, "Failed to write, errno=%d", errno);
134 }
135 }
136 close(fd);
137}
138
John Reckf1480762016-07-03 18:28:25 -0700139static bool setBenchmarkFormat(const char* format) {
140 if (!strcmp(format, "tabular")) {
141 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
142 } else if (!strcmp(format, "json")) {
143 gBenchmarkReporter.reset(new benchmark::JSONReporter());
John Reckf1480762016-07-03 18:28:25 -0700144 } else {
John Reck39207682021-05-12 19:10:47 -0400145 fprintf(stderr, "Unknown format '%s'\n", format);
John Reckf1480762016-07-03 18:28:25 -0700146 return false;
147 }
148 return true;
149}
150
John Reck113ddd92017-11-09 16:21:21 -0800151static bool setRenderer(const char* renderer) {
John Reck18f442e2018-04-09 16:56:34 -0700152 if (!strcmp(renderer, "skiagl")) {
John Reck113ddd92017-11-09 16:21:21 -0800153 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL);
154 } else if (!strcmp(renderer, "skiavk")) {
155 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan);
156 } else {
John Reck39207682021-05-12 19:10:47 -0400157 fprintf(stderr, "Unknown format '%s'\n", renderer);
John Reck113ddd92017-11-09 16:21:21 -0800158 return false;
159 }
160 return true;
161}
162
John Reck682573c2015-10-30 10:37:35 -0700163// For options that only exist in long-form. Anything in the
164// 0-255 range is reserved for short options (which just use their ASCII value)
165namespace LongOpts {
166enum {
167 Reserved = 255,
168 List,
169 WaitForGpu,
170 ReportFrametime,
171 CpuSet,
John Reckf1480762016-07-03 18:28:25 -0700172 BenchmarkFormat,
sergeyv202c10b2016-07-11 17:53:45 -0700173 Onscreen,
John Reckf1480762016-07-03 18:28:25 -0700174 Offscreen,
John Reck113ddd92017-11-09 16:21:21 -0800175 Renderer,
John Recka8427802021-05-10 17:47:50 -0400176 SkipLeakCheck,
John Reck66e06d42021-05-11 17:04:54 -0400177 ReportGpuMemory,
John Reck682573c2015-10-30 10:37:35 -0700178};
179}
180
John Reckb7dd29e2015-10-06 13:28:17 -0700181static const struct option LONG_OPTIONS[] = {
John Reck1bcacfd2017-11-03 10:12:19 -0700182 {"frames", required_argument, nullptr, 'f'},
183 {"repeat", required_argument, nullptr, 'r'},
184 {"help", no_argument, nullptr, 'h'},
185 {"list", no_argument, nullptr, LongOpts::List},
186 {"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
187 {"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
188 {"cpuset", required_argument, nullptr, LongOpts::CpuSet},
189 {"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
190 {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
191 {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
John Reck113ddd92017-11-09 16:21:21 -0800192 {"renderer", required_argument, nullptr, LongOpts::Renderer},
John Recka8427802021-05-10 17:47:50 -0400193 {"skip-leak-check", no_argument, nullptr, LongOpts::SkipLeakCheck},
John Reck39207682021-05-12 19:10:47 -0400194 {"report-gpu-memory", optional_argument, nullptr, LongOpts::ReportGpuMemory},
John Reck1bcacfd2017-11-03 10:12:19 -0700195 {0, 0, 0, 0}};
John Reckb7dd29e2015-10-06 13:28:17 -0700196
197static const char* SHORT_OPTIONS = "c:r:h";
198
199void parseOptions(int argc, char* argv[]) {
200 int c;
John Reckb7dd29e2015-10-06 13:28:17 -0700201 bool error = false;
202 opterr = 0;
203
204 while (true) {
John Reckb7dd29e2015-10-06 13:28:17 -0700205 /* getopt_long stores the option index here. */
206 int option_index = 0;
207
208 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
209
John Reck1bcacfd2017-11-03 10:12:19 -0700210 if (c == -1) break;
John Reckb7dd29e2015-10-06 13:28:17 -0700211
212 switch (c) {
John Reck1bcacfd2017-11-03 10:12:19 -0700213 case 0:
214 // Option set a flag, don't need to do anything
215 // (although none of the current LONG_OPTIONS do this...)
216 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700217
John Reck1bcacfd2017-11-03 10:12:19 -0700218 case LongOpts::List:
219 listTests();
220 exit(EXIT_SUCCESS);
221 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700222
John Reck1bcacfd2017-11-03 10:12:19 -0700223 case 'c':
John Recka8427802021-05-10 17:47:50 -0400224 gOpts.frameCount = atoi(optarg);
225 if (!gOpts.frameCount) {
John Reck1bcacfd2017-11-03 10:12:19 -0700226 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
John Reck682573c2015-10-30 10:37:35 -0700227 error = true;
228 }
John Reck682573c2015-10-30 10:37:35 -0700229 break;
John Reck682573c2015-10-30 10:37:35 -0700230
John Reck1bcacfd2017-11-03 10:12:19 -0700231 case 'r':
John Recka8427802021-05-10 17:47:50 -0400232 gOpts.repeatCount = atoi(optarg);
233 if (!gOpts.repeatCount) {
John Reck1bcacfd2017-11-03 10:12:19 -0700234 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
235 error = true;
236 } else {
John Recka8427802021-05-10 17:47:50 -0400237 gOpts.repeatCount = (gOpts.repeatCount > 0 ? gOpts.repeatCount : INT_MAX);
John Reck1bcacfd2017-11-03 10:12:19 -0700238 }
John Reckf1480762016-07-03 18:28:25 -0700239 break;
John Reckf1480762016-07-03 18:28:25 -0700240
John Reck1bcacfd2017-11-03 10:12:19 -0700241 case LongOpts::ReportFrametime:
242 if (optarg) {
243 gOpts.reportFrametimeWeight = atoi(optarg);
244 if (!gOpts.reportFrametimeWeight) {
245 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
246 error = true;
247 }
248 } else {
249 gOpts.reportFrametimeWeight = 10;
250 }
251 break;
sergeyv202c10b2016-07-11 17:53:45 -0700252
John Reck1bcacfd2017-11-03 10:12:19 -0700253 case LongOpts::WaitForGpu:
254 Properties::waitForGpuCompletion = true;
255 break;
John Reckf1480762016-07-03 18:28:25 -0700256
John Reck1bcacfd2017-11-03 10:12:19 -0700257 case LongOpts::CpuSet:
258 if (!optarg) {
259 error = true;
260 break;
261 }
262 moveToCpuSet(optarg);
263 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700264
John Reck1bcacfd2017-11-03 10:12:19 -0700265 case LongOpts::BenchmarkFormat:
266 if (!optarg) {
267 error = true;
268 break;
269 }
270 if (!setBenchmarkFormat(optarg)) {
271 error = true;
272 }
273 break;
274
John Reck113ddd92017-11-09 16:21:21 -0800275 case LongOpts::Renderer:
276 if (!optarg) {
277 error = true;
278 break;
279 }
280 if (!setRenderer(optarg)) {
281 error = true;
282 }
283 break;
284
John Reck1bcacfd2017-11-03 10:12:19 -0700285 case LongOpts::Onscreen:
286 gOpts.renderOffscreen = false;
287 break;
288
289 case LongOpts::Offscreen:
290 gOpts.renderOffscreen = true;
291 break;
292
John Recka8427802021-05-10 17:47:50 -0400293 case LongOpts::SkipLeakCheck:
294 gRunLeakCheck = false;
295 break;
296
John Reck66e06d42021-05-11 17:04:54 -0400297 case LongOpts::ReportGpuMemory:
298 gOpts.reportGpuMemoryUsage = true;
John Reck39207682021-05-12 19:10:47 -0400299 if (optarg) {
300 if (!strcmp("verbose", optarg)) {
301 gOpts.reportGpuMemoryUsageVerbose = true;
302 } else {
303 fprintf(stderr, "Invalid report gpu memory option '%s'\n", optarg);
304 error = true;
305 }
306 }
John Reck66e06d42021-05-11 17:04:54 -0400307 break;
308
John Reck1bcacfd2017-11-03 10:12:19 -0700309 case 'h':
310 printHelp();
311 exit(EXIT_SUCCESS);
312 break;
313
314 case '?':
315 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
Chih-Hung Hsiehe1afb6c2018-10-22 12:25:50 -0700316 [[fallthrough]];
John Reck1bcacfd2017-11-03 10:12:19 -0700317 default:
318 error = true;
319 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700320 }
321 }
322
323 if (error) {
John Reck39207682021-05-12 19:10:47 -0400324 fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
John Reckb7dd29e2015-10-06 13:28:17 -0700325 exit(EXIT_FAILURE);
326 }
327
328 /* Print any remaining command line arguments (not options). */
329 if (optind < argc) {
330 do {
331 const char* test = argv[optind++];
John Reck66e06d42021-05-11 17:04:54 -0400332 if (strchr(test, '*')) {
333 // Glob match
334 for (auto& iter : TestScene::testMap()) {
335 if (!fnmatch(test, iter.first.c_str(), 0)) {
336 gRunTests.push_back(iter.second);
337 }
338 }
John Reckb7dd29e2015-10-06 13:28:17 -0700339 } else {
John Reck66e06d42021-05-11 17:04:54 -0400340 auto pos = TestScene::testMap().find(test);
341 if (pos == TestScene::testMap().end()) {
342 fprintf(stderr, "Unknown test '%s'\n", test);
343 exit(EXIT_FAILURE);
344 } else {
345 gRunTests.push_back(pos->second);
346 }
John Reckb7dd29e2015-10-06 13:28:17 -0700347 }
348 } while (optind < argc);
349 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700350 for (auto& iter : TestScene::testMap()) {
351 gRunTests.push_back(iter.second);
352 }
John Reckb7dd29e2015-10-06 13:28:17 -0700353 }
354}
355
Chris Craik03188872015-02-02 18:39:33 -0800356int main(int argc, char* argv[]) {
Seigo Nonakab6e20132016-11-14 14:07:41 +0900357 Typeface::setRobotoTypefaceForTest();
358
John Reckb7dd29e2015-10-06 13:28:17 -0700359 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700360 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
361 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
362 }
363
364 if (gBenchmarkReporter) {
365 size_t name_field_width = 10;
366 for (auto&& test : gRunTests) {
367 name_field_width = std::max<size_t>(name_field_width, test.name.size());
368 }
369 // _50th, _90th, etc...
370 name_field_width += 5;
371
372 benchmark::BenchmarkReporter::Context context;
John Reckf1480762016-07-03 18:28:25 -0700373 context.name_field_width = name_field_width;
374 gBenchmarkReporter->ReportContext(context);
375 }
John Reckb7dd29e2015-10-06 13:28:17 -0700376
John Recka8427802021-05-10 17:47:50 -0400377 for (auto&& test : gRunTests) {
378 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700379 }
John Reckf1480762016-07-03 18:28:25 -0700380
381 if (gBenchmarkReporter) {
382 gBenchmarkReporter->Finalize();
383 }
384
John Reck6104cea2019-01-10 14:37:17 -0800385 renderthread::RenderProxy::trimMemory(100);
386 HardwareBitmapUploader::terminate();
387
John Recka8427802021-05-10 17:47:50 -0400388 if (gRunLeakCheck) {
389 LeakChecker::checkForLeaks();
390 }
John Reck94c40fe2014-10-08 09:28:43 -0700391 return 0;
392}