blob: 2bf9b406df1cfbe26e5a1c462b12e8e533d80a53 [file] [log] [blame]
Po-Hsien Wang00777b22019-04-24 16:37:09 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <getopt.h>
Po-Hsien Wang00777b22019-04-24 16:37:09 -07006#include <unistd.h>
7#include <algorithm>
8#include <iterator>
9#include <map>
10#include <vector>
11
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070012#include "constant.h"
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080013#include "drawSizeTest.h"
Po-Hsien Wang00777b22019-04-24 16:37:09 -070014#include "submitTest.h"
15#include "utils.h"
16
17// g_iteration determines the total iteration to run for each test
18int g_iteration = 1;
19// g_verbose determine the logging level to print into the screen.
20int g_verbose = false;
21// g_vlayer enables the vulkan verification layer if it is set.
22int g_vlayer = false;
Po-Hsien Wang00777b22019-04-24 16:37:09 -070023
Po-Hsien Wang00777b22019-04-24 16:37:09 -070024// kLongOptions defines the options for argument options.
25const static struct option kLongOptions[] = {
26 {"iterations", required_argument, nullptr, 'i'},
27 {"tests", required_argument, nullptr, 't'},
28 {"blacklist", required_argument, nullptr, 'b'},
29 {"list", no_argument, nullptr, 'l'},
30 {"help", no_argument, nullptr, 'h'},
Po-Hsien Wang00777b22019-04-24 16:37:09 -070031 {"vlayer", no_argument, &g_vlayer, 1},
32 {"verbose", no_argument, &g_verbose, 1},
33 {0, 0, 0, 0}};
34
35// TimeTest times the test by looping it iteration times.
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070036// @param test: test to be excuted.
37// @param iteration: how many times should the test be executed.
Po-Hsien Wang00777b22019-04-24 16:37:09 -070038inline uint64_t TimeTest(vkbench::testBase* test, uint64_t iteration) {
39 uint64_t start = GetUTime();
Po-Hsien Wang00777b22019-04-24 16:37:09 -070040 try {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070041 test->Setup();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070042 } catch (const vk::SystemError& err) {
43 LOG("Setup failed: %s", err.what());
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080044 test->Cleanup();
45 throw;
Po-Hsien Wang00777b22019-04-24 16:37:09 -070046 }
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +080047 DEFER(test->Cleanup());
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070048
49 try {
50 for (int i = 0; i < iteration; i++) {
51 test->Run();
52 }
53 } catch (const vk::SystemError& err) {
54 LOG("TestRun failed: %s", err.what());
55 throw TEST_FAIL;
Po-Hsien Wang00777b22019-04-24 16:37:09 -070056 }
57 return GetUTime() - start;
58}
59
60// Run the test and pre/post processes.
Po-Hsien Wang00777b22019-04-24 16:37:09 -070061// @param duration_us: The test would to iterate till duration_us is reached.
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070062void Run(vkbench::testBase* test, const uint64_t duration_us = 1000000) {
Po-Hsien Wang00777b22019-04-24 16:37:09 -070063 try {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070064 test->Initialize();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070065 } catch (const vk::SystemError& err) {
66 LOG("Test failed to initialize: %s", err.what());
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080067 test->Destroy();
68 throw;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070069 }
70 DEFER(test->Destroy());
71
72 // Do some iterations since initial timings may vary.
73 TimeTest(test, 2);
74 // Target minimum iteration is 1s for each test.
75 uint64_t time = 0;
76 uint64_t iteration = 1;
77 double score = -1.f;
78 do {
79 time = TimeTest(test, iteration);
80 DEBUG("iterations: %llu, time: %llu us, time/iter: %llu us", iteration,
81 time, time / iteration)
82 if (time > duration_us) {
83 score = time / iteration;
84 break;
Po-Hsien Wang00777b22019-04-24 16:37:09 -070085 }
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070086 iteration = iteration * 2;
87 } while ((1ull << 40) > iteration);
88 // Returns 0.0 if it ran max iterations in less than test time.
89 if (score <= 0.01f)
90 LOG("%s: measurement may not be accurate.", test->Name())
91 score = test->FormatMeasurement(score);
92 LOG("@RESULT: %46s = %10.2f %-15s", test->Name(), score, test->Unit());
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080093 try {
94 test->SaveImage(((std::string)test->Name()));
95 } catch (std::runtime_error err) {
96 DEBUG("Get runtime_error while SaveImage: %s.", err.what());
97 }
Po-Hsien Wang00777b22019-04-24 16:37:09 -070098}
99
100void PrintHelp() {
101 LOG(R",(
102Usage: vkbench [OPTIONS]
103 -i, --iterations=N Specify the iterations to run the tests.
104 -t, --tests=TESTS Tests to run in colon separated form.
105 -b, --blacklist=TESTS Tests to not run in colon separated form.
106 --list List the tests available.
107 --verbose Show verbose messages.
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700108 --vlayer Enable vulkan verification layer.),")
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700109}
110
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700111bool prefixFind(std::vector<std::string> list, std::string name) {
112 for (const std::string item : list) {
113 if (name.rfind(item, 0) == 0) {
114 return true;
115 }
116 }
117 return false;
118}
119
120bool ParseArgv(int argc,
121 char** argv,
122 std::vector<vkbench::testBase*>& all_tests) {
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700123 std::vector<std::string> enabled_tests;
124 std::vector<std::string> disabled_tests;
125 int c;
126 int option_index = 0;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700127 bool print_test = false;
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700128 while ((c = getopt_long(argc, argv, "i:t:b:", kLongOptions, &option_index)) !=
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700129 -1) {
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700130 if (c == 'i') {
131 g_iteration = atoi(optarg);
132 } else if (c == 't') {
133 enabled_tests = SplitString(std::string(optarg), ':');
134 } else if (c == 'b') {
135 disabled_tests = SplitString(std::string(optarg), ':');
136 } else if (c == 'l') {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700137 print_test = true;
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700138 } else if (c == '?' || c == 'h') {
139 PrintHelp();
140 return false;
141 }
142 }
143
144 if (optind < argc) {
145 ERROR("Unknown argv: ")
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700146 while (optind < argc)
147 ERROR("%s ", argv[optind++])
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700148 return false;
149 }
150
151 all_tests.erase(
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700152 remove_if(all_tests.begin(), all_tests.end(),
153 [enabled_tests, disabled_tests](const vkbench::testBase* test) {
154 bool should_run = enabled_tests.empty() ||
155 prefixFind(enabled_tests, test->Name());
156 should_run &= !prefixFind(disabled_tests, test->Name());
157 if (!should_run)
158 delete test;
159 return !should_run;
160 }),
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700161 all_tests.end());
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700162
163 if (print_test) {
164 for (const auto& test : all_tests) {
165 LOG("%s: %s", test->Name(), test->Desp())
166 }
167 return false;
168 }
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700169 return true;
170}
171
172int main(int argc, char* argv[]) {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700173 vkbench::vkBase simpleVulkan;
174 // all_tests list all the available tests.
175 std::vector<vkbench::testBase*> all_tests = {
176 new vkbench::SubmitTest(10, &simpleVulkan),
177 new vkbench::SubmitTest(100, &simpleVulkan),
178 new vkbench::SubmitTest(1000, &simpleVulkan),
179 new vkbench::SubmitTest(10000, &simpleVulkan),
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800180 new vkbench::SubmitTest(100000, &simpleVulkan),
181 new vkbench::DrawSizeTest(16, &simpleVulkan),
182 new vkbench::DrawSizeTest(64, &simpleVulkan),
183 new vkbench::DrawSizeTest(128, &simpleVulkan),
184 new vkbench::DrawSizeTest(512, &simpleVulkan),
185 new vkbench::DrawSizeTest(1024, &simpleVulkan),
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700186 };
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700187
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800188 // Sort to bundle tests using same vulkan instance together.
189 std::stable_sort(all_tests.begin(), all_tests.end(),
190 [](vkbench::testBase* a, vkbench::testBase* b) -> bool {
191 return a->vk < b->vk;
192 });
193
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700194 if (!ParseArgv(argc, argv, all_tests)) {
195 return 0;
196 }
197
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700198 std::map<const char*, int> failed_test;
199 LOG("@TEST_BEGIN")
200 PrintDateTime();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700201 for (auto i = 0; i < all_tests.size(); i++) {
202 auto& test = all_tests[i];
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700203 bool reuse_vulkan = false;
204 if (i + 1 < all_tests.size() && all_tests[i]->vk == all_tests[i + 1]->vk) {
205 reuse_vulkan = true;
206 }
207
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800208 for (auto iter = 0; iter < g_iteration; iter++) {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700209 try {
210 test->vk->Initialize();
211 Run(test, 1000000);
212 if (!reuse_vulkan)
213 test->vk->Destroy();
214 } catch (const ERROR_TYPE& type) {
215 switch (type) {
216 case TEST_PASS:
217 break;
218 case TEST_FAIL:
219 failed_test[test->Name()] += 1;
220 break;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700221 default:
222 ERROR("Unimplemented error type");
223 throw;
224 }
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800225 } catch (const std::runtime_error error) {
226 failed_test[test->Name()] += 1;
227 LOG("Runtime Error: %s", error.what());
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700228 }
229 }
230 }
231 PrintDateTime();
232 LOG("@TEST_END")
233
234 for (auto& keyval : failed_test) {
235 LOG("%s failed %d times.", keyval.first, keyval.second)
236 }
237
238 for (auto& test : all_tests) {
239 delete test;
240 }
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700241}