blob: e9e962a78b0c8918dd420dd6de462758d38b47c6 [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 Reck66e06d42021-05-11 17:04:54 -040074 --report-gpu-memory 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 {
145 fprintf(stderr, "Unknown format '%s'", format);
146 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 {
157 fprintf(stderr, "Unknown format '%s'", renderer);
158 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 Reck66e06d42021-05-11 17:04:54 -0400194 {"report-gpu-memory", no_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;
299 break;
300
John Reck1bcacfd2017-11-03 10:12:19 -0700301 case 'h':
302 printHelp();
303 exit(EXIT_SUCCESS);
304 break;
305
306 case '?':
307 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
Chih-Hung Hsiehe1afb6c2018-10-22 12:25:50 -0700308 [[fallthrough]];
John Reck1bcacfd2017-11-03 10:12:19 -0700309 default:
310 error = true;
311 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700312 }
313 }
314
315 if (error) {
316 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
317 exit(EXIT_FAILURE);
318 }
319
320 /* Print any remaining command line arguments (not options). */
321 if (optind < argc) {
322 do {
323 const char* test = argv[optind++];
John Reck66e06d42021-05-11 17:04:54 -0400324 if (strchr(test, '*')) {
325 // Glob match
326 for (auto& iter : TestScene::testMap()) {
327 if (!fnmatch(test, iter.first.c_str(), 0)) {
328 gRunTests.push_back(iter.second);
329 }
330 }
John Reckb7dd29e2015-10-06 13:28:17 -0700331 } else {
John Reck66e06d42021-05-11 17:04:54 -0400332 auto pos = TestScene::testMap().find(test);
333 if (pos == TestScene::testMap().end()) {
334 fprintf(stderr, "Unknown test '%s'\n", test);
335 exit(EXIT_FAILURE);
336 } else {
337 gRunTests.push_back(pos->second);
338 }
John Reckb7dd29e2015-10-06 13:28:17 -0700339 }
340 } while (optind < argc);
341 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700342 for (auto& iter : TestScene::testMap()) {
343 gRunTests.push_back(iter.second);
344 }
John Reckb7dd29e2015-10-06 13:28:17 -0700345 }
346}
347
Chris Craik03188872015-02-02 18:39:33 -0800348int main(int argc, char* argv[]) {
Seigo Nonakab6e20132016-11-14 14:07:41 +0900349 Typeface::setRobotoTypefaceForTest();
350
John Reckb7dd29e2015-10-06 13:28:17 -0700351 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700352 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
353 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
354 }
355
356 if (gBenchmarkReporter) {
357 size_t name_field_width = 10;
358 for (auto&& test : gRunTests) {
359 name_field_width = std::max<size_t>(name_field_width, test.name.size());
360 }
361 // _50th, _90th, etc...
362 name_field_width += 5;
363
364 benchmark::BenchmarkReporter::Context context;
John Reckf1480762016-07-03 18:28:25 -0700365 context.name_field_width = name_field_width;
366 gBenchmarkReporter->ReportContext(context);
367 }
John Reckb7dd29e2015-10-06 13:28:17 -0700368
John Recka8427802021-05-10 17:47:50 -0400369 for (auto&& test : gRunTests) {
370 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700371 }
John Reckf1480762016-07-03 18:28:25 -0700372
373 if (gBenchmarkReporter) {
374 gBenchmarkReporter->Finalize();
375 }
376
John Reck6104cea2019-01-10 14:37:17 -0800377 renderthread::RenderProxy::trimMemory(100);
378 HardwareBitmapUploader::terminate();
379
John Recka8427802021-05-10 17:47:50 -0400380 if (gRunLeakCheck) {
381 LeakChecker::checkForLeaks();
382 }
John Reck94c40fe2014-10-08 09:28:43 -0700383 return 0;
384}