~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mm/compaction_test.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  *
  4  * A test for the patch "Allow compaction of unevictable pages".
  5  * With this patch we should be able to allocate at least 1/4
  6  * of RAM in huge pages. Without the patch much less is
  7  * allocated.
  8  */
  9 
 10 #include <stdio.h>
 11 #include <stdlib.h>
 12 #include <sys/mman.h>
 13 #include <sys/resource.h>
 14 #include <fcntl.h>
 15 #include <errno.h>
 16 #include <unistd.h>
 17 #include <string.h>
 18 
 19 #include "../kselftest.h"
 20 
 21 #define MAP_SIZE_MB     100
 22 #define MAP_SIZE        (MAP_SIZE_MB * 1024 * 1024)
 23 
 24 struct map_list {
 25         void *map;
 26         struct map_list *next;
 27 };
 28 
 29 int read_memory_info(unsigned long *memfree, unsigned long *hugepagesize)
 30 {
 31         char  buffer[256] = {0};
 32         char *cmd = "cat /proc/meminfo | grep -i memfree | grep -o '[0-9]*'";
 33         FILE *cmdfile = popen(cmd, "r");
 34 
 35         if (!(fgets(buffer, sizeof(buffer), cmdfile))) {
 36                 ksft_print_msg("Failed to read meminfo: %s\n", strerror(errno));
 37                 return -1;
 38         }
 39 
 40         pclose(cmdfile);
 41 
 42         *memfree = atoll(buffer);
 43         cmd = "cat /proc/meminfo | grep -i hugepagesize | grep -o '[0-9]*'";
 44         cmdfile = popen(cmd, "r");
 45 
 46         if (!(fgets(buffer, sizeof(buffer), cmdfile))) {
 47                 ksft_print_msg("Failed to read meminfo: %s\n", strerror(errno));
 48                 return -1;
 49         }
 50 
 51         pclose(cmdfile);
 52         *hugepagesize = atoll(buffer);
 53 
 54         return 0;
 55 }
 56 
 57 int prereq(void)
 58 {
 59         char allowed;
 60         int fd;
 61 
 62         fd = open("/proc/sys/vm/compact_unevictable_allowed",
 63                   O_RDONLY | O_NONBLOCK);
 64         if (fd < 0) {
 65                 ksft_print_msg("Failed to open /proc/sys/vm/compact_unevictable_allowed: %s\n",
 66                                strerror(errno));
 67                 return -1;
 68         }
 69 
 70         if (read(fd, &allowed, sizeof(char)) != sizeof(char)) {
 71                 ksft_print_msg("Failed to read from /proc/sys/vm/compact_unevictable_allowed: %s\n",
 72                                strerror(errno));
 73                 close(fd);
 74                 return -1;
 75         }
 76 
 77         close(fd);
 78         if (allowed == '1')
 79                 return 0;
 80 
 81         ksft_print_msg("Compaction isn't allowed\n");
 82         return -1;
 83 }
 84 
 85 int check_compaction(unsigned long mem_free, unsigned long hugepage_size,
 86                      unsigned long initial_nr_hugepages)
 87 {
 88         unsigned long nr_hugepages_ul;
 89         int fd, ret = -1;
 90         int compaction_index = 0;
 91         char nr_hugepages[20] = {0};
 92         char init_nr_hugepages[20] = {0};
 93 
 94         sprintf(init_nr_hugepages, "%lu", initial_nr_hugepages);
 95 
 96         /* We want to test with 80% of available memory. Else, OOM killer comes
 97            in to play */
 98         mem_free = mem_free * 0.8;
 99 
100         fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK);
101         if (fd < 0) {
102                 ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n",
103                                strerror(errno));
104                 ret = -1;
105                 goto out;
106         }
107 
108         /* Request a large number of huge pages. The Kernel will allocate
109            as much as it can */
110         if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) {
111                 ksft_print_msg("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n",
112                                strerror(errno));
113                 goto close_fd;
114         }
115 
116         lseek(fd, 0, SEEK_SET);
117 
118         if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) {
119                 ksft_print_msg("Failed to re-read from /proc/sys/vm/nr_hugepages: %s\n",
120                                strerror(errno));
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         nr_hugepages_ul = strtoul(nr_hugepages, NULL, 10);
127         if (!nr_hugepages_ul) {
128                 ksft_print_msg("ERROR: No memory is available as huge pages\n");
129                 goto close_fd;
130         }
131         compaction_index = mem_free/(nr_hugepages_ul * hugepage_size);
132 
133         lseek(fd, 0, SEEK_SET);
134 
135         if (write(fd, init_nr_hugepages, strlen(init_nr_hugepages))
136             != strlen(init_nr_hugepages)) {
137                 ksft_print_msg("Failed to write value to /proc/sys/vm/nr_hugepages: %s\n",
138                                strerror(errno));
139                 goto close_fd;
140         }
141 
142         ksft_print_msg("Number of huge pages allocated = %lu\n",
143                        nr_hugepages_ul);
144 
145         if (compaction_index > 3) {
146                 ksft_print_msg("ERROR: Less than 1/%d of memory is available\n"
147                                "as huge pages\n", compaction_index);
148                 goto close_fd;
149         }
150 
151         ret = 0;
152 
153  close_fd:
154         close(fd);
155  out:
156         ksft_test_result(ret == 0, "check_compaction\n");
157         return ret;
158 }
159 
160 int set_zero_hugepages(unsigned long *initial_nr_hugepages)
161 {
162         int fd, ret = -1;
163         char nr_hugepages[20] = {0};
164 
165         fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK);
166         if (fd < 0) {
167                 ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n",
168                                strerror(errno));
169                 goto out;
170         }
171         if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) {
172                 ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n",
173                                strerror(errno));
174                 goto close_fd;
175         }
176 
177         lseek(fd, 0, SEEK_SET);
178 
179         /* Start with the initial condition of 0 huge pages */
180         if (write(fd, "", sizeof(char)) != sizeof(char)) {
181                 ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
182                                strerror(errno));
183                 goto close_fd;
184         }
185 
186         *initial_nr_hugepages = strtoul(nr_hugepages, NULL, 10);
187         ret = 0;
188 
189  close_fd:
190         close(fd);
191 
192  out:
193         return ret;
194 }
195 
196 int main(int argc, char **argv)
197 {
198         struct rlimit lim;
199         struct map_list *list = NULL, *entry;
200         size_t page_size, i;
201         void *map = NULL;
202         unsigned long mem_free = 0;
203         unsigned long hugepage_size = 0;
204         long mem_fragmentable_MB = 0;
205         unsigned long initial_nr_hugepages;
206 
207         ksft_print_header();
208 
209         if (prereq() || geteuid())
210                 ksft_exit_skip("Prerequisites unsatisfied\n");
211 
212         ksft_set_plan(1);
213 
214         /* Start the test without hugepages reducing mem_free */
215         if (set_zero_hugepages(&initial_nr_hugepages))
216                 ksft_exit_fail();
217 
218         lim.rlim_cur = RLIM_INFINITY;
219         lim.rlim_max = RLIM_INFINITY;
220         if (setrlimit(RLIMIT_MEMLOCK, &lim))
221                 ksft_exit_fail_msg("Failed to set rlimit: %s\n", strerror(errno));
222 
223         page_size = getpagesize();
224 
225         if (read_memory_info(&mem_free, &hugepage_size) != 0)
226                 ksft_exit_fail_msg("Failed to get meminfo\n");
227 
228         mem_fragmentable_MB = mem_free * 0.8 / 1024;
229 
230         while (mem_fragmentable_MB > 0) {
231                 map = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE,
232                            MAP_ANONYMOUS | MAP_PRIVATE | MAP_LOCKED, -1, 0);
233                 if (map == MAP_FAILED)
234                         break;
235 
236                 entry = malloc(sizeof(struct map_list));
237                 if (!entry) {
238                         munmap(map, MAP_SIZE);
239                         break;
240                 }
241                 entry->map = map;
242                 entry->next = list;
243                 list = entry;
244 
245                 /* Write something (in this case the address of the map) to
246                  * ensure that KSM can't merge the mapped pages
247                  */
248                 for (i = 0; i < MAP_SIZE; i += page_size)
249                         *(unsigned long *)(map + i) = (unsigned long)map + i;
250 
251                 mem_fragmentable_MB -= MAP_SIZE_MB;
252         }
253 
254         for (entry = list; entry != NULL; entry = entry->next) {
255                 munmap(entry->map, MAP_SIZE);
256                 if (!entry->next)
257                         break;
258                 entry = entry->next;
259         }
260 
261         if (check_compaction(mem_free, hugepage_size,
262                              initial_nr_hugepages) == 0)
263                 ksft_exit_pass();
264 
265         ksft_exit_fail();
266 }
267 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php