Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/mm/thp_swap_allocator_test.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* thp_swap_allocator_test
4
*
5
* The purpose of this test program is helping check if THP swpout
6
* can correctly get swap slots to swap out as a whole instead of
7
* being split. It randomly releases swap entries through madvise
8
* DONTNEED and swapin/out on two memory areas: a memory area for
9
* 64KB THP and the other area for small folios. The second memory
10
* can be enabled by "-s".
11
* Before running the program, we need to setup a zRAM or similar
12
* swap device by:
13
* echo lzo > /sys/block/zram0/comp_algorithm
14
* echo 64M > /sys/block/zram0/disksize
15
* echo never > /sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled
16
* echo always > /sys/kernel/mm/transparent_hugepage/hugepages-64kB/enabled
17
* mkswap /dev/zram0
18
* swapon /dev/zram0
19
* The expected result should be 0% anon swpout fallback ratio w/ or
20
* w/o "-s".
21
*
22
* Author(s): Barry Song <[email protected]>
23
*/
24
25
#define _GNU_SOURCE
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <unistd.h>
29
#include <string.h>
30
#include <linux/mman.h>
31
#include <sys/mman.h>
32
#include <errno.h>
33
#include <time.h>
34
35
#define MEMSIZE_MTHP (60 * 1024 * 1024)
36
#define MEMSIZE_SMALLFOLIO (4 * 1024 * 1024)
37
#define ALIGNMENT_MTHP (64 * 1024)
38
#define ALIGNMENT_SMALLFOLIO (4 * 1024)
39
#define TOTAL_DONTNEED_MTHP (16 * 1024 * 1024)
40
#define TOTAL_DONTNEED_SMALLFOLIO (1 * 1024 * 1024)
41
#define MTHP_FOLIO_SIZE (64 * 1024)
42
43
#define SWPOUT_PATH \
44
"/sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/swpout"
45
#define SWPOUT_FALLBACK_PATH \
46
"/sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/swpout_fallback"
47
48
static void *aligned_alloc_mem(size_t size, size_t alignment)
49
{
50
void *mem = NULL;
51
52
if (posix_memalign(&mem, alignment, size) != 0) {
53
perror("posix_memalign");
54
return NULL;
55
}
56
return mem;
57
}
58
59
/*
60
* This emulates the behavior of native libc and Java heap,
61
* as well as process exit and munmap. It helps generate mTHP
62
* and ensures that iterations can proceed with mTHP, as we
63
* currently don't support large folios swap-in.
64
*/
65
static void random_madvise_dontneed(void *mem, size_t mem_size,
66
size_t align_size, size_t total_dontneed_size)
67
{
68
size_t num_pages = total_dontneed_size / align_size;
69
size_t i;
70
size_t offset;
71
void *addr;
72
73
for (i = 0; i < num_pages; ++i) {
74
offset = (rand() % (mem_size / align_size)) * align_size;
75
addr = (char *)mem + offset;
76
if (madvise(addr, align_size, MADV_DONTNEED) != 0)
77
perror("madvise dontneed");
78
79
memset(addr, 0x11, align_size);
80
}
81
}
82
83
static void random_swapin(void *mem, size_t mem_size,
84
size_t align_size, size_t total_swapin_size)
85
{
86
size_t num_pages = total_swapin_size / align_size;
87
size_t i;
88
size_t offset;
89
void *addr;
90
91
for (i = 0; i < num_pages; ++i) {
92
offset = (rand() % (mem_size / align_size)) * align_size;
93
addr = (char *)mem + offset;
94
memset(addr, 0x11, align_size);
95
}
96
}
97
98
static unsigned long read_stat(const char *path)
99
{
100
FILE *file;
101
unsigned long value;
102
103
file = fopen(path, "r");
104
if (!file) {
105
perror("fopen");
106
return 0;
107
}
108
109
if (fscanf(file, "%lu", &value) != 1) {
110
perror("fscanf");
111
fclose(file);
112
return 0;
113
}
114
115
fclose(file);
116
return value;
117
}
118
119
int main(int argc, char *argv[])
120
{
121
int use_small_folio = 0, aligned_swapin = 0;
122
void *mem1 = NULL, *mem2 = NULL;
123
int i;
124
125
for (i = 1; i < argc; ++i) {
126
if (strcmp(argv[i], "-s") == 0)
127
use_small_folio = 1;
128
else if (strcmp(argv[i], "-a") == 0)
129
aligned_swapin = 1;
130
}
131
132
mem1 = aligned_alloc_mem(MEMSIZE_MTHP, ALIGNMENT_MTHP);
133
if (mem1 == NULL) {
134
fprintf(stderr, "Failed to allocate large folios memory\n");
135
return EXIT_FAILURE;
136
}
137
138
if (madvise(mem1, MEMSIZE_MTHP, MADV_HUGEPAGE) != 0) {
139
perror("madvise hugepage for mem1");
140
free(mem1);
141
return EXIT_FAILURE;
142
}
143
144
if (use_small_folio) {
145
mem2 = aligned_alloc_mem(MEMSIZE_SMALLFOLIO, ALIGNMENT_MTHP);
146
if (mem2 == NULL) {
147
fprintf(stderr, "Failed to allocate small folios memory\n");
148
free(mem1);
149
return EXIT_FAILURE;
150
}
151
152
if (madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_NOHUGEPAGE) != 0) {
153
perror("madvise nohugepage for mem2");
154
free(mem1);
155
free(mem2);
156
return EXIT_FAILURE;
157
}
158
}
159
160
/* warm-up phase to occupy the swapfile */
161
memset(mem1, 0x11, MEMSIZE_MTHP);
162
madvise(mem1, MEMSIZE_MTHP, MADV_PAGEOUT);
163
if (use_small_folio) {
164
memset(mem2, 0x11, MEMSIZE_SMALLFOLIO);
165
madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_PAGEOUT);
166
}
167
168
/* iterations with newly created mTHP, swap-in, and swap-out */
169
for (i = 0; i < 100; ++i) {
170
unsigned long initial_swpout;
171
unsigned long initial_swpout_fallback;
172
unsigned long final_swpout;
173
unsigned long final_swpout_fallback;
174
unsigned long swpout_inc;
175
unsigned long swpout_fallback_inc;
176
double fallback_percentage;
177
178
initial_swpout = read_stat(SWPOUT_PATH);
179
initial_swpout_fallback = read_stat(SWPOUT_FALLBACK_PATH);
180
181
/*
182
* The following setup creates a 1:1 ratio of mTHP to small folios
183
* since large folio swap-in isn't supported yet. Once we support
184
* mTHP swap-in, we'll likely need to reduce MEMSIZE_MTHP and
185
* increase MEMSIZE_SMALLFOLIO to maintain the ratio.
186
*/
187
random_swapin(mem1, MEMSIZE_MTHP,
188
aligned_swapin ? ALIGNMENT_MTHP : ALIGNMENT_SMALLFOLIO,
189
TOTAL_DONTNEED_MTHP);
190
random_madvise_dontneed(mem1, MEMSIZE_MTHP, ALIGNMENT_MTHP,
191
TOTAL_DONTNEED_MTHP);
192
193
if (use_small_folio) {
194
random_swapin(mem2, MEMSIZE_SMALLFOLIO,
195
ALIGNMENT_SMALLFOLIO,
196
TOTAL_DONTNEED_SMALLFOLIO);
197
}
198
199
if (madvise(mem1, MEMSIZE_MTHP, MADV_PAGEOUT) != 0) {
200
perror("madvise pageout for mem1");
201
free(mem1);
202
if (mem2 != NULL)
203
free(mem2);
204
return EXIT_FAILURE;
205
}
206
207
if (use_small_folio) {
208
if (madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_PAGEOUT) != 0) {
209
perror("madvise pageout for mem2");
210
free(mem1);
211
free(mem2);
212
return EXIT_FAILURE;
213
}
214
}
215
216
final_swpout = read_stat(SWPOUT_PATH);
217
final_swpout_fallback = read_stat(SWPOUT_FALLBACK_PATH);
218
219
swpout_inc = final_swpout - initial_swpout;
220
swpout_fallback_inc = final_swpout_fallback - initial_swpout_fallback;
221
222
fallback_percentage = (double)swpout_fallback_inc /
223
(swpout_fallback_inc + swpout_inc) * 100;
224
225
printf("Iteration %d: swpout inc: %lu, swpout fallback inc: %lu, Fallback percentage: %.2f%%\n",
226
i + 1, swpout_inc, swpout_fallback_inc, fallback_percentage);
227
}
228
229
free(mem1);
230
if (mem2 != NULL)
231
free(mem2);
232
233
return EXIT_SUCCESS;
234
}
235
236