Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/amd/compiler/tests/main.cpp
7099 views
1
/*
2
* Copyright © 2020 Valve Corporation
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
* IN THE SOFTWARE.
22
*
23
*/
24
#include <map>
25
#include <set>
26
#include <string>
27
#include <vector>
28
#include <stdio.h>
29
#include <string.h>
30
#include <getopt.h>
31
#include <unistd.h>
32
#include <stdarg.h>
33
#include <llvm-c/Target.h>
34
#include "aco_ir.h"
35
#include "framework.h"
36
37
#include "util/u_cpu_detect.h"
38
39
static const char *help_message =
40
"Usage: %s [-h] [-l --list] [--no-check] [TEST [TEST ...]]\n"
41
"\n"
42
"Run ACO unit test(s). If TEST is not provided, all tests are run.\n"
43
"\n"
44
"positional arguments:\n"
45
" TEST Run TEST. If TEST ends with a '.', run tests with names\n"
46
" starting with TEST. The test variant (after the '/') can\n"
47
" be omitted to run all variants\n"
48
"\n"
49
"optional arguments:\n"
50
" -h, --help Show this help message and exit.\n"
51
" -l --list List unit tests.\n"
52
" --no-check Print test output instead of checking it.\n";
53
54
std::map<std::string, TestDef> tests;
55
FILE *output = NULL;
56
57
static TestDef current_test;
58
static unsigned tests_written = 0;
59
static FILE *checker_stdin = NULL;
60
static char *checker_stdin_data = NULL;
61
static size_t checker_stdin_size = 0;
62
63
static char *output_data = NULL;
64
static size_t output_size = 0;
65
static size_t output_offset = 0;
66
67
static char current_variant[64] = {0};
68
static std::set<std::string> *variant_filter = NULL;
69
70
bool test_failed = false;
71
bool test_skipped = false;
72
static char fail_message[256] = {0};
73
74
void write_test()
75
{
76
if (!checker_stdin) {
77
/* not entirely correct, but shouldn't matter */
78
tests_written++;
79
return;
80
}
81
82
fflush(output);
83
if (output_offset == output_size && !test_skipped && !test_failed)
84
return;
85
86
char *data = output_data + output_offset;
87
uint32_t size = output_size - output_offset;
88
89
fwrite("test", 1, 4, checker_stdin);
90
fwrite(current_test.name, 1, strlen(current_test.name)+1, checker_stdin);
91
fwrite(current_variant, 1, strlen(current_variant)+1, checker_stdin);
92
fwrite(current_test.source_file, 1, strlen(current_test.source_file)+1, checker_stdin);
93
if (test_failed || test_skipped) {
94
const char *res = test_failed ? "failed" : "skipped";
95
fwrite("\x01", 1, 1, checker_stdin);
96
fwrite(res, 1, strlen(res)+1, checker_stdin);
97
fwrite(fail_message, 1, strlen(fail_message)+1, checker_stdin);
98
} else {
99
fwrite("\x00", 1, 1, checker_stdin);
100
}
101
fwrite(&size, 4, 1, checker_stdin);
102
fwrite(data, 1, size, checker_stdin);
103
104
tests_written++;
105
output_offset += size;
106
}
107
108
bool set_variant(const char *name)
109
{
110
if (variant_filter && !variant_filter->count(name))
111
return false;
112
113
write_test();
114
test_failed = false;
115
test_skipped = false;
116
strncpy(current_variant, name, sizeof(current_variant) - 1);
117
118
printf("Running '%s/%s'\n", current_test.name, name);
119
120
return true;
121
}
122
123
void fail_test(const char *fmt, ...)
124
{
125
va_list args;
126
va_start(args, fmt);
127
128
test_failed = true;
129
vsnprintf(fail_message, sizeof(fail_message), fmt, args);
130
131
va_end(args);
132
}
133
134
void skip_test(const char *fmt, ...)
135
{
136
va_list args;
137
va_start(args, fmt);
138
139
test_skipped = true;
140
vsnprintf(fail_message, sizeof(fail_message), fmt, args);
141
142
va_end(args);
143
}
144
145
void run_test(TestDef def)
146
{
147
current_test = def;
148
output_data = NULL;
149
output_size = 0;
150
output_offset = 0;
151
test_failed = false;
152
test_skipped = false;
153
memset(current_variant, 0, sizeof(current_variant));
154
155
if (checker_stdin)
156
output = open_memstream(&output_data, &output_size);
157
else
158
output = stdout;
159
160
current_test.func();
161
write_test();
162
163
if (checker_stdin)
164
fclose(output);
165
free(output_data);
166
}
167
168
int check_output(char **argv)
169
{
170
fflush(stdout);
171
fflush(stderr);
172
173
fclose(checker_stdin);
174
175
int stdin_pipe[2];
176
pipe(stdin_pipe);
177
178
pid_t child_pid = fork();
179
if (child_pid == -1) {
180
fprintf(stderr, "%s: fork() failed: %s\n", argv[0], strerror(errno));
181
return 99;
182
} else if (child_pid != 0) {
183
/* Evaluate test output externally using Python */
184
dup2(stdin_pipe[0], STDIN_FILENO);
185
close(stdin_pipe[0]);
186
close(stdin_pipe[1]);
187
188
execlp(ACO_TEST_PYTHON_BIN, ACO_TEST_PYTHON_BIN, ACO_TEST_SOURCE_DIR "/check_output.py", NULL);
189
fprintf(stderr, "%s: execlp() failed: %s\n", argv[0], strerror(errno));
190
return 99;
191
} else {
192
/* Feed input data to the Python process. Writing large streams to
193
* stdin will block eventually, so this is done in a forked process
194
* to let the test checker process chunks of data as they arrive */
195
write(stdin_pipe[1], checker_stdin_data, checker_stdin_size);
196
close(stdin_pipe[0]);
197
close(stdin_pipe[1]);
198
_exit(0);
199
}
200
}
201
202
bool match_test(std::string name, std::string pattern)
203
{
204
if (name.length() < pattern.length())
205
return false;
206
if (pattern.back() == '.')
207
name.resize(pattern.length());
208
return name == pattern;
209
}
210
211
int main(int argc, char **argv)
212
{
213
int print_help = 0;
214
int do_list = 0;
215
int do_check = 1;
216
const struct option opts[] = {
217
{ "help", no_argument, &print_help, 1 },
218
{ "list", no_argument, &do_list, 1 },
219
{ "no-check", no_argument, &do_check, 0 },
220
{ NULL, 0, NULL, 0 }
221
};
222
223
int c;
224
while ((c = getopt_long(argc, argv, "hl", opts, NULL)) != -1) {
225
switch (c) {
226
case 'h':
227
print_help = 1;
228
break;
229
case 'l':
230
do_list = 1;
231
break;
232
case 0:
233
break;
234
case '?':
235
default:
236
fprintf(stderr, "%s: Invalid argument\n", argv[0]);
237
return 99;
238
}
239
}
240
241
if (print_help) {
242
fprintf(stderr, help_message, argv[0]);
243
return 99;
244
}
245
246
util_cpu_detect();
247
248
if (do_list) {
249
for (auto test : tests)
250
printf("%s\n", test.first.c_str());
251
return 99;
252
}
253
254
std::vector<std::pair<std::string, std::string>> names;
255
for (int i = optind; i < argc; i++) {
256
std::string name = argv[i];
257
std::string variant;
258
size_t pos = name.find('/');
259
if (pos != std::string::npos) {
260
variant = name.substr(pos + 1);
261
name = name.substr(0, pos);
262
}
263
names.emplace_back(std::pair<std::string, std::string>(name, variant));
264
}
265
266
if (do_check)
267
checker_stdin = open_memstream(&checker_stdin_data, &checker_stdin_size);
268
269
LLVMInitializeAMDGPUTargetInfo();
270
LLVMInitializeAMDGPUTarget();
271
LLVMInitializeAMDGPUTargetMC();
272
LLVMInitializeAMDGPUDisassembler();
273
274
aco::init();
275
276
for (auto pair : tests) {
277
bool found = names.empty();
278
bool all_variants = names.empty();
279
std::set<std::string> variants;
280
for (const std::pair<std::string, std::string>& name : names) {
281
if (match_test(pair.first, name.first)) {
282
found = true;
283
if (name.second.empty())
284
all_variants = true;
285
else
286
variants.insert(name.second);
287
}
288
}
289
290
if (found) {
291
variant_filter = all_variants ? NULL : &variants;
292
printf("Running '%s'\n", pair.first.c_str());
293
run_test(pair.second);
294
}
295
}
296
if (!tests_written) {
297
fprintf(stderr, "%s: No matching tests\n", argv[0]);
298
return 99;
299
}
300
301
if (checker_stdin) {
302
printf("\n");
303
return check_output(argv);
304
} else {
305
printf("Tests ran\n");
306
return 99;
307
}
308
}
309
310