/* * hugepage_alloc_test1.c - test the availabilty of * largepages/hugepages * * Written by Roland Mainz */ #include #include #include #include #include #include #include #include #include /* * Before using this Linux 5.10.0-13-rt-686-pae requires that "root" * reserves hugepages like this: * * $ printf '128' > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages * $ cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages * 128 * * Notes: * - Terminology: UNIX uses the term "largepages", Linux defiantly * uses "hugepages" * - the value is the number of MMU (large-/huge-)pages, NOT the * number of bytes. * - $ /usr/bin/pagesize -a # can inform you which pagesizes are * available (i686 usually has { 4k, 2M } pagesizes, SPARCv9 has * { 8k, 64k, 4M, 32M, ... } ) */ /* Linux-specific version */ ssize_t get_number_of_free_hugepages(void) { int dirfd; int fd; /* * |round(log10(18446744073709551615))| is |19| on a 64bit * system, so |128| should be enough (including sign) */ char buf[128]; ssize_t numpages; ssize_t rs; /* read size */ /* * extra step here, since real-world applications likely * want to look at "nr_hugepages" etc, too */ dirfd = open("/sys/kernel/mm/hugepages/hugepages-2048kB/", O_DIRECTORY); if (dirfd < 0) { perror("open sysfs hugepage dir"); return -1; } fd = openat(dirfd, "free_hugepages", O_RDONLY); if (fd < 0) { perror("open sysfs hugepage free pages file"); (void)close(dirfd); return -1; } rs = read(fd, buf, sizeof(buf)); if (rs < 0) { perror("read error sysfs hugepage free pages file"); (void)close(dirfd); (void)close(fd); return -1; } (void)close(dirfd); (void)close(fd); buf[rs] = '\0'; #if MYDEBUG if ((rs > 0) && (buf[rs-1] == '\n')) buf[rs-1] = '\0'; (void)printf("string returned: |%s|\n", buf); #endif /* MYDEBUG */ errno = 0; numpages = strtol(buf, NULL, 10); if (errno != 0) { perror("error parsing value of free hugepages"); return -1; } return numpages; } int main(int ac, char *av[]) { void *p; int saved_errno; #define TEST_NUM_ALLOC_PAGES (32) const size_t size = TEST_NUM_ALLOC_PAGES*1024*1024; ssize_t free_numpages; (void)puts("#start."); free_numpages = get_number_of_free_hugepages(); if (free_numpages < (TEST_NUM_ALLOC_PAGES+8)) { (void)fprintf(stderr, "not enough hugepages, currently free %ld\n", (long)free_numpages); return EXIT_FAILURE; } /* get mmap()'ed memory with hugepage attribute */ p = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0); saved_errno = errno; if (p == MAP_FAILED) { perror("mmap"); return EXIT_FAILURE; } (void)printf("map address = 0x%lx, errno=%d\n", (unsigned long)p, (int)saved_errno); /* use memory */ volatile unsigned char *c = p; for (size_t i = 0 ; i < size ; i++) { c[i] = (unsigned char)(i % 255); } #if MYDEBUG_USE_PROC_SMAPS /* * Wait here so we can check out * $ cat /proc/$mypid/smaps | fgrep -i huge # */ sleep(1000); #endif /* MYDEBUG_USE_PROC_SMAPS */ if (munmap(p, size) == -1) perror("munmap"); (void)puts("#done."); return EXIT_SUCCESS; }