Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/cgroup/test_hugetlb_memcg.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
#define _GNU_SOURCE
3
4
#include <linux/limits.h>
5
#include <sys/mman.h>
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include <fcntl.h>
10
#include "../kselftest.h"
11
#include "cgroup_util.h"
12
13
#define ADDR ((void *)(0x0UL))
14
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
15
/* mapping 8 MBs == 4 hugepages */
16
#define LENGTH (8UL*1024*1024)
17
#define PROTECTION (PROT_READ | PROT_WRITE)
18
19
/* borrowed from mm/hmm-tests.c */
20
static long get_hugepage_size(void)
21
{
22
int fd;
23
char buf[2048];
24
int len;
25
char *p, *q, *path = "/proc/meminfo", *tag = "Hugepagesize:";
26
long val;
27
28
fd = open(path, O_RDONLY);
29
if (fd < 0) {
30
/* Error opening the file */
31
return -1;
32
}
33
34
len = read(fd, buf, sizeof(buf));
35
close(fd);
36
if (len < 0) {
37
/* Error in reading the file */
38
return -1;
39
}
40
if (len == sizeof(buf)) {
41
/* Error file is too large */
42
return -1;
43
}
44
buf[len] = '\0';
45
46
/* Search for a tag if provided */
47
if (tag) {
48
p = strstr(buf, tag);
49
if (!p)
50
return -1; /* looks like the line we want isn't there */
51
p += strlen(tag);
52
} else
53
p = buf;
54
55
val = strtol(p, &q, 0);
56
if (*q != ' ') {
57
/* Error parsing the file */
58
return -1;
59
}
60
61
return val;
62
}
63
64
static int set_file(const char *path, long value)
65
{
66
FILE *file;
67
int ret;
68
69
file = fopen(path, "w");
70
if (!file)
71
return -1;
72
ret = fprintf(file, "%ld\n", value);
73
fclose(file);
74
return ret;
75
}
76
77
static int set_nr_hugepages(long value)
78
{
79
return set_file("/proc/sys/vm/nr_hugepages", value);
80
}
81
82
static unsigned int check_first(char *addr)
83
{
84
return *(unsigned int *)addr;
85
}
86
87
static void write_data(char *addr)
88
{
89
unsigned long i;
90
91
for (i = 0; i < LENGTH; i++)
92
*(addr + i) = (char)i;
93
}
94
95
static int hugetlb_test_program(const char *cgroup, void *arg)
96
{
97
char *test_group = (char *)arg;
98
void *addr;
99
long old_current, expected_current, current;
100
int ret = EXIT_FAILURE;
101
102
old_current = cg_read_long(test_group, "memory.current");
103
set_nr_hugepages(20);
104
current = cg_read_long(test_group, "memory.current");
105
if (current - old_current >= MB(2)) {
106
ksft_print_msg(
107
"setting nr_hugepages should not increase hugepage usage.\n");
108
ksft_print_msg("before: %ld, after: %ld\n", old_current, current);
109
return EXIT_FAILURE;
110
}
111
112
addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
113
if (addr == MAP_FAILED) {
114
ksft_print_msg("fail to mmap.\n");
115
return EXIT_FAILURE;
116
}
117
current = cg_read_long(test_group, "memory.current");
118
if (current - old_current >= MB(2)) {
119
ksft_print_msg("mmap should not increase hugepage usage.\n");
120
ksft_print_msg("before: %ld, after: %ld\n", old_current, current);
121
goto out_failed_munmap;
122
}
123
old_current = current;
124
125
/* read the first page */
126
check_first(addr);
127
expected_current = old_current + MB(2);
128
current = cg_read_long(test_group, "memory.current");
129
if (!values_close(expected_current, current, 5)) {
130
ksft_print_msg("memory usage should increase by around 2MB.\n");
131
ksft_print_msg(
132
"expected memory: %ld, actual memory: %ld\n",
133
expected_current, current);
134
goto out_failed_munmap;
135
}
136
137
/* write to the whole range */
138
write_data(addr);
139
current = cg_read_long(test_group, "memory.current");
140
expected_current = old_current + MB(8);
141
if (!values_close(expected_current, current, 5)) {
142
ksft_print_msg("memory usage should increase by around 8MB.\n");
143
ksft_print_msg(
144
"expected memory: %ld, actual memory: %ld\n",
145
expected_current, current);
146
goto out_failed_munmap;
147
}
148
149
/* unmap the whole range */
150
munmap(addr, LENGTH);
151
current = cg_read_long(test_group, "memory.current");
152
expected_current = old_current;
153
if (!values_close(expected_current, current, 5)) {
154
ksft_print_msg("memory usage should go back down.\n");
155
ksft_print_msg(
156
"expected memory: %ld, actual memory: %ld\n",
157
expected_current, current);
158
return ret;
159
}
160
161
ret = EXIT_SUCCESS;
162
return ret;
163
164
out_failed_munmap:
165
munmap(addr, LENGTH);
166
return ret;
167
}
168
169
static int test_hugetlb_memcg(char *root)
170
{
171
int ret = KSFT_FAIL;
172
char *test_group;
173
174
test_group = cg_name(root, "hugetlb_memcg_test");
175
if (!test_group || cg_create(test_group)) {
176
ksft_print_msg("fail to create cgroup.\n");
177
goto out;
178
}
179
180
if (cg_write(test_group, "memory.max", "100M")) {
181
ksft_print_msg("fail to set cgroup memory limit.\n");
182
goto out;
183
}
184
185
/* disable swap */
186
if (cg_write(test_group, "memory.swap.max", "0")) {
187
ksft_print_msg("fail to disable swap.\n");
188
goto out;
189
}
190
191
if (!cg_run(test_group, hugetlb_test_program, (void *)test_group))
192
ret = KSFT_PASS;
193
out:
194
cg_destroy(test_group);
195
free(test_group);
196
return ret;
197
}
198
199
int main(int argc, char **argv)
200
{
201
char root[PATH_MAX];
202
int ret = EXIT_SUCCESS, has_memory_hugetlb_acc;
203
204
has_memory_hugetlb_acc = proc_mount_contains("memory_hugetlb_accounting");
205
if (has_memory_hugetlb_acc < 0)
206
ksft_exit_skip("Failed to query cgroup mount option\n");
207
else if (!has_memory_hugetlb_acc)
208
ksft_exit_skip("memory hugetlb accounting is disabled\n");
209
210
/* Unit is kB! */
211
if (get_hugepage_size() != 2048) {
212
ksft_print_msg("test_hugetlb_memcg requires 2MB hugepages\n");
213
ksft_test_result_skip("test_hugetlb_memcg\n");
214
return ret;
215
}
216
217
if (cg_find_unified_root(root, sizeof(root), NULL))
218
ksft_exit_skip("cgroup v2 isn't mounted\n");
219
220
switch (test_hugetlb_memcg(root)) {
221
case KSFT_PASS:
222
ksft_test_result_pass("test_hugetlb_memcg\n");
223
break;
224
case KSFT_SKIP:
225
ksft_test_result_skip("test_hugetlb_memcg\n");
226
break;
227
default:
228
ret = EXIT_FAILURE;
229
ksft_test_result_fail("test_hugetlb_memcg\n");
230
break;
231
}
232
233
return ret;
234
}
235
236