gcc/libgomp/testsuite/libgomp.c/alloc-pinned-4.c
Andrew Stubbs 348874f0ba libgomp: basic pinned memory on Linux
Implement the OpenMP pinned memory trait on Linux hosts using the mlock
syscall.  Pinned allocations are performed using mmap, not malloc, to ensure
that they can be unpinned safely when freed.

This implementation will work OK for page-scale allocations, and finer-grained
allocations will be implemented in a future patch.

libgomp/ChangeLog:

	* allocator.c (MEMSPACE_ALLOC): Add PIN.
	(MEMSPACE_CALLOC): Add PIN.
	(MEMSPACE_REALLOC): Add PIN.
	(MEMSPACE_FREE): Add PIN.
	(MEMSPACE_VALIDATE): Add PIN.
	(omp_init_allocator): Use MEMSPACE_VALIDATE to check pinning.
	(omp_aligned_alloc): Add pinning to all MEMSPACE_* calls.
	(omp_aligned_calloc): Likewise.
	(omp_realloc): Likewise.
	(omp_free): Likewise.
	* config/linux/allocator.c: New file.
	* config/nvptx/allocator.c (MEMSPACE_ALLOC): Add PIN.
	(MEMSPACE_CALLOC): Add PIN.
	(MEMSPACE_REALLOC): Add PIN.
	(MEMSPACE_FREE): Add PIN.
	(MEMSPACE_VALIDATE): Add PIN.
	* config/gcn/allocator.c (MEMSPACE_ALLOC): Add PIN.
	(MEMSPACE_CALLOC): Add PIN.
	(MEMSPACE_REALLOC): Add PIN.
	(MEMSPACE_FREE): Add PIN.
	* libgomp.texi: Switch pinned trait to supported.
	(MEMSPACE_VALIDATE): Add PIN.
	* testsuite/libgomp.c/alloc-pinned-1.c: New test.
	* testsuite/libgomp.c/alloc-pinned-2.c: New test.
	* testsuite/libgomp.c/alloc-pinned-3.c: New test.
	* testsuite/libgomp.c/alloc-pinned-4.c: New test.

Co-Authored-By: Thomas Schwinge <thomas@codesourcery.com>
2023-12-13 14:27:07 +00:00

150 lines
2.9 KiB
C

/* { dg-do run } */
/* Test that pinned memory fails correctly, pool_size code path. */
#include <stdio.h>
#include <stdlib.h>
#ifdef __linux__
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/resource.h>
#define PAGE_SIZE sysconf(_SC_PAGESIZE)
int
get_pinned_mem ()
{
int pid = getpid ();
char buf[100];
sprintf (buf, "/proc/%d/status", pid);
FILE *proc = fopen (buf, "r");
if (!proc)
abort ();
while (fgets (buf, 100, proc))
{
int val;
if (sscanf (buf, "VmLck: %d", &val))
{
fclose (proc);
return val;
}
}
abort ();
}
void
set_pin_limit (int size)
{
struct rlimit limit;
if (getrlimit (RLIMIT_MEMLOCK, &limit))
abort ();
limit.rlim_cur = (limit.rlim_max < size ? limit.rlim_max : size);
if (setrlimit (RLIMIT_MEMLOCK, &limit))
abort ();
}
#else
#define PAGE_SIZE 10000 * 1024 /* unknown */
#define EXPECT_OMP_NULL_ALLOCATOR
int
get_pinned_mem ()
{
return 0;
}
void
set_pin_limit ()
{
}
#endif
static void
verify0 (char *p, size_t s)
{
for (size_t i = 0; i < s; ++i)
if (p[i] != 0)
abort ();
}
#include <omp.h>
int
main ()
{
/* This needs to be large enough to cover multiple pages. */
const int SIZE = PAGE_SIZE * 4;
/* Pinned memory, no fallback. */
const omp_alloctrait_t traits1[] = {
{ omp_atk_pinned, 1 },
{ omp_atk_fallback, omp_atv_null_fb },
{ omp_atk_pool_size, SIZE * 8 }
};
omp_allocator_handle_t allocator1 = omp_init_allocator (omp_default_mem_space,
3, traits1);
/* Pinned memory, plain memory fallback. */
const omp_alloctrait_t traits2[] = {
{ omp_atk_pinned, 1 },
{ omp_atk_fallback, omp_atv_default_mem_fb },
{ omp_atk_pool_size, SIZE * 8 }
};
omp_allocator_handle_t allocator2 = omp_init_allocator (omp_default_mem_space,
3, traits2);
#ifdef EXPECT_OMP_NULL_ALLOCATOR
if (allocator1 == omp_null_allocator
&& allocator2 == omp_null_allocator)
return 0;
#endif
/* Ensure that the limit is smaller than the allocation. */
set_pin_limit (SIZE / 2);
// Sanity check
if (get_pinned_mem () != 0)
abort ();
// Should fail
void *p = omp_alloc (SIZE, allocator1);
if (p)
abort ();
// Should fail
p = omp_calloc (1, SIZE, allocator1);
if (p)
abort ();
// Should fall back
p = omp_alloc (SIZE, allocator2);
if (!p)
abort ();
// Should fall back
p = omp_calloc (1, SIZE, allocator2);
if (!p)
abort ();
verify0 (p, SIZE);
// Should fail to realloc
void *notpinned = omp_alloc (SIZE, omp_default_mem_alloc);
p = omp_realloc (notpinned, SIZE, allocator1, omp_default_mem_alloc);
if (!notpinned || p)
abort ();
// Should fall back to no realloc needed
p = omp_realloc (notpinned, SIZE, allocator2, omp_default_mem_alloc);
if (p != notpinned)
abort ();
// No memory should have been pinned
int amount = get_pinned_mem ();
if (amount != 0)
abort ();
return 0;
}