162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Stress test for transparent huge pages, memory compaction and migration. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Authors: Konstantin Khlebnikov <koct9i@gmail.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This is free and unencumbered software released into the public domain. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <stdlib.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <stdint.h> 1262306a36Sopenharmony_ci#include <err.h> 1362306a36Sopenharmony_ci#include <time.h> 1462306a36Sopenharmony_ci#include <unistd.h> 1562306a36Sopenharmony_ci#include <fcntl.h> 1662306a36Sopenharmony_ci#include <string.h> 1762306a36Sopenharmony_ci#include <sys/mman.h> 1862306a36Sopenharmony_ci#include "vm_util.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciint backing_fd = -1; 2162306a36Sopenharmony_ciint mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE; 2262306a36Sopenharmony_ci#define PROT_RW (PROT_READ | PROT_WRITE) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciint main(int argc, char **argv) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci size_t ram, len; 2762306a36Sopenharmony_ci void *ptr, *p; 2862306a36Sopenharmony_ci struct timespec start, a, b; 2962306a36Sopenharmony_ci int i = 0; 3062306a36Sopenharmony_ci char *name = NULL; 3162306a36Sopenharmony_ci double s; 3262306a36Sopenharmony_ci uint8_t *map; 3362306a36Sopenharmony_ci size_t map_len; 3462306a36Sopenharmony_ci int pagemap_fd; 3562306a36Sopenharmony_ci int duration = 0; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci ram = sysconf(_SC_PHYS_PAGES); 3862306a36Sopenharmony_ci if (ram > SIZE_MAX / psize() / 4) 3962306a36Sopenharmony_ci ram = SIZE_MAX / 4; 4062306a36Sopenharmony_ci else 4162306a36Sopenharmony_ci ram *= psize(); 4262306a36Sopenharmony_ci len = ram; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci while (++i < argc) { 4562306a36Sopenharmony_ci if (!strcmp(argv[i], "-h")) 4662306a36Sopenharmony_ci errx(1, "usage: %s [-f <filename>] [-d <duration>] [size in MiB]", argv[0]); 4762306a36Sopenharmony_ci else if (!strcmp(argv[i], "-f")) 4862306a36Sopenharmony_ci name = argv[++i]; 4962306a36Sopenharmony_ci else if (!strcmp(argv[i], "-d")) 5062306a36Sopenharmony_ci duration = atoi(argv[++i]); 5162306a36Sopenharmony_ci else 5262306a36Sopenharmony_ci len = atoll(argv[i]) << 20; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (name) { 5662306a36Sopenharmony_ci backing_fd = open(name, O_RDWR); 5762306a36Sopenharmony_ci if (backing_fd == -1) 5862306a36Sopenharmony_ci errx(2, "open %s", name); 5962306a36Sopenharmony_ci mmap_flags = MAP_SHARED; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci warnx("allocate %zd transhuge pages, using %zd MiB virtual memory" 6362306a36Sopenharmony_ci " and %zd MiB of ram", len >> HPAGE_SHIFT, len >> 20, 6462306a36Sopenharmony_ci ram >> (20 + HPAGE_SHIFT - pshift() - 1)); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 6762306a36Sopenharmony_ci if (pagemap_fd < 0) 6862306a36Sopenharmony_ci err(2, "open pagemap"); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci len -= len % HPAGE_SIZE; 7162306a36Sopenharmony_ci ptr = mmap(NULL, len + HPAGE_SIZE, PROT_RW, mmap_flags, backing_fd, 0); 7262306a36Sopenharmony_ci if (ptr == MAP_FAILED) 7362306a36Sopenharmony_ci err(2, "initial mmap"); 7462306a36Sopenharmony_ci ptr += HPAGE_SIZE - (uintptr_t)ptr % HPAGE_SIZE; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (madvise(ptr, len, MADV_HUGEPAGE)) 7762306a36Sopenharmony_ci err(2, "MADV_HUGEPAGE"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci map_len = ram >> (HPAGE_SHIFT - 1); 8062306a36Sopenharmony_ci map = malloc(map_len); 8162306a36Sopenharmony_ci if (!map) 8262306a36Sopenharmony_ci errx(2, "map malloc"); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &start); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci while (1) { 8762306a36Sopenharmony_ci int nr_succeed = 0, nr_failed = 0, nr_pages = 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci memset(map, 0, map_len); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &a); 9262306a36Sopenharmony_ci for (p = ptr; p < ptr + len; p += HPAGE_SIZE) { 9362306a36Sopenharmony_ci int64_t pfn; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci pfn = allocate_transhuge(p, pagemap_fd); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (pfn < 0) { 9862306a36Sopenharmony_ci nr_failed++; 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci size_t idx = pfn >> (HPAGE_SHIFT - pshift()); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci nr_succeed++; 10362306a36Sopenharmony_ci if (idx >= map_len) { 10462306a36Sopenharmony_ci map = realloc(map, idx + 1); 10562306a36Sopenharmony_ci if (!map) 10662306a36Sopenharmony_ci errx(2, "map realloc"); 10762306a36Sopenharmony_ci memset(map + map_len, 0, idx + 1 - map_len); 10862306a36Sopenharmony_ci map_len = idx + 1; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci if (!map[idx]) 11162306a36Sopenharmony_ci nr_pages++; 11262306a36Sopenharmony_ci map[idx] = 1; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* split transhuge page, keep last page */ 11662306a36Sopenharmony_ci if (madvise(p, HPAGE_SIZE - psize(), MADV_DONTNEED)) 11762306a36Sopenharmony_ci err(2, "MADV_DONTNEED"); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &b); 12062306a36Sopenharmony_ci s = b.tv_sec - a.tv_sec + (b.tv_nsec - a.tv_nsec) / 1000000000.; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci warnx("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t" 12362306a36Sopenharmony_ci "%4d succeed, %4d failed, %4d different pages", 12462306a36Sopenharmony_ci s, s * 1000 / (len >> HPAGE_SHIFT), len / s / (1 << 20), 12562306a36Sopenharmony_ci nr_succeed, nr_failed, nr_pages); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (duration > 0 && b.tv_sec - start.tv_sec >= duration) 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci} 131