Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/kvm/lib/test_util.c
38237 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* tools/testing/selftests/kvm/lib/test_util.c
4
*
5
* Copyright (C) 2020, Google LLC.
6
*/
7
#include <stdio.h>
8
#include <stdarg.h>
9
#include <assert.h>
10
#include <ctype.h>
11
#include <limits.h>
12
#include <stdlib.h>
13
#include <time.h>
14
#include <sys/stat.h>
15
#include <sys/syscall.h>
16
#include <linux/mman.h>
17
#include "linux/kernel.h"
18
19
#include "test_util.h"
20
21
sigjmp_buf expect_sigbus_jmpbuf;
22
23
void __attribute__((used)) expect_sigbus_handler(int signum)
24
{
25
siglongjmp(expect_sigbus_jmpbuf, 1);
26
}
27
28
/*
29
* Random number generator that is usable from guest code. This is the
30
* Park-Miller LCG using standard constants.
31
*/
32
33
struct guest_random_state new_guest_random_state(uint32_t seed)
34
{
35
struct guest_random_state s = {.seed = seed};
36
return s;
37
}
38
39
uint32_t guest_random_u32(struct guest_random_state *state)
40
{
41
state->seed = (uint64_t)state->seed * 48271 % ((uint32_t)(1 << 31) - 1);
42
return state->seed;
43
}
44
45
/*
46
* Parses "[0-9]+[kmgt]?".
47
*/
48
size_t parse_size(const char *size)
49
{
50
size_t base;
51
char *scale;
52
int shift = 0;
53
54
TEST_ASSERT(size && isdigit(size[0]), "Need at least one digit in '%s'", size);
55
56
base = strtoull(size, &scale, 0);
57
58
TEST_ASSERT(base != ULLONG_MAX, "Overflow parsing size!");
59
60
switch (tolower(*scale)) {
61
case 't':
62
shift = 40;
63
break;
64
case 'g':
65
shift = 30;
66
break;
67
case 'm':
68
shift = 20;
69
break;
70
case 'k':
71
shift = 10;
72
break;
73
case 'b':
74
case '\0':
75
shift = 0;
76
break;
77
default:
78
TEST_ASSERT(false, "Unknown size letter %c", *scale);
79
}
80
81
TEST_ASSERT((base << shift) >> shift == base, "Overflow scaling size!");
82
83
return base << shift;
84
}
85
86
int64_t timespec_to_ns(struct timespec ts)
87
{
88
return (int64_t)ts.tv_nsec + 1000000000LL * (int64_t)ts.tv_sec;
89
}
90
91
struct timespec timespec_add_ns(struct timespec ts, int64_t ns)
92
{
93
struct timespec res;
94
95
res.tv_nsec = ts.tv_nsec + ns;
96
res.tv_sec = ts.tv_sec + res.tv_nsec / 1000000000LL;
97
res.tv_nsec %= 1000000000LL;
98
99
return res;
100
}
101
102
struct timespec timespec_add(struct timespec ts1, struct timespec ts2)
103
{
104
int64_t ns1 = timespec_to_ns(ts1);
105
int64_t ns2 = timespec_to_ns(ts2);
106
return timespec_add_ns((struct timespec){0}, ns1 + ns2);
107
}
108
109
struct timespec timespec_sub(struct timespec ts1, struct timespec ts2)
110
{
111
int64_t ns1 = timespec_to_ns(ts1);
112
int64_t ns2 = timespec_to_ns(ts2);
113
return timespec_add_ns((struct timespec){0}, ns1 - ns2);
114
}
115
116
struct timespec timespec_elapsed(struct timespec start)
117
{
118
struct timespec end;
119
120
clock_gettime(CLOCK_MONOTONIC, &end);
121
return timespec_sub(end, start);
122
}
123
124
struct timespec timespec_div(struct timespec ts, int divisor)
125
{
126
int64_t ns = timespec_to_ns(ts) / divisor;
127
128
return timespec_add_ns((struct timespec){0}, ns);
129
}
130
131
void print_skip(const char *fmt, ...)
132
{
133
va_list ap;
134
135
assert(fmt);
136
va_start(ap, fmt);
137
vprintf(fmt, ap);
138
va_end(ap);
139
puts(", skipping test");
140
}
141
142
static bool test_sysfs_path(const char *path)
143
{
144
struct stat statbuf;
145
int ret;
146
147
ret = stat(path, &statbuf);
148
TEST_ASSERT(ret == 0 || (ret == -1 && errno == ENOENT),
149
"Error in stat()ing '%s'", path);
150
151
return ret == 0;
152
}
153
154
bool thp_configured(void)
155
{
156
return test_sysfs_path("/sys/kernel/mm/transparent_hugepage");
157
}
158
159
static size_t get_sysfs_val(const char *path)
160
{
161
size_t size;
162
FILE *f;
163
int ret;
164
165
f = fopen(path, "r");
166
TEST_ASSERT(f, "Error opening '%s'", path);
167
168
ret = fscanf(f, "%ld", &size);
169
TEST_ASSERT(ret > 0, "Error reading '%s'", path);
170
171
/* Re-scan the input stream to verify the entire file was read. */
172
ret = fscanf(f, "%ld", &size);
173
TEST_ASSERT(ret < 1, "Error reading '%s'", path);
174
175
fclose(f);
176
return size;
177
}
178
179
size_t get_trans_hugepagesz(void)
180
{
181
TEST_ASSERT(thp_configured(), "THP is not configured in host kernel");
182
183
return get_sysfs_val("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size");
184
}
185
186
bool is_numa_balancing_enabled(void)
187
{
188
if (!test_sysfs_path("/proc/sys/kernel/numa_balancing"))
189
return false;
190
return get_sysfs_val("/proc/sys/kernel/numa_balancing") == 1;
191
}
192
193
size_t get_def_hugetlb_pagesz(void)
194
{
195
char buf[64];
196
const char *hugepagesize = "Hugepagesize:";
197
const char *hugepages_total = "HugePages_Total:";
198
FILE *f;
199
200
f = fopen("/proc/meminfo", "r");
201
TEST_ASSERT(f != NULL, "Error in opening /proc/meminfo");
202
203
while (fgets(buf, sizeof(buf), f) != NULL) {
204
if (strstr(buf, hugepages_total) == buf) {
205
unsigned long long total = strtoull(buf + strlen(hugepages_total), NULL, 10);
206
if (!total) {
207
fprintf(stderr, "HUGETLB is not enabled in /proc/sys/vm/nr_hugepages\n");
208
exit(KSFT_SKIP);
209
}
210
}
211
if (strstr(buf, hugepagesize) == buf) {
212
fclose(f);
213
return strtoull(buf + strlen(hugepagesize), NULL, 10) << 10;
214
}
215
}
216
217
if (feof(f)) {
218
fprintf(stderr, "HUGETLB is not configured in host kernel");
219
exit(KSFT_SKIP);
220
}
221
222
TEST_FAIL("Error in reading /proc/meminfo");
223
}
224
225
#define ANON_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS)
226
#define ANON_HUGE_FLAGS (ANON_FLAGS | MAP_HUGETLB)
227
228
const struct vm_mem_backing_src_alias *vm_mem_backing_src_alias(uint32_t i)
229
{
230
static const struct vm_mem_backing_src_alias aliases[] = {
231
[VM_MEM_SRC_ANONYMOUS] = {
232
.name = "anonymous",
233
.flag = ANON_FLAGS,
234
},
235
[VM_MEM_SRC_ANONYMOUS_THP] = {
236
.name = "anonymous_thp",
237
.flag = ANON_FLAGS,
238
},
239
[VM_MEM_SRC_ANONYMOUS_HUGETLB] = {
240
.name = "anonymous_hugetlb",
241
.flag = ANON_HUGE_FLAGS,
242
},
243
[VM_MEM_SRC_ANONYMOUS_HUGETLB_16KB] = {
244
.name = "anonymous_hugetlb_16kb",
245
.flag = ANON_HUGE_FLAGS | MAP_HUGE_16KB,
246
},
247
[VM_MEM_SRC_ANONYMOUS_HUGETLB_64KB] = {
248
.name = "anonymous_hugetlb_64kb",
249
.flag = ANON_HUGE_FLAGS | MAP_HUGE_64KB,
250
},
251
[VM_MEM_SRC_ANONYMOUS_HUGETLB_512KB] = {
252
.name = "anonymous_hugetlb_512kb",
253
.flag = ANON_HUGE_FLAGS | MAP_HUGE_512KB,
254
},
255
[VM_MEM_SRC_ANONYMOUS_HUGETLB_1MB] = {
256
.name = "anonymous_hugetlb_1mb",
257
.flag = ANON_HUGE_FLAGS | MAP_HUGE_1MB,
258
},
259
[VM_MEM_SRC_ANONYMOUS_HUGETLB_2MB] = {
260
.name = "anonymous_hugetlb_2mb",
261
.flag = ANON_HUGE_FLAGS | MAP_HUGE_2MB,
262
},
263
[VM_MEM_SRC_ANONYMOUS_HUGETLB_8MB] = {
264
.name = "anonymous_hugetlb_8mb",
265
.flag = ANON_HUGE_FLAGS | MAP_HUGE_8MB,
266
},
267
[VM_MEM_SRC_ANONYMOUS_HUGETLB_16MB] = {
268
.name = "anonymous_hugetlb_16mb",
269
.flag = ANON_HUGE_FLAGS | MAP_HUGE_16MB,
270
},
271
[VM_MEM_SRC_ANONYMOUS_HUGETLB_32MB] = {
272
.name = "anonymous_hugetlb_32mb",
273
.flag = ANON_HUGE_FLAGS | MAP_HUGE_32MB,
274
},
275
[VM_MEM_SRC_ANONYMOUS_HUGETLB_256MB] = {
276
.name = "anonymous_hugetlb_256mb",
277
.flag = ANON_HUGE_FLAGS | MAP_HUGE_256MB,
278
},
279
[VM_MEM_SRC_ANONYMOUS_HUGETLB_512MB] = {
280
.name = "anonymous_hugetlb_512mb",
281
.flag = ANON_HUGE_FLAGS | MAP_HUGE_512MB,
282
},
283
[VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB] = {
284
.name = "anonymous_hugetlb_1gb",
285
.flag = ANON_HUGE_FLAGS | MAP_HUGE_1GB,
286
},
287
[VM_MEM_SRC_ANONYMOUS_HUGETLB_2GB] = {
288
.name = "anonymous_hugetlb_2gb",
289
.flag = ANON_HUGE_FLAGS | MAP_HUGE_2GB,
290
},
291
[VM_MEM_SRC_ANONYMOUS_HUGETLB_16GB] = {
292
.name = "anonymous_hugetlb_16gb",
293
.flag = ANON_HUGE_FLAGS | MAP_HUGE_16GB,
294
},
295
[VM_MEM_SRC_SHMEM] = {
296
.name = "shmem",
297
.flag = MAP_SHARED,
298
},
299
[VM_MEM_SRC_SHARED_HUGETLB] = {
300
.name = "shared_hugetlb",
301
/*
302
* No MAP_HUGETLB, we use MFD_HUGETLB instead. Since
303
* we're using "file backed" memory, we need to specify
304
* this when the FD is created, not when the area is
305
* mapped.
306
*/
307
.flag = MAP_SHARED,
308
},
309
};
310
_Static_assert(ARRAY_SIZE(aliases) == NUM_SRC_TYPES,
311
"Missing new backing src types?");
312
313
TEST_ASSERT(i < NUM_SRC_TYPES, "Backing src type ID %d too big", i);
314
315
return &aliases[i];
316
}
317
318
#define MAP_HUGE_PAGE_SIZE(x) (1ULL << ((x >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK))
319
320
size_t get_backing_src_pagesz(uint32_t i)
321
{
322
uint32_t flag = vm_mem_backing_src_alias(i)->flag;
323
324
switch (i) {
325
case VM_MEM_SRC_ANONYMOUS:
326
case VM_MEM_SRC_SHMEM:
327
return getpagesize();
328
case VM_MEM_SRC_ANONYMOUS_THP:
329
return get_trans_hugepagesz();
330
case VM_MEM_SRC_ANONYMOUS_HUGETLB:
331
case VM_MEM_SRC_SHARED_HUGETLB:
332
return get_def_hugetlb_pagesz();
333
default:
334
return MAP_HUGE_PAGE_SIZE(flag);
335
}
336
}
337
338
bool is_backing_src_hugetlb(uint32_t i)
339
{
340
return !!(vm_mem_backing_src_alias(i)->flag & MAP_HUGETLB);
341
}
342
343
static void print_available_backing_src_types(const char *prefix)
344
{
345
int i;
346
347
printf("%sAvailable backing src types:\n", prefix);
348
349
for (i = 0; i < NUM_SRC_TYPES; i++)
350
printf("%s %s\n", prefix, vm_mem_backing_src_alias(i)->name);
351
}
352
353
void backing_src_help(const char *flag)
354
{
355
printf(" %s: specify the type of memory that should be used to\n"
356
" back the guest data region. (default: %s)\n",
357
flag, vm_mem_backing_src_alias(DEFAULT_VM_MEM_SRC)->name);
358
print_available_backing_src_types(" ");
359
}
360
361
enum vm_mem_backing_src_type parse_backing_src_type(const char *type_name)
362
{
363
int i;
364
365
for (i = 0; i < NUM_SRC_TYPES; i++)
366
if (!strcmp(type_name, vm_mem_backing_src_alias(i)->name))
367
return i;
368
369
print_available_backing_src_types("");
370
TEST_FAIL("Unknown backing src type: %s", type_name);
371
return -1;
372
}
373
374
long get_run_delay(void)
375
{
376
char path[64];
377
long val[2];
378
FILE *fp;
379
380
sprintf(path, "/proc/%ld/schedstat", syscall(SYS_gettid));
381
fp = fopen(path, "r");
382
/* Return MIN_RUN_DELAY_NS upon failure just to be safe */
383
if (fscanf(fp, "%ld %ld ", &val[0], &val[1]) < 2)
384
val[1] = MIN_RUN_DELAY_NS;
385
fclose(fp);
386
387
return val[1];
388
}
389
390
int atoi_paranoid(const char *num_str)
391
{
392
char *end_ptr;
393
long num;
394
395
errno = 0;
396
num = strtol(num_str, &end_ptr, 0);
397
TEST_ASSERT(!errno, "strtol(\"%s\") failed", num_str);
398
TEST_ASSERT(num_str != end_ptr,
399
"strtol(\"%s\") didn't find a valid integer.", num_str);
400
TEST_ASSERT(*end_ptr == '\0',
401
"strtol(\"%s\") failed to parse trailing characters \"%s\".",
402
num_str, end_ptr);
403
TEST_ASSERT(num >= INT_MIN && num <= INT_MAX,
404
"%ld not in range of [%d, %d]", num, INT_MIN, INT_MAX);
405
406
return num;
407
}
408
409
char *strdup_printf(const char *fmt, ...)
410
{
411
va_list ap;
412
char *str;
413
414
va_start(ap, fmt);
415
TEST_ASSERT(vasprintf(&str, fmt, ap) >= 0, "vasprintf() failed");
416
va_end(ap);
417
418
return str;
419
}
420
421
#define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource"
422
423
char *sys_get_cur_clocksource(void)
424
{
425
char *clk_name;
426
struct stat st;
427
FILE *fp;
428
429
fp = fopen(CLOCKSOURCE_PATH, "r");
430
TEST_ASSERT(fp, "failed to open clocksource file, errno: %d", errno);
431
432
TEST_ASSERT(!fstat(fileno(fp), &st), "failed to stat clocksource file, errno: %d",
433
errno);
434
435
clk_name = malloc(st.st_size);
436
TEST_ASSERT(clk_name, "failed to allocate buffer to read file");
437
438
TEST_ASSERT(fgets(clk_name, st.st_size, fp), "failed to read clocksource file: %d",
439
ferror(fp));
440
441
fclose(fp);
442
443
return clk_name;
444
}
445
446