139 lines · c
1/*2 * Stress test for transparent huge pages, memory compaction and migration.3 *4 * Authors: Konstantin Khlebnikov <koct9i@gmail.com>5 *6 * This is free and unencumbered software released into the public domain.7 */8 9#include <stdlib.h>10#include <stdio.h>11#include <stdint.h>12#include <err.h>13#include <time.h>14#include <unistd.h>15#include <fcntl.h>16#include <string.h>17#include <sys/mman.h>18#include "vm_util.h"19#include "../kselftest.h"20 21int backing_fd = -1;22int mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE;23#define PROT_RW (PROT_READ | PROT_WRITE)24 25int main(int argc, char **argv)26{27 size_t ram, len;28 void *ptr, *p;29 struct timespec start, a, b;30 int i = 0;31 char *name = NULL;32 double s;33 uint8_t *map;34 size_t map_len;35 int pagemap_fd;36 int duration = 0;37 38 ksft_print_header();39 40 ram = sysconf(_SC_PHYS_PAGES);41 if (ram > SIZE_MAX / psize() / 4)42 ram = SIZE_MAX / 4;43 else44 ram *= psize();45 len = ram;46 47 while (++i < argc) {48 if (!strcmp(argv[i], "-h"))49 ksft_exit_fail_msg("usage: %s [-f <filename>] [-d <duration>] [size in MiB]\n",50 argv[0]);51 else if (!strcmp(argv[i], "-f"))52 name = argv[++i];53 else if (!strcmp(argv[i], "-d"))54 duration = atoi(argv[++i]);55 else56 len = atoll(argv[i]) << 20;57 }58 59 ksft_set_plan(1);60 61 if (name) {62 backing_fd = open(name, O_RDWR);63 if (backing_fd == -1)64 ksft_exit_fail_msg("open %s\n", name);65 mmap_flags = MAP_SHARED;66 }67 68 warnx("allocate %zd transhuge pages, using %zd MiB virtual memory"69 " and %zd MiB of ram", len >> HPAGE_SHIFT, len >> 20,70 ram >> (20 + HPAGE_SHIFT - pshift() - 1));71 72 pagemap_fd = open("/proc/self/pagemap", O_RDONLY);73 if (pagemap_fd < 0)74 ksft_exit_fail_msg("open pagemap\n");75 76 len -= len % HPAGE_SIZE;77 ptr = mmap(NULL, len + HPAGE_SIZE, PROT_RW, mmap_flags, backing_fd, 0);78 if (ptr == MAP_FAILED)79 ksft_exit_fail_msg("initial mmap");80 ptr += HPAGE_SIZE - (uintptr_t)ptr % HPAGE_SIZE;81 82 if (madvise(ptr, len, MADV_HUGEPAGE))83 ksft_exit_fail_msg("MADV_HUGEPAGE");84 85 map_len = ram >> (HPAGE_SHIFT - 1);86 map = malloc(map_len);87 if (!map)88 ksft_exit_fail_msg("map malloc\n");89 90 clock_gettime(CLOCK_MONOTONIC, &start);91 92 while (1) {93 int nr_succeed = 0, nr_failed = 0, nr_pages = 0;94 95 memset(map, 0, map_len);96 97 clock_gettime(CLOCK_MONOTONIC, &a);98 for (p = ptr; p < ptr + len; p += HPAGE_SIZE) {99 int64_t pfn;100 101 pfn = allocate_transhuge(p, pagemap_fd);102 103 if (pfn < 0) {104 nr_failed++;105 } else {106 size_t idx = pfn >> (HPAGE_SHIFT - pshift());107 108 nr_succeed++;109 if (idx >= map_len) {110 map = realloc(map, idx + 1);111 if (!map)112 ksft_exit_fail_msg("map realloc\n");113 memset(map + map_len, 0, idx + 1 - map_len);114 map_len = idx + 1;115 }116 if (!map[idx])117 nr_pages++;118 map[idx] = 1;119 }120 121 /* split transhuge page, keep last page */122 if (madvise(p, HPAGE_SIZE - psize(), MADV_DONTNEED))123 ksft_exit_fail_msg("MADV_DONTNEED");124 }125 clock_gettime(CLOCK_MONOTONIC, &b);126 s = b.tv_sec - a.tv_sec + (b.tv_nsec - a.tv_nsec) / 1000000000.;127 128 ksft_print_msg("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t"129 "%4d succeed, %4d failed, %4d different pages\n",130 s, s * 1000 / (len >> HPAGE_SHIFT), len / s / (1 << 20),131 nr_succeed, nr_failed, nr_pages);132 133 if (duration > 0 && b.tv_sec - start.tv_sec >= duration) {134 ksft_test_result_pass("Completed\n");135 ksft_finished();136 }137 }138}139