blob: acbbb9562f12fc41f0b37cc19bdcc87d75914da2 [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 Reckb7dd29e2015-10-06 13:28:17 -070026#include <getopt.h>
John Reck1bcacfd2017-11-03 10:12:19 -070027#include <pthread.h>
John Recke702c9c2015-10-07 10:26:02 -070028#include <stdio.h>
John Recke702c9c2015-10-07 10:26:02 -070029#include <unistd.h>
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 Reck682573c2015-10-30 10:37:35 -070034#include <errno.h>
John Reck1bcacfd2017-11-03 10:12:19 -070035#include <fcntl.h>
36#include <sys/stat.h>
37#include <sys/types.h>
John Reck682573c2015-10-30 10:37:35 -070038
John Reck94c40fe2014-10-08 09:28:43 -070039using namespace android;
40using namespace android::uirenderer;
Chris Craik27e58b42015-12-07 10:01:38 -080041using namespace android::uirenderer::test;
John Reck94c40fe2014-10-08 09:28:43 -070042
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 Recka8427802021-05-10 17:47:50 -040045static bool gRunLeakCheck = true;
John Reckf1480762016-07-03 18:28:25 -070046std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
John Reckb7dd29e2015-10-06 13:28:17 -070047
John Reckf1480762016-07-03 18:28:25 -070048void run(const TestScene::Info& info, const TestScene::Options& opts,
John Reck1bcacfd2017-11-03 10:12:19 -070049 benchmark::BenchmarkReporter* reporter);
John Reck16c9d6a2015-11-17 15:51:08 -080050
John Reckb7dd29e2015-10-06 13:28:17 -070051static void printHelp() {
John Reck682573c2015-10-30 10:37:35 -070052 printf(R"(
sergeyv202c10b2016-07-11 17:53:45 -070053USAGE: hwuimacro [OPTIONS] <TESTNAME>
John Reck682573c2015-10-30 10:37:35 -070054
55OPTIONS:
56 -c, --count=NUM NUM loops a test should run (example, number of frames)
57 -r, --runs=NUM Repeat the test(s) NUM times
58 -h, --help Display this help
59 --list List all tests
60 --wait-for-gpu Set this to wait for the GPU before producing the
61 next frame. Note that without locked clocks this will
62 pathologically bad performance due to large idle time
63 --report-frametime[=weight] If set, the test will print to stdout the
64 moving average frametime. Weight is optional, default is 10
65 --cpuset=name Adds the test to the specified cpuset before running
66 Not supported on all devices and needs root
sergeyv202c10b2016-07-11 17:53:45 -070067 --offscreen Render tests off device screen. This option is on by default
68 --onscreen Render tests on device screen. By default tests
69 are offscreen rendered
70 --benchmark_format Set output format. Possible values are tabular, json, csv
John Reck18f442e2018-04-09 16:56:34 -070071 --renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
John Recka8427802021-05-10 17:47:50 -040072 --skip-leak-check Skips the memory leak check
John Reck682573c2015-10-30 10:37:35 -070073)");
John Reckb7dd29e2015-10-06 13:28:17 -070074}
75
76static void listTests() {
77 printf("Tests: \n");
Chris Craik27e58b42015-12-07 10:01:38 -080078 for (auto&& test : TestScene::testMap()) {
John Recke702c9c2015-10-07 10:26:02 -070079 auto&& info = test.second;
80 const char* col1 = info.name.c_str();
81 int dlen = info.description.length();
82 const char* col2 = info.description.c_str();
83 // World's best line breaking algorithm.
84 do {
85 int toPrint = dlen;
86 if (toPrint > 50) {
John Reck1bcacfd2017-11-03 10:12:19 -070087 char* found = (char*)memrchr(col2, ' ', 50);
John Recke702c9c2015-10-07 10:26:02 -070088 if (found) {
89 toPrint = found - col2;
90 } else {
91 toPrint = 50;
92 }
93 }
94 printf("%-20s %.*s\n", col1, toPrint, col2);
95 col1 = "";
96 col2 += toPrint;
97 dlen -= toPrint;
98 while (*col2 == ' ') {
John Reck1bcacfd2017-11-03 10:12:19 -070099 col2++;
100 dlen--;
John Recke702c9c2015-10-07 10:26:02 -0700101 }
102 } while (dlen > 0);
103 printf("\n");
John Reckb7dd29e2015-10-06 13:28:17 -0700104 }
105}
106
John Reck682573c2015-10-30 10:37:35 -0700107static void moveToCpuSet(const char* cpusetName) {
108 if (access("/dev/cpuset/tasks", F_OK)) {
109 fprintf(stderr, "don't have access to cpusets, skipping...\n");
110 return;
111 }
112 static const int BUF_SIZE = 100;
113 char buffer[BUF_SIZE];
114
115 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
116 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
117 return;
118 }
119 int fd = open(buffer, O_WRONLY | O_CLOEXEC);
120 if (fd == -1) {
121 fprintf(stderr, "Error opening file %d\n", errno);
122 return;
123 }
124 pid_t pid = getpid();
125
John Reck1bcacfd2017-11-03 10:12:19 -0700126 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
John Reck682573c2015-10-30 10:37:35 -0700127 if (towrite >= BUF_SIZE) {
128 fprintf(stderr, "Buffer wasn't large enough?\n");
129 } else {
130 if (write(fd, buffer, towrite) != towrite) {
131 fprintf(stderr, "Failed to write, errno=%d", errno);
132 }
133 }
134 close(fd);
135}
136
John Reckf1480762016-07-03 18:28:25 -0700137static bool setBenchmarkFormat(const char* format) {
138 if (!strcmp(format, "tabular")) {
139 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
140 } else if (!strcmp(format, "json")) {
141 gBenchmarkReporter.reset(new benchmark::JSONReporter());
John Reckf1480762016-07-03 18:28:25 -0700142 } else {
143 fprintf(stderr, "Unknown format '%s'", format);
144 return false;
145 }
146 return true;
147}
148
John Reck113ddd92017-11-09 16:21:21 -0800149static bool setRenderer(const char* renderer) {
John Reck18f442e2018-04-09 16:56:34 -0700150 if (!strcmp(renderer, "skiagl")) {
John Reck113ddd92017-11-09 16:21:21 -0800151 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL);
152 } else if (!strcmp(renderer, "skiavk")) {
153 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan);
154 } else {
155 fprintf(stderr, "Unknown format '%s'", renderer);
156 return false;
157 }
158 return true;
159}
160
John Reck682573c2015-10-30 10:37:35 -0700161// For options that only exist in long-form. Anything in the
162// 0-255 range is reserved for short options (which just use their ASCII value)
163namespace LongOpts {
164enum {
165 Reserved = 255,
166 List,
167 WaitForGpu,
168 ReportFrametime,
169 CpuSet,
John Reckf1480762016-07-03 18:28:25 -0700170 BenchmarkFormat,
sergeyv202c10b2016-07-11 17:53:45 -0700171 Onscreen,
John Reckf1480762016-07-03 18:28:25 -0700172 Offscreen,
John Reck113ddd92017-11-09 16:21:21 -0800173 Renderer,
John Recka8427802021-05-10 17:47:50 -0400174 SkipLeakCheck,
John Reck682573c2015-10-30 10:37:35 -0700175};
176}
177
John Reckb7dd29e2015-10-06 13:28:17 -0700178static const struct option LONG_OPTIONS[] = {
John Reck1bcacfd2017-11-03 10:12:19 -0700179 {"frames", required_argument, nullptr, 'f'},
180 {"repeat", required_argument, nullptr, 'r'},
181 {"help", no_argument, nullptr, 'h'},
182 {"list", no_argument, nullptr, LongOpts::List},
183 {"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
184 {"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
185 {"cpuset", required_argument, nullptr, LongOpts::CpuSet},
186 {"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
187 {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
188 {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
John Reck113ddd92017-11-09 16:21:21 -0800189 {"renderer", required_argument, nullptr, LongOpts::Renderer},
John Recka8427802021-05-10 17:47:50 -0400190 {"skip-leak-check", no_argument, nullptr, LongOpts::SkipLeakCheck},
John Reck1bcacfd2017-11-03 10:12:19 -0700191 {0, 0, 0, 0}};
John Reckb7dd29e2015-10-06 13:28:17 -0700192
193static const char* SHORT_OPTIONS = "c:r:h";
194
195void parseOptions(int argc, char* argv[]) {
196 int c;
John Reckb7dd29e2015-10-06 13:28:17 -0700197 bool error = false;
198 opterr = 0;
199
200 while (true) {
John Reckb7dd29e2015-10-06 13:28:17 -0700201 /* getopt_long stores the option index here. */
202 int option_index = 0;
203
204 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
205
John Reck1bcacfd2017-11-03 10:12:19 -0700206 if (c == -1) break;
John Reckb7dd29e2015-10-06 13:28:17 -0700207
208 switch (c) {
John Reck1bcacfd2017-11-03 10:12:19 -0700209 case 0:
210 // Option set a flag, don't need to do anything
211 // (although none of the current LONG_OPTIONS do this...)
212 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700213
John Reck1bcacfd2017-11-03 10:12:19 -0700214 case LongOpts::List:
215 listTests();
216 exit(EXIT_SUCCESS);
217 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700218
John Reck1bcacfd2017-11-03 10:12:19 -0700219 case 'c':
John Recka8427802021-05-10 17:47:50 -0400220 gOpts.frameCount = atoi(optarg);
221 if (!gOpts.frameCount) {
John Reck1bcacfd2017-11-03 10:12:19 -0700222 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
John Reck682573c2015-10-30 10:37:35 -0700223 error = true;
224 }
John Reck682573c2015-10-30 10:37:35 -0700225 break;
John Reck682573c2015-10-30 10:37:35 -0700226
John Reck1bcacfd2017-11-03 10:12:19 -0700227 case 'r':
John Recka8427802021-05-10 17:47:50 -0400228 gOpts.repeatCount = atoi(optarg);
229 if (!gOpts.repeatCount) {
John Reck1bcacfd2017-11-03 10:12:19 -0700230 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
231 error = true;
232 } else {
John Recka8427802021-05-10 17:47:50 -0400233 gOpts.repeatCount = (gOpts.repeatCount > 0 ? gOpts.repeatCount : INT_MAX);
John Reck1bcacfd2017-11-03 10:12:19 -0700234 }
John Reckf1480762016-07-03 18:28:25 -0700235 break;
John Reckf1480762016-07-03 18:28:25 -0700236
John Reck1bcacfd2017-11-03 10:12:19 -0700237 case LongOpts::ReportFrametime:
238 if (optarg) {
239 gOpts.reportFrametimeWeight = atoi(optarg);
240 if (!gOpts.reportFrametimeWeight) {
241 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
242 error = true;
243 }
244 } else {
245 gOpts.reportFrametimeWeight = 10;
246 }
247 break;
sergeyv202c10b2016-07-11 17:53:45 -0700248
John Reck1bcacfd2017-11-03 10:12:19 -0700249 case LongOpts::WaitForGpu:
250 Properties::waitForGpuCompletion = true;
251 break;
John Reckf1480762016-07-03 18:28:25 -0700252
John Reck1bcacfd2017-11-03 10:12:19 -0700253 case LongOpts::CpuSet:
254 if (!optarg) {
255 error = true;
256 break;
257 }
258 moveToCpuSet(optarg);
259 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700260
John Reck1bcacfd2017-11-03 10:12:19 -0700261 case LongOpts::BenchmarkFormat:
262 if (!optarg) {
263 error = true;
264 break;
265 }
266 if (!setBenchmarkFormat(optarg)) {
267 error = true;
268 }
269 break;
270
John Reck113ddd92017-11-09 16:21:21 -0800271 case LongOpts::Renderer:
272 if (!optarg) {
273 error = true;
274 break;
275 }
276 if (!setRenderer(optarg)) {
277 error = true;
278 }
279 break;
280
John Reck1bcacfd2017-11-03 10:12:19 -0700281 case LongOpts::Onscreen:
282 gOpts.renderOffscreen = false;
283 break;
284
285 case LongOpts::Offscreen:
286 gOpts.renderOffscreen = true;
287 break;
288
John Recka8427802021-05-10 17:47:50 -0400289 case LongOpts::SkipLeakCheck:
290 gRunLeakCheck = false;
291 break;
292
John Reck1bcacfd2017-11-03 10:12:19 -0700293 case 'h':
294 printHelp();
295 exit(EXIT_SUCCESS);
296 break;
297
298 case '?':
299 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
Chih-Hung Hsiehe1afb6c2018-10-22 12:25:50 -0700300 [[fallthrough]];
John Reck1bcacfd2017-11-03 10:12:19 -0700301 default:
302 error = true;
303 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700304 }
305 }
306
307 if (error) {
308 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
309 exit(EXIT_FAILURE);
310 }
311
312 /* Print any remaining command line arguments (not options). */
313 if (optind < argc) {
314 do {
315 const char* test = argv[optind++];
sergeyv202c10b2016-07-11 17:53:45 -0700316 auto pos = TestScene::testMap().find(test);
317 if (pos == TestScene::testMap().end()) {
318 fprintf(stderr, "Unknown test '%s'\n", test);
319 exit(EXIT_FAILURE);
John Reckb7dd29e2015-10-06 13:28:17 -0700320 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700321 gRunTests.push_back(pos->second);
John Reckb7dd29e2015-10-06 13:28:17 -0700322 }
323 } while (optind < argc);
324 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700325 for (auto& iter : TestScene::testMap()) {
326 gRunTests.push_back(iter.second);
327 }
John Reckb7dd29e2015-10-06 13:28:17 -0700328 }
329}
330
Chris Craik03188872015-02-02 18:39:33 -0800331int main(int argc, char* argv[]) {
Seigo Nonakab6e20132016-11-14 14:07:41 +0900332 Typeface::setRobotoTypefaceForTest();
333
John Reckb7dd29e2015-10-06 13:28:17 -0700334 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700335 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
336 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
337 }
338
339 if (gBenchmarkReporter) {
340 size_t name_field_width = 10;
341 for (auto&& test : gRunTests) {
342 name_field_width = std::max<size_t>(name_field_width, test.name.size());
343 }
344 // _50th, _90th, etc...
345 name_field_width += 5;
346
347 benchmark::BenchmarkReporter::Context context;
John Reckf1480762016-07-03 18:28:25 -0700348 context.name_field_width = name_field_width;
349 gBenchmarkReporter->ReportContext(context);
350 }
John Reckb7dd29e2015-10-06 13:28:17 -0700351
John Recka8427802021-05-10 17:47:50 -0400352 for (auto&& test : gRunTests) {
353 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700354 }
John Reckf1480762016-07-03 18:28:25 -0700355
356 if (gBenchmarkReporter) {
357 gBenchmarkReporter->Finalize();
358 }
359
John Reck6104cea2019-01-10 14:37:17 -0800360 renderthread::RenderProxy::trimMemory(100);
361 HardwareBitmapUploader::terminate();
362
John Recka8427802021-05-10 17:47:50 -0400363 if (gRunLeakCheck) {
364 LeakChecker::checkForLeaks();
365 }
John Reck94c40fe2014-10-08 09:28:43 -0700366 return 0;
367}