blob: 4cb5cfdd729b0714f49e0c2555a8efdeffb0f84c [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#include "protos/hwui.pb.h"
23
John Reck1bcacfd2017-11-03 10:12:19 -070024#include <benchmark/benchmark.h>
John Reckb7dd29e2015-10-06 13:28:17 -070025#include <getopt.h>
John Reck1bcacfd2017-11-03 10:12:19 -070026#include <pthread.h>
John Recke702c9c2015-10-07 10:26:02 -070027#include <stdio.h>
John Recke702c9c2015-10-07 10:26:02 -070028#include <unistd.h>
John Reck1bcacfd2017-11-03 10:12:19 -070029#include <string>
John Recke702c9c2015-10-07 10:26:02 -070030#include <unordered_map>
John Reckb7dd29e2015-10-06 13:28:17 -070031#include <vector>
John Reck7f2e5e32015-05-05 11:00:53 -070032
John Reck682573c2015-10-30 10:37:35 -070033#include <errno.h>
John Reck1bcacfd2017-11-03 10:12:19 -070034#include <fcntl.h>
35#include <sys/stat.h>
36#include <sys/types.h>
John Reck682573c2015-10-30 10:37:35 -070037
John Reck94c40fe2014-10-08 09:28:43 -070038using namespace android;
39using namespace android::uirenderer;
Chris Craik27e58b42015-12-07 10:01:38 -080040using namespace android::uirenderer::test;
John Reck94c40fe2014-10-08 09:28:43 -070041
John Reckb7dd29e2015-10-06 13:28:17 -070042static int gRepeatCount = 1;
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 Reckf1480762016-07-03 18:28:25 -070045std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
John Reckb7dd29e2015-10-06 13:28:17 -070046
John Reckf1480762016-07-03 18:28:25 -070047void run(const TestScene::Info& info, const TestScene::Options& opts,
John Reck1bcacfd2017-11-03 10:12:19 -070048 benchmark::BenchmarkReporter* reporter);
John Reck16c9d6a2015-11-17 15:51:08 -080049
John Reckb7dd29e2015-10-06 13:28:17 -070050static void printHelp() {
John Reck682573c2015-10-30 10:37:35 -070051 printf(R"(
sergeyv202c10b2016-07-11 17:53:45 -070052USAGE: hwuimacro [OPTIONS] <TESTNAME>
John Reck682573c2015-10-30 10:37:35 -070053
54OPTIONS:
55 -c, --count=NUM NUM loops a test should run (example, number of frames)
56 -r, --runs=NUM Repeat the test(s) NUM times
57 -h, --help Display this help
58 --list List all tests
59 --wait-for-gpu Set this to wait for the GPU before producing the
60 next frame. Note that without locked clocks this will
61 pathologically bad performance due to large idle time
62 --report-frametime[=weight] If set, the test will print to stdout the
63 moving average frametime. Weight is optional, default is 10
64 --cpuset=name Adds the test to the specified cpuset before running
65 Not supported on all devices and needs root
sergeyv202c10b2016-07-11 17:53:45 -070066 --offscreen Render tests off device screen. This option is on by default
67 --onscreen Render tests on device screen. By default tests
68 are offscreen rendered
69 --benchmark_format Set output format. Possible values are tabular, json, csv
John Reck113ddd92017-11-09 16:21:21 -080070 --renderer=TYPE Sets the render pipeline to use. May be opengl, skiagl, or skiavk
John Reckec100972018-04-05 16:41:41 -070071 --render-ahead=NUM Sets how far to render-ahead. Must be 0 (default), 1, or 2.
John Reck682573c2015-10-30 10:37:35 -070072)");
John Reckb7dd29e2015-10-06 13:28:17 -070073}
74
75static void listTests() {
76 printf("Tests: \n");
Chris Craik27e58b42015-12-07 10:01:38 -080077 for (auto&& test : TestScene::testMap()) {
John Recke702c9c2015-10-07 10:26:02 -070078 auto&& info = test.second;
79 const char* col1 = info.name.c_str();
80 int dlen = info.description.length();
81 const char* col2 = info.description.c_str();
82 // World's best line breaking algorithm.
83 do {
84 int toPrint = dlen;
85 if (toPrint > 50) {
John Reck1bcacfd2017-11-03 10:12:19 -070086 char* found = (char*)memrchr(col2, ' ', 50);
John Recke702c9c2015-10-07 10:26:02 -070087 if (found) {
88 toPrint = found - col2;
89 } else {
90 toPrint = 50;
91 }
92 }
93 printf("%-20s %.*s\n", col1, toPrint, col2);
94 col1 = "";
95 col2 += toPrint;
96 dlen -= toPrint;
97 while (*col2 == ' ') {
John Reck1bcacfd2017-11-03 10:12:19 -070098 col2++;
99 dlen--;
John Recke702c9c2015-10-07 10:26:02 -0700100 }
101 } while (dlen > 0);
102 printf("\n");
John Reckb7dd29e2015-10-06 13:28:17 -0700103 }
104}
105
John Reck682573c2015-10-30 10:37:35 -0700106static void moveToCpuSet(const char* cpusetName) {
107 if (access("/dev/cpuset/tasks", F_OK)) {
108 fprintf(stderr, "don't have access to cpusets, skipping...\n");
109 return;
110 }
111 static const int BUF_SIZE = 100;
112 char buffer[BUF_SIZE];
113
114 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
115 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
116 return;
117 }
118 int fd = open(buffer, O_WRONLY | O_CLOEXEC);
119 if (fd == -1) {
120 fprintf(stderr, "Error opening file %d\n", errno);
121 return;
122 }
123 pid_t pid = getpid();
124
John Reck1bcacfd2017-11-03 10:12:19 -0700125 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
John Reck682573c2015-10-30 10:37:35 -0700126 if (towrite >= BUF_SIZE) {
127 fprintf(stderr, "Buffer wasn't large enough?\n");
128 } else {
129 if (write(fd, buffer, towrite) != towrite) {
130 fprintf(stderr, "Failed to write, errno=%d", errno);
131 }
132 }
133 close(fd);
134}
135
John Reckf1480762016-07-03 18:28:25 -0700136static bool setBenchmarkFormat(const char* format) {
137 if (!strcmp(format, "tabular")) {
138 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
139 } else if (!strcmp(format, "json")) {
140 gBenchmarkReporter.reset(new benchmark::JSONReporter());
141 } else if (!strcmp(format, "csv")) {
142 gBenchmarkReporter.reset(new benchmark::CSVReporter());
143 } else {
144 fprintf(stderr, "Unknown format '%s'", format);
145 return false;
146 }
147 return true;
148}
149
John Reck113ddd92017-11-09 16:21:21 -0800150static bool setRenderer(const char* renderer) {
151 if (!strcmp(renderer, "opengl")) {
152 Properties::overrideRenderPipelineType(RenderPipelineType::OpenGL);
153 } else if (!strcmp(renderer, "skiagl")) {
154 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL);
155 } else if (!strcmp(renderer, "skiavk")) {
156 Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan);
157 } else {
158 fprintf(stderr, "Unknown format '%s'", renderer);
159 return false;
160 }
161 return true;
162}
163
John Reck682573c2015-10-30 10:37:35 -0700164// For options that only exist in long-form. Anything in the
165// 0-255 range is reserved for short options (which just use their ASCII value)
166namespace LongOpts {
167enum {
168 Reserved = 255,
169 List,
170 WaitForGpu,
171 ReportFrametime,
172 CpuSet,
John Reckf1480762016-07-03 18:28:25 -0700173 BenchmarkFormat,
sergeyv202c10b2016-07-11 17:53:45 -0700174 Onscreen,
John Reckf1480762016-07-03 18:28:25 -0700175 Offscreen,
John Reck113ddd92017-11-09 16:21:21 -0800176 Renderer,
John Reckec100972018-04-05 16:41:41 -0700177 RenderAhead,
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 Reckec100972018-04-05 16:41:41 -0700193 {"render-ahead", required_argument, nullptr, LongOpts::RenderAhead},
John Reck1bcacfd2017-11-03 10:12:19 -0700194 {0, 0, 0, 0}};
John Reckb7dd29e2015-10-06 13:28:17 -0700195
196static const char* SHORT_OPTIONS = "c:r:h";
197
198void parseOptions(int argc, char* argv[]) {
199 int c;
John Reckb7dd29e2015-10-06 13:28:17 -0700200 bool error = false;
201 opterr = 0;
202
203 while (true) {
John Reckb7dd29e2015-10-06 13:28:17 -0700204 /* getopt_long stores the option index here. */
205 int option_index = 0;
206
207 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
208
John Reck1bcacfd2017-11-03 10:12:19 -0700209 if (c == -1) break;
John Reckb7dd29e2015-10-06 13:28:17 -0700210
211 switch (c) {
John Reck1bcacfd2017-11-03 10:12:19 -0700212 case 0:
213 // Option set a flag, don't need to do anything
214 // (although none of the current LONG_OPTIONS do this...)
215 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700216
John Reck1bcacfd2017-11-03 10:12:19 -0700217 case LongOpts::List:
218 listTests();
219 exit(EXIT_SUCCESS);
220 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700221
John Reck1bcacfd2017-11-03 10:12:19 -0700222 case 'c':
223 gOpts.count = atoi(optarg);
224 if (!gOpts.count) {
225 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
John Reck682573c2015-10-30 10:37:35 -0700226 error = true;
227 }
John Reck682573c2015-10-30 10:37:35 -0700228 break;
John Reck682573c2015-10-30 10:37:35 -0700229
John Reck1bcacfd2017-11-03 10:12:19 -0700230 case 'r':
231 gRepeatCount = atoi(optarg);
232 if (!gRepeatCount) {
233 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
234 error = true;
235 } else {
236 gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
237 }
John Reckf1480762016-07-03 18:28:25 -0700238 break;
John Reckf1480762016-07-03 18:28:25 -0700239
John Reck1bcacfd2017-11-03 10:12:19 -0700240 case LongOpts::ReportFrametime:
241 if (optarg) {
242 gOpts.reportFrametimeWeight = atoi(optarg);
243 if (!gOpts.reportFrametimeWeight) {
244 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
245 error = true;
246 }
247 } else {
248 gOpts.reportFrametimeWeight = 10;
249 }
250 break;
sergeyv202c10b2016-07-11 17:53:45 -0700251
John Reck1bcacfd2017-11-03 10:12:19 -0700252 case LongOpts::WaitForGpu:
253 Properties::waitForGpuCompletion = true;
254 break;
John Reckf1480762016-07-03 18:28:25 -0700255
John Reck1bcacfd2017-11-03 10:12:19 -0700256 case LongOpts::CpuSet:
257 if (!optarg) {
258 error = true;
259 break;
260 }
261 moveToCpuSet(optarg);
262 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700263
John Reck1bcacfd2017-11-03 10:12:19 -0700264 case LongOpts::BenchmarkFormat:
265 if (!optarg) {
266 error = true;
267 break;
268 }
269 if (!setBenchmarkFormat(optarg)) {
270 error = true;
271 }
272 break;
273
John Reck113ddd92017-11-09 16:21:21 -0800274 case LongOpts::Renderer:
275 if (!optarg) {
276 error = true;
277 break;
278 }
279 if (!setRenderer(optarg)) {
280 error = true;
281 }
282 break;
283
John Reck1bcacfd2017-11-03 10:12:19 -0700284 case LongOpts::Onscreen:
285 gOpts.renderOffscreen = false;
286 break;
287
288 case LongOpts::Offscreen:
289 gOpts.renderOffscreen = true;
290 break;
291
John Reckec100972018-04-05 16:41:41 -0700292 case LongOpts::RenderAhead:
293 if (!optarg) {
294 error = true;
295 }
296 gOpts.renderAhead = atoi(optarg);
297 if (gOpts.renderAhead < 0 || gOpts.renderAhead > 2) {
298 error = true;
299 }
300 break;
301
John Reck1bcacfd2017-11-03 10:12:19 -0700302 case 'h':
303 printHelp();
304 exit(EXIT_SUCCESS);
305 break;
306
307 case '?':
308 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
John Reckb7dd29e2015-10-06 13:28:17 -0700309 // fall-through
John Reck1bcacfd2017-11-03 10:12:19 -0700310 default:
311 error = true;
312 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700313 }
314 }
315
316 if (error) {
317 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
318 exit(EXIT_FAILURE);
319 }
320
321 /* Print any remaining command line arguments (not options). */
322 if (optind < argc) {
323 do {
324 const char* test = argv[optind++];
sergeyv202c10b2016-07-11 17:53:45 -0700325 auto pos = TestScene::testMap().find(test);
326 if (pos == TestScene::testMap().end()) {
327 fprintf(stderr, "Unknown test '%s'\n", test);
328 exit(EXIT_FAILURE);
John Reckb7dd29e2015-10-06 13:28:17 -0700329 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700330 gRunTests.push_back(pos->second);
John Reckb7dd29e2015-10-06 13:28:17 -0700331 }
332 } while (optind < argc);
333 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700334 for (auto& iter : TestScene::testMap()) {
335 gRunTests.push_back(iter.second);
336 }
John Reckb7dd29e2015-10-06 13:28:17 -0700337 }
338}
339
Chris Craik03188872015-02-02 18:39:33 -0800340int main(int argc, char* argv[]) {
John Reck682573c2015-10-30 10:37:35 -0700341 // set defaults
342 gOpts.count = 150;
343
Seigo Nonakab6e20132016-11-14 14:07:41 +0900344 Typeface::setRobotoTypefaceForTest();
345
John Reckb7dd29e2015-10-06 13:28:17 -0700346 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700347 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
348 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
349 }
350
351 if (gBenchmarkReporter) {
352 size_t name_field_width = 10;
353 for (auto&& test : gRunTests) {
354 name_field_width = std::max<size_t>(name_field_width, test.name.size());
355 }
356 // _50th, _90th, etc...
357 name_field_width += 5;
358
359 benchmark::BenchmarkReporter::Context context;
John Reckf1480762016-07-03 18:28:25 -0700360 context.name_field_width = name_field_width;
361 gBenchmarkReporter->ReportContext(context);
362 }
John Reckb7dd29e2015-10-06 13:28:17 -0700363
364 for (int i = 0; i < gRepeatCount; i++) {
365 for (auto&& test : gRunTests) {
John Reckf1480762016-07-03 18:28:25 -0700366 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700367 }
368 }
John Reckf1480762016-07-03 18:28:25 -0700369
370 if (gBenchmarkReporter) {
371 gBenchmarkReporter->Finalize();
372 }
373
sergeyv7dc370b2016-06-17 11:21:11 -0700374 LeakChecker::checkForLeaks();
John Reck94c40fe2014-10-08 09:28:43 -0700375 return 0;
376}