1be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root/* 2be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * Copyright (C) 2014 The Android Open Source Project 3be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * 4be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 5be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * you may not use this file except in compliance with the License. 6be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * You may obtain a copy of the License at 7be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * 8be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * http://www.apache.org/licenses/LICENSE-2.0 9be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * 10be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * Unless required by applicable law or agreed to in writing, software 11be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * distributed under the License is distributed on an "AS IS" BASIS, 12be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * See the License for the specific language governing permissions and 14be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root * limitations under the License. 15be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root */ 16be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root 17be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include "tests/common/LeakChecker.h" 18be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include "tests/common/TestScene.h" 19be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root 20be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include "Properties.h" 21be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include "hwui/Typeface.h" 22be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include "protos/hwui.pb.h" 23be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root 24be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <benchmark/benchmark.h> 25be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <getopt.h> 26be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <pthread.h> 27be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <stdio.h> 28be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <unistd.h> 29c6baf563ba6aa207a48317c177b29f1d2b70cf3dChih-Hung Hsieh#include <string> 30be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <unordered_map> 31be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <vector> 32be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root 332b3a8cd808a4013f43c881eca64a870ff0ea735bAndreas Gampe#include <errno.h> 342b3a8cd808a4013f43c881eca64a870ff0ea735bAndreas Gampe#include <fcntl.h> 35be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <sys/stat.h> 36be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root#include <sys/types.h> 3734b33887a17a312167666be217a0f521236b393dSudheer Shanka 38be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Rootusing namespace android; 39be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Rootusing namespace android::uirenderer; 40be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Rootusing namespace android::uirenderer::test; 41be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root 42be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Rootstatic int gRepeatCount = 1; 43be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Rootstatic std::vector<TestScene::Info> gRunTests; 44be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Rootstatic TestScene::Options gOpts; 45be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Rootstd::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter; 46be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root 47be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Rootvoid run(const TestScene::Info& info, const TestScene::Options& opts, 48af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root benchmark::BenchmarkReporter* reporter); 49af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 50af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootstatic void printHelp() { 51be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root printf(R"( 52be857d42849eaaa554d4772dbba7755f8a0f3547Kenny RootUSAGE: hwuimacro [OPTIONS] <TESTNAME> 532b3a8cd808a4013f43c881eca64a870ff0ea735bAndreas Gampe 54be857d42849eaaa554d4772dbba7755f8a0f3547Kenny RootOPTIONS: 55be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root -c, --count=NUM NUM loops a test should run (example, number of frames) 56be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root -r, --runs=NUM Repeat the test(s) NUM times 57be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root -h, --help Display this help 58be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root --list List all tests 59be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root --wait-for-gpu Set this to wait for the GPU before producing the 60be857d42849eaaa554d4772dbba7755f8a0f3547Kenny Root next frame. Note that without locked clocks this will 612b3a8cd808a4013f43c881eca64a870ff0ea735bAndreas Gampe 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 66 --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 70 --renderer=TYPE Sets the render pipeline to use. May be opengl, skiagl, or skiavk 71)"); 72} 73 74static void listTests() { 75 printf("Tests: \n"); 76 for (auto&& test : TestScene::testMap()) { 77 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++; 98 dlen--; 99 } 100 } while (dlen > 0); 101 printf("\n"); 102 } 103} 104 105static 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 124 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid); 125 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 135static 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 149static 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 163// 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, 172 BenchmarkFormat, 173 Onscreen, 174 Offscreen, 175 Renderer, 176}; 177} 178 179static const struct option LONG_OPTIONS[] = { 180 {"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}, 190 {"renderer", required_argument, nullptr, LongOpts::Renderer}, 191 {0, 0, 0, 0}}; 192 193static const char* SHORT_OPTIONS = "c:r:h"; 194 195void parseOptions(int argc, char* argv[]) { 196 int c; 197 bool error = false; 198 opterr = 0; 199 200 while (true) { 201 /* 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 206 if (c == -1) break; 207 208 switch (c) { 209 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; 213 214 case LongOpts::List: 215 listTests(); 216 exit(EXIT_SUCCESS); 217 break; 218 219 case 'c': 220 gOpts.count = atoi(optarg); 221 if (!gOpts.count) { 222 fprintf(stderr, "Invalid frames argument '%s'\n", optarg); 223 error = true; 224 } 225 break; 226 227 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 } 235 break; 236 237 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; 248 249 case LongOpts::WaitForGpu: 250 Properties::waitForGpuCompletion = true; 251 break; 252 253 case LongOpts::CpuSet: 254 if (!optarg) { 255 error = true; 256 break; 257 } 258 moveToCpuSet(optarg); 259 break; 260 261 case LongOpts::BenchmarkFormat: 262 if (!optarg) { 263 error = true; 264 break; 265 } 266 if (!setBenchmarkFormat(optarg)) { 267 error = true; 268 } 269 break; 270 271 case LongOpts::Renderer: 272 if (!optarg) { 273 error = true; 274 break; 275 } 276 if (!setRenderer(optarg)) { 277 error = true; 278 } 279 break; 280 281 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]); 296 // fall-through 297 default: 298 error = true; 299 break; 300 } 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++]; 312 auto pos = TestScene::testMap().find(test); 313 if (pos == TestScene::testMap().end()) { 314 fprintf(stderr, "Unknown test '%s'\n", test); 315 exit(EXIT_FAILURE); 316 } else { 317 gRunTests.push_back(pos->second); 318 } 319 } while (optind < argc); 320 } else { 321 for (auto& iter : TestScene::testMap()) { 322 gRunTests.push_back(iter.second); 323 } 324 } 325} 326 327int main(int argc, char* argv[]) { 328 // set defaults 329 gOpts.count = 150; 330 331 Typeface::setRobotoTypefaceForTest(); 332 333 parseOptions(argc, argv); 334 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; 347 context.name_field_width = name_field_width; 348 gBenchmarkReporter->ReportContext(context); 349 } 350 351 for (int i = 0; i < gRepeatCount; i++) { 352 for (auto&& test : gRunTests) { 353 run(test, gOpts, gBenchmarkReporter.get()); 354 } 355 } 356 357 if (gBenchmarkReporter) { 358 gBenchmarkReporter->Finalize(); 359 } 360 361 LeakChecker::checkForLeaks(); 362 return 0; 363} 364