openmp: Add basic library allocator support
Jakub Jelinek
jakub@redhat.com
Tue May 19 08:24:36 GMT 2020
Hi!
This patch adds very basic allocator support (omp_{init,destroy}_allocator,
omp_{alloc,free}, omp_[sg]et_default_allocator).
The plan is to use memkind (likely dlopened) for high bandwidth memory, but
that part isn't implemented yet, probably mlock for pinned memory and see
what other options there are for other kinds of memory.
For offloading targets, we need to decide if we want to support the
dynamic allocators (and on which targets), or if e.g. all we do is at compile
time replace omp_alloc/omp_free calls with constexpr predefined allocators
with something special.
And allocate directive and allocator/uses_allocators clauses are future work
too.
Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.
2020-05-19 Jakub Jelinek <jakub@redhat.com>
* omp.h.in (omp_uintptr_t): New typedef.
(__GOMP_UINTPTR_T_ENUM): Define.
(omp_memspace_handle_t, omp_allocator_handle_t, omp_alloctrait_key_t,
omp_alloctrait_value_t, omp_alloctrait_t): New typedefs.
(__GOMP_DEFAULT_NULL_ALLOCATOR): Define.
(omp_init_allocator, omp_destroy_allocator, omp_set_default_allocator,
omp_get_default_allocator, omp_alloc, omp_free): Declare.
* libgomp.h (struct gomp_team_state): Add def_allocator field.
(gomp_def_allocator): Declare.
* libgomp.map (OMP_5.0.1): Export omp_set_default_allocator,
omp_get_default_allocator, omp_init_allocator, omp_destroy_allocator,
omp_alloc and omp_free.
* team.c (gomp_team_start): Copy over ts.def_allocator.
* env.c (gomp_def_allocator): New variable.
(parse_wait_policy): Adjust function comment.
(parse_allocator): New function.
(handle_omp_display_env): Print OMP_ALLOCATOR.
(initialize_env): Call parse_allocator.
* Makefile.am (libgomp_la_SOURCES): Add allocator.c.
* allocator.c: New file.
* icv.c (omp_set_default_allocator, omp_get_default_allocator): New
functions.
* testsuite/libgomp.c-c++-common/alloc-1.c: New test.
* testsuite/libgomp.c-c++-common/alloc-2.c: New test.
* testsuite/libgomp.c-c++-common/alloc-3.c: New test.
* Makefile.in: Regenerated.
--- libgomp/omp.h.in.jj 2020-01-12 11:54:39.018374107 +0100
+++ libgomp/omp.h.in 2020-05-14 15:46:58.046243665 +0200
@@ -90,11 +90,87 @@ typedef enum omp_pause_resource_t
omp_pause_hard = 2
} omp_pause_resource_t;
+typedef __UINTPTR_TYPE__ omp_uintptr_t;
+
+#if __cplusplus >= 201103L
+# define __GOMP_UINTPTR_T_ENUM : omp_uintptr_t
+#else
+# define __GOMP_UINTPTR_T_ENUM
+#endif
+
+typedef enum omp_memspace_handle_t __GOMP_UINTPTR_T_ENUM
+{
+ omp_default_mem_space = 0,
+ omp_large_cap_mem_space = 1,
+ omp_const_mem_space = 2,
+ omp_high_bw_mem_space = 3,
+ omp_low_lat_mem_space = 4,
+ __omp_memspace_handle_t_max__ = __UINTPTR_MAX__
+} omp_memspace_handle_t;
+
+typedef enum omp_allocator_handle_t __GOMP_UINTPTR_T_ENUM
+{
+ omp_null_allocator = 0,
+ omp_default_mem_alloc = 1,
+ omp_large_cap_mem_alloc = 2,
+ omp_const_mem_alloc = 3,
+ omp_high_bw_mem_alloc = 4,
+ omp_low_lat_mem_alloc = 5,
+ omp_cgroup_mem_alloc = 6,
+ omp_pteam_mem_alloc = 7,
+ omp_thread_mem_alloc = 8,
+ __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef enum omp_alloctrait_key_t
+{
+ omp_atk_sync_hint = 1,
+ omp_atk_alignment = 2,
+ omp_atk_access = 3,
+ omp_atk_pool_size = 4,
+ omp_atk_fallback = 5,
+ omp_atk_fb_data = 6,
+ omp_atk_pinned = 7,
+ omp_atk_partition = 8
+} omp_alloctrait_key_t;
+
+typedef enum omp_alloctrait_value_t
+{
+ omp_atv_false = 0,
+ omp_atv_true = 1,
+ omp_atv_default = 2,
+ omp_atv_contended = 3,
+ omp_atv_uncontended = 4,
+ omp_atv_sequential = 5,
+ omp_atv_private = 6,
+ omp_atv_all = 7,
+ omp_atv_thread = 8,
+ omp_atv_pteam = 9,
+ omp_atv_cgroup = 10,
+ omp_atv_default_mem_fb = 11,
+ omp_atv_null_fb = 12,
+ omp_atv_abort_fb = 13,
+ omp_atv_allocator_fb = 14,
+ omp_atv_environment = 15,
+ omp_atv_nearest = 16,
+ omp_atv_blocked = 17,
+ omp_atv_interleaved = 18,
+ __omp_alloctrait_value_max__ = __UINTPTR_MAX__
+} omp_alloctrait_value_t;
+
+typedef struct omp_alloctrait_t
+{
+ omp_alloctrait_key_t key;
+ omp_uintptr_t value;
+} omp_alloctrait_t;
+
#ifdef __cplusplus
extern "C" {
# define __GOMP_NOTHROW throw ()
+# define __GOMP_DEFAULT_NULL_ALLOCATOR = omp_null_allocator
#else
# define __GOMP_NOTHROW __attribute__((__nothrow__))
+# define __GOMP_DEFAULT_NULL_ALLOCATOR
#endif
extern void omp_set_num_threads (int) __GOMP_NOTHROW;
@@ -188,6 +264,20 @@ extern __SIZE_TYPE__ omp_capture_affinit
extern int omp_pause_resource (omp_pause_resource_t, int) __GOMP_NOTHROW;
extern int omp_pause_resource_all (omp_pause_resource_t) __GOMP_NOTHROW;
+extern omp_allocator_handle_t omp_init_allocator (omp_memspace_handle_t,
+ int,
+ const omp_alloctrait_t [])
+ __GOMP_NOTHROW;
+extern void omp_destroy_allocator (omp_allocator_handle_t) __GOMP_NOTHROW;
+extern void omp_set_default_allocator (omp_allocator_handle_t) __GOMP_NOTHROW;
+extern omp_allocator_handle_t omp_get_default_allocator (void) __GOMP_NOTHROW;
+extern void *omp_alloc (__SIZE_TYPE__,
+ omp_allocator_handle_t __GOMP_DEFAULT_NULL_ALLOCATOR)
+ __GOMP_NOTHROW;
+extern void omp_free (void *,
+ omp_allocator_handle_t __GOMP_DEFAULT_NULL_ALLOCATOR)
+ __GOMP_NOTHROW;
+
#ifdef __cplusplus
}
#endif
--- libgomp/libgomp.h.jj 2020-01-12 11:54:39.016374137 +0100
+++ libgomp/libgomp.h 2020-05-14 19:21:25.791171136 +0200
@@ -397,6 +397,9 @@ struct gomp_team_state
unsigned place_partition_off;
unsigned place_partition_len;
+ /* Def-allocator-var ICV. */
+ uintptr_t def_allocator;
+
#ifdef HAVE_SYNC_BUILTINS
/* Number of single stmts encountered. */
unsigned long single_count;
@@ -450,6 +453,7 @@ extern int gomp_debug_var;
extern bool gomp_display_affinity_var;
extern char *gomp_affinity_format_var;
extern size_t gomp_affinity_format_len;
+extern uintptr_t gomp_def_allocator;
extern int goacc_device_num;
extern char *goacc_device_type;
extern int goacc_default_dims[GOMP_DIM_MAX];
--- libgomp/libgomp.map.jj 2020-01-12 11:54:39.016374137 +0100
+++ libgomp/libgomp.map 2020-05-15 16:14:40.084583166 +0200
@@ -180,6 +180,16 @@ OMP_5.0 {
omp_pause_resource_all_;
} OMP_4.5;
+OMP_5.0.1 {
+ global:
+ omp_set_default_allocator;
+ omp_get_default_allocator;
+ omp_init_allocator;
+ omp_destroy_allocator;
+ omp_alloc;
+ omp_free;
+} OMP_5.0;
+
GOMP_1.0 {
global:
GOMP_atomic_end;
--- libgomp/team.c.jj 2020-01-12 11:54:39.020374077 +0100
+++ libgomp/team.c 2020-05-18 14:42:26.221685703 +0200
@@ -636,6 +636,7 @@ gomp_team_start (void (*fn) (void *), vo
nthr->ts.active_level = thr->ts.active_level;
nthr->ts.place_partition_off = place_partition_off;
nthr->ts.place_partition_len = place_partition_len;
+ nthr->ts.def_allocator = thr->ts.def_allocator;
#ifdef HAVE_SYNC_BUILTINS
nthr->ts.single_count = 0;
#endif
@@ -823,6 +824,7 @@ gomp_team_start (void (*fn) (void *), vo
start_data->ts.team_id = i;
start_data->ts.level = team->prev_ts.level + 1;
start_data->ts.active_level = thr->ts.active_level;
+ start_data->ts.def_allocator = thr->ts.def_allocator;
#ifdef HAVE_SYNC_BUILTINS
start_data->ts.single_count = 0;
#endif
--- libgomp/env.c.jj 2020-01-12 11:54:39.016374137 +0100
+++ libgomp/env.c 2020-05-14 19:24:58.280004821 +0200
@@ -86,6 +86,7 @@ char *gomp_bind_var_list;
unsigned long gomp_bind_var_list_len;
void **gomp_places_list;
unsigned long gomp_places_list_len;
+uintptr_t gomp_def_allocator = omp_default_mem_alloc;
int gomp_debug_var;
unsigned int gomp_num_teams_var;
bool gomp_display_affinity_var;
@@ -949,8 +950,7 @@ parse_boolean (const char *name, bool *v
gomp_error ("Invalid value for environment variable %s", name);
}
-/* Parse the OMP_WAIT_POLICY environment variable and store the
- result in gomp_active_wait_policy. */
+/* Parse the OMP_WAIT_POLICY environment variable and return the value. */
static int
parse_wait_policy (void)
@@ -1084,6 +1084,47 @@ parse_affinity (bool ignore)
return false;
}
+/* Parse the OMP_ALLOCATOR environment variable and return the value. */
+
+static uintptr_t
+parse_allocator (void)
+{
+ const char *env;
+ uintptr_t ret = omp_default_mem_alloc;
+
+ env = getenv ("OMP_ALLOCATOR");
+ if (env == NULL)
+ return ret;
+
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (0)
+ ;
+#define C(v) \
+ else if (strncasecmp (env, #v, sizeof (#v) - 1) == 0) \
+ { \
+ ret = v; \
+ env += sizeof (#v) - 1; \
+ }
+ C (omp_default_mem_alloc)
+ C (omp_large_cap_mem_alloc)
+ C (omp_const_mem_alloc)
+ C (omp_high_bw_mem_alloc)
+ C (omp_low_lat_mem_alloc)
+ C (omp_cgroup_mem_alloc)
+ C (omp_pteam_mem_alloc)
+ C (omp_thread_mem_alloc)
+#undef C
+ else
+ env = "X";
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == '\0')
+ return ret;
+ gomp_error ("Invalid value for environment variable OMP_ALLOCATOR");
+ return omp_default_mem_alloc;
+}
+
static void
parse_acc_device_type (void)
{
@@ -1276,6 +1317,22 @@ handle_omp_display_env (unsigned long st
gomp_display_affinity_var ? "TRUE" : "FALSE");
fprintf (stderr, " OMP_AFFINITY_FORMAT = '%s'\n",
gomp_affinity_format_var);
+ fprintf (stderr, " OMP_ALLOCATOR = '");
+ switch (gomp_def_allocator)
+ {
+#define C(v) case v: fputs (#v, stderr); break;
+ C (omp_default_mem_alloc)
+ C (omp_large_cap_mem_alloc)
+ C (omp_const_mem_alloc)
+ C (omp_high_bw_mem_alloc)
+ C (omp_low_lat_mem_alloc)
+ C (omp_cgroup_mem_alloc)
+ C (omp_pteam_mem_alloc)
+ C (omp_thread_mem_alloc)
+#undef C
+ default: break;
+ }
+ fputs ("'\n", stderr);
if (verbose)
{
@@ -1312,6 +1369,7 @@ initialize_env (void)
parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true);
parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
true);
+ gomp_def_allocator = parse_allocator ();
if (parse_unsigned_long ("OMP_THREAD_LIMIT", &thread_limit_var, false))
{
gomp_global_icv.thread_limit_var
--- libgomp/Makefile.am.jj 2020-01-12 11:54:39.010374227 +0100
+++ libgomp/Makefile.am 2020-05-15 18:51:40.796738975 +0200
@@ -65,7 +65,7 @@ libgomp_la_SOURCES = alloc.c atomic.c ba
proc.c sem.c bar.c ptrlock.c time.c fortran.c affinity.c target.c \
splay-tree.c libgomp-plugin.c oacc-parallel.c oacc-host.c oacc-init.c \
oacc-mem.c oacc-async.c oacc-plugin.c oacc-cuda.c priority_queue.c \
- affinity-fmt.c teams.c oacc-profiling.c oacc-target.c
+ affinity-fmt.c teams.c allocator.c oacc-profiling.c oacc-target.c
include $(top_srcdir)/plugin/Makefrag.am
--- libgomp/allocator.c.jj 2020-05-14 17:00:13.351421911 +0200
+++ libgomp/allocator.c 2020-05-18 13:15:55.037731741 +0200
@@ -0,0 +1,354 @@
+/* Copyright (C) 2020 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ This file is part of the GNU Offloading and Multi Processing Library
+ (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file contains wrappers for the system allocation routines. Most
+ places in the OpenMP API do not make any provision for failure, so in
+ general we cannot allow memory allocation to fail. */
+
+#define _GNU_SOURCE
+#include "libgomp.h"
+#include <stdlib.h>
+
+#define omp_max_predefined_alloc omp_thread_mem_alloc
+
+struct omp_allocator_data
+{
+ omp_memspace_handle_t memspace;
+ omp_uintptr_t alignment;
+ omp_uintptr_t pool_size;
+ omp_uintptr_t used_pool_size;
+ omp_allocator_handle_t fb_data;
+ unsigned int sync_hint : 8;
+ unsigned int access : 8;
+ unsigned int fallback : 8;
+ unsigned int pinned : 1;
+ unsigned int partition : 7;
+#ifndef HAVE_SYNC_BUILTINS
+ gomp_mutex_t lock;
+#endif
+};
+
+struct omp_mem_header
+{
+ void *ptr;
+ size_t size;
+ omp_allocator_handle_t allocator;
+ void *pad;
+};
+
+omp_allocator_handle_t
+omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,
+ const omp_alloctrait_t traits[])
+{
+ struct omp_allocator_data data
+ = { memspace, 1, ~(uintptr_t) 0, 0, 0, omp_atv_contended, omp_atv_all,
+ omp_atv_default_mem_fb, omp_atv_false, omp_atv_environment };
+ struct omp_allocator_data *ret;
+ int i;
+
+ if (memspace > omp_low_lat_mem_space)
+ return omp_null_allocator;
+ for (i = 0; i < ntraits; i++)
+ switch (traits[i].key)
+ {
+ case omp_atk_sync_hint:
+ switch (traits[i].value)
+ {
+ case omp_atv_default:
+ data.sync_hint = omp_atv_contended;
+ break;
+ case omp_atv_contended:
+ case omp_atv_uncontended:
+ case omp_atv_sequential:
+ case omp_atv_private:
+ data.sync_hint = traits[i].value;
+ break;
+ default:
+ return omp_null_allocator;
+ }
+ break;
+ case omp_atk_alignment:
+ if ((traits[i].value & (traits[i].value - 1)) != 0
+ || !traits[i].value)
+ return omp_null_allocator;
+ data.alignment = traits[i].value;
+ break;
+ case omp_atk_access:
+ switch (traits[i].value)
+ {
+ case omp_atv_default:
+ data.access = omp_atv_all;
+ break;
+ case omp_atv_all:
+ case omp_atv_cgroup:
+ case omp_atv_pteam:
+ case omp_atv_thread:
+ data.access = traits[i].value;
+ break;
+ default:
+ return omp_null_allocator;
+ }
+ break;
+ case omp_atk_pool_size:
+ data.pool_size = traits[i].value;
+ break;
+ case omp_atk_fallback:
+ switch (traits[i].value)
+ {
+ case omp_atv_default:
+ data.fallback = omp_atv_default_mem_fb;
+ break;
+ case omp_atv_default_mem_fb:
+ case omp_atv_null_fb:
+ case omp_atv_abort_fb:
+ case omp_atv_allocator_fb:
+ data.fallback = traits[i].value;
+ break;
+ default:
+ return omp_null_allocator;
+ }
+ break;
+ case omp_atk_fb_data:
+ data.fb_data = traits[i].value;
+ break;
+ case omp_atk_pinned:
+ switch (traits[i].value)
+ {
+ case omp_atv_default:
+ case omp_atv_false:
+ data.pinned = omp_atv_false;
+ break;
+ case omp_atv_true:
+ data.pinned = omp_atv_true;
+ break;
+ default:
+ return omp_null_allocator;
+ }
+ break;
+ case omp_atk_partition:
+ switch (traits[i].value)
+ {
+ case omp_atv_default:
+ data.partition = omp_atv_environment;
+ break;
+ case omp_atv_environment:
+ case omp_atv_nearest:
+ case omp_atv_blocked:
+ case omp_atv_interleaved:
+ data.partition = traits[i].value;
+ break;
+ default:
+ return omp_null_allocator;
+ }
+ break;
+ default:
+ return omp_null_allocator;
+ }
+
+ if (data.alignment < sizeof (void *))
+ data.alignment = sizeof (void *);
+
+ /* No support for these so far (for hbw will use memkind). */
+ if (data.pinned || data.memspace == omp_high_bw_mem_space)
+ return omp_null_allocator;
+
+ ret = gomp_malloc (sizeof (struct omp_allocator_data));
+ *ret = data;
+#ifndef HAVE_SYNC_BUILTINS
+ gomp_mutex_init (&ret->lock);
+#endif
+ return (omp_allocator_handle_t) ret;
+}
+
+void
+omp_destroy_allocator (omp_allocator_handle_t allocator)
+{
+ if (allocator != omp_null_allocator)
+ {
+#ifndef HAVE_SYNC_BUILTINS
+ gomp_mutex_destroy (&((struct omp_allocator_data *) allocator)->lock);
+#endif
+ free ((void *) allocator);
+ }
+}
+
+void *
+omp_alloc (size_t size, omp_allocator_handle_t allocator)
+{
+ struct omp_allocator_data *allocator_data;
+ size_t alignment, new_size;
+ void *ptr, *ret;
+
+retry:
+ if (allocator == omp_null_allocator)
+ {
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->ts.def_allocator == omp_null_allocator)
+ thr->ts.def_allocator = gomp_def_allocator;
+ allocator = (omp_allocator_handle_t) thr->ts.def_allocator;
+ }
+
+ if (allocator > omp_max_predefined_alloc)
+ {
+ allocator_data = (struct omp_allocator_data *) allocator;
+ alignment = allocator_data->alignment;
+ }
+ else
+ {
+ allocator_data = NULL;
+ alignment = sizeof (void *);
+ }
+
+ new_size = sizeof (struct omp_mem_header);
+ if (alignment > sizeof (void *))
+ new_size += alignment - sizeof (void *);
+ if (__builtin_add_overflow (size, new_size, &new_size))
+ goto fail;
+
+ if (__builtin_expect (allocator_data
+ && allocator_data->pool_size < ~(uintptr_t) 0, 0))
+ {
+ uintptr_t used_pool_size;
+ if (new_size > allocator_data->pool_size)
+ goto fail;
+#ifdef HAVE_SYNC_BUILTINS
+ used_pool_size = __atomic_load_n (&allocator_data->used_pool_size,
+ MEMMODEL_RELAXED);
+ do
+ {
+ uintptr_t new_pool_size;
+ if (__builtin_add_overflow (used_pool_size, new_size,
+ &new_pool_size)
+ || new_pool_size > allocator_data->pool_size)
+ goto fail;
+ if (__atomic_compare_exchange_n (&allocator_data->used_pool_size,
+ &used_pool_size, new_pool_size,
+ true, MEMMODEL_RELAXED,
+ MEMMODEL_RELAXED))
+ break;
+ }
+ while (1);
+#else
+ gomp_mutex_lock (&allocator_data->lock);
+ if (__builtin_add_overflow (allocator_data->used_pool_size, new_size,
+ &used_pool_size)
+ || used_pool_size > allocator_data->pool_size)
+ {
+ gomp_mutex_unlock (&allocator_data->lock);
+ goto fail;
+ }
+ allocator_data->used_pool_size = used_pool_size;
+ gomp_mutex_unlock (&allocator_data->lock);
+#endif
+ ptr = malloc (new_size);
+ if (ptr == NULL)
+ {
+#ifdef HAVE_SYNC_BUILTINS
+ __atomic_add_fetch (&allocator_data->used_pool_size, -new_size,
+ MEMMODEL_RELAXED);
+#else
+ gomp_mutex_lock (&allocator_data->lock);
+ allocator_data->used_pool_size -= new_size;
+ gomp_mutex_unlock (&allocator_data->lock);
+#endif
+ goto fail;
+ }
+ }
+ else
+ {
+ ptr = malloc (new_size);
+ if (ptr == NULL)
+ goto fail;
+ }
+
+ if (alignment > sizeof (void *))
+ ret = (void *) (((uintptr_t) ptr
+ + sizeof (struct omp_mem_header)
+ + alignment - sizeof (void *)) & ~(alignment - 1));
+ else
+ ret = (char *) ptr + sizeof (struct omp_mem_header);
+ ((struct omp_mem_header *) ret)[-1].ptr = ptr;
+ ((struct omp_mem_header *) ret)[-1].size = new_size;
+ ((struct omp_mem_header *) ret)[-1].allocator = allocator;
+ return ret;
+
+fail:
+ if (allocator_data)
+ {
+ switch (allocator_data->fallback)
+ {
+ case omp_atv_default_mem_fb:
+ if (alignment > sizeof (void *)
+ || (allocator_data
+ && allocator_data->pool_size < ~(uintptr_t) 0))
+ {
+ allocator = omp_default_mem_alloc;
+ goto retry;
+ }
+ /* Otherwise, we've already performed default mem allocation
+ and if that failed, it won't succeed again (unless it was
+ intermitent. Return NULL then, as that is the fallback. */
+ break;
+ case omp_atv_null_fb:
+ break;
+ default:
+ case omp_atv_abort_fb:
+ gomp_fatal ("Out of memory allocating %lu bytes",
+ (unsigned long) size);
+ case omp_atv_allocator_fb:
+ allocator = allocator_data->fb_data;
+ goto retry;
+ }
+ }
+ return NULL;
+}
+
+void
+omp_free (void *ptr, omp_allocator_handle_t allocator)
+{
+ struct omp_mem_header *data;
+
+ if (ptr == NULL)
+ return;
+ (void) allocator;
+ data = &((struct omp_mem_header *) ptr)[-1];
+ if (data->allocator > omp_max_predefined_alloc)
+ {
+ struct omp_allocator_data *allocator_data
+ = (struct omp_allocator_data *) (data->allocator);
+ if (allocator_data->pool_size < ~(uintptr_t) 0)
+ {
+#ifdef HAVE_SYNC_BUILTINS
+ __atomic_add_fetch (&allocator_data->used_pool_size, -data->size,
+ MEMMODEL_RELAXED);
+#else
+ gomp_mutex_lock (&allocator_data->lock);
+ allocator_data->used_pool_size -= data->new_size;
+ gomp_mutex_unlock (&allocator_data->lock);
+#endif
+ }
+ }
+ free (data->ptr);
+}
--- libgomp/icv.c.jj 2020-01-12 11:54:39.016374137 +0100
+++ libgomp/icv.c 2020-05-14 19:24:18.074603926 +0200
@@ -197,6 +197,25 @@ omp_get_partition_place_nums (int *place
*place_nums++ = thr->ts.place_partition_off + i;
}
+void
+omp_set_default_allocator (omp_allocator_handle_t allocator)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ if (allocator == omp_null_allocator)
+ allocator = omp_default_mem_alloc;
+ thr->ts.def_allocator = (uintptr_t) allocator;
+}
+
+omp_allocator_handle_t
+omp_get_default_allocator (void)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ if (thr->ts.def_allocator == omp_null_allocator)
+ return (omp_allocator_handle_t) gomp_def_allocator;
+ else
+ return (omp_allocator_handle_t) thr->ts.def_allocator;
+}
+
ialias (omp_set_dynamic)
ialias (omp_set_nested)
ialias (omp_set_num_threads)
--- libgomp/testsuite/libgomp.c-c++-common/alloc-1.c.jj 2020-05-18 12:46:01.630710546 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/alloc-1.c 2020-05-18 14:18:16.091446145 +0200
@@ -0,0 +1,157 @@
+#include <omp.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+const omp_alloctrait_t traits2[]
+= { { omp_atk_alignment, 16 },
+ { omp_atk_sync_hint, omp_atv_default },
+ { omp_atk_access, omp_atv_default },
+ { omp_atk_pool_size, 1024 },
+ { omp_atk_fallback, omp_atv_default_mem_fb },
+ { omp_atk_partition, omp_atv_environment } };
+omp_alloctrait_t traits3[]
+= { { omp_atk_sync_hint, omp_atv_uncontended },
+ { omp_atk_alignment, 32 },
+ { omp_atk_access, omp_atv_all },
+ { omp_atk_pool_size, 512 },
+ { omp_atk_fallback, omp_atv_allocator_fb },
+ { omp_atk_fb_data, 0 },
+ { omp_atk_partition, omp_atv_default } };
+const omp_alloctrait_t traits4[]
+= { { omp_atk_alignment, 128 },
+ { omp_atk_pool_size, 1024 },
+ { omp_atk_fallback, omp_atv_null_fb } };
+
+int
+main ()
+{
+ int *volatile p = (int *) omp_alloc (3 * sizeof (int), omp_default_mem_alloc);
+ int *volatile q;
+ int *volatile r;
+ omp_alloctrait_t traits[3]
+ = { { omp_atk_alignment, 64 },
+ { omp_atk_fallback, omp_atv_null_fb },
+ { omp_atk_pool_size, 4096 } };
+ omp_allocator_handle_t a, a2;
+
+ if ((((uintptr_t) p) % __alignof (int)) != 0)
+ abort ();
+ p[0] = 1;
+ p[1] = 2;
+ p[2] = 3;
+ omp_free (p, omp_default_mem_alloc);
+ p = (int *) omp_alloc (2 * sizeof (int), omp_default_mem_alloc);
+ if ((((uintptr_t) p) % __alignof (int)) != 0)
+ abort ();
+ p[0] = 1;
+ p[1] = 2;
+ omp_free (p, omp_null_allocator);
+ omp_set_default_allocator (omp_default_mem_alloc);
+ p = (int *) omp_alloc (sizeof (int), omp_null_allocator);
+ if ((((uintptr_t) p) % __alignof (int)) != 0)
+ abort ();
+ p[0] = 3;
+ omp_free (p, omp_get_default_allocator ());
+
+ a = omp_init_allocator (omp_default_mem_space, 3, traits);
+ if (a == omp_null_allocator)
+ abort ();
+ p = (int *) omp_alloc (3072, a);
+ if ((((uintptr_t) p) % 64) != 0)
+ abort ();
+ p[0] = 1;
+ p[3071 / sizeof (int)] = 2;
+ if (omp_alloc (3072, a) != NULL)
+ abort ();
+ omp_free (p, a);
+ p = (int *) omp_alloc (3072, a);
+ p[0] = 3;
+ p[3071 / sizeof (int)] = 4;
+ omp_free (p, omp_null_allocator);
+ omp_set_default_allocator (a);
+ if (omp_get_default_allocator () != a)
+ abort ();
+ p = (int *) omp_alloc (3072, omp_null_allocator);
+ if (omp_alloc (3072, omp_null_allocator) != NULL)
+ abort ();
+ omp_free (p, a);
+ omp_destroy_allocator (a);
+
+ a = omp_init_allocator (omp_default_mem_space,
+ sizeof (traits2) / sizeof (traits2[0]),
+ traits2);
+ if (a == omp_null_allocator)
+ abort ();
+ if (traits3[5].key != omp_atk_fb_data)
+ abort ();
+ traits3[5].value = (uintptr_t) a;
+ a2 = omp_init_allocator (omp_default_mem_space,
+ sizeof (traits3) / sizeof (traits3[0]),
+ traits3);
+ if (a2 == omp_null_allocator)
+ abort ();
+ p = (int *) omp_alloc (420, a2);
+ if ((((uintptr_t) p) % 32) != 0)
+ abort ();
+ p[0] = 5;
+ p[419 / sizeof (int)] = 6;
+ q = (int *) omp_alloc (768, a2);
+ if ((((uintptr_t) q) % 16) != 0)
+ abort ();
+ q[0] = 7;
+ q[767 / sizeof (int)] = 8;
+ r = (int *) omp_alloc (512, a2);
+ if ((((uintptr_t) r) % __alignof (int)) != 0)
+ abort ();
+ r[0] = 9;
+ r[511 / sizeof (int)] = 10;
+ omp_free (p, omp_null_allocator);
+ omp_free (q, a2);
+ omp_free (r, omp_null_allocator);
+ omp_destroy_allocator (a2);
+ omp_destroy_allocator (a);
+
+ a = omp_init_allocator (omp_default_mem_space,
+ sizeof (traits4) / sizeof (traits4[0]),
+ traits4);
+ if (a == omp_null_allocator)
+ abort ();
+ if (traits3[5].key != omp_atk_fb_data)
+ abort ();
+ traits3[5].value = (uintptr_t) a;
+ a2 = omp_init_allocator (omp_default_mem_space,
+ sizeof (traits3) / sizeof (traits3[0]),
+ traits3);
+ if (a2 == omp_null_allocator)
+ abort ();
+ omp_set_default_allocator (a2);
+#ifdef __cplusplus
+ p = static_cast <int *> (omp_alloc (420));
+#else
+ p = (int *) omp_alloc (420, omp_null_allocator);
+#endif
+ if ((((uintptr_t) p) % 32) != 0)
+ abort ();
+ p[0] = 5;
+ p[419 / sizeof (int)] = 6;
+ q = (int *) omp_alloc (768, omp_null_allocator);
+ if ((((uintptr_t) q) % 128) != 0)
+ abort ();
+ q[0] = 7;
+ q[767 / sizeof (int)] = 8;
+ if (omp_alloc (768, omp_null_allocator) != NULL)
+ abort ();
+#ifdef __cplusplus
+ omp_free (p);
+ omp_free (q);
+ omp_free (NULL);
+#else
+ omp_free (p, omp_null_allocator);
+ omp_free (q, omp_null_allocator);
+ omp_free (NULL, omp_null_allocator);
+#endif
+ omp_free (NULL, omp_null_allocator);
+ omp_destroy_allocator (a2);
+ omp_destroy_allocator (a);
+ return 0;
+}
--- libgomp/testsuite/libgomp.c-c++-common/alloc-2.c.jj 2020-05-18 13:32:30.862751223 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/alloc-2.c 2020-05-18 14:20:18.269607455 +0200
@@ -0,0 +1,46 @@
+#include <omp.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ omp_alloctrait_t traits[3]
+ = { { omp_atk_alignment, 64 },
+ { omp_atk_fallback, omp_atv_null_fb },
+ { omp_atk_pool_size, 4096 } };
+ omp_allocator_handle_t a
+ = omp_init_allocator (omp_default_mem_space, 3, traits);
+ if (a == omp_null_allocator)
+ abort ();
+
+ #pragma omp parallel num_threads(4)
+ {
+ int n = omp_get_thread_num ();
+ double *volatile p, *volatile q;
+ omp_set_default_allocator ((n & 1) ? a : omp_default_mem_alloc);
+ p = (double *) omp_alloc (1696, omp_null_allocator);
+ if (p == NULL)
+ abort ();
+ p[0] = 1.0;
+ p[1695 / sizeof (double *)] = 2.0;
+ #pragma omp barrier
+ omp_set_default_allocator ((n & 1) ? omp_default_mem_alloc : a);
+ q = (double *) omp_alloc (1696, omp_null_allocator);
+ if (n & 1)
+ {
+ if (q == NULL)
+ abort ();
+ q[0] = 3.0;
+ q[1695 / sizeof (double *)] = 4.0;
+ }
+ else if (q != NULL)
+ abort ();
+ #pragma omp barrier
+ omp_free (p, omp_null_allocator);
+ omp_free (q, omp_null_allocator);
+ omp_set_default_allocator (omp_default_mem_alloc);
+ }
+ omp_destroy_allocator (a);
+ return 0;
+}
--- libgomp/testsuite/libgomp.c-c++-common/alloc-3.c.jj 2020-05-18 14:29:03.975695993 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/alloc-3.c 2020-05-18 14:32:26.953650327 +0200
@@ -0,0 +1,28 @@
+/* { dg-set-target-env-var OMP_ALLOCATOR "omp_cgroup_mem_alloc" } */
+/* { dg-set-target-env-var OMP_DISPLAY_ENV "true" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <omp.h>
+
+int
+main ()
+{
+ const char *p = getenv ("OMP_ALLOCATOR");
+ if (p && strcmp (p, "omp_cgroup_mem_alloc") == 0)
+ {
+ if (omp_get_default_allocator () != omp_cgroup_mem_alloc)
+ abort ();
+ #pragma omp parallel num_threads (2)
+ {
+ if (omp_get_default_allocator () != omp_cgroup_mem_alloc)
+ abort ();
+ #pragma omp parallel num_threads (2)
+ {
+ if (omp_get_default_allocator () != omp_cgroup_mem_alloc)
+ abort ();
+ }
+ }
+ }
+ return 0;
+}
--- libgomp/Makefile.in.jj 2020-01-24 22:34:36.386640520 +0100
+++ libgomp/Makefile.in 2020-05-15 18:57:45.661185739 +0200
@@ -231,7 +231,8 @@ am_libgomp_la_OBJECTS = alloc.lo atomic.
target.lo splay-tree.lo libgomp-plugin.lo oacc-parallel.lo \
oacc-host.lo oacc-init.lo oacc-mem.lo oacc-async.lo \
oacc-plugin.lo oacc-cuda.lo priority_queue.lo affinity-fmt.lo \
- teams.lo oacc-profiling.lo oacc-target.lo $(am__objects_1)
+ teams.lo allocator.lo oacc-profiling.lo oacc-target.lo \
+ $(am__objects_1)
libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -572,7 +573,7 @@ libgomp_la_SOURCES = alloc.c atomic.c ba
affinity.c target.c splay-tree.c libgomp-plugin.c \
oacc-parallel.c oacc-host.c oacc-init.c oacc-mem.c \
oacc-async.c oacc-plugin.c oacc-cuda.c priority_queue.c \
- affinity-fmt.c teams.c oacc-profiling.c oacc-target.c \
+ affinity-fmt.c teams.c allocator.c oacc-profiling.c oacc-target.c \
$(am__append_4)
# Nvidia PTX OpenACC plugin.
@@ -765,6 +766,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinity-fmt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinity.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bar.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/barrier.Plo@am__quote@
Jakub
More information about the Gcc-patches
mailing list