blob: 12352d02be5670cf37891755fa629c41bad56943 [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 Wang5372c812020-10-02 09:41:01 +080012#include "clearTest.h"
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070013#include "constant.h"
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080014#include "drawSizeTest.h"
Po-Hsien Wanga956e652020-11-11 16:29:04 -080015#include "filepath.h"
Po-Hsien Wang00777b22019-04-24 16:37:09 -070016#include "submitTest.h"
17#include "utils.h"
18
Po-Hsien Wang93cc6892020-10-28 17:01:28 -070019// g_list determines should we show the test list.
20int g_list = false;
Po-Hsien Wang00777b22019-04-24 16:37:09 -070021// g_iteration determines the total iteration to run for each test
22int g_iteration = 1;
Po-Hsien Wang93cc6892020-10-28 17:01:28 -070023// g_verbose determines the logging level to print into the screen.
Po-Hsien Wang00777b22019-04-24 16:37:09 -070024int g_verbose = false;
25// g_vlayer enables the vulkan verification layer if it is set.
26int g_vlayer = false;
Po-Hsien Wang513fe192020-10-02 11:40:07 +080027// g_hasty enables the hasty mode. Tests would tries to reuse vulkan instance if
28// possible.
29int g_hasty = false;
Po-Hsien Wang93cc6892020-10-28 17:01:28 -070030// g_spirv_dir is the path to the folder contains spirv code for test.
Po-Hsien Wanga956e652020-11-11 16:29:04 -080031FilePath g_spirv_dir = FilePath("shaders");
32// g_out_dir is the path to the folder to store the output image.
33FilePath g_out_dir = FilePath("");
Po-Hsien Wang00777b22019-04-24 16:37:09 -070034
Po-Hsien Wang00777b22019-04-24 16:37:09 -070035// kLongOptions defines the options for argument options.
36const static struct option kLongOptions[] = {
37 {"iterations", required_argument, nullptr, 'i'},
38 {"tests", required_argument, nullptr, 't'},
39 {"blacklist", required_argument, nullptr, 'b'},
Po-Hsien Wang93cc6892020-10-28 17:01:28 -070040 {"spirv_dir", required_argument, nullptr, 's'},
Po-Hsien Wanga956e652020-11-11 16:29:04 -080041 {"out_dir", required_argument, nullptr, 'o'},
Po-Hsien Wang00777b22019-04-24 16:37:09 -070042 {"help", no_argument, nullptr, 'h'},
Po-Hsien Wang93cc6892020-10-28 17:01:28 -070043 {"list", no_argument, &g_list, 1},
Po-Hsien Wang00777b22019-04-24 16:37:09 -070044 {"vlayer", no_argument, &g_vlayer, 1},
45 {"verbose", no_argument, &g_verbose, 1},
Po-Hsien Wang513fe192020-10-02 11:40:07 +080046 {"hasty", no_argument, &g_hasty, 1},
Po-Hsien Wang00777b22019-04-24 16:37:09 -070047 {0, 0, 0, 0}};
48
49// TimeTest times the test by looping it iteration times.
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070050// @param test: test to be excuted.
51// @param iteration: how many times should the test be executed.
Po-Hsien Wang00777b22019-04-24 16:37:09 -070052inline uint64_t TimeTest(vkbench::testBase* test, uint64_t iteration) {
53 uint64_t start = GetUTime();
Po-Hsien Wang00777b22019-04-24 16:37:09 -070054 try {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070055 test->Setup();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070056 } catch (const vk::SystemError& err) {
57 LOG("Setup failed: %s", err.what());
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080058 test->Cleanup();
59 throw;
Po-Hsien Wang00777b22019-04-24 16:37:09 -070060 }
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +080061 DEFER(test->Cleanup());
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070062
63 try {
64 for (int i = 0; i < iteration; i++) {
65 test->Run();
66 }
67 } catch (const vk::SystemError& err) {
68 LOG("TestRun failed: %s", err.what());
69 throw TEST_FAIL;
Po-Hsien Wang00777b22019-04-24 16:37:09 -070070 }
71 return GetUTime() - start;
72}
73
74// Run the test and pre/post processes.
Po-Hsien Wang00777b22019-04-24 16:37:09 -070075// @param duration_us: The test would to iterate till duration_us is reached.
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070076void Run(vkbench::testBase* test, const uint64_t duration_us = 1000000) {
Po-Hsien Wang00777b22019-04-24 16:37:09 -070077 try {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070078 test->Initialize();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070079 } catch (const vk::SystemError& err) {
80 LOG("Test failed to initialize: %s", err.what());
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080081 test->Destroy();
82 throw;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070083 }
84 DEFER(test->Destroy());
85
86 // Do some iterations since initial timings may vary.
87 TimeTest(test, 2);
88 // Target minimum iteration is 1s for each test.
89 uint64_t time = 0;
90 uint64_t iteration = 1;
91 double score = -1.f;
92 do {
93 time = TimeTest(test, iteration);
94 DEBUG("iterations: %llu, time: %llu us, time/iter: %llu us", iteration,
95 time, time / iteration)
96 if (time > duration_us) {
97 score = time / iteration;
98 break;
Po-Hsien Wang00777b22019-04-24 16:37:09 -070099 }
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700100 iteration = iteration * 2;
101 } while ((1ull << 40) > iteration);
102 // Returns 0.0 if it ran max iterations in less than test time.
103 if (score <= 0.01f)
104 LOG("%s: measurement may not be accurate.", test->Name())
105 score = test->FormatMeasurement(score);
106 LOG("@RESULT: %46s = %10.2f %-15s", test->Name(), score, test->Unit());
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800107 try {
Po-Hsien Wang53230a22020-11-12 18:03:18 -0800108 char file_name[1024];
109 sprintf(file_name, "%s.png", test->Name());
110 FilePath file_path = g_out_dir.Append(FilePath(file_name));
111
112 vkbench::Image image = test->GetImage();
113 image.Save(file_path);
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800114 } catch (std::runtime_error err) {
115 DEBUG("Get runtime_error while SaveImage: %s.", err.what());
116 }
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700117}
118
119void PrintHelp() {
120 LOG(R",(
121Usage: vkbench [OPTIONS]
122 -i, --iterations=N Specify the iterations to run the tests.
123 -t, --tests=TESTS Tests to run in colon separated form.
124 -b, --blacklist=TESTS Tests to not run in colon separated form.
125 --list List the tests available.
126 --verbose Show verbose messages.
Po-Hsien Wang513fe192020-10-02 11:40:07 +0800127 --vlayer Enable vulkan verification layer.
Po-Hsien Wang93cc6892020-10-28 17:01:28 -0700128 --hasty Enable hasty mode.
Po-Hsien Wanga956e652020-11-11 16:29:04 -0800129 --spirv_dir Path to SPIRV code for test.(default: shaders/)
130 --out_dir Path to the output directory.),")
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700131}
132
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700133bool prefixFind(std::vector<std::string> list, std::string name) {
134 for (const std::string item : list) {
135 if (name.rfind(item, 0) == 0) {
136 return true;
137 }
138 }
139 return false;
140}
141
142bool ParseArgv(int argc,
143 char** argv,
144 std::vector<vkbench::testBase*>& all_tests) {
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700145 std::vector<std::string> enabled_tests;
146 std::vector<std::string> disabled_tests;
147 int c;
148 int option_index = 0;
149 while ((c = getopt_long(argc, argv, "i:t:b:", kLongOptions, &option_index)) !=
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700150 -1) {
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700151 if (c == 'i') {
152 g_iteration = atoi(optarg);
153 } else if (c == 't') {
154 enabled_tests = SplitString(std::string(optarg), ':');
155 } else if (c == 'b') {
156 disabled_tests = SplitString(std::string(optarg), ':');
Po-Hsien Wang93cc6892020-10-28 17:01:28 -0700157 } else if (c == 's') {
Po-Hsien Wanga956e652020-11-11 16:29:04 -0800158 g_spirv_dir = FilePath(optarg);
159 } else if (c == 'o') {
160 g_out_dir = FilePath(optarg);
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700161 } else if (c == '?' || c == 'h') {
162 PrintHelp();
163 return false;
164 }
165 }
166
167 if (optind < argc) {
168 ERROR("Unknown argv: ")
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700169 while (optind < argc)
170 ERROR("%s ", argv[optind++])
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700171 return false;
172 }
173
174 all_tests.erase(
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700175 remove_if(all_tests.begin(), all_tests.end(),
176 [enabled_tests, disabled_tests](const vkbench::testBase* test) {
177 bool should_run = enabled_tests.empty() ||
178 prefixFind(enabled_tests, test->Name());
179 should_run &= !prefixFind(disabled_tests, test->Name());
180 if (!should_run)
181 delete test;
182 return !should_run;
183 }),
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700184 all_tests.end());
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700185
Po-Hsien Wang93cc6892020-10-28 17:01:28 -0700186 if (g_list) {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700187 for (const auto& test : all_tests) {
188 LOG("%s: %s", test->Name(), test->Desp())
189 }
190 return false;
191 }
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700192 return true;
193}
194
195int main(int argc, char* argv[]) {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700196 vkbench::vkBase simpleVulkan;
197 // all_tests list all the available tests.
198 std::vector<vkbench::testBase*> all_tests = {
199 new vkbench::SubmitTest(10, &simpleVulkan),
200 new vkbench::SubmitTest(100, &simpleVulkan),
201 new vkbench::SubmitTest(1000, &simpleVulkan),
202 new vkbench::SubmitTest(10000, &simpleVulkan),
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800203 new vkbench::SubmitTest(100000, &simpleVulkan),
204 new vkbench::DrawSizeTest(16, &simpleVulkan),
205 new vkbench::DrawSizeTest(64, &simpleVulkan),
206 new vkbench::DrawSizeTest(128, &simpleVulkan),
207 new vkbench::DrawSizeTest(512, &simpleVulkan),
208 new vkbench::DrawSizeTest(1024, &simpleVulkan),
Po-Hsien Wang5372c812020-10-02 09:41:01 +0800209 new vkbench::ClearTest(&simpleVulkan),
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700210 };
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700211
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800212 // Sort to bundle tests using same vulkan instance together.
213 std::stable_sort(all_tests.begin(), all_tests.end(),
214 [](vkbench::testBase* a, vkbench::testBase* b) -> bool {
215 return a->vk < b->vk;
216 });
217
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700218 if (!ParseArgv(argc, argv, all_tests)) {
219 return 0;
220 }
221
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700222 std::map<const char*, int> failed_test;
223 LOG("@TEST_BEGIN")
224 PrintDateTime();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700225 for (auto i = 0; i < all_tests.size(); i++) {
226 auto& test = all_tests[i];
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800227 for (auto iter = 0; iter < g_iteration; iter++) {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700228 try {
Po-Hsien Wang513fe192020-10-02 11:40:07 +0800229 if (!test->vk->IsInitialized())
230 test->vk->Initialize();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700231 Run(test, 1000000);
Po-Hsien Wang513fe192020-10-02 11:40:07 +0800232 if (!g_hasty)
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700233 test->vk->Destroy();
234 } catch (const ERROR_TYPE& type) {
235 switch (type) {
236 case TEST_PASS:
237 break;
238 case TEST_FAIL:
239 failed_test[test->Name()] += 1;
240 break;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700241 default:
242 ERROR("Unimplemented error type");
243 throw;
244 }
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800245 } catch (const std::runtime_error error) {
246 failed_test[test->Name()] += 1;
247 LOG("Runtime Error: %s", error.what());
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700248 }
249 }
Po-Hsien Wang513fe192020-10-02 11:40:07 +0800250
251 // keep test->vk initialized for the next test.
252 if (g_hasty && test->vk->IsInitialized()) {
253 if (i + 1 >= all_tests.size() || test->vk != all_tests[i + 1]->vk) {
254 test->vk->Destroy();
255 }
256 }
Po-Hsien Wang00777b22019-04-24 16:37:09 -0700257 }
258 PrintDateTime();
259 LOG("@TEST_END")
260
261 for (auto& keyval : failed_test) {
262 LOG("%s failed %d times.", keyval.first, keyval.second)
263 }
264
265 for (auto& test : all_tests) {
266 delete test;
267 }
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700268}