Last active
May 27, 2021 10:11
-
-
Save christophercrouzet/52b5be85207e758806ccc1c1eddcfce6 to your computer and use it in GitHub Desktop.
Linux's `mremap()`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <unistd.h> | |
#include <sys/mman.h> | |
#include <assert.h> | |
#include <stddef.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <time.h> | |
#if !defined(MAP_ANONYMOUS) | |
#if defined(MAP_ANON) | |
#define MAP_ANONYMOUS MAP_ANON | |
#else | |
#error "anonymous pages not available" | |
#endif | |
#endif | |
// Helpers | |
// ----------------------------------------------------------------------------- | |
static size_t | |
get_page_size() | |
{ | |
return (size_t)sysconf(_SC_PAGESIZE); | |
} | |
static void | |
touch_pages(void *buf, size_t size, size_t page_size) | |
{ | |
size_t i; | |
for (i = 0; i < size; i += page_size) { | |
void *ptr; | |
ptr = (void *)((uintptr_t)buf + i); | |
*((size_t *)ptr) = 123; | |
} | |
} | |
static void | |
check_pages(void *buf, size_t size, size_t page_size) | |
{ | |
size_t i; | |
for (i = 0; i < size; i += page_size) { | |
void *ptr; | |
ptr = (void *)((uintptr_t)buf + i); | |
if (*((size_t *)ptr) != 123) { | |
printf("invalid data!\n"); | |
exit(0); | |
} | |
} | |
printf("all good!\n"); | |
} | |
static uint64_t | |
get_time() | |
{ | |
struct timespec time; | |
if (clock_gettime(CLOCK_MONOTONIC, &time) != 0) { | |
printf("failed to retrieve the current time\n"); | |
exit(0); | |
} | |
return (uint64_t)time.tv_sec * 1000000000ull + (uint64_t)time.tv_nsec; | |
} | |
// ----------------------------------------------------------------------------- | |
int | |
main(void) | |
{ | |
size_t page_size; | |
void *addr; | |
size_t alloc_size; | |
uint64_t start, stop; | |
// ------------------------------------------------------------------------- | |
page_size = get_page_size(); | |
addr = (void *)0x10000000; | |
#if 0 | |
alloc_size = 0x40000000; // 1 GB | |
#else | |
alloc_size = 0x00010000; // 64 KB | |
#endif | |
printf("press any key to continue...\n"); | |
getchar(); | |
// ------------------------------------------------------------------------- | |
void *alloc_1 = mmap( | |
(void *)0x10000000, | |
alloc_size, | |
PROT_READ | PROT_WRITE, | |
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | |
-1, | |
0 | |
); | |
if (alloc_1 == NULL) { | |
printf("alloc_1: mmap failed\n"); | |
exit(0); | |
} | |
touch_pages(alloc_1, alloc_size, page_size); | |
printf("finished mapping alloc_1...\n"); | |
getchar(); | |
// ------------------------------------------------------------------------- | |
void *alloc_2 = mmap( | |
(void *)((uintptr_t)alloc_1 + alloc_size), | |
alloc_size, | |
PROT_READ | PROT_WRITE, | |
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | |
-1, | |
0 | |
); | |
if (alloc_2 == NULL) { | |
printf("alloc_2: mmap failed\n"); | |
exit(0); | |
} | |
touch_pages(alloc_2, alloc_size, page_size); | |
printf("finished mapping alloc_2...\n"); | |
getchar(); | |
// ------------------------------------------------------------------------- | |
#if 1 | |
start = get_time(); | |
void *alloc_3 = mmap( | |
(void *)((uintptr_t)alloc_2 + alloc_size), | |
alloc_size * 2, | |
PROT_READ | PROT_WRITE, | |
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | |
-1, | |
0 | |
); | |
if (alloc_3 == NULL) { | |
printf("alloc_3: mmap failed\n"); | |
exit(0); | |
} | |
memcpy(alloc_3, alloc_1, alloc_size); | |
stop = get_time(); | |
printf( | |
"finished mmapping + memcpying (alloc_size = %zu KB)...\n", | |
alloc_size / 1024); | |
printf("elapsed: %f s\n", (double)(stop - start) * 1e-9); | |
#else | |
start = get_time(); | |
void *alloc_3 = mremap( | |
alloc_1, | |
alloc_size, | |
alloc_size * 2, | |
MREMAP_MAYMOVE | |
); | |
if (alloc_3 == NULL) { | |
printf("alloc_3: mremap failed\n"); | |
exit(0); | |
} | |
stop = get_time(); | |
printf( | |
"finished remapping (alloc_size = %zu KB)...\n", | |
alloc_size / 1024); | |
printf("elapsed: %f s\n", (double)(stop - start) * 1e-9); | |
#endif | |
getchar(); | |
check_pages(alloc_3, alloc_size, page_size); | |
// ------------------------------------------------------------------------- | |
printf("terminating...\n"); | |
getchar(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment