blob: 1f5622252f6a2076763a2832808096074a52b04e [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
Seigo Nonakab6e20132016-11-14 14:07:41 +090020#include "hwui/Typeface.h"
John Recke248bd12015-08-05 13:53:53 -070021#include "protos/hwui.pb.h"
John Reck682573c2015-10-30 10:37:35 -070022#include "Properties.h"
John Recke248bd12015-08-05 13:53:53 -070023
John Reckf1480762016-07-03 18:28:25 -070024#include <benchmark/benchmark.h>
25#include <../src/sysinfo.h>
John Reckb7dd29e2015-10-06 13:28:17 -070026#include <getopt.h>
John Recke702c9c2015-10-07 10:26:02 -070027#include <stdio.h>
28#include <string>
29#include <unistd.h>
30#include <unordered_map>
John Reckb7dd29e2015-10-06 13:28:17 -070031#include <vector>
John Reck38e0c322015-11-10 12:19:17 -080032#include <pthread.h>
John Reck7f2e5e32015-05-05 11:00:53 -070033
John Reck682573c2015-10-30 10:37:35 -070034#include <sys/types.h>
35#include <sys/stat.h>
36#include <fcntl.h>
37#include <errno.h>
38
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
John Reckb7dd29e2015-10-06 13:28:17 -070043static int gRepeatCount = 1;
Chris Craik27e58b42015-12-07 10:01:38 -080044static std::vector<TestScene::Info> gRunTests;
John Reck682573c2015-10-30 10:37:35 -070045static TestScene::Options gOpts;
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,
49 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 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) {
85 char* found = (char*) memrchr(col2, ' ', 50);
86 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 == ' ') {
97 col2++; dlen--;
98 }
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
123 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
124 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());
139 } else if (!strcmp(format, "csv")) {
140 gBenchmarkReporter.reset(new benchmark::CSVReporter());
141 } else {
142 fprintf(stderr, "Unknown format '%s'", format);
143 return false;
144 }
145 return true;
146}
147
John Reck682573c2015-10-30 10:37:35 -0700148// For options that only exist in long-form. Anything in the
149// 0-255 range is reserved for short options (which just use their ASCII value)
150namespace LongOpts {
151enum {
152 Reserved = 255,
153 List,
154 WaitForGpu,
155 ReportFrametime,
156 CpuSet,
John Reckf1480762016-07-03 18:28:25 -0700157 BenchmarkFormat,
sergeyv202c10b2016-07-11 17:53:45 -0700158 Onscreen,
John Reckf1480762016-07-03 18:28:25 -0700159 Offscreen,
John Reck682573c2015-10-30 10:37:35 -0700160};
161}
162
John Reckb7dd29e2015-10-06 13:28:17 -0700163static const struct option LONG_OPTIONS[] = {
164 { "frames", required_argument, nullptr, 'f' },
165 { "repeat", required_argument, nullptr, 'r' },
166 { "help", no_argument, nullptr, 'h' },
John Reck682573c2015-10-30 10:37:35 -0700167 { "list", no_argument, nullptr, LongOpts::List },
168 { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
169 { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
170 { "cpuset", required_argument, nullptr, LongOpts::CpuSet },
John Reckf1480762016-07-03 18:28:25 -0700171 { "benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat },
sergeyv202c10b2016-07-11 17:53:45 -0700172 { "onscreen", no_argument, nullptr, LongOpts::Onscreen },
John Reckf1480762016-07-03 18:28:25 -0700173 { "offscreen", no_argument, nullptr, LongOpts::Offscreen },
John Reckb7dd29e2015-10-06 13:28:17 -0700174 { 0, 0, 0, 0 }
175};
176
177static const char* SHORT_OPTIONS = "c:r:h";
178
179void parseOptions(int argc, char* argv[]) {
180 int c;
John Reckb7dd29e2015-10-06 13:28:17 -0700181 bool error = false;
182 opterr = 0;
183
184 while (true) {
185
186 /* getopt_long stores the option index here. */
187 int option_index = 0;
188
189 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
190
191 if (c == -1)
192 break;
193
194 switch (c) {
195 case 0:
196 // Option set a flag, don't need to do anything
197 // (although none of the current LONG_OPTIONS do this...)
198 break;
199
John Reck682573c2015-10-30 10:37:35 -0700200 case LongOpts::List:
John Reckb7dd29e2015-10-06 13:28:17 -0700201 listTests();
202 exit(EXIT_SUCCESS);
203 break;
204
205 case 'c':
John Reck682573c2015-10-30 10:37:35 -0700206 gOpts.count = atoi(optarg);
207 if (!gOpts.count) {
John Reckb7dd29e2015-10-06 13:28:17 -0700208 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
209 error = true;
John Reckb7dd29e2015-10-06 13:28:17 -0700210 }
211 break;
212
213 case 'r':
John Reck682573c2015-10-30 10:37:35 -0700214 gRepeatCount = atoi(optarg);
215 if (!gRepeatCount) {
John Reckb7dd29e2015-10-06 13:28:17 -0700216 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
217 error = true;
218 } else {
John Reck682573c2015-10-30 10:37:35 -0700219 gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
John Reckb7dd29e2015-10-06 13:28:17 -0700220 }
221 break;
222
John Reck682573c2015-10-30 10:37:35 -0700223 case LongOpts::ReportFrametime:
224 if (optarg) {
225 gOpts.reportFrametimeWeight = atoi(optarg);
226 if (!gOpts.reportFrametimeWeight) {
227 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
228 error = true;
229 }
230 } else {
231 gOpts.reportFrametimeWeight = 10;
232 }
233 break;
234
235 case LongOpts::WaitForGpu:
236 Properties::waitForGpuCompletion = true;
237 break;
238
239 case LongOpts::CpuSet:
240 if (!optarg) {
241 error = true;
242 break;
243 }
244 moveToCpuSet(optarg);
245 break;
246
John Reckf1480762016-07-03 18:28:25 -0700247 case LongOpts::BenchmarkFormat:
248 if (!optarg) {
249 error = true;
250 break;
251 }
252 if (!setBenchmarkFormat(optarg)) {
253 error = true;
254 }
255 break;
256
sergeyv202c10b2016-07-11 17:53:45 -0700257 case LongOpts::Onscreen:
258 gOpts.renderOffscreen = false;
259 break;
260
John Reckf1480762016-07-03 18:28:25 -0700261 case LongOpts::Offscreen:
262 gOpts.renderOffscreen = true;
263 break;
264
John Reckb7dd29e2015-10-06 13:28:17 -0700265 case 'h':
266 printHelp();
267 exit(EXIT_SUCCESS);
268 break;
269
270 case '?':
271 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
272 // fall-through
273 default:
274 error = true;
275 break;
276 }
277 }
278
279 if (error) {
280 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
281 exit(EXIT_FAILURE);
282 }
283
284 /* Print any remaining command line arguments (not options). */
285 if (optind < argc) {
286 do {
287 const char* test = argv[optind++];
sergeyv202c10b2016-07-11 17:53:45 -0700288 auto pos = TestScene::testMap().find(test);
289 if (pos == TestScene::testMap().end()) {
290 fprintf(stderr, "Unknown test '%s'\n", test);
291 exit(EXIT_FAILURE);
John Reckb7dd29e2015-10-06 13:28:17 -0700292 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700293 gRunTests.push_back(pos->second);
John Reckb7dd29e2015-10-06 13:28:17 -0700294 }
295 } while (optind < argc);
296 } else {
sergeyv202c10b2016-07-11 17:53:45 -0700297 for (auto& iter : TestScene::testMap()) {
298 gRunTests.push_back(iter.second);
299 }
John Reckb7dd29e2015-10-06 13:28:17 -0700300 }
301}
302
Chris Craik03188872015-02-02 18:39:33 -0800303int main(int argc, char* argv[]) {
John Reck682573c2015-10-30 10:37:35 -0700304 // set defaults
305 gOpts.count = 150;
306
Seigo Nonakab6e20132016-11-14 14:07:41 +0900307 Typeface::setRobotoTypefaceForTest();
308
John Reckb7dd29e2015-10-06 13:28:17 -0700309 parseOptions(argc, argv);
John Reckf1480762016-07-03 18:28:25 -0700310 if (!gBenchmarkReporter && gOpts.renderOffscreen) {
311 gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
312 }
313
314 if (gBenchmarkReporter) {
315 size_t name_field_width = 10;
316 for (auto&& test : gRunTests) {
317 name_field_width = std::max<size_t>(name_field_width, test.name.size());
318 }
319 // _50th, _90th, etc...
320 name_field_width += 5;
321
322 benchmark::BenchmarkReporter::Context context;
323 context.num_cpus = benchmark::NumCPUs();
324 context.mhz_per_cpu = benchmark::CyclesPerSecond() / 1000000.0f;
325 context.cpu_scaling_enabled = benchmark::CpuScalingEnabled();
326 context.name_field_width = name_field_width;
327 gBenchmarkReporter->ReportContext(context);
328 }
John Reckb7dd29e2015-10-06 13:28:17 -0700329
330 for (int i = 0; i < gRepeatCount; i++) {
331 for (auto&& test : gRunTests) {
John Reckf1480762016-07-03 18:28:25 -0700332 run(test, gOpts, gBenchmarkReporter.get());
Tim Murray1a0f1c72015-05-06 11:37:37 -0700333 }
334 }
John Reckf1480762016-07-03 18:28:25 -0700335
336 if (gBenchmarkReporter) {
337 gBenchmarkReporter->Finalize();
338 }
339
sergeyv7dc370b2016-06-17 11:21:11 -0700340 LeakChecker::checkForLeaks();
John Reck94c40fe2014-10-08 09:28:43 -0700341 return 0;
342}