main.cpp revision 682573c84b7c21dc8ce4a2375da3961147442c4a
1/* 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 17#include "tests/common/TestScene.h" 18 19#include "protos/hwui.pb.h" 20#include "Properties.h" 21 22#include <getopt.h> 23#include <stdio.h> 24#include <string> 25#include <unistd.h> 26#include <unordered_map> 27#include <vector> 28 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <fcntl.h> 32#include <errno.h> 33 34using namespace android; 35using namespace android::uirenderer; 36using namespace android::uirenderer::test; 37 38static int gRepeatCount = 1; 39static std::vector<TestScene::Info> gRunTests; 40static TestScene::Options gOpts; 41 42void run(const TestScene::Info& info, const TestScene::Options& opts); 43 44static void printHelp() { 45 printf(R"( 46USAGE: hwuitest [OPTIONS] <TESTNAME> 47 48OPTIONS: 49 -c, --count=NUM NUM loops a test should run (example, number of frames) 50 -r, --runs=NUM Repeat the test(s) NUM times 51 -h, --help Display this help 52 --list List all tests 53 --wait-for-gpu Set this to wait for the GPU before producing the 54 next frame. Note that without locked clocks this will 55 pathologically bad performance due to large idle time 56 --report-frametime[=weight] If set, the test will print to stdout the 57 moving average frametime. Weight is optional, default is 10 58 --cpuset=name Adds the test to the specified cpuset before running 59 Not supported on all devices and needs root 60)"); 61} 62 63static void listTests() { 64 printf("Tests: \n"); 65 for (auto&& test : TestScene::testMap()) { 66 auto&& info = test.second; 67 const char* col1 = info.name.c_str(); 68 int dlen = info.description.length(); 69 const char* col2 = info.description.c_str(); 70 // World's best line breaking algorithm. 71 do { 72 int toPrint = dlen; 73 if (toPrint > 50) { 74 char* found = (char*) memrchr(col2, ' ', 50); 75 if (found) { 76 toPrint = found - col2; 77 } else { 78 toPrint = 50; 79 } 80 } 81 printf("%-20s %.*s\n", col1, toPrint, col2); 82 col1 = ""; 83 col2 += toPrint; 84 dlen -= toPrint; 85 while (*col2 == ' ') { 86 col2++; dlen--; 87 } 88 } while (dlen > 0); 89 printf("\n"); 90 } 91} 92 93static void moveToCpuSet(const char* cpusetName) { 94 if (access("/dev/cpuset/tasks", F_OK)) { 95 fprintf(stderr, "don't have access to cpusets, skipping...\n"); 96 return; 97 } 98 static const int BUF_SIZE = 100; 99 char buffer[BUF_SIZE]; 100 101 if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) { 102 fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName); 103 return; 104 } 105 int fd = open(buffer, O_WRONLY | O_CLOEXEC); 106 if (fd == -1) { 107 fprintf(stderr, "Error opening file %d\n", errno); 108 return; 109 } 110 pid_t pid = getpid(); 111 112 int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid); 113 if (towrite >= BUF_SIZE) { 114 fprintf(stderr, "Buffer wasn't large enough?\n"); 115 } else { 116 if (write(fd, buffer, towrite) != towrite) { 117 fprintf(stderr, "Failed to write, errno=%d", errno); 118 } 119 } 120 close(fd); 121} 122 123// For options that only exist in long-form. Anything in the 124// 0-255 range is reserved for short options (which just use their ASCII value) 125namespace LongOpts { 126enum { 127 Reserved = 255, 128 List, 129 WaitForGpu, 130 ReportFrametime, 131 CpuSet, 132}; 133} 134 135static const struct option LONG_OPTIONS[] = { 136 { "frames", required_argument, nullptr, 'f' }, 137 { "repeat", required_argument, nullptr, 'r' }, 138 { "help", no_argument, nullptr, 'h' }, 139 { "list", no_argument, nullptr, LongOpts::List }, 140 { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu }, 141 { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime }, 142 { "cpuset", required_argument, nullptr, LongOpts::CpuSet }, 143 { 0, 0, 0, 0 } 144}; 145 146static const char* SHORT_OPTIONS = "c:r:h"; 147 148void parseOptions(int argc, char* argv[]) { 149 int c; 150 bool error = false; 151 opterr = 0; 152 153 while (true) { 154 155 /* getopt_long stores the option index here. */ 156 int option_index = 0; 157 158 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index); 159 160 if (c == -1) 161 break; 162 163 switch (c) { 164 case 0: 165 // Option set a flag, don't need to do anything 166 // (although none of the current LONG_OPTIONS do this...) 167 break; 168 169 case LongOpts::List: 170 listTests(); 171 exit(EXIT_SUCCESS); 172 break; 173 174 case 'c': 175 gOpts.count = atoi(optarg); 176 if (!gOpts.count) { 177 fprintf(stderr, "Invalid frames argument '%s'\n", optarg); 178 error = true; 179 } 180 break; 181 182 case 'r': 183 gRepeatCount = atoi(optarg); 184 if (!gRepeatCount) { 185 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg); 186 error = true; 187 } else { 188 gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX); 189 } 190 break; 191 192 case LongOpts::ReportFrametime: 193 if (optarg) { 194 gOpts.reportFrametimeWeight = atoi(optarg); 195 if (!gOpts.reportFrametimeWeight) { 196 fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg); 197 error = true; 198 } 199 } else { 200 gOpts.reportFrametimeWeight = 10; 201 } 202 break; 203 204 case LongOpts::WaitForGpu: 205 Properties::waitForGpuCompletion = true; 206 break; 207 208 case LongOpts::CpuSet: 209 if (!optarg) { 210 error = true; 211 break; 212 } 213 moveToCpuSet(optarg); 214 break; 215 216 case 'h': 217 printHelp(); 218 exit(EXIT_SUCCESS); 219 break; 220 221 case '?': 222 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]); 223 // fall-through 224 default: 225 error = true; 226 break; 227 } 228 } 229 230 if (error) { 231 fprintf(stderr, "Try 'hwuitest --help' for more information.\n"); 232 exit(EXIT_FAILURE); 233 } 234 235 /* Print any remaining command line arguments (not options). */ 236 if (optind < argc) { 237 do { 238 const char* test = argv[optind++]; 239 auto pos = TestScene::testMap().find(test); 240 if (pos == TestScene::testMap().end()) { 241 fprintf(stderr, "Unknown test '%s'\n", test); 242 exit(EXIT_FAILURE); 243 } else { 244 gRunTests.push_back(pos->second); 245 } 246 } while (optind < argc); 247 } else { 248 gRunTests.push_back(TestScene::testMap()["shadowgrid"]); 249 } 250} 251 252int main(int argc, char* argv[]) { 253 // set defaults 254 gOpts.count = 150; 255 256 parseOptions(argc, argv); 257 258 for (int i = 0; i < gRepeatCount; i++) { 259 for (auto&& test : gRunTests) { 260 run(test, gOpts); 261 } 262 } 263 printf("Success!\n"); 264 return 0; 265} 266