File Index
Files and directories
Sign in
FILE

thuge-gen.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/mm/thuge-gen.c C
  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
 53unsigned long page_sizes[NUM_PAGESIZES];
 54int num_page_sizes;
 55
 56int ilog2(unsigned long v)
 57{
 58	int l = 0;
 59	while ((1UL << l) < v)
 60		l++;
 61	return l;
 62}
 63
 64void 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
 80unsigned long read_free(unsigned long ps)
 81{
 82	unsigned long val = 0;
 83	char buf[100];
 84
 85	snprintf(buf, sizeof(buf),
 86		 "/sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
 87		 ps >> 10);
 88	if (read_sysfs(buf, &val) && ps != getpagesize())
 89		ksft_print_msg("missing %s\n", buf);
 90
 91	return val;
 92}
 93
 94void test_mmap(unsigned long size, unsigned flags)
 95{
 96	char *map;
 97	unsigned long before, after;
 98
 99	before = read_free(size);
100	map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE,
101			MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, -1, 0);
102	if (map == MAP_FAILED)
103		ksft_exit_fail_msg("mmap: %s\n", strerror(errno));
104
105	memset(map, 0xff, size*NUM_PAGES);
106	after = read_free(size);
107
108	show(size);
109	ksft_test_result(size == getpagesize() || (before - after) == NUM_PAGES,
110			 "%s mmap %lu %x\n", __func__, size, flags);
111
112	if (munmap(map, size * NUM_PAGES))
113		ksft_exit_fail_msg("%s: unmap %s\n", __func__, strerror(errno));
114}
115
116void test_shmget(unsigned long size, unsigned flags)
117{
118	int id;
119	unsigned long before, after;
120	struct shm_info i;
121	char *map;
122
123	before = read_free(size);
124	id = shmget(IPC_PRIVATE, size * NUM_PAGES, IPC_CREAT|0600|flags);
125	if (id < 0) {
126		if (errno == EPERM) {
127			ksft_test_result_skip("shmget requires root privileges: %s\n",
128					      strerror(errno));
129			return;
130		}
131		ksft_exit_fail_msg("shmget: %s\n", strerror(errno));
132	}
133
134	if (shmctl(id, SHM_INFO, (void *)&i) < 0)
135		ksft_exit_fail_msg("shmctl: %s\n", strerror(errno));
136
137	map = shmat(id, NULL, 0600);
138	if (map == MAP_FAILED)
139		ksft_exit_fail_msg("shmat: %s\n", strerror(errno));
140
141	shmctl(id, IPC_RMID, NULL);
142
143	memset(map, 0xff, size*NUM_PAGES);
144	after = read_free(size);
145
146	show(size);
147	ksft_test_result(size == getpagesize() || (before - after) == NUM_PAGES,
148			 "%s: mmap %lu %x\n", __func__, size, flags);
149	if (shmdt(map))
150		ksft_exit_fail_msg("%s: shmdt: %s\n", __func__, strerror(errno));
151}
152
153void find_pagesizes(void)
154{
155	unsigned long largest = getpagesize();
156	unsigned long shmmax_val = 0;
157	int i;
158	glob_t g;
159
160	glob("/sys/kernel/mm/hugepages/hugepages-*kB", 0, NULL, &g);
161	assert(g.gl_pathc <= NUM_PAGESIZES);
162	for (i = 0; (i < g.gl_pathc) && (num_page_sizes < NUM_PAGESIZES); i++) {
163		sscanf(g.gl_pathv[i], "/sys/kernel/mm/hugepages/hugepages-%lukB",
164				&page_sizes[num_page_sizes]);
165		page_sizes[num_page_sizes] <<= 10;
166		ksft_print_msg("Found %luMB\n", page_sizes[i] >> 20);
167
168		if (page_sizes[num_page_sizes] > largest)
169			largest = page_sizes[i];
170
171		if (read_free(page_sizes[num_page_sizes]) >= NUM_PAGES)
172			num_page_sizes++;
173		else
174			ksft_print_msg("SKIP for size %lu MB as not enough huge pages, need %u\n",
175				       page_sizes[num_page_sizes] >> 20, NUM_PAGES);
176	}
177	globfree(&g);
178
179	read_sysfs("/proc/sys/kernel/shmmax", &shmmax_val);
180	if (shmmax_val < NUM_PAGES * largest) {
181		ksft_print_msg("WARNING: shmmax is too small to run this test.\n");
182		ksft_print_msg("Please run the following command to increase shmmax:\n");
183		ksft_print_msg("echo %lu > /proc/sys/kernel/shmmax\n", largest * NUM_PAGES);
184		ksft_exit_skip("Test skipped due to insufficient shmmax value.\n");
185	}
186
187#if defined(__x86_64__)
188	if (largest != 1U<<30) {
189		ksft_exit_skip("No GB pages available on x86-64\n"
190				   "Please boot with hugepagesz=1G hugepages=%d\n", NUM_PAGES);
191	}
192#endif
193}
194
195int main(void)
196{
197	unsigned default_hps = default_huge_page_size();
198	int i;
199
200	ksft_print_header();
201
202	find_pagesizes();
203
204	if (!num_page_sizes)
205		ksft_finished();
206
207	ksft_set_plan(2 * num_page_sizes + 3);
208
209	for (i = 0; i < num_page_sizes; i++) {
210		unsigned long ps = page_sizes[i];
211		int arg = ilog2(ps) << MAP_HUGE_SHIFT;
212
213		ksft_print_msg("Testing %luMB mmap with shift %x\n", ps >> 20, arg);
214		test_mmap(ps, MAP_HUGETLB | arg);
215	}
216
217	ksft_print_msg("Testing default huge mmap\n");
218	test_mmap(default_hps, MAP_HUGETLB);
219
220	ksft_print_msg("Testing non-huge shmget\n");
221	test_shmget(getpagesize(), 0);
222
223	for (i = 0; i < num_page_sizes; i++) {
224		unsigned long ps = page_sizes[i];
225		int arg = ilog2(ps) << SHM_HUGE_SHIFT;
226		ksft_print_msg("Testing %luMB shmget with shift %x\n", ps >> 20, arg);
227		test_shmget(ps, SHM_HUGETLB | arg);
228	}
229
230	ksft_print_msg("default huge shmget\n");
231	test_shmget(default_hps, SHM_HUGETLB);
232
233	ksft_finished();
234}
~/ Read-only file preview.