brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · e4370b7 Raw
250 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Test selecting other page sizes for mmap/shmget.3 4   Before running this huge pages for each huge page size must have been5   reserved.6   For large pages beyond MAX_PAGE_ORDER (like 1GB on x86) boot options must7   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 with12   ipcrm -m by hand, like this13   sudo ipcs | awk '$1 == "0x00000000" {print $2}' | xargs -n1 sudo ipcrm -m14   (warning this will remove all if someone else uses them) */15 16#define _GNU_SOURCE17#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	0x4000034#endif35 36#define SHM_HUGETLB     04000   /* segment will use huge TLB pages */37#ifndef SHM_HUGE_SHIFT38#define SHM_HUGE_SHIFT  2639#endif40#ifndef SHM_HUGE_MASK41#define SHM_HUGE_MASK   0x3f42#endif43#ifndef SHM_HUGE_2MB44#define SHM_HUGE_2MB    (21 << SHM_HUGE_SHIFT)45#endif46#ifndef SHM_HUGE_1GB47#define SHM_HUGE_1GB    (30 << SHM_HUGE_SHIFT)48#endif49 50#define NUM_PAGESIZES   551#define NUM_PAGES 452 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_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 107unsigned 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 114void 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 136void 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 173void 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		else193			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#endif208}209 210int 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