blob: 0a9a74eccfc9bb677a0b8bbc5eccc942328c1d5f [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 Reck682573c2015-10-30 10:37:35 -070071)");
John Reckb7dd29e2015-10-06 13:28:17 -070072}
73
74static void listTests() {
75 printf("Tests: \n");
Chris Craik27e58b42015-12-07 10:01:38 -080076 for (auto&& test : TestScene::testMap()) {
John Recke702c9c2015-10-07 10:26:02 -070077 auto&& info = test.second;
78 const char* col1 = info.name.c_str();
79 int dlen = info.description.length();
80 const char* col2 = info.description.c_str();
81 // World's best line breaking algorithm.
82 do {
83 int toPrint = dlen;
84 if (toPrint > 50) {
John Reck1bcacfd2017-11-03 10:12:19 -070085 char* found = (char*)memrchr(col2, ' ', 50);
John Recke702c9c2015-10-07 10:26:02 -070086 if (found) {
87 toPrint = found - col2;
88 } else {
89 toPrint = 50;
90 }
91 }
92 printf("%-20s %.*s\n", col1, toPrint, col2);
93 col1 = "";
94 col2 += toPrint;
95 dlen -= toPrint;
96 while (*col2 == ' ') {
John Reck1bcacfd2017-11-03 10:12:19 -070097 col2++;
98 dlen--;
John Recke702c9c2015-10-07 10:26:02 -070099 }
100 } while (dlen > 0);
101 printf("\n");
John Reckb7dd29e2015-10-06 13:28:17 -0700102 }
103}
104
John Reck682573c2015-10-30 10:37:35 -0700105static void moveToCpuSet(const char* cpusetName) {
106 if (access("/dev/cpuset/tasks", F_OK)) {
107 fprintf(stderr, "don't have access to cpusets, skipping...\n");
108 return;
109 }
110 static const int BUF_SIZE = 100;
111 char buffer[BUF_SIZE];
112
113 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
114 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
115 return;
116 }
117 int fd = open(buffer, O_WRONLY | O_CLOEXEC);
118 if (fd == -1) {
119 fprintf(stderr, "Error opening file %d\n", errno);
120 return;
121 }
122 pid_t pid = getpid();
123
John Reck1bcacfd2017-11-03 10:12:19 -0700124 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
John Reck682573c2015-10-30 10:37:35 -0700125 if (towrite >= BUF_SIZE) {
126 fprintf(stderr, "Buffer wasn't large enough?\n");
127 } else {
128 if (write(fd, buffer, towrite) != towrite) {
129 fprintf(stderr, "Failed to write, errno=%d", errno);
130 }
131 }
132 close(fd);
133}
134
John Reckf1480762016-07-03 18:28:25 -0700135static bool setBenchmarkFormat(const char* format) {
136 if (!strcmp(format, "tabular")) {
137 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
138 } else if (!strcmp(format, "json")) {
139 gBenchmarkReporter.reset(new benchmark::JSONReporter());
140 } else if (!strcmp(format, "csv")) {
141 gBenchmarkReporter.reset(new benchmark::CSVReporter());
142 } 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) {
150 if (!strcmp(renderer, "opengl")) {
151 Properties::overrideRenderPipelineType(RenderPipelineType::OpenGL);
152 } else if (!strcmp(renderer, "skiagl")) {
153 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 Reck682573c2015-10-30 10:37:35 -0700176};
177}
178
John Reckb7dd29e2015-10-06 13:28:17 -0700179static const struct option LONG_OPTIONS[] = {
John Reck1bcacfd2017-11-03 10:12:19 -0700180 {"frames", required_argument, nullptr, 'f'},
181 {"repeat", required_argument, nullptr, 'r'},
182 {"help", no_argument, nullptr, 'h'},
183 {"list", no_argument, nullptr, LongOpts::List},
184 {"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
185 {"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
186 {"cpuset", required_argument, nullptr, LongOpts::CpuSet},
187 {"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
188 {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
189 {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
John Reck113ddd92017-11-09 16:21:21 -0800190 {"renderer", required_argument, nullptr, LongOpts::Renderer},
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':
220 gOpts.count = atoi(optarg);
221 if (!gOpts.count) {
222 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':
228 gRepeatCount = atoi(optarg);
229 if (!gRepeatCount) {
230 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
231 error = true;
232 } else {
233 gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
234 }
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
289 case 'h':
290 printHelp();
291 exit(EXIT_SUCCESS);
292 break;
293
294 case '?':
295 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
John Reckb7dd29e2015-10-06 13:28:17 -0700296 // fall-through
John Reck1bcacfd2017-11-03 10:12:19 -0700297 default:
298 error = true;
299 break;
John Reckb7dd29e2015-10-06 13:28:17 -0700300 }
301 }
302
303 if (error) {
304 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
305 exit(EXIT_FAILURE);
306 }
307
308 /* Print any remaining command line arguments (not options). */
309 if (optind < argc) {
310 do {
311 const char* test = argv[optind++];
sergeyv202c10b2016-07-11 17:53:45 -0700312 auto pos = TestScene::testMap().find(test);
313 if (pos == TestScene::testMap().end()) {
314 fprintf(stderr, "Unknown test '%s'\n", test);
315 exit(EXIT_FAILURE);
John Reckb7dd29e2015-10-06 13:28:17 -0700316 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700317 gRunTests.push_back(pos->second);
John Reckb7dd29e2015-10-06 13:28:17 -0700318 }
319 } while (optind < argc);
320 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700321 for (auto& iter : TestScene::testMap()) {
322 gRunTests.push_back(iter.second);
323 }
John Reckb7dd29e2015-10-06 13:28:17 -0700324 }
325}
326
Chris Craik03188872015-02-02 18:39:33 -0800327int main(int argc, char* argv[]) {
John Reck682573c2015-10-30 10:37:35 -0700328 // set defaults
329 gOpts.count = 150;
330
Seigo Nonakab6e20132016-11-14 14:07:41 +0900331 Typeface::setRobotoTypefaceForTest();
332
John Reckb7dd29e2015-10-06 13:28:17 -0700333 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700334 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
335 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
336 }
337
338 if (gBenchmarkReporter) {
339 size_t name_field_width = 10;
340 for (auto&& test : gRunTests) {
341 name_field_width = std::max<size_t>(name_field_width, test.name.size());
342 }
343 // _50th, _90th, etc...
344 name_field_width += 5;
345
346 benchmark::BenchmarkReporter::Context context;
John Reckf1480762016-07-03 18:28:25 -0700347 context.name_field_width = name_field_width;
348 gBenchmarkReporter->ReportContext(context);
349 }
John Reckb7dd29e2015-10-06 13:28:17 -0700350
351 for (int i = 0; i < gRepeatCount; i++) {
352 for (auto&& test : gRunTests) {
John Reckf1480762016-07-03 18:28:25 -0700353 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700354 }
355 }
John Reckf1480762016-07-03 18:28:25 -0700356
357 if (gBenchmarkReporter) {
358 gBenchmarkReporter->Finalize();
359 }
360
sergeyv7dc370b2016-06-17 11:21:11 -0700361 LeakChecker::checkForLeaks();
John Reck94c40fe2014-10-08 09:28:43 -0700362 return 0;
363}