blob: 524dfb0fe4ef080b6dca5275df6d7272392c2f55 [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
John Reck1bcacfd2017-11-03 10:12:19 -070023#include <benchmark/benchmark.h>
John Reckb7dd29e2015-10-06 13:28:17 -070024#include <getopt.h>
John Reck1bcacfd2017-11-03 10:12:19 -070025#include <pthread.h>
John Recke702c9c2015-10-07 10:26:02 -070026#include <stdio.h>
John Recke702c9c2015-10-07 10:26:02 -070027#include <unistd.h>
John Reck1bcacfd2017-11-03 10:12:19 -070028#include <string>
John Recke702c9c2015-10-07 10:26:02 -070029#include <unordered_map>
John Reckb7dd29e2015-10-06 13:28:17 -070030#include <vector>
John Reck7f2e5e32015-05-05 11:00:53 -070031
John Reck682573c2015-10-30 10:37:35 -070032#include <errno.h>
John Reck1bcacfd2017-11-03 10:12:19 -070033#include <fcntl.h>
34#include <sys/stat.h>
35#include <sys/types.h>
John Reck682573c2015-10-30 10:37:35 -070036
John Reck94c40fe2014-10-08 09:28:43 -070037using namespace android;
38using namespace android::uirenderer;
Chris Craik27e58b42015-12-07 10:01:38 -080039using namespace android::uirenderer::test;
John Reck94c40fe2014-10-08 09:28:43 -070040
John Reckb7dd29e2015-10-06 13:28:17 -070041static int gRepeatCount = 1;
Chris Craik27e58b42015-12-07 10:01:38 -080042static std::vector<TestScene::Info> gRunTests;
John Reck682573c2015-10-30 10:37:35 -070043static TestScene::Options gOpts;
John Reckf1480762016-07-03 18:28:25 -070044std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
John Reckb7dd29e2015-10-06 13:28:17 -070045
John Reckf1480762016-07-03 18:28:25 -070046void run(const TestScene::Info& info, const TestScene::Options& opts,
John Reck1bcacfd2017-11-03 10:12:19 -070047 benchmark::BenchmarkReporter* reporter);
John Reck16c9d6a2015-11-17 15:51:08 -080048
John Reckb7dd29e2015-10-06 13:28:17 -070049static void printHelp() {
John Reck682573c2015-10-30 10:37:35 -070050 printf(R"(
sergeyv202c10b2016-07-11 17:53:45 -070051USAGE: hwuimacro [OPTIONS] <TESTNAME>
John Reck682573c2015-10-30 10:37:35 -070052
53OPTIONS:
54 -c, --count=NUM NUM loops a test should run (example, number of frames)
55 -r, --runs=NUM Repeat the test(s) NUM times
56 -h, --help Display this help
57 --list List all tests
58 --wait-for-gpu Set this to wait for the GPU before producing the
59 next frame. Note that without locked clocks this will
60 pathologically bad performance due to large idle time
61 --report-frametime[=weight] If set, the test will print to stdout the
62 moving average frametime. Weight is optional, default is 10
63 --cpuset=name Adds the test to the specified cpuset before running
64 Not supported on all devices and needs root
sergeyv202c10b2016-07-11 17:53:45 -070065 --offscreen Render tests off device screen. This option is on by default
66 --onscreen Render tests on device screen. By default tests
67 are offscreen rendered
68 --benchmark_format Set output format. Possible values are tabular, json, csv
John Reck18f442e2018-04-09 16:56:34 -070069 --renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
John Reck682573c2015-10-30 10:37:35 -070070)");
John Reckb7dd29e2015-10-06 13:28:17 -070071}
72
73static void listTests() {
74 printf("Tests: \n");
Chris Craik27e58b42015-12-07 10:01:38 -080075 for (auto&& test : TestScene::testMap()) {
John Recke702c9c2015-10-07 10:26:02 -070076 auto&& info = test.second;
77 const char* col1 = info.name.c_str();
78 int dlen = info.description.length();
79 const char* col2 = info.description.c_str();
80 // World's best line breaking algorithm.
81 do {
82 int toPrint = dlen;
83 if (toPrint > 50) {
John Reck1bcacfd2017-11-03 10:12:19 -070084 char* found = (char*)memrchr(col2, ' ', 50);
John Recke702c9c2015-10-07 10:26:02 -070085 if (found) {
86 toPrint = found - col2;
87 } else {
88 toPrint = 50;
89 }
90 }
91 printf("%-20s %.*s\n", col1, toPrint, col2);
92 col1 = "";
93 col2 += toPrint;
94 dlen -= toPrint;
95 while (*col2 == ' ') {
John Reck1bcacfd2017-11-03 10:12:19 -070096 col2++;
97 dlen--;
John Recke702c9c2015-10-07 10:26:02 -070098 }
99 } while (dlen > 0);
100 printf("\n");
John Reckb7dd29e2015-10-06 13:28:17 -0700101 }
102}
103
John Reck682573c2015-10-30 10:37:35 -0700104static void moveToCpuSet(const char* cpusetName) {
105 if (access("/dev/cpuset/tasks", F_OK)) {
106 fprintf(stderr, "don't have access to cpusets, skipping...\n");
107 return;
108 }
109 static const int BUF_SIZE = 100;
110 char buffer[BUF_SIZE];
111
112 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
113 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
114 return;
115 }
116 int fd = open(buffer, O_WRONLY | O_CLOEXEC);
117 if (fd == -1) {
118 fprintf(stderr, "Error opening file %d\n", errno);
119 return;
120 }
121 pid_t pid = getpid();
122
John Reck1bcacfd2017-11-03 10:12:19 -0700123 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
John Reck682573c2015-10-30 10:37:35 -0700124 if (towrite >= BUF_SIZE) {
125 fprintf(stderr, "Buffer wasn't large enough?\n");
126 } else {
127 if (write(fd, buffer, towrite) != towrite) {
128 fprintf(stderr, "Failed to write, errno=%d", errno);
129 }
130 }
131 close(fd);
132}
133
John Reckf1480762016-07-03 18:28:25 -0700134static bool setBenchmarkFormat(const char* format) {
135 if (!strcmp(format, "tabular")) {
136 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
137 } else if (!strcmp(format, "json")) {
138 gBenchmarkReporter.reset(new benchmark::JSONReporter());
John Reckf1480762016-07-03 18:28:25 -0700139 } else {
140 fprintf(stderr, "Unknown format '%s'", format);
141 return false;
142 }
143 return true;
144}
145
John Reck113ddd92017-11-09 16:21:21 -0800146static bool setRenderer(const char* renderer) {
John Reck18f442e2018-04-09 16:56:34 -0700147 if (!strcmp(renderer, "skiagl")) {
John Reck113ddd92017-11-09 16:21:21 -0800148 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL);
149 } else if (!strcmp(renderer, "skiavk")) {
150 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan);
151 } else {
152 fprintf(stderr, "Unknown format '%s'", renderer);
153 return false;
154 }
155 return true;
156}
157
John Reck682573c2015-10-30 10:37:35 -0700158// For options that only exist in long-form. Anything in the
159// 0-255 range is reserved for short options (which just use their ASCII value)
160namespace LongOpts {
161enum {
162 Reserved = 255,
163 List,
164 WaitForGpu,
165 ReportFrametime,
166 CpuSet,
John Reckf1480762016-07-03 18:28:25 -0700167 BenchmarkFormat,
sergeyv202c10b2016-07-11 17:53:45 -0700168 Onscreen,
John Reckf1480762016-07-03 18:28:25 -0700169 Offscreen,
John Reck113ddd92017-11-09 16:21:21 -0800170 Renderer,
John Reck682573c2015-10-30 10:37:35 -0700171};
172}
173
John Reckb7dd29e2015-10-06 13:28:17 -0700174static const struct option LONG_OPTIONS[] = {
John Reck1bcacfd2017-11-03 10:12:19 -0700175 {"frames", required_argument, nullptr, 'f'},
176 {"repeat", required_argument, nullptr, 'r'},
177 {"help", no_argument, nullptr, 'h'},
178 {"list", no_argument, nullptr, LongOpts::List},
179 {"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
180 {"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
181 {"cpuset", required_argument, nullptr, LongOpts::CpuSet},
182 {"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
183 {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
184 {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
John Reck113ddd92017-11-09 16:21:21 -0800185 {"renderer", required_argument, nullptr, LongOpts::Renderer},
John Reck1bcacfd2017-11-03 10:12:19 -0700186 {0, 0, 0, 0}};
John Reckb7dd29e2015-10-06 13:28:17 -0700187
188static const char* SHORT_OPTIONS = "c:r:h";
189
190void parseOptions(int argc, char* argv[]) {
191 int c;
John Reckb7dd29e2015-10-06 13:28:17 -0700192 bool error = false;
193 opterr = 0;
194
195 while (true) {
John Reckb7dd29e2015-10-06 13:28:17 -0700196 /* getopt_long stores the option index here. */
197 int option_index = 0;
198
199 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
200
John Reck1bcacfd2017-11-03 10:12:19 -0700201 if (c == -1) break;
John Reckb7dd29e2015-10-06 13:28:17 -0700202
203 switch (c) {
John Reck1bcacfd2017-11-03 10:12:19 -0700204 case 0:
205 // Option set a flag, don't need to do anything
206 // (although none of the current LONG_OPTIONS do this...)
207 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700208
John Reck1bcacfd2017-11-03 10:12:19 -0700209 case LongOpts::List:
210 listTests();
211 exit(EXIT_SUCCESS);
212 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700213
John Reck1bcacfd2017-11-03 10:12:19 -0700214 case 'c':
215 gOpts.count = atoi(optarg);
216 if (!gOpts.count) {
217 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
John Reck682573c2015-10-30 10:37:35 -0700218 error = true;
219 }
John Reck682573c2015-10-30 10:37:35 -0700220 break;
John Reck682573c2015-10-30 10:37:35 -0700221
John Reck1bcacfd2017-11-03 10:12:19 -0700222 case 'r':
223 gRepeatCount = atoi(optarg);
224 if (!gRepeatCount) {
225 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
226 error = true;
227 } else {
228 gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
229 }
John Reckf1480762016-07-03 18:28:25 -0700230 break;
John Reckf1480762016-07-03 18:28:25 -0700231
John Reck1bcacfd2017-11-03 10:12:19 -0700232 case LongOpts::ReportFrametime:
233 if (optarg) {
234 gOpts.reportFrametimeWeight = atoi(optarg);
235 if (!gOpts.reportFrametimeWeight) {
236 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
237 error = true;
238 }
239 } else {
240 gOpts.reportFrametimeWeight = 10;
241 }
242 break;
sergeyv202c10b2016-07-11 17:53:45 -0700243
John Reck1bcacfd2017-11-03 10:12:19 -0700244 case LongOpts::WaitForGpu:
245 Properties::waitForGpuCompletion = true;
246 break;
John Reckf1480762016-07-03 18:28:25 -0700247
John Reck1bcacfd2017-11-03 10:12:19 -0700248 case LongOpts::CpuSet:
249 if (!optarg) {
250 error = true;
251 break;
252 }
253 moveToCpuSet(optarg);
254 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700255
John Reck1bcacfd2017-11-03 10:12:19 -0700256 case LongOpts::BenchmarkFormat:
257 if (!optarg) {
258 error = true;
259 break;
260 }
261 if (!setBenchmarkFormat(optarg)) {
262 error = true;
263 }
264 break;
265
John Reck113ddd92017-11-09 16:21:21 -0800266 case LongOpts::Renderer:
267 if (!optarg) {
268 error = true;
269 break;
270 }
271 if (!setRenderer(optarg)) {
272 error = true;
273 }
274 break;
275
John Reck1bcacfd2017-11-03 10:12:19 -0700276 case LongOpts::Onscreen:
277 gOpts.renderOffscreen = false;
278 break;
279
280 case LongOpts::Offscreen:
281 gOpts.renderOffscreen = true;
282 break;
283
284 case 'h':
285 printHelp();
286 exit(EXIT_SUCCESS);
287 break;
288
289 case '?':
290 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
Chih-Hung Hsiehe1afb6c2018-10-22 12:25:50 -0700291 [[fallthrough]];
John Reck1bcacfd2017-11-03 10:12:19 -0700292 default:
293 error = true;
294 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700295 }
296 }
297
298 if (error) {
299 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
300 exit(EXIT_FAILURE);
301 }
302
303 /* Print any remaining command line arguments (not options). */
304 if (optind < argc) {
305 do {
306 const char* test = argv[optind++];
sergeyv202c10b2016-07-11 17:53:45 -0700307 auto pos = TestScene::testMap().find(test);
308 if (pos == TestScene::testMap().end()) {
309 fprintf(stderr, "Unknown test '%s'\n", test);
310 exit(EXIT_FAILURE);
John Reckb7dd29e2015-10-06 13:28:17 -0700311 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700312 gRunTests.push_back(pos->second);
John Reckb7dd29e2015-10-06 13:28:17 -0700313 }
314 } while (optind < argc);
315 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700316 for (auto& iter : TestScene::testMap()) {
317 gRunTests.push_back(iter.second);
318 }
John Reckb7dd29e2015-10-06 13:28:17 -0700319 }
320}
321
Chris Craik03188872015-02-02 18:39:33 -0800322int main(int argc, char* argv[]) {
John Reck682573c2015-10-30 10:37:35 -0700323 // set defaults
324 gOpts.count = 150;
325
Seigo Nonakab6e20132016-11-14 14:07:41 +0900326 Typeface::setRobotoTypefaceForTest();
327
John Reckb7dd29e2015-10-06 13:28:17 -0700328 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700329 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
330 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
331 }
332
333 if (gBenchmarkReporter) {
334 size_t name_field_width = 10;
335 for (auto&& test : gRunTests) {
336 name_field_width = std::max<size_t>(name_field_width, test.name.size());
337 }
338 // _50th, _90th, etc...
339 name_field_width += 5;
340
341 benchmark::BenchmarkReporter::Context context;
John Reckf1480762016-07-03 18:28:25 -0700342 context.name_field_width = name_field_width;
343 gBenchmarkReporter->ReportContext(context);
344 }
John Reckb7dd29e2015-10-06 13:28:17 -0700345
346 for (int i = 0; i < gRepeatCount; i++) {
347 for (auto&& test : gRunTests) {
John Reckf1480762016-07-03 18:28:25 -0700348 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700349 }
350 }
John Reckf1480762016-07-03 18:28:25 -0700351
352 if (gBenchmarkReporter) {
353 gBenchmarkReporter->Finalize();
354 }
355
sergeyv7dc370b2016-06-17 11:21:11 -0700356 LeakChecker::checkForLeaks();
John Reck94c40fe2014-10-08 09:28:43 -0700357 return 0;
358}