Home | History | Annotate | Download | only in macrobench
      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 
     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 
     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 
     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 
    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 
    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