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

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mm/thuge-gen.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ 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 /* Test selecting other page sizes for mmap/shmget.
  3 
  4    Before running this huge pages for each huge page size must have been
  5    reserved.
  6    For large pages beyond MAX_PAGE_ORDER (like 1GB on x86) boot options must
  7    be used. 1GB wouldn't be tested if it isn't available.
  8    Also shmmax must be increased.
  9    And you need to run as root to work around some weird permissions in shm.
 10    And nothing using huge pages should run in parallel.
 11    When the program aborts you may need to clean up the shm segments with
 12    ipcrm -m by hand, like this
 13    sudo ipcs | awk '$1 == "0x00000000" {print $2}' | xargs -n1 sudo ipcrm -m
 14    (warning this will remove all if someone else uses them) */
 15 
 16 #define _GNU_SOURCE
 17 #include <sys/mman.h>
 18 #include <linux/mman.h>
 19 #include <stdlib.h>
 20 #include <stdio.h>
 21 #include <sys/ipc.h>
 22 #include <sys/shm.h>
 23 #include <sys/stat.h>
 24 #include <glob.h>
 25 #include <assert.h>
 26 #include <unistd.h>
 27 #include <stdarg.h>
 28 #include <string.h>
 29 #include "vm_util.h"
 30 #include "../kselftest.h"
 31 
 32 #if !defined(MAP_HUGETLB)
 33 #define MAP_HUGETLB     0x40000
 34 #endif
 35 
 36 #define SHM_HUGETLB     04000   /* segment will use huge TLB pages */
 37 #ifndef SHM_HUGE_SHIFT
 38 #define SHM_HUGE_SHIFT  26
 39 #endif
 40 #ifndef SHM_HUGE_MASK
 41 #define SHM_HUGE_MASK   0x3f
 42 #endif
 43 #ifndef SHM_HUGE_2MB
 44 #define SHM_HUGE_2MB    (21 << SHM_HUGE_SHIFT)
 45 #endif
 46 #ifndef SHM_HUGE_1GB
 47 #define SHM_HUGE_1GB    (30 << SHM_HUGE_SHIFT)
 48 #endif
 49 
 50 #define NUM_PAGESIZES   5
 51 #define NUM_PAGES 4
 52 
 53 unsigned long page_sizes[NUM_PAGESIZES];
 54 int num_page_sizes;
 55 
 56 int ilog2(unsigned long v)
 57 {
 58         int l = 0;
 59         while ((1UL << l) < v)
 60                 l++;
 61         return l;
 62 }
 63 
 64 void show(unsigned long ps)
 65 {
 66         char buf[100];
 67 
 68         if (ps == getpagesize())
 69                 return;
 70 
 71         ksft_print_msg("%luMB: ", ps >> 20);
 72 
 73         fflush(stdout);
 74         snprintf(buf, sizeof buf,
 75                 "cat /sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
 76                 ps >> 10);
 77         system(buf);
 78 }
 79 
 80 unsigned long read_sysfs(int warn, char *fmt, ...)
 81 {
 82         char *line = NULL;
 83         size_t linelen = 0;
 84         char buf[100];
 85         FILE *f;
 86         va_list ap;
 87         unsigned long val = 0;
 88 
 89         va_start(ap, fmt);
 90         vsnprintf(buf, sizeof buf, fmt, ap);
 91         va_end(ap);
 92 
 93         f = fopen(buf, "r");
 94         if (!f) {
 95                 if (warn)
 96                         ksft_print_msg("missing %s\n", buf);
 97                 return 0;
 98         }
 99         if (getline(&line, &linelen, f) > 0) {
100                 sscanf(line, "%lu", &val);
101         }
102         fclose(f);
103         free(line);
104         return val;
105 }
106 
107 unsigned long read_free(unsigned long ps)
108 {
109         return read_sysfs(ps != getpagesize(),
110                           "/sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
111                           ps >> 10);
112 }
113 
114 void test_mmap(unsigned long size, unsigned flags)
115 {
116         char *map;
117         unsigned long before, after;
118 
119         before = read_free(size);
120         map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE,
121                         MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, -1, 0);
122         if (map == MAP_FAILED)
123                 ksft_exit_fail_msg("mmap: %s\n", strerror(errno));
124 
125         memset(map, 0xff, size*NUM_PAGES);
126         after = read_free(size);
127 
128         show(size);
129         ksft_test_result(size == getpagesize() || (before - after) == NUM_PAGES,
130                          "%s mmap\n", __func__);
131 
132         if (munmap(map, size * NUM_PAGES))
133                 ksft_exit_fail_msg("%s: unmap %s\n", __func__, strerror(errno));
134 }
135 
136 void test_shmget(unsigned long size, unsigned flags)
137 {
138         int id;
139         unsigned long before, after;
140         struct shm_info i;
141         char *map;
142 
143         before = read_free(size);
144         id = shmget(IPC_PRIVATE, size * NUM_PAGES, IPC_CREAT|0600|flags);
145         if (id < 0) {
146                 if (errno == EPERM) {
147                         ksft_test_result_skip("shmget requires root privileges: %s\n",
148                                               strerror(errno));
149                         return;
150                 }
151                 ksft_exit_fail_msg("shmget: %s\n", strerror(errno));
152         }
153 
154         if (shmctl(id, SHM_INFO, (void *)&i) < 0)
155                 ksft_exit_fail_msg("shmctl: %s\n", strerror(errno));
156 
157         map = shmat(id, NULL, 0600);
158         if (map == MAP_FAILED)
159                 ksft_exit_fail_msg("shmat: %s\n", strerror(errno));
160 
161         shmctl(id, IPC_RMID, NULL);
162 
163         memset(map, 0xff, size*NUM_PAGES);
164         after = read_free(size);
165 
166         show(size);
167         ksft_test_result(size == getpagesize() || (before - after) == NUM_PAGES,
168                          "%s: mmap\n", __func__);
169         if (shmdt(map))
170                 ksft_exit_fail_msg("%s: shmdt: %s\n", __func__, strerror(errno));
171 }
172 
173 void find_pagesizes(void)
174 {
175         unsigned long largest = getpagesize();
176         int i;
177         glob_t g;
178 
179         glob("/sys/kernel/mm/hugepages/hugepages-*kB", 0, NULL, &g);
180         assert(g.gl_pathc <= NUM_PAGESIZES);
181         for (i = 0; (i < g.gl_pathc) && (num_page_sizes < NUM_PAGESIZES); i++) {
182                 sscanf(g.gl_pathv[i], "/sys/kernel/mm/hugepages/hugepages-%lukB",
183                                 &page_sizes[num_page_sizes]);
184                 page_sizes[num_page_sizes] <<= 10;
185                 ksft_print_msg("Found %luMB\n", page_sizes[i] >> 20);
186 
187                 if (page_sizes[num_page_sizes] > largest)
188                         largest = page_sizes[i];
189 
190                 if (read_free(page_sizes[num_page_sizes]) >= NUM_PAGES)
191                         num_page_sizes++;
192                 else
193                         ksft_print_msg("SKIP for size %lu MB as not enough huge pages, need %u\n",
194                                        page_sizes[num_page_sizes] >> 20, NUM_PAGES);
195         }
196         globfree(&g);
197 
198         if (read_sysfs(0, "/proc/sys/kernel/shmmax") < NUM_PAGES * largest)
199                 ksft_exit_fail_msg("Please do echo %lu > /proc/sys/kernel/shmmax",
200                                    largest * NUM_PAGES);
201 
202 #if defined(__x86_64__)
203         if (largest != 1U<<30) {
204                 ksft_exit_fail_msg("No GB pages available on x86-64\n"
205                                    "Please boot with hugepagesz=1G hugepages=%d\n", NUM_PAGES);
206         }
207 #endif
208 }
209 
210 int main(void)
211 {
212         unsigned default_hps = default_huge_page_size();
213         int i;
214 
215         ksft_print_header();
216 
217         find_pagesizes();
218 
219         if (!num_page_sizes)
220                 ksft_finished();
221 
222         ksft_set_plan(2 * num_page_sizes + 3);
223 
224         for (i = 0; i < num_page_sizes; i++) {
225                 unsigned long ps = page_sizes[i];
226                 int arg = ilog2(ps) << MAP_HUGE_SHIFT;
227 
228                 ksft_print_msg("Testing %luMB mmap with shift %x\n", ps >> 20, arg);
229                 test_mmap(ps, MAP_HUGETLB | arg);
230         }
231 
232         ksft_print_msg("Testing default huge mmap\n");
233         test_mmap(default_hps, MAP_HUGETLB);
234 
235         ksft_print_msg("Testing non-huge shmget\n");
236         test_shmget(getpagesize(), 0);
237 
238         for (i = 0; i < num_page_sizes; i++) {
239                 unsigned long ps = page_sizes[i];
240                 int arg = ilog2(ps) << SHM_HUGE_SHIFT;
241                 ksft_print_msg("Testing %luMB shmget with shift %x\n", ps >> 20, arg);
242                 test_shmget(ps, SHM_HUGETLB | arg);
243         }
244 
245         ksft_print_msg("default huge shmget\n");
246         test_shmget(default_hps, SHM_HUGETLB);
247 
248         ksft_finished();
249 }
250 

~ [ 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