diff options
author | Sri Jayaramappa <sjayaram@akamai.com> | 2015-04-23 14:21:41 -0400 |
---|---|---|
committer | Shuah Khan <shuahkh@osg.samsung.com> | 2015-05-26 17:58:06 -0400 |
commit | bd67d5c15cc190f52eb2f2a2f6f6b800ca33d9dd (patch) | |
tree | a562c98b5e48e543e2c367a319e9af67524ec9b5 /tools/testing | |
parent | d0bd7f2ac785468ee99e24a0e7b37420e5a242e8 (diff) |
Test compaction of mlocked memory
Commit commit 5bbe3547aa3b ("mm: allow compaction of unevictable pages")
introduced a sysctl that allows userspace to enable scanning of locked
pages for compaction. This patch introduces a new test which fragments
main memory and attempts to allocate a number of huge pages to exercise
this compaction logic.
Tested on machines with up to 32 GB RAM. With the patch a much larger
number of huge pages can be allocated than on the kernel without the
patch.
Example output:
On a machine with 16 GB RAM:
sudo make run_tests vm
...
-----------------------
running compaction_test
-----------------------
No of huge pages allocated = 3834
[PASS]
...
Signed-off-by: Sri Jayaramappa <sjayaram@akamai.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-api@vger.kernel.org
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Eric B Munson <emunson@akamai.com>
Reviewed-by: Eric B Munson <emunson@akamai.com>
Acked-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
Diffstat (limited to 'tools/testing')
-rw-r--r-- | tools/testing/selftests/vm/Makefile | 7 | ||||
-rw-r--r-- | tools/testing/selftests/vm/compaction_test.c | 225 | ||||
-rwxr-xr-x | tools/testing/selftests/vm/run_vmtests | 12 |
3 files changed, 243 insertions, 1 deletions
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index a5ce9534eb15..231b9a031f6a 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile | |||
@@ -1,7 +1,12 @@ | |||
1 | # Makefile for vm selftests | 1 | # Makefile for vm selftests |
2 | 2 | ||
3 | CFLAGS = -Wall | 3 | CFLAGS = -Wall |
4 | BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest | 4 | BINARIES = compaction_test |
5 | BINARIES += hugepage-mmap | ||
6 | BINARIES += hugepage-shm | ||
7 | BINARIES += hugetlbfstest | ||
8 | BINARIES += map_hugetlb | ||
9 | BINARIES += thuge-gen | ||
5 | BINARIES += transhuge-stress | 10 | BINARIES += transhuge-stress |
6 | 11 | ||
7 | all: $(BINARIES) | 12 | all: $(BINARIES) |
diff --git a/tools/testing/selftests/vm/compaction_test.c b/tools/testing/selftests/vm/compaction_test.c new file mode 100644 index 000000000000..932ff577ffc0 --- /dev/null +++ b/tools/testing/selftests/vm/compaction_test.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * | ||
3 | * A test for the patch "Allow compaction of unevictable pages". | ||
4 | * With this patch we should be able to allocate at least 1/4 | ||
5 | * of RAM in huge pages. Without the patch much less is | ||
6 | * allocated. | ||
7 | */ | ||
8 | |||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <sys/mman.h> | ||
12 | #include <sys/resource.h> | ||
13 | #include <fcntl.h> | ||
14 | #include <errno.h> | ||
15 | #include <unistd.h> | ||
16 | #include <string.h> | ||
17 | |||
18 | #define MAP_SIZE 1048576 | ||
19 | |||
20 | struct map_list { | ||
21 | void *map; | ||
22 | struct map_list *next; | ||
23 | }; | ||
24 | |||
25 | int read_memory_info(unsigned long *memfree, unsigned long *hugepagesize) | ||
26 | { | ||
27 | char buffer[256] = {0}; | ||
28 | char *cmd = "cat /proc/meminfo | grep -i memfree | grep -o '[0-9]*'"; | ||
29 | FILE *cmdfile = popen(cmd, "r"); | ||
30 | |||
31 | if (!(fgets(buffer, sizeof(buffer), cmdfile))) { | ||
32 | perror("Failed to read meminfo\n"); | ||
33 | return -1; | ||
34 | } | ||
35 | |||
36 | pclose(cmdfile); | ||
37 | |||
38 | *memfree = atoll(buffer); | ||
39 | cmd = "cat /proc/meminfo | grep -i hugepagesize | grep -o '[0-9]*'"; | ||
40 | cmdfile = popen(cmd, "r"); | ||
41 | |||
42 | if (!(fgets(buffer, sizeof(buffer), cmdfile))) { | ||
43 | perror("Failed to read meminfo\n"); | ||
44 | return -1; | ||
45 | } | ||
46 | |||
47 | pclose(cmdfile); | ||
48 | *hugepagesize = atoll(buffer); | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | int prereq(void) | ||
54 | { | ||
55 | char allowed; | ||
56 | int fd; | ||
57 | |||
58 | fd = open("/proc/sys/vm/compact_unevictable_allowed", | ||
59 | O_RDONLY | O_NONBLOCK); | ||
60 | if (fd < 0) { | ||
61 | perror("Failed to open\n" | ||
62 | "/proc/sys/vm/compact_unevictable_allowed\n"); | ||
63 | return -1; | ||
64 | } | ||
65 | |||
66 | if (read(fd, &allowed, sizeof(char)) != sizeof(char)) { | ||
67 | perror("Failed to read from\n" | ||
68 | "/proc/sys/vm/compact_unevictable_allowed\n"); | ||
69 | close(fd); | ||
70 | return -1; | ||
71 | } | ||
72 | |||
73 | close(fd); | ||
74 | if (allowed == '1') | ||
75 | return 0; | ||
76 | |||
77 | return -1; | ||
78 | } | ||
79 | |||
80 | int check_compaction(unsigned long mem_free, unsigned int hugepage_size) | ||
81 | { | ||
82 | int fd; | ||
83 | int compaction_index = 0; | ||
84 | char initial_nr_hugepages[10] = {0}; | ||
85 | char nr_hugepages[10] = {0}; | ||
86 | |||
87 | /* We want to test with 80% of available memory. Else, OOM killer comes | ||
88 | in to play */ | ||
89 | mem_free = mem_free * 0.8; | ||
90 | |||
91 | fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK); | ||
92 | if (fd < 0) { | ||
93 | perror("Failed to open /proc/sys/vm/nr_hugepages"); | ||
94 | return -1; | ||
95 | } | ||
96 | |||
97 | if (read(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) <= 0) { | ||
98 | perror("Failed to read from /proc/sys/vm/nr_hugepages"); | ||
99 | goto close_fd; | ||
100 | } | ||
101 | |||
102 | /* Start with the initial condition of 0 huge pages*/ | ||
103 | if (write(fd, "0", sizeof(char)) != sizeof(char)) { | ||
104 | perror("Failed to write to /proc/sys/vm/nr_hugepages\n"); | ||
105 | goto close_fd; | ||
106 | } | ||
107 | |||
108 | lseek(fd, 0, SEEK_SET); | ||
109 | |||
110 | /* Request a large number of huge pages. The Kernel will allocate | ||
111 | as much as it can */ | ||
112 | if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { | ||
113 | perror("Failed to write to /proc/sys/vm/nr_hugepages\n"); | ||
114 | goto close_fd; | ||
115 | } | ||
116 | |||
117 | lseek(fd, 0, SEEK_SET); | ||
118 | |||
119 | if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) { | ||
120 | perror("Failed to read from /proc/sys/vm/nr_hugepages\n"); | ||
121 | goto close_fd; | ||
122 | } | ||
123 | |||
124 | /* We should have been able to request at least 1/3 rd of the memory in | ||
125 | huge pages */ | ||
126 | compaction_index = mem_free/(atoi(nr_hugepages) * hugepage_size); | ||
127 | |||
128 | if (compaction_index > 3) { | ||
129 | printf("No of huge pages allocated = %d\n", | ||
130 | (atoi(nr_hugepages))); | ||
131 | fprintf(stderr, "ERROR: Less that 1/%d of memory is available\n" | ||
132 | "as huge pages\n", compaction_index); | ||
133 | goto close_fd; | ||
134 | } | ||
135 | |||
136 | printf("No of huge pages allocated = %d\n", | ||
137 | (atoi(nr_hugepages))); | ||
138 | |||
139 | if (write(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) | ||
140 | != strlen(initial_nr_hugepages)) { | ||
141 | perror("Failed to write to /proc/sys/vm/nr_hugepages\n"); | ||
142 | goto close_fd; | ||
143 | } | ||
144 | |||
145 | close(fd); | ||
146 | return 0; | ||
147 | |||
148 | close_fd: | ||
149 | close(fd); | ||
150 | printf("Not OK. Compaction test failed."); | ||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | |||
155 | int main(int argc, char **argv) | ||
156 | { | ||
157 | struct rlimit lim; | ||
158 | struct map_list *list, *entry; | ||
159 | size_t page_size, i; | ||
160 | void *map = NULL; | ||
161 | unsigned long mem_free = 0; | ||
162 | unsigned long hugepage_size = 0; | ||
163 | unsigned long mem_fragmentable = 0; | ||
164 | |||
165 | if (prereq() != 0) { | ||
166 | printf("Either the sysctl compact_unevictable_allowed is not\n" | ||
167 | "set to 1 or couldn't read the proc file.\n" | ||
168 | "Skipping the test\n"); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | lim.rlim_cur = RLIM_INFINITY; | ||
173 | lim.rlim_max = RLIM_INFINITY; | ||
174 | if (setrlimit(RLIMIT_MEMLOCK, &lim)) { | ||
175 | perror("Failed to set rlimit:\n"); | ||
176 | return -1; | ||
177 | } | ||
178 | |||
179 | page_size = getpagesize(); | ||
180 | |||
181 | list = NULL; | ||
182 | |||
183 | if (read_memory_info(&mem_free, &hugepage_size) != 0) { | ||
184 | printf("ERROR: Cannot read meminfo\n"); | ||
185 | return -1; | ||
186 | } | ||
187 | |||
188 | mem_fragmentable = mem_free * 0.8 / 1024; | ||
189 | |||
190 | while (mem_fragmentable > 0) { | ||
191 | map = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, | ||
192 | MAP_ANONYMOUS | MAP_PRIVATE | MAP_LOCKED, -1, 0); | ||
193 | if (map == MAP_FAILED) | ||
194 | break; | ||
195 | |||
196 | entry = malloc(sizeof(struct map_list)); | ||
197 | if (!entry) { | ||
198 | munmap(map, MAP_SIZE); | ||
199 | break; | ||
200 | } | ||
201 | entry->map = map; | ||
202 | entry->next = list; | ||
203 | list = entry; | ||
204 | |||
205 | /* Write something (in this case the address of the map) to | ||
206 | * ensure that KSM can't merge the mapped pages | ||
207 | */ | ||
208 | for (i = 0; i < MAP_SIZE; i += page_size) | ||
209 | *(unsigned long *)(map + i) = (unsigned long)map + i; | ||
210 | |||
211 | mem_fragmentable--; | ||
212 | } | ||
213 | |||
214 | for (entry = list; entry != NULL; entry = entry->next) { | ||
215 | munmap(entry->map, MAP_SIZE); | ||
216 | if (!entry->next) | ||
217 | break; | ||
218 | entry = entry->next; | ||
219 | } | ||
220 | |||
221 | if (check_compaction(mem_free, hugepage_size) == 0) | ||
222 | return 0; | ||
223 | |||
224 | return -1; | ||
225 | } | ||
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index c87b6812300d..49ece11ff7fd 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests | |||
@@ -90,4 +90,16 @@ fi | |||
90 | umount $mnt | 90 | umount $mnt |
91 | rm -rf $mnt | 91 | rm -rf $mnt |
92 | echo $nr_hugepgs > /proc/sys/vm/nr_hugepages | 92 | echo $nr_hugepgs > /proc/sys/vm/nr_hugepages |
93 | |||
94 | echo "-----------------------" | ||
95 | echo "running compaction_test" | ||
96 | echo "-----------------------" | ||
97 | ./compaction_test | ||
98 | if [ $? -ne 0 ]; then | ||
99 | echo "[FAIL]" | ||
100 | exitcode=1 | ||
101 | else | ||
102 | echo "[PASS]" | ||
103 | fi | ||
104 | |||
93 | exit $exitcode | 105 | exit $exitcode |