blob: e227999c2432d6e0790c0aef5a636c6d9a005b07 [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
John Reck697779e2023-07-17 17:00:37 -040017#include <android-base/parsebool.h>
John Reck1bcacfd2017-11-03 10:12:19 -070018#include <benchmark/benchmark.h>
John Reck697779e2023-07-17 17:00:37 -040019#include <errno.h>
20#include <fcntl.h>
John Reck66e06d42021-05-11 17:04:54 -040021#include <fnmatch.h>
John Reckb7dd29e2015-10-06 13:28:17 -070022#include <getopt.h>
John Reck1bcacfd2017-11-03 10:12:19 -070023#include <pthread.h>
John Recke702c9c2015-10-07 10:26:02 -070024#include <stdio.h>
John Reck697779e2023-07-17 17:00:37 -040025#include <sys/stat.h>
26#include <sys/types.h>
John Recke702c9c2015-10-07 10:26:02 -070027#include <unistd.h>
John Reck697779e2023-07-17 17:00:37 -040028
29#include <regex>
John Reck1bcacfd2017-11-03 10:12:19 -070030#include <string>
John Recke702c9c2015-10-07 10:26:02 -070031#include <unordered_map>
John Reckb7dd29e2015-10-06 13:28:17 -070032#include <vector>
John Reck7f2e5e32015-05-05 11:00:53 -070033
John Reck697779e2023-07-17 17:00:37 -040034#include "HardwareBitmapUploader.h"
35#include "Properties.h"
36#include "hwui/Typeface.h"
37#include "renderthread/RenderProxy.h"
38#include "tests/common/LeakChecker.h"
39#include "tests/common/TestScene.h"
John Reck682573c2015-10-30 10:37:35 -070040
John Reck94c40fe2014-10-08 09:28:43 -070041using namespace android;
John Reck697779e2023-07-17 17:00:37 -040042using namespace android::base;
John Reck94c40fe2014-10-08 09:28:43 -070043using namespace android::uirenderer;
Chris Craik27e58b42015-12-07 10:01:38 -080044using namespace android::uirenderer::test;
John Reck94c40fe2014-10-08 09:28:43 -070045
Chris Craik27e58b42015-12-07 10:01:38 -080046static std::vector<TestScene::Info> gRunTests;
John Reck682573c2015-10-30 10:37:35 -070047static TestScene::Options gOpts;
John Recka8427802021-05-10 17:47:50 -040048static bool gRunLeakCheck = true;
John Reckf1480762016-07-03 18:28:25 -070049std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
John Reckb7dd29e2015-10-06 13:28:17 -070050
John Reckf1480762016-07-03 18:28:25 -070051void run(const TestScene::Info& info, const TestScene::Options& opts,
John Reck1bcacfd2017-11-03 10:12:19 -070052 benchmark::BenchmarkReporter* reporter);
John Reck16c9d6a2015-11-17 15:51:08 -080053
John Reckb7dd29e2015-10-06 13:28:17 -070054static void printHelp() {
John Reck682573c2015-10-30 10:37:35 -070055 printf(R"(
sergeyv202c10b2016-07-11 17:53:45 -070056USAGE: hwuimacro [OPTIONS] <TESTNAME>
John Reck682573c2015-10-30 10:37:35 -070057
58OPTIONS:
59 -c, --count=NUM NUM loops a test should run (example, number of frames)
60 -r, --runs=NUM Repeat the test(s) NUM times
61 -h, --help Display this help
62 --list List all tests
63 --wait-for-gpu Set this to wait for the GPU before producing the
64 next frame. Note that without locked clocks this will
65 pathologically bad performance due to large idle time
66 --report-frametime[=weight] If set, the test will print to stdout the
67 moving average frametime. Weight is optional, default is 10
68 --cpuset=name Adds the test to the specified cpuset before running
69 Not supported on all devices and needs root
sergeyv202c10b2016-07-11 17:53:45 -070070 --offscreen Render tests off device screen. This option is on by default
71 --onscreen Render tests on device screen. By default tests
72 are offscreen rendered
73 --benchmark_format Set output format. Possible values are tabular, json, csv
John Reck697779e2023-07-17 17:00:37 -040074 --benchmark_list_tests Lists the tests that would run but does not run them
75 --benchmark_filter=<regex> Filters the test set to the given regex. If prefixed with `-` and test
76 that doesn't match the given regex is run
John Reck18f442e2018-04-09 16:56:34 -070077 --renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
John Recka8427802021-05-10 17:47:50 -040078 --skip-leak-check Skips the memory leak check
John Reck39207682021-05-12 19:10:47 -040079 --report-gpu-memory[=verbose] Dumps the GPU memory usage after each test run
John Reck682573c2015-10-30 10:37:35 -070080)");
John Reckb7dd29e2015-10-06 13:28:17 -070081}
82
83static void listTests() {
84 printf("Tests: \n");
Chris Craik27e58b42015-12-07 10:01:38 -080085 for (auto&& test : TestScene::testMap()) {
John Recke702c9c2015-10-07 10:26:02 -070086 auto&& info = test.second;
87 const char* col1 = info.name.c_str();
88 int dlen = info.description.length();
89 const char* col2 = info.description.c_str();
90 // World's best line breaking algorithm.
91 do {
92 int toPrint = dlen;
93 if (toPrint > 50) {
John Reck1bcacfd2017-11-03 10:12:19 -070094 char* found = (char*)memrchr(col2, ' ', 50);
John Recke702c9c2015-10-07 10:26:02 -070095 if (found) {
96 toPrint = found - col2;
97 } else {
98 toPrint = 50;
99 }
100 }
101 printf("%-20s %.*s\n", col1, toPrint, col2);
102 col1 = "";
103 col2 += toPrint;
104 dlen -= toPrint;
105 while (*col2 == ' ') {
John Reck1bcacfd2017-11-03 10:12:19 -0700106 col2++;
107 dlen--;
John Recke702c9c2015-10-07 10:26:02 -0700108 }
109 } while (dlen > 0);
110 printf("\n");
John Reckb7dd29e2015-10-06 13:28:17 -0700111 }
112}
113
John Reck682573c2015-10-30 10:37:35 -0700114static void moveToCpuSet(const char* cpusetName) {
115 if (access("/dev/cpuset/tasks", F_OK)) {
116 fprintf(stderr, "don't have access to cpusets, skipping...\n");
117 return;
118 }
119 static const int BUF_SIZE = 100;
120 char buffer[BUF_SIZE];
121
122 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
123 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
124 return;
125 }
126 int fd = open(buffer, O_WRONLY | O_CLOEXEC);
127 if (fd == -1) {
128 fprintf(stderr, "Error opening file %d\n", errno);
129 return;
130 }
131 pid_t pid = getpid();
132
John Reck1bcacfd2017-11-03 10:12:19 -0700133 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
John Reck682573c2015-10-30 10:37:35 -0700134 if (towrite >= BUF_SIZE) {
135 fprintf(stderr, "Buffer wasn't large enough?\n");
136 } else {
137 if (write(fd, buffer, towrite) != towrite) {
138 fprintf(stderr, "Failed to write, errno=%d", errno);
139 }
140 }
141 close(fd);
142}
143
John Reckf1480762016-07-03 18:28:25 -0700144static bool setBenchmarkFormat(const char* format) {
145 if (!strcmp(format, "tabular")) {
146 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
147 } else if (!strcmp(format, "json")) {
John Reck697779e2023-07-17 17:00:37 -0400148 // We cannot print the leak check if outputing to JSON as that will break
149 // JSON parsers since it's not JSON-formatted
150 gRunLeakCheck = false;
John Reckf1480762016-07-03 18:28:25 -0700151 gBenchmarkReporter.reset(new benchmark::JSONReporter());
John Reckf1480762016-07-03 18:28:25 -0700152 } else {
John Reck39207682021-05-12 19:10:47 -0400153 fprintf(stderr, "Unknown format '%s'\n", format);
John Reckf1480762016-07-03 18:28:25 -0700154 return false;
155 }
156 return true;
157}
158
John Reck113ddd92017-11-09 16:21:21 -0800159static bool setRenderer(const char* renderer) {
John Reck18f442e2018-04-09 16:56:34 -0700160 if (!strcmp(renderer, "skiagl")) {
John Reck113ddd92017-11-09 16:21:21 -0800161 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL);
162 } else if (!strcmp(renderer, "skiavk")) {
163 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan);
164 } else {
John Reck39207682021-05-12 19:10:47 -0400165 fprintf(stderr, "Unknown format '%s'\n", renderer);
John Reck113ddd92017-11-09 16:21:21 -0800166 return false;
167 }
168 return true;
169}
170
John Reck697779e2023-07-17 17:00:37 -0400171static void addTestsThatMatchFilter(std::string spec) {
172 if (spec.empty() || spec == "all") {
173 spec = "."; // Regexp that matches all benchmarks
174 }
175 bool isNegativeFilter = false;
176 if (spec[0] == '-') {
177 spec.replace(0, 1, "");
178 isNegativeFilter = true;
179 }
180 std::regex re(spec, std::regex_constants::extended);
181 for (auto& iter : TestScene::testMap()) {
182 if ((isNegativeFilter && !std::regex_search(iter.first, re)) ||
183 (!isNegativeFilter && std::regex_search(iter.first, re))) {
184 gRunTests.push_back(iter.second);
185 }
186 }
187}
188
John Reck682573c2015-10-30 10:37:35 -0700189// For options that only exist in long-form. Anything in the
190// 0-255 range is reserved for short options (which just use their ASCII value)
191namespace LongOpts {
192enum {
193 Reserved = 255,
194 List,
195 WaitForGpu,
196 ReportFrametime,
197 CpuSet,
John Reckf1480762016-07-03 18:28:25 -0700198 BenchmarkFormat,
John Reck697779e2023-07-17 17:00:37 -0400199 BenchmarkListTests,
200 BenchmarkFilter,
sergeyv202c10b2016-07-11 17:53:45 -0700201 Onscreen,
John Reckf1480762016-07-03 18:28:25 -0700202 Offscreen,
John Reck113ddd92017-11-09 16:21:21 -0800203 Renderer,
John Recka8427802021-05-10 17:47:50 -0400204 SkipLeakCheck,
John Reck66e06d42021-05-11 17:04:54 -0400205 ReportGpuMemory,
John Reck682573c2015-10-30 10:37:35 -0700206};
207}
208
John Reckb7dd29e2015-10-06 13:28:17 -0700209static const struct option LONG_OPTIONS[] = {
John Reck697779e2023-07-17 17:00:37 -0400210 {"count", required_argument, nullptr, 'c'},
211 {"runs", required_argument, nullptr, 'r'},
John Reck1bcacfd2017-11-03 10:12:19 -0700212 {"help", no_argument, nullptr, 'h'},
213 {"list", no_argument, nullptr, LongOpts::List},
214 {"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
215 {"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
216 {"cpuset", required_argument, nullptr, LongOpts::CpuSet},
217 {"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
John Reck697779e2023-07-17 17:00:37 -0400218 {"benchmark_list_tests", optional_argument, nullptr, LongOpts::BenchmarkListTests},
219 {"benchmark_filter", required_argument, nullptr, LongOpts::BenchmarkFilter},
John Reck1bcacfd2017-11-03 10:12:19 -0700220 {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
221 {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
John Reck113ddd92017-11-09 16:21:21 -0800222 {"renderer", required_argument, nullptr, LongOpts::Renderer},
John Recka8427802021-05-10 17:47:50 -0400223 {"skip-leak-check", no_argument, nullptr, LongOpts::SkipLeakCheck},
John Reck39207682021-05-12 19:10:47 -0400224 {"report-gpu-memory", optional_argument, nullptr, LongOpts::ReportGpuMemory},
John Reck1bcacfd2017-11-03 10:12:19 -0700225 {0, 0, 0, 0}};
John Reckb7dd29e2015-10-06 13:28:17 -0700226
227static const char* SHORT_OPTIONS = "c:r:h";
228
229void parseOptions(int argc, char* argv[]) {
John Reck697779e2023-07-17 17:00:37 -0400230 benchmark::BenchmarkReporter::Context::executable_name = (argc > 0) ? argv[0] : "unknown";
231
John Reckb7dd29e2015-10-06 13:28:17 -0700232 int c;
John Reckb7dd29e2015-10-06 13:28:17 -0700233 bool error = false;
John Reck697779e2023-07-17 17:00:37 -0400234 bool listTestsOnly = false;
235 bool testsAreFiltered = false;
John Reckb7dd29e2015-10-06 13:28:17 -0700236 opterr = 0;
237
238 while (true) {
John Reckb7dd29e2015-10-06 13:28:17 -0700239 /* getopt_long stores the option index here. */
240 int option_index = 0;
241
242 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
243
John Reck1bcacfd2017-11-03 10:12:19 -0700244 if (c == -1) break;
John Reckb7dd29e2015-10-06 13:28:17 -0700245
246 switch (c) {
John Reck1bcacfd2017-11-03 10:12:19 -0700247 case 0:
248 // Option set a flag, don't need to do anything
249 // (although none of the current LONG_OPTIONS do this...)
250 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700251
John Reck1bcacfd2017-11-03 10:12:19 -0700252 case LongOpts::List:
253 listTests();
254 exit(EXIT_SUCCESS);
255 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700256
John Reck1bcacfd2017-11-03 10:12:19 -0700257 case 'c':
John Recka8427802021-05-10 17:47:50 -0400258 gOpts.frameCount = atoi(optarg);
259 if (!gOpts.frameCount) {
John Reck1bcacfd2017-11-03 10:12:19 -0700260 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
John Reck682573c2015-10-30 10:37:35 -0700261 error = true;
262 }
John Reck682573c2015-10-30 10:37:35 -0700263 break;
John Reck682573c2015-10-30 10:37:35 -0700264
John Reck1bcacfd2017-11-03 10:12:19 -0700265 case 'r':
John Recka8427802021-05-10 17:47:50 -0400266 gOpts.repeatCount = atoi(optarg);
267 if (!gOpts.repeatCount) {
John Reck1bcacfd2017-11-03 10:12:19 -0700268 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
269 error = true;
270 } else {
John Recka8427802021-05-10 17:47:50 -0400271 gOpts.repeatCount = (gOpts.repeatCount > 0 ? gOpts.repeatCount : INT_MAX);
John Reck1bcacfd2017-11-03 10:12:19 -0700272 }
John Reckf1480762016-07-03 18:28:25 -0700273 break;
John Reckf1480762016-07-03 18:28:25 -0700274
John Reck1bcacfd2017-11-03 10:12:19 -0700275 case LongOpts::ReportFrametime:
276 if (optarg) {
277 gOpts.reportFrametimeWeight = atoi(optarg);
278 if (!gOpts.reportFrametimeWeight) {
279 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
280 error = true;
281 }
282 } else {
283 gOpts.reportFrametimeWeight = 10;
284 }
285 break;
sergeyv202c10b2016-07-11 17:53:45 -0700286
John Reck1bcacfd2017-11-03 10:12:19 -0700287 case LongOpts::WaitForGpu:
288 Properties::waitForGpuCompletion = true;
289 break;
John Reckf1480762016-07-03 18:28:25 -0700290
John Reck1bcacfd2017-11-03 10:12:19 -0700291 case LongOpts::CpuSet:
292 if (!optarg) {
293 error = true;
294 break;
295 }
296 moveToCpuSet(optarg);
297 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700298
John Reck1bcacfd2017-11-03 10:12:19 -0700299 case LongOpts::BenchmarkFormat:
300 if (!optarg) {
301 error = true;
302 break;
303 }
304 if (!setBenchmarkFormat(optarg)) {
305 error = true;
306 }
307 break;
308
John Reck697779e2023-07-17 17:00:37 -0400309 case LongOpts::BenchmarkListTests:
310 if (!optarg || ParseBool(optarg) == ParseBoolResult::kTrue) {
311 listTestsOnly = true;
312 }
313 break;
314
315 case LongOpts::BenchmarkFilter:
316 if (!optarg) {
317 error = true;
318 break;
319 }
320 addTestsThatMatchFilter(optarg);
321 testsAreFiltered = true;
322 break;
323
John Reck113ddd92017-11-09 16:21:21 -0800324 case LongOpts::Renderer:
325 if (!optarg) {
326 error = true;
327 break;
328 }
329 if (!setRenderer(optarg)) {
330 error = true;
331 }
332 break;
333
John Reck1bcacfd2017-11-03 10:12:19 -0700334 case LongOpts::Onscreen:
335 gOpts.renderOffscreen = false;
336 break;
337
338 case LongOpts::Offscreen:
339 gOpts.renderOffscreen = true;
340 break;
341
John Recka8427802021-05-10 17:47:50 -0400342 case LongOpts::SkipLeakCheck:
343 gRunLeakCheck = false;
344 break;
345
John Reck66e06d42021-05-11 17:04:54 -0400346 case LongOpts::ReportGpuMemory:
347 gOpts.reportGpuMemoryUsage = true;
John Reck39207682021-05-12 19:10:47 -0400348 if (optarg) {
349 if (!strcmp("verbose", optarg)) {
350 gOpts.reportGpuMemoryUsageVerbose = true;
351 } else {
352 fprintf(stderr, "Invalid report gpu memory option '%s'\n", optarg);
353 error = true;
354 }
355 }
John Reck66e06d42021-05-11 17:04:54 -0400356 break;
357
John Reck1bcacfd2017-11-03 10:12:19 -0700358 case 'h':
359 printHelp();
360 exit(EXIT_SUCCESS);
361 break;
362
363 case '?':
364 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
Chih-Hung Hsiehe1afb6c2018-10-22 12:25:50 -0700365 [[fallthrough]];
John Reck1bcacfd2017-11-03 10:12:19 -0700366 default:
367 error = true;
368 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700369 }
370 }
371
372 if (error) {
John Reck39207682021-05-12 19:10:47 -0400373 fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
John Reckb7dd29e2015-10-06 13:28:17 -0700374 exit(EXIT_FAILURE);
375 }
376
377 /* Print any remaining command line arguments (not options). */
378 if (optind < argc) {
379 do {
380 const char* test = argv[optind++];
John Reck66e06d42021-05-11 17:04:54 -0400381 if (strchr(test, '*')) {
382 // Glob match
383 for (auto& iter : TestScene::testMap()) {
384 if (!fnmatch(test, iter.first.c_str(), 0)) {
385 gRunTests.push_back(iter.second);
386 }
387 }
John Reckb7dd29e2015-10-06 13:28:17 -0700388 } else {
John Reck66e06d42021-05-11 17:04:54 -0400389 auto pos = TestScene::testMap().find(test);
390 if (pos == TestScene::testMap().end()) {
391 fprintf(stderr, "Unknown test '%s'\n", test);
392 exit(EXIT_FAILURE);
393 } else {
394 gRunTests.push_back(pos->second);
395 }
John Reckb7dd29e2015-10-06 13:28:17 -0700396 }
397 } while (optind < argc);
John Reck697779e2023-07-17 17:00:37 -0400398 } else if (gRunTests.empty() && !testsAreFiltered) {
sergeyv202c10b2016-07-11 17:53:45 -0700399 for (auto& iter : TestScene::testMap()) {
400 gRunTests.push_back(iter.second);
401 }
John Reckb7dd29e2015-10-06 13:28:17 -0700402 }
John Reck697779e2023-07-17 17:00:37 -0400403
404 if (listTestsOnly) {
405 for (auto& iter : gRunTests) {
406 std::cout << iter.name << std::endl;
407 }
408 exit(EXIT_SUCCESS);
409 }
John Reckb7dd29e2015-10-06 13:28:17 -0700410}
411
Chris Craik03188872015-02-02 18:39:33 -0800412int main(int argc, char* argv[]) {
Seigo Nonakab6e20132016-11-14 14:07:41 +0900413 Typeface::setRobotoTypefaceForTest();
414
John Reckb7dd29e2015-10-06 13:28:17 -0700415 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700416 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
417 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
418 }
419
420 if (gBenchmarkReporter) {
421 size_t name_field_width = 10;
422 for (auto&& test : gRunTests) {
423 name_field_width = std::max<size_t>(name_field_width, test.name.size());
424 }
425 // _50th, _90th, etc...
426 name_field_width += 5;
427
428 benchmark::BenchmarkReporter::Context context;
John Reckf1480762016-07-03 18:28:25 -0700429 context.name_field_width = name_field_width;
430 gBenchmarkReporter->ReportContext(context);
431 }
John Reckb7dd29e2015-10-06 13:28:17 -0700432
John Recka8427802021-05-10 17:47:50 -0400433 for (auto&& test : gRunTests) {
434 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700435 }
John Reckf1480762016-07-03 18:28:25 -0700436
437 if (gBenchmarkReporter) {
438 gBenchmarkReporter->Finalize();
439 }
440
John Reck6104cea2019-01-10 14:37:17 -0800441 renderthread::RenderProxy::trimMemory(100);
442 HardwareBitmapUploader::terminate();
443
John Recka8427802021-05-10 17:47:50 -0400444 if (gRunLeakCheck) {
445 LeakChecker::checkForLeaks();
446 }
John Reck94c40fe2014-10-08 09:28:43 -0700447 return 0;
448}