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