Skip to content

Instantly share code, notes, and snippets.

@christophercrouzet
Last active May 27, 2021 10:11
Show Gist options
  • Save christophercrouzet/52b5be85207e758806ccc1c1eddcfce6 to your computer and use it in GitHub Desktop.
Save christophercrouzet/52b5be85207e758806ccc1c1eddcfce6 to your computer and use it in GitHub Desktop.
Linux's `mremap()`
#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