diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 0011763acd8..5d406191853 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,32 @@ +2020-05-19 Jakub Jelinek + + * 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. + 2020-05-15 H.J. Lu PR bootstrap/95147 diff --git a/libgomp/Makefile.am b/libgomp/Makefile.am index 669b9e4defd..b84156291e8 100644 --- a/libgomp/Makefile.am +++ b/libgomp/Makefile.am @@ -65,7 +65,7 @@ libgomp_la_SOURCES = alloc.c atomic.c barrier.c critical.c env.c error.c \ 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 diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in index 7c426caeb68..5ff2ac14db9 100644 --- a/libgomp/Makefile.in +++ b/libgomp/Makefile.in @@ -231,7 +231,8 @@ am_libgomp_la_OBJECTS = alloc.lo atomic.lo barrier.lo critical.lo \ 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 barrier.c critical.c env.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 \ $(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@ diff --git a/libgomp/env.c b/libgomp/env.c index dbec3ae98a0..c0c4730d47c 100644 --- a/libgomp/env.c +++ b/libgomp/env.c @@ -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 *value) 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 stacksize, int wait_policy) 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 diff --git a/libgomp/icv.c b/libgomp/icv.c index ff4430eb76d..b13289b47a7 100644 --- a/libgomp/icv.c +++ b/libgomp/icv.c @@ -197,6 +197,25 @@ omp_get_partition_place_nums (int *place_nums) *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) diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index f5415bb156c..ca42e0de640 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -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]; diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index c7268bfc8e7..012e3d645fe 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -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; diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in index 06a96c55dc8..e2db33e005f 100644 --- a/libgomp/omp.h.in +++ b/libgomp/omp.h.in @@ -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_affinity (char *, __SIZE_TYPE__, const char *) 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 diff --git a/libgomp/team.c b/libgomp/team.c index 82f26a05687..cbc3aec0265 100644 --- a/libgomp/team.c +++ b/libgomp/team.c @@ -636,6 +636,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads, 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 *), void *data, unsigned nthreads, 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 diff --git a/libgomp/testsuite/libgomp.c-c++-common/alloc-1.c b/libgomp/testsuite/libgomp.c-c++-common/alloc-1.c new file mode 100644 index 00000000000..9259a9c44df --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/alloc-1.c @@ -0,0 +1,157 @@ +#include +#include +#include + +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 (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; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/alloc-2.c b/libgomp/testsuite/libgomp.c-c++-common/alloc-2.c new file mode 100644 index 00000000000..ee539580f2b --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/alloc-2.c @@ -0,0 +1,46 @@ +#include +#include +#include + +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; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/alloc-3.c b/libgomp/testsuite/libgomp.c-c++-common/alloc-3.c new file mode 100644 index 00000000000..a30cdc05e60 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/alloc-3.c @@ -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 +#include +#include + +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; +}