Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,16 @@
# Makefile for vm selftests
CC = $(CROSS_COMPILE)gcc
CFLAGS = -Wall
BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest
BINARIES += transhuge-stress
all: $(BINARIES)
%: %.c
$(CC) $(CFLAGS) -o $@ $^
run_tests: all
@/bin/sh ./run_vmtests || (echo "vmtests: [FAIL]"; exit 1)
clean:
$(RM) $(BINARIES)

View file

@ -0,0 +1,92 @@
/*
* hugepage-mmap:
*
* Example of using huge page memory in a user application using the mmap
* system call. Before running this application, make sure that the
* administrator has mounted the hugetlbfs filesystem (on some directory
* like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
* example, the app is requesting memory of size 256MB that is backed by
* huge pages.
*
* For the ia64 architecture, the Linux kernel reserves Region number 4 for
* huge pages. That means that if one requires a fixed address, a huge page
* aligned address starting with 0x800000... will be required. If a fixed
* address is not required, the kernel will select an address in the proper
* range.
* Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#define FILE_NAME "huge/hugepagefile"
#define LENGTH (256UL*1024*1024)
#define PROTECTION (PROT_READ | PROT_WRITE)
/* Only ia64 requires this */
#ifdef __ia64__
#define ADDR (void *)(0x8000000000000000UL)
#define FLAGS (MAP_SHARED | MAP_FIXED)
#else
#define ADDR (void *)(0x0UL)
#define FLAGS (MAP_SHARED)
#endif
static void check_bytes(char *addr)
{
printf("First hex is %x\n", *((unsigned int *)addr));
}
static void write_bytes(char *addr)
{
unsigned long i;
for (i = 0; i < LENGTH; i++)
*(addr + i) = (char)i;
}
static int read_bytes(char *addr)
{
unsigned long i;
check_bytes(addr);
for (i = 0; i < LENGTH; i++)
if (*(addr + i) != (char)i) {
printf("Mismatch at %lu\n", i);
return 1;
}
return 0;
}
int main(void)
{
void *addr;
int fd, ret;
fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
if (fd < 0) {
perror("Open failed");
exit(1);
}
addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap");
unlink(FILE_NAME);
exit(1);
}
printf("Returned address is %p\n", addr);
check_bytes(addr);
write_bytes(addr);
ret = read_bytes(addr);
munmap(addr, LENGTH);
close(fd);
unlink(FILE_NAME);
return ret;
}

View file

@ -0,0 +1,100 @@
/*
* hugepage-shm:
*
* Example of using huge page memory in a user application using Sys V shared
* memory system calls. In this example the app is requesting 256MB of
* memory that is backed by huge pages. The application uses the flag
* SHM_HUGETLB in the shmget system call to inform the kernel that it is
* requesting huge pages.
*
* For the ia64 architecture, the Linux kernel reserves Region number 4 for
* huge pages. That means that if one requires a fixed address, a huge page
* aligned address starting with 0x800000... will be required. If a fixed
* address is not required, the kernel will select an address in the proper
* range.
* Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
*
* Note: The default shared memory limit is quite low on many kernels,
* you may need to increase it via:
*
* echo 268435456 > /proc/sys/kernel/shmmax
*
* This will increase the maximum size per shared memory segment to 256MB.
* The other limit that you will hit eventually is shmall which is the
* total amount of shared memory in pages. To set it to 16GB on a system
* with a 4kB pagesize do:
*
* echo 4194304 > /proc/sys/kernel/shmall
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#ifndef SHM_HUGETLB
#define SHM_HUGETLB 04000
#endif
#define LENGTH (256UL*1024*1024)
#define dprintf(x) printf(x)
/* Only ia64 requires this */
#ifdef __ia64__
#define ADDR (void *)(0x8000000000000000UL)
#define SHMAT_FLAGS (SHM_RND)
#else
#define ADDR (void *)(0x0UL)
#define SHMAT_FLAGS (0)
#endif
int main(void)
{
int shmid;
unsigned long i;
char *shmaddr;
shmid = shmget(2, LENGTH, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
if (shmid < 0) {
perror("shmget");
exit(1);
}
printf("shmid: 0x%x\n", shmid);
shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
if (shmaddr == (char *)-1) {
perror("Shared memory attach failure");
shmctl(shmid, IPC_RMID, NULL);
exit(2);
}
printf("shmaddr: %p\n", shmaddr);
dprintf("Starting the writes:\n");
for (i = 0; i < LENGTH; i++) {
shmaddr[i] = (char)(i);
if (!(i % (1024 * 1024)))
dprintf(".");
}
dprintf("\n");
dprintf("Starting the Check...");
for (i = 0; i < LENGTH; i++)
if (shmaddr[i] != (char)i) {
printf("\nIndex %lu mismatched\n", i);
exit(3);
}
dprintf("Done.\n");
if (shmdt((const void *)shmaddr) != 0) {
perror("Detach failure");
shmctl(shmid, IPC_RMID, NULL);
exit(4);
}
shmctl(shmid, IPC_RMID, NULL);
return 0;
}

View file

@ -0,0 +1,84 @@
#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
typedef unsigned long long u64;
static size_t length = 1 << 24;
static u64 read_rss(void)
{
char buf[4096], *s = buf;
int i, fd;
u64 rss;
fd = open("/proc/self/statm", O_RDONLY);
assert(fd > 2);
memset(buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf) - 1);
for (i = 0; i < 1; i++)
s = strchr(s, ' ') + 1;
rss = strtoull(s, NULL, 10);
return rss << 12; /* assumes 4k pagesize */
}
static void do_mmap(int fd, int extra_flags, int unmap)
{
int *p;
int flags = MAP_PRIVATE | MAP_POPULATE | extra_flags;
u64 before, after;
before = read_rss();
p = mmap(NULL, length, PROT_READ | PROT_WRITE, flags, fd, 0);
assert(p != MAP_FAILED ||
!"mmap returned an unexpected error");
after = read_rss();
assert(llabs(after - before - length) < 0x40000 ||
!"rss didn't grow as expected");
if (!unmap)
return;
munmap(p, length);
after = read_rss();
assert(llabs(after - before) < 0x40000 ||
!"rss didn't shrink as expected");
}
static int open_file(const char *path)
{
int fd, err;
unlink(path);
fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL
| O_LARGEFILE | O_CLOEXEC, 0600);
assert(fd > 2);
unlink(path);
err = ftruncate(fd, length);
assert(!err);
return fd;
}
int main(void)
{
int hugefd, fd;
fd = open_file("/dev/shm/hugetlbhog");
hugefd = open_file("/hugepages/hugetlbhog");
system("echo 100 > /proc/sys/vm/nr_hugepages");
do_mmap(-1, MAP_ANONYMOUS, 1);
do_mmap(fd, 0, 1);
do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 1);
do_mmap(hugefd, 0, 1);
do_mmap(hugefd, MAP_HUGETLB, 1);
/* Leak the last one to test do_exit() */
do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 0);
printf("oll korrekt.\n");
return 0;
}

View file

@ -0,0 +1,79 @@
/*
* Example of using hugepage memory in a user application using the mmap
* system call with MAP_HUGETLB flag. Before running this program make
* sure the administrator has allocated enough default sized huge pages
* to cover the 256 MB allocation.
*
* For ia64 architecture, Linux kernel reserves Region number 4 for hugepages.
* That means the addresses starting with 0x800000... will need to be
* specified. Specifying a fixed address is not required on ppc64, i386
* or x86_64.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#define LENGTH (256UL*1024*1024)
#define PROTECTION (PROT_READ | PROT_WRITE)
#ifndef MAP_HUGETLB
#define MAP_HUGETLB 0x40000 /* arch specific */
#endif
/* Only ia64 requires this */
#ifdef __ia64__
#define ADDR (void *)(0x8000000000000000UL)
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
#else
#define ADDR (void *)(0x0UL)
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
#endif
static void check_bytes(char *addr)
{
printf("First hex is %x\n", *((unsigned int *)addr));
}
static void write_bytes(char *addr)
{
unsigned long i;
for (i = 0; i < LENGTH; i++)
*(addr + i) = (char)i;
}
static int read_bytes(char *addr)
{
unsigned long i;
check_bytes(addr);
for (i = 0; i < LENGTH; i++)
if (*(addr + i) != (char)i) {
printf("Mismatch at %lu\n", i);
return 1;
}
return 0;
}
int main(void)
{
void *addr;
int ret;
addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
if (addr == MAP_FAILED) {
perror("mmap");
exit(1);
}
printf("Returned address is %p\n", addr);
check_bytes(addr);
write_bytes(addr);
ret = read_bytes(addr);
munmap(addr, LENGTH);
return ret;
}

View file

@ -0,0 +1,93 @@
#!/bin/bash
#please run as root
#we need 256M, below is the size in kB
needmem=262144
mnt=./huge
exitcode=0
#get pagesize and freepages from /proc/meminfo
while read name size unit; do
if [ "$name" = "HugePages_Free:" ]; then
freepgs=$size
fi
if [ "$name" = "Hugepagesize:" ]; then
pgsize=$size
fi
done < /proc/meminfo
#set proper nr_hugepages
if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then
nr_hugepgs=`cat /proc/sys/vm/nr_hugepages`
needpgs=`expr $needmem / $pgsize`
if [ $freepgs -lt $needpgs ]; then
lackpgs=$(( $needpgs - $freepgs ))
echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages
if [ $? -ne 0 ]; then
echo "Please run this test as root"
exit 1
fi
fi
else
echo "no hugetlbfs support in kernel?"
exit 1
fi
mkdir $mnt
mount -t hugetlbfs none $mnt
echo "--------------------"
echo "running hugepage-mmap"
echo "--------------------"
./hugepage-mmap
if [ $? -ne 0 ]; then
echo "[FAIL]"
exitcode=1
else
echo "[PASS]"
fi
shmmax=`cat /proc/sys/kernel/shmmax`
shmall=`cat /proc/sys/kernel/shmall`
echo 268435456 > /proc/sys/kernel/shmmax
echo 4194304 > /proc/sys/kernel/shmall
echo "--------------------"
echo "running hugepage-shm"
echo "--------------------"
./hugepage-shm
if [ $? -ne 0 ]; then
echo "[FAIL]"
exitcode=1
else
echo "[PASS]"
fi
echo $shmmax > /proc/sys/kernel/shmmax
echo $shmall > /proc/sys/kernel/shmall
echo "--------------------"
echo "running map_hugetlb"
echo "--------------------"
./map_hugetlb
if [ $? -ne 0 ]; then
echo "[FAIL]"
exitcode=1
else
echo "[PASS]"
fi
echo "--------------------"
echo "running hugetlbfstest"
echo "--------------------"
./hugetlbfstest
if [ $? -ne 0 ]; then
echo "[FAIL]"
exitcode=1
else
echo "[PASS]"
fi
#cleanup
umount $mnt
rm -rf $mnt
echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
exit $exitcode

View file

@ -0,0 +1,254 @@
/* Test selecting other page sizes for mmap/shmget.
Before running this huge pages for each huge page size must have been
reserved.
For large pages beyond MAX_ORDER (like 1GB on x86) boot options must be used.
Also shmmax must be increased.
And you need to run as root to work around some weird permissions in shm.
And nothing using huge pages should run in parallel.
When the program aborts you may need to clean up the shm segments with
ipcrm -m by hand, like this
sudo ipcs | awk '$1 == "0x00000000" {print $2}' | xargs -n1 sudo ipcrm -m
(warning this will remove all if someone else uses them) */
#define _GNU_SOURCE 1
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <glob.h>
#include <assert.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#define err(x) perror(x), exit(1)
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
#define MAP_HUGETLB 0x40000
#define SHM_HUGETLB 04000 /* segment will use huge TLB pages */
#define SHM_HUGE_SHIFT 26
#define SHM_HUGE_MASK 0x3f
#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT)
#define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT)
#define NUM_PAGESIZES 5
#define NUM_PAGES 4
#define Dprintf(fmt...) // printf(fmt)
unsigned long page_sizes[NUM_PAGESIZES];
int num_page_sizes;
int ilog2(unsigned long v)
{
int l = 0;
while ((1UL << l) < v)
l++;
return l;
}
void find_pagesizes(void)
{
glob_t g;
int i;
glob("/sys/kernel/mm/hugepages/hugepages-*kB", 0, NULL, &g);
assert(g.gl_pathc <= NUM_PAGESIZES);
for (i = 0; i < g.gl_pathc; i++) {
sscanf(g.gl_pathv[i], "/sys/kernel/mm/hugepages/hugepages-%lukB",
&page_sizes[i]);
page_sizes[i] <<= 10;
printf("Found %luMB\n", page_sizes[i] >> 20);
}
num_page_sizes = g.gl_pathc;
globfree(&g);
}
unsigned long default_huge_page_size(void)
{
unsigned long hps = 0;
char *line = NULL;
size_t linelen = 0;
FILE *f = fopen("/proc/meminfo", "r");
if (!f)
return 0;
while (getline(&line, &linelen, f) > 0) {
if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
hps <<= 10;
break;
}
}
free(line);
return hps;
}
void show(unsigned long ps)
{
char buf[100];
if (ps == getpagesize())
return;
printf("%luMB: ", ps >> 20);
fflush(stdout);
snprintf(buf, sizeof buf,
"cat /sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
ps >> 10);
system(buf);
}
unsigned long read_sysfs(int warn, char *fmt, ...)
{
char *line = NULL;
size_t linelen = 0;
char buf[100];
FILE *f;
va_list ap;
unsigned long val = 0;
va_start(ap, fmt);
vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
f = fopen(buf, "r");
if (!f) {
if (warn)
printf("missing %s\n", buf);
return 0;
}
if (getline(&line, &linelen, f) > 0) {
sscanf(line, "%lu", &val);
}
fclose(f);
free(line);
return val;
}
unsigned long read_free(unsigned long ps)
{
return read_sysfs(ps != getpagesize(),
"/sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
ps >> 10);
}
void test_mmap(unsigned long size, unsigned flags)
{
char *map;
unsigned long before, after;
int err;
before = read_free(size);
map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, 0, 0);
if (map == (char *)-1) err("mmap");
memset(map, 0xff, size*NUM_PAGES);
after = read_free(size);
Dprintf("before %lu after %lu diff %ld size %lu\n",
before, after, before - after, size);
assert(size == getpagesize() || (before - after) == NUM_PAGES);
show(size);
err = munmap(map, size);
assert(!err);
}
void test_shmget(unsigned long size, unsigned flags)
{
int id;
unsigned long before, after;
int err;
before = read_free(size);
id = shmget(IPC_PRIVATE, size * NUM_PAGES, IPC_CREAT|0600|flags);
if (id < 0) err("shmget");
struct shm_info i;
if (shmctl(id, SHM_INFO, (void *)&i) < 0) err("shmctl");
Dprintf("alloc %lu res %lu\n", i.shm_tot, i.shm_rss);
Dprintf("id %d\n", id);
char *map = shmat(id, NULL, 0600);
if (map == (char*)-1) err("shmat");
shmctl(id, IPC_RMID, NULL);
memset(map, 0xff, size*NUM_PAGES);
after = read_free(size);
Dprintf("before %lu after %lu diff %ld size %lu\n",
before, after, before - after, size);
assert(size == getpagesize() || (before - after) == NUM_PAGES);
show(size);
err = shmdt(map);
assert(!err);
}
void sanity_checks(void)
{
int i;
unsigned long largest = getpagesize();
for (i = 0; i < num_page_sizes; i++) {
if (page_sizes[i] > largest)
largest = page_sizes[i];
if (read_free(page_sizes[i]) < NUM_PAGES) {
printf("Not enough huge pages for page size %lu MB, need %u\n",
page_sizes[i] >> 20,
NUM_PAGES);
exit(0);
}
}
if (read_sysfs(0, "/proc/sys/kernel/shmmax") < NUM_PAGES * largest) {
printf("Please do echo %lu > /proc/sys/kernel/shmmax", largest * NUM_PAGES);
exit(0);
}
#if defined(__x86_64__)
if (largest != 1U<<30) {
printf("No GB pages available on x86-64\n"
"Please boot with hugepagesz=1G hugepages=%d\n", NUM_PAGES);
exit(0);
}
#endif
}
int main(void)
{
int i;
unsigned default_hps = default_huge_page_size();
find_pagesizes();
sanity_checks();
for (i = 0; i < num_page_sizes; i++) {
unsigned long ps = page_sizes[i];
int arg = ilog2(ps) << MAP_HUGE_SHIFT;
printf("Testing %luMB mmap with shift %x\n", ps >> 20, arg);
test_mmap(ps, MAP_HUGETLB | arg);
}
printf("Testing default huge mmap\n");
test_mmap(default_hps, SHM_HUGETLB);
puts("Testing non-huge shmget");
test_shmget(getpagesize(), 0);
for (i = 0; i < num_page_sizes; i++) {
unsigned long ps = page_sizes[i];
int arg = ilog2(ps) << SHM_HUGE_SHIFT;
printf("Testing %luMB shmget with shift %x\n", ps >> 20, arg);
test_shmget(ps, SHM_HUGETLB | arg);
}
puts("default huge shmget");
test_shmget(default_hps, SHM_HUGETLB);
return 0;
}

View file

@ -0,0 +1,144 @@
/*
* Stress test for transparent huge pages, memory compaction and migration.
*
* Authors: Konstantin Khlebnikov <koct9i@gmail.com>
*
* This is free and unencumbered software released into the public domain.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <err.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#define PAGE_SHIFT 12
#define HPAGE_SHIFT 21
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define HPAGE_SIZE (1 << HPAGE_SHIFT)
#define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0)
#define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1))
int pagemap_fd;
int64_t allocate_transhuge(void *ptr)
{
uint64_t ent[2];
/* drop pmd */
if (mmap(ptr, HPAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_ANONYMOUS |
MAP_NORESERVE | MAP_PRIVATE, -1, 0) != ptr)
errx(2, "mmap transhuge");
if (madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE))
err(2, "MADV_HUGEPAGE");
/* allocate transparent huge page */
*(volatile void **)ptr = ptr;
if (pread(pagemap_fd, ent, sizeof(ent),
(uintptr_t)ptr >> (PAGE_SHIFT - 3)) != sizeof(ent))
err(2, "read pagemap");
if (PAGEMAP_PRESENT(ent[0]) && PAGEMAP_PRESENT(ent[1]) &&
PAGEMAP_PFN(ent[0]) + 1 == PAGEMAP_PFN(ent[1]) &&
!(PAGEMAP_PFN(ent[0]) & ((1 << (HPAGE_SHIFT - PAGE_SHIFT)) - 1)))
return PAGEMAP_PFN(ent[0]);
return -1;
}
int main(int argc, char **argv)
{
size_t ram, len;
void *ptr, *p;
struct timespec a, b;
double s;
uint8_t *map;
size_t map_len;
ram = sysconf(_SC_PHYS_PAGES);
if (ram > SIZE_MAX / sysconf(_SC_PAGESIZE) / 4)
ram = SIZE_MAX / 4;
else
ram *= sysconf(_SC_PAGESIZE);
if (argc == 1)
len = ram;
else if (!strcmp(argv[1], "-h"))
errx(1, "usage: %s [size in MiB]", argv[0]);
else
len = atoll(argv[1]) << 20;
warnx("allocate %zd transhuge pages, using %zd MiB virtual memory"
" and %zd MiB of ram", len >> HPAGE_SHIFT, len >> 20,
len >> (20 + HPAGE_SHIFT - PAGE_SHIFT - 1));
pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
if (pagemap_fd < 0)
err(2, "open pagemap");
len -= len % HPAGE_SIZE;
ptr = mmap(NULL, len + HPAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
if (ptr == MAP_FAILED)
err(2, "initial mmap");
ptr += HPAGE_SIZE - (uintptr_t)ptr % HPAGE_SIZE;
if (madvise(ptr, len, MADV_HUGEPAGE))
err(2, "MADV_HUGEPAGE");
map_len = ram >> (HPAGE_SHIFT - 1);
map = malloc(map_len);
if (!map)
errx(2, "map malloc");
while (1) {
int nr_succeed = 0, nr_failed = 0, nr_pages = 0;
memset(map, 0, map_len);
clock_gettime(CLOCK_MONOTONIC, &a);
for (p = ptr; p < ptr + len; p += HPAGE_SIZE) {
int64_t pfn;
pfn = allocate_transhuge(p);
if (pfn < 0) {
nr_failed++;
} else {
size_t idx = pfn >> (HPAGE_SHIFT - PAGE_SHIFT);
nr_succeed++;
if (idx >= map_len) {
map = realloc(map, idx + 1);
if (!map)
errx(2, "map realloc");
memset(map + map_len, 0, idx + 1 - map_len);
map_len = idx + 1;
}
if (!map[idx])
nr_pages++;
map[idx] = 1;
}
/* split transhuge page, keep last page */
if (madvise(p, HPAGE_SIZE - PAGE_SIZE, MADV_DONTNEED))
err(2, "MADV_DONTNEED");
}
clock_gettime(CLOCK_MONOTONIC, &b);
s = b.tv_sec - a.tv_sec + (b.tv_nsec - a.tv_nsec) / 1000000000.;
warnx("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t"
"%4d succeed, %4d failed, %4d different pages",
s, s * 1000 / (len >> HPAGE_SHIFT), len / s / (1 << 20),
nr_succeed, nr_failed, nr_pages);
}
}