1 | /* |
2 | * Stress test for transparent huge pages, memory compaction and migration. |
3 | * |
4 | * Authors: Konstantin Khlebnikov <koct9i@gmail.com> |
5 | * |
6 | * This is free and unencumbered software released into the public domain. |
7 | */ |
8 | |
9 | #include <stdlib.h> |
10 | #include <stdio.h> |
11 | #include <stdint.h> |
12 | #include <err.h> |
13 | #include <time.h> |
14 | #include <unistd.h> |
15 | #include <fcntl.h> |
16 | #include <string.h> |
17 | #include <sys/mman.h> |
18 | #include "vm_util.h" |
19 | #include "../kselftest.h" |
20 | |
21 | int backing_fd = -1; |
22 | int mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE; |
23 | #define PROT_RW (PROT_READ | PROT_WRITE) |
24 | |
25 | int main(int argc, char **argv) |
26 | { |
27 | size_t ram, len; |
28 | void *ptr, *p; |
29 | struct timespec start, a, b; |
30 | int i = 0; |
31 | char *name = NULL; |
32 | double s; |
33 | uint8_t *map; |
34 | size_t map_len; |
35 | int pagemap_fd; |
36 | int duration = 0; |
37 | |
38 | ksft_print_header(); |
39 | |
40 | ram = sysconf(_SC_PHYS_PAGES); |
41 | if (ram > SIZE_MAX / psize() / 4) |
42 | ram = SIZE_MAX / 4; |
43 | else |
44 | ram *= psize(); |
45 | len = ram; |
46 | |
47 | while (++i < argc) { |
48 | if (!strcmp(argv[i], "-h" )) |
49 | ksft_exit_fail_msg(msg: "usage: %s [-f <filename>] [-d <duration>] [size in MiB]\n" , |
50 | argv[0]); |
51 | else if (!strcmp(argv[i], "-f" )) |
52 | name = argv[++i]; |
53 | else if (!strcmp(argv[i], "-d" )) |
54 | duration = atoi(argv[++i]); |
55 | else |
56 | len = atoll(argv[i]) << 20; |
57 | } |
58 | |
59 | ksft_set_plan(plan: 1); |
60 | |
61 | if (name) { |
62 | backing_fd = open(name, O_RDWR); |
63 | if (backing_fd == -1) |
64 | ksft_exit_fail_msg(msg: "open %s\n" , name); |
65 | mmap_flags = MAP_SHARED; |
66 | } |
67 | |
68 | warnx("allocate %zd transhuge pages, using %zd MiB virtual memory" |
69 | " and %zd MiB of ram" , len >> HPAGE_SHIFT, len >> 20, |
70 | ram >> (20 + HPAGE_SHIFT - pshift() - 1)); |
71 | |
72 | pagemap_fd = open("/proc/self/pagemap" , O_RDONLY); |
73 | if (pagemap_fd < 0) |
74 | ksft_exit_fail_msg(msg: "open pagemap\n" ); |
75 | |
76 | len -= len % HPAGE_SIZE; |
77 | ptr = mmap(NULL, len + HPAGE_SIZE, PROT_RW, mmap_flags, backing_fd, 0); |
78 | if (ptr == MAP_FAILED) |
79 | ksft_exit_fail_msg(msg: "initial mmap" ); |
80 | ptr += HPAGE_SIZE - (uintptr_t)ptr % HPAGE_SIZE; |
81 | |
82 | if (madvise(ptr, len, MADV_HUGEPAGE)) |
83 | ksft_exit_fail_msg(msg: "MADV_HUGEPAGE" ); |
84 | |
85 | map_len = ram >> (HPAGE_SHIFT - 1); |
86 | map = malloc(map_len); |
87 | if (!map) |
88 | ksft_exit_fail_msg(msg: "map malloc\n" ); |
89 | |
90 | clock_gettime(CLOCK_MONOTONIC, &start); |
91 | |
92 | while (1) { |
93 | int nr_succeed = 0, nr_failed = 0, nr_pages = 0; |
94 | |
95 | memset(map, 0, map_len); |
96 | |
97 | clock_gettime(CLOCK_MONOTONIC, &a); |
98 | for (p = ptr; p < ptr + len; p += HPAGE_SIZE) { |
99 | int64_t pfn; |
100 | |
101 | pfn = allocate_transhuge(p, pagemap_fd); |
102 | |
103 | if (pfn < 0) { |
104 | nr_failed++; |
105 | } else { |
106 | size_t idx = pfn >> (HPAGE_SHIFT - pshift()); |
107 | |
108 | nr_succeed++; |
109 | if (idx >= map_len) { |
110 | map = realloc(map, idx + 1); |
111 | if (!map) |
112 | ksft_exit_fail_msg("map realloc\n" ); |
113 | memset(map + map_len, 0, idx + 1 - map_len); |
114 | map_len = idx + 1; |
115 | } |
116 | if (!map[idx]) |
117 | nr_pages++; |
118 | map[idx] = 1; |
119 | } |
120 | |
121 | /* split transhuge page, keep last page */ |
122 | if (madvise(p, HPAGE_SIZE - psize(), MADV_DONTNEED)) |
123 | ksft_exit_fail_msg("MADV_DONTNEED" ); |
124 | } |
125 | clock_gettime(CLOCK_MONOTONIC, &b); |
126 | s = b.tv_sec - a.tv_sec + (b.tv_nsec - a.tv_nsec) / 1000000000.; |
127 | |
128 | ksft_print_msg("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t" |
129 | "%4d succeed, %4d failed, %4d different pages\n" , |
130 | s, s * 1000 / (len >> HPAGE_SHIFT), len / s / (1 << 20), |
131 | nr_succeed, nr_failed, nr_pages); |
132 | |
133 | if (duration > 0 && b.tv_sec - start.tv_sec >= duration) { |
134 | ksft_test_result_pass(msg: "Completed\n" ); |
135 | ksft_finished(); |
136 | } |
137 | } |
138 | } |
139 | |