2 * Stress test for transparent huge pages, memory compaction and migration.
4 * Authors: Konstantin Khlebnikov <koct9i@gmail.com>
6 * This is free and unencumbered software released into the public domain.
20 #define HPAGE_SHIFT 21
22 #define PAGE_SIZE (1 << PAGE_SHIFT)
23 #define HPAGE_SIZE (1 << HPAGE_SHIFT)
25 #define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0)
26 #define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1))
30 int64_t allocate_transhuge(void *ptr
)
35 if (mmap(ptr
, HPAGE_SIZE
, PROT_READ
| PROT_WRITE
,
36 MAP_FIXED
| MAP_ANONYMOUS
|
37 MAP_NORESERVE
| MAP_PRIVATE
, -1, 0) != ptr
)
38 errx(2, "mmap transhuge");
40 if (madvise(ptr
, HPAGE_SIZE
, MADV_HUGEPAGE
))
41 err(2, "MADV_HUGEPAGE");
43 /* allocate transparent huge page */
44 *(volatile void **)ptr
= ptr
;
46 if (pread(pagemap_fd
, ent
, sizeof(ent
),
47 (uintptr_t)ptr
>> (PAGE_SHIFT
- 3)) != sizeof(ent
))
48 err(2, "read pagemap");
50 if (PAGEMAP_PRESENT(ent
[0]) && PAGEMAP_PRESENT(ent
[1]) &&
51 PAGEMAP_PFN(ent
[0]) + 1 == PAGEMAP_PFN(ent
[1]) &&
52 !(PAGEMAP_PFN(ent
[0]) & ((1 << (HPAGE_SHIFT
- PAGE_SHIFT
)) - 1)))
53 return PAGEMAP_PFN(ent
[0]);
58 int main(int argc
, char **argv
)
67 ram
= sysconf(_SC_PHYS_PAGES
);
68 if (ram
> SIZE_MAX
/ sysconf(_SC_PAGESIZE
) / 4)
71 ram
*= sysconf(_SC_PAGESIZE
);
75 else if (!strcmp(argv
[1], "-h"))
76 errx(1, "usage: %s [size in MiB]", argv
[0]);
78 len
= atoll(argv
[1]) << 20;
80 warnx("allocate %zd transhuge pages, using %zd MiB virtual memory"
81 " and %zd MiB of ram", len
>> HPAGE_SHIFT
, len
>> 20,
82 len
>> (20 + HPAGE_SHIFT
- PAGE_SHIFT
- 1));
84 pagemap_fd
= open("/proc/self/pagemap", O_RDONLY
);
86 err(2, "open pagemap");
88 len
-= len
% HPAGE_SIZE
;
89 ptr
= mmap(NULL
, len
+ HPAGE_SIZE
, PROT_READ
| PROT_WRITE
,
90 MAP_ANONYMOUS
| MAP_NORESERVE
| MAP_PRIVATE
, -1, 0);
91 if (ptr
== MAP_FAILED
)
92 err(2, "initial mmap");
93 ptr
+= HPAGE_SIZE
- (uintptr_t)ptr
% HPAGE_SIZE
;
95 if (madvise(ptr
, len
, MADV_HUGEPAGE
))
96 err(2, "MADV_HUGEPAGE");
98 map_len
= ram
>> (HPAGE_SHIFT
- 1);
99 map
= malloc(map_len
);
101 errx(2, "map malloc");
104 int nr_succeed
= 0, nr_failed
= 0, nr_pages
= 0;
106 memset(map
, 0, map_len
);
108 clock_gettime(CLOCK_MONOTONIC
, &a
);
109 for (p
= ptr
; p
< ptr
+ len
; p
+= HPAGE_SIZE
) {
112 pfn
= allocate_transhuge(p
);
117 size_t idx
= pfn
>> (HPAGE_SHIFT
- PAGE_SHIFT
);
120 if (idx
>= map_len
) {
121 map
= realloc(map
, idx
+ 1);
123 errx(2, "map realloc");
124 memset(map
+ map_len
, 0, idx
+ 1 - map_len
);
132 /* split transhuge page, keep last page */
133 if (madvise(p
, HPAGE_SIZE
- PAGE_SIZE
, MADV_DONTNEED
))
134 err(2, "MADV_DONTNEED");
136 clock_gettime(CLOCK_MONOTONIC
, &b
);
137 s
= b
.tv_sec
- a
.tv_sec
+ (b
.tv_nsec
- a
.tv_nsec
) / 1000000000.;
139 warnx("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t"
140 "%4d succeed, %4d failed, %4d different pages",
141 s
, s
* 1000 / (len
>> HPAGE_SHIFT
), len
/ s
/ (1 << 20),
142 nr_succeed
, nr_failed
, nr_pages
);