libgomp: Extend OMP_ALLOCATOR, add affinity env var doc

Support OpenMP 5.1's syntax for OMP_ALLOCATOR as well,
which permits besides predefined allocators also
predefined memspaces optionally followed by traits.

Additionally, this commit adds the previously lacking
documentation for OMP_ALLOCATOR, OMP_AFFINITY_FORMAT
and OMP_DISPLAY_AFFINITY.

libgomp/ChangeLog:

	* env.c (gomp_def_allocator_envvar): New var.
	(parse_allocator): Handle OpenMP 5.1 syntax.
	(cleanup_env): New.
	(omp_display_env): Output gomp_def_allocator_envvar
	for an allocator with traits.
	* libgomp.texi (OMP_ALLOCATOR, OMP_AFFINITY_FORMAT,
	OMP_DISPLAY_AFFINITY): New.
	* testsuite/libgomp.c/allocator-1.c: New test.
	* testsuite/libgomp.c/allocator-2.c: New test.
	* testsuite/libgomp.c/allocator-3.c: New test.
	* testsuite/libgomp.c/allocator-4.c: New test.
	* testsuite/libgomp.c/allocator-5.c: New test.
	* testsuite/libgomp.c/allocator-6.c: New test.
This commit is contained in:
Tobias Burnus 2023-06-15 12:55:58 +02:00
parent a4df0ce78d
commit 73a0d3bf89
8 changed files with 419 additions and 13 deletions

View file

@ -112,6 +112,7 @@ 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;
char *gomp_def_allocator_envvar = NULL;
int gomp_debug_var;
unsigned int gomp_num_teams_var;
int gomp_nteams_var;
@ -1233,8 +1234,12 @@ parse_affinity (bool ignore)
static bool
parse_allocator (const char *env, const char *val, void *const params[])
{
const char *orig_val = val;
uintptr_t *ret = (uintptr_t *) params[0];
*ret = omp_default_mem_alloc;
bool memspace = false;
size_t ntraits = 0;
omp_alloctrait_t *traits;
if (val == NULL)
return false;
@ -1243,28 +1248,169 @@ parse_allocator (const char *env, const char *val, void *const params[])
++val;
if (0)
;
#define C(v) \
#define C(v, m) \
else if (strncasecmp (val, #v, sizeof (#v) - 1) == 0) \
{ \
*ret = v; \
val += sizeof (#v) - 1; \
memspace = m; \
}
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)
C (omp_default_mem_alloc, false)
C (omp_large_cap_mem_alloc, false)
C (omp_const_mem_alloc, false)
C (omp_high_bw_mem_alloc, false)
C (omp_low_lat_mem_alloc, false)
C (omp_cgroup_mem_alloc, false)
C (omp_pteam_mem_alloc, false)
C (omp_thread_mem_alloc, false)
C (omp_default_mem_space, true)
C (omp_large_cap_mem_space, true)
C (omp_const_mem_space, true)
C (omp_high_bw_mem_space, true)
C (omp_low_lat_mem_space, true)
#undef C
else
val = "X";
goto invalid;
if (memspace && *val == ':')
{
++val;
const char *cp = val;
while (*cp != '\0')
{
if (*cp == '=')
++ntraits;
++cp;
}
traits = gomp_alloca (ntraits * sizeof (omp_alloctrait_t));
size_t n = 0;
while (*val != '\0')
{
#define C(v) \
else if (strncasecmp (val, #v "=", sizeof (#v)) == 0) \
{ \
val += sizeof (#v); \
traits[n].key = omp_atk_ ## v;
#define V(v) \
else if (strncasecmp (val, #v, sizeof (#v) - 1) == 0) \
{ \
val += sizeof (#v) - 1; \
traits[n].value = omp_atv_ ## v; \
}
if (0)
;
C (sync_hint)
if (0)
;
V (contended)
V (uncontended)
V (serialized)
V (private)
else
goto invalid;
}
C (alignment)
char *end;
errno = 0;
traits[n].value = strtol (val, &end, 10);
if (errno || end == val || traits[n].value <= 0)
goto invalid;
val = end;
}
C (access)
if (0)
;
V (all)
V (cgroup)
V (pteam)
V (thread)
else
goto invalid;
}
C (pool_size)
char *end;
errno = 0;
traits[n].value = strtol (val, &end, 10);
if (errno || end == val || traits[n].value <= 0)
goto invalid;
val = end;
}
C (fallback)
if (0)
;
V (default_mem_fb)
V (null_fb)
V (abort_fb)
V (allocator_fb)
else
goto invalid;
}
/* Ignore fb_data, which expects an allocator handle. */
C (pinned)
if (0)
;
V (true)
V (false)
else
goto invalid;
}
C (partition)
if (0)
;
V (environment)
V (nearest)
V (blocked)
V (interleaved)
else
goto invalid;
}
else
goto invalid;
if (*val != ',')
break;
++val;
++n;
if (*val == '\0')
goto invalid;
}
#undef C
#undef V
}
else if (memspace)
switch (*ret)
{
case omp_default_mem_space: *ret = omp_default_mem_alloc; break;
case omp_large_cap_mem_space: *ret = omp_large_cap_mem_alloc; break;
case omp_const_mem_space: *ret = omp_const_mem_alloc; break;
case omp_high_bw_mem_space: *ret = omp_high_bw_mem_alloc; break;
case omp_low_lat_mem_space: *ret = omp_low_lat_mem_alloc; break;
default: __builtin_unreachable ();
}
while (isspace ((unsigned char) *val))
++val;
if (*val == '\0')
return true;
print_env_var_error (env, val);
{
if (ntraits)
{
*ret = omp_init_allocator (*ret, ntraits, traits);
if (*ret == omp_null_allocator)
{
gomp_error ("Allocator of environment variable %.*s cannot be "
"created, using omp_default_mem_alloc instead",
(int) (orig_val - env - 1), env);
*ret = omp_default_mem_alloc;
}
else
gomp_def_allocator_envvar = strdup (orig_val);
}
return true;
}
invalid:
int len = (orig_val - env - 1);
if (*val == '\0')
gomp_error ("Missing value at the end of environment variable %s", env);
else
gomp_error ("Invalid value for environment variable %.*s when parsing: %s",
len, env, val);
*ret = omp_default_mem_alloc;
return false;
}
@ -1784,7 +1930,11 @@ omp_display_env (int verbose)
C (omp_pteam_mem_alloc)
C (omp_thread_mem_alloc)
#undef C
default: break;
/* For an OMP_ALLOCATOR with traits, '' will be output. */
default:
if (gomp_def_allocator_envvar)
fputs (gomp_def_allocator_envvar, stderr);
break;
}
fputs ("'\n", stderr);
@ -2036,6 +2186,16 @@ startswith (const char *str, const char *prefix)
return strncmp (str, prefix, strlen (prefix)) == 0;
}
static void __attribute__((destructor))
cleanup_env (void)
{
if (gomp_def_allocator_envvar != NULL)
{
free (gomp_def_allocator_envvar);
omp_destroy_allocator (gomp_def_allocator);
}
}
static void __attribute__((constructor))
initialize_env (void)
{

View file

@ -1937,7 +1937,10 @@ section 4 of the OpenMP specification in version 4.5, while those
beginning with @env{GOMP_} are GNU extensions.
@menu
* OMP_ALLOCATOR:: Set the default allocator
* OMP_AFFINITY_FORMAT:: Set the format string used for affinity display
* OMP_CANCELLATION:: Set whether cancellation is activated
* OMP_DISPLAY_AFFINITY:: Display thread affinity information
* OMP_DISPLAY_ENV:: Show OpenMP version and environment variables
* OMP_DEFAULT_DEVICE:: Set the device used in target regions
* OMP_DYNAMIC:: Dynamic adjustment of threads
@ -1962,6 +1965,125 @@ beginning with @env{GOMP_} are GNU extensions.
@end menu
@node OMP_ALLOCATOR
@section @env{OMP_ALLOCATOR} -- Set the default allocator
@cindex Environment Variable
@table @asis
@item @emph{Description}:
Sets the default allocator that is used when no allocator has been specified
in the @code{allocate} or @code{allocator} clause or if an OpenMP memory
routine is invoked with the @code{omp_null_allocator} allocator.
If unset, @code{omp_default_mem_alloc} is used.
The value can either be a predefined allocator or a predefined memory space
or a predefined memory space followed by a colon and a comma-separated list
of memory trait and value pairs, separated by @code{=}.
@multitable @columnfractions .45 .45
@headitem Predefined allocators @tab Predefined memory spaces
@item omp_default_mem_alloc @tab omp_default_mem_space
@item omp_large_cap_mem_alloc @tab omp_large_cap_mem_space
@item omp_const_mem_alloc @tab omp_const_mem_space
@item omp_high_bw_mem_alloc @tab omp_high_bw_mem_space
@item omp_low_lat_mem_alloc @tab omp_low_lat_mem_space
@item omp_cgroup_mem_alloc @tab --
@item omp_pteam_mem_alloc @tab --
@item omp_thread_mem_alloc @tab --
@end multitable
@multitable @columnfractions .30 .60
@headitem Trait @tab Allowed values
@item @code{sync_hint} @tab @code{contended}, @code{uncontended},
@code{serialized}, @code{private}
@item @code{alignment} @tab Positive integer being a power of two
@item @code{access} @tab @code{all}, @code{cgroup},
@code{pteam}, @code{thread}
@item @code{pool_size} @tab Positive integer
@item @code{fallback} @tab @code{default_mem_fb}, @code{null_fb},
@code{abort_fb}, @code{allocator_fb}
@item @code{fb_data} @tab @emph{unsupported as it needs an allocator handle}
@item @code{pinned} @tab @code{true}, @code{false}
@item @code{partition} @tab @code{environment}, @code{nearest},
@code{blocked}, @code{interleaved}
@end multitable
Examples:
@smallexample
OMP_ALLOCATOR=omp_high_bw_mem_alloc
OMP_ALLOCATOR=omp_large_cap_mem_space
OMP_ALLOCATR=omp_low_lat_mem_space:pinned=true,partition=nearest
@end smallexample
@c @item @emph{See also}:
@item @emph{Reference}:
@uref{https://www.openmp.org, OpenMP specification v5.0}, Section 6.21
@end table
@node OMP_AFFINITY_FORMAT
@section @env{OMP_AFFINITY_FORMAT} -- Set the format string used for affinity display
@cindex Environment Variable
@table @asis
@item @emph{Description}:
Sets the format string used when displaying OpenMP thread affinity information.
Special values are output using @code{%} followed by an optional size
specification and then either the single-character field type or its long
name enclosed in curly braces; using @code{%%} will display a literal percent.
The size specification consists of an optional @code{0.} or @code{.} followed
by a positive integer, specifing the minimal width of the output. With
@code{0.} and numerical values, the output is padded with zeros on the left;
with @code{.}, the output is padded by spaces on the left; otherwise, the
output is padded by spaces on the right. If unset, the value is
``@code{level %L thread %i affinity %A}''.
Supported field types are:
@multitable @columnfractions .10 .25 .60
@item t @tab team_num @tab value returned by @code{omp_get_team_num}
@item T @tab num_teams @tab value returned by @code{omp_get_num_teams}
@item L @tab nesting_level @tab value returned by @code{omp_get_level}
@item n @tab thread_num @tab value returned by @code{omp_get_thread_num}
@item N @tab num_threads @tab value returned by @code{omp_get_num_threads}
@item a @tab ancestor_tnum
@tab value returned by
@code{omp_get_ancestor_thread_num(omp_get_level()-1)}
@item H @tab host @tab name of the host that executes the thread
@item P @tab process_id @tab process identifier
@item i @tab native_thread_id @tab native thread identifier
@item A @tab thread_affinity
@tab comma separated list of integer values or ranges, representing the
processors on which a process might execute, subject to affinity
mechanisms
@end multitable
For instance, after setting
@smallexample
OMP_AFFINITY_FORMAT="%0.2a!%n!%.4L!%N;%.2t;%0.2T;%@{team_num@};%@{num_teams@};%A"
@end smallexample
with either @code{OMP_DISPLAY_AFFINITY} being set or when calling
@code{omp_display_affinity} with @code{NULL} or an empty string, the program
might display the following:
@smallexample
00!0! 1!4; 0;01;0;1;0-11
00!3! 1!4; 0;01;0;1;0-11
00!2! 1!4; 0;01;0;1;0-11
00!1! 1!4; 0;01;0;1;0-11
@end smallexample
@item @emph{See also}:
@ref{OMP_DISPLAY_AFFINITY}
@item @emph{Reference}:
@uref{https://www.openmp.org, OpenMP specification v5.0}, Section 6.14
@end table
@node OMP_CANCELLATION
@section @env{OMP_CANCELLATION} -- Set whether cancellation is activated
@cindex Environment Variable
@ -1979,6 +2101,26 @@ if unset, cancellation is disabled and the @code{cancel} construct is ignored.
@node OMP_DISPLAY_AFFINITY
@section @env{OMP_DISPLAY_AFFINITY} -- Display thread affinity information
@cindex Environment Variable
@table @asis
@item @emph{Description}:
If set to @code{FALSE} or if unset, affinity displaying is disabled.
If set to @code{TRUE}, the runtime will display affinity information about
OpenMP threads in a parallel region upon entering the region and every time
any change occurs.
@item @emph{See also}:
@ref{OMP_AFFINITY_FORMAT}
@item @emph{Reference}:
@uref{https://www.openmp.org, OpenMP specification v5.0}, Section 6.13
@end table
@node OMP_DISPLAY_ENV
@section @env{OMP_DISPLAY_ENV} -- Show OpenMP version and environment variables
@cindex Environment Variable

View file

@ -0,0 +1,15 @@
/* { dg-set-target-env-var OMP_ALLOCATOR "omp_large_cap_mem_alloc" } */
/* { dg-set-target-env-var OMP_DISPLAY_ENV "true" } */
/* { dg-output ".\\\[host\\\] OMP_ALLOCATOR = 'omp_large_cap_mem_alloc'.*" } */
#include <omp.h>
int
main ()
{
omp_allocator_handle_t m = omp_get_default_allocator ();
if (m != omp_large_cap_mem_alloc)
__builtin_abort ();
return 0;
}

View file

@ -0,0 +1,17 @@
/* { dg-set-target-env-var OMP_ALLOCATOR "omp_large_cap_mem_space" } */
/* { dg-set-target-env-var OMP_DISPLAY_ENV "true" } */
/* Expect omp_large_cap_mem_alloc as allocator for omp_large_cap_mem_space. */
/* { dg-output ".\\\[host\\\] OMP_ALLOCATOR = 'omp_large_cap_mem_alloc'.*" } */
#include <omp.h>
int
main ()
{
omp_allocator_handle_t m = omp_get_default_allocator ();
/* Without traits, omp_large_cap_mem_space implies
omp_large_cap_mem_alloc. */
if (m != omp_large_cap_mem_alloc)
__builtin_abort ();
return 0;
}

View file

@ -0,0 +1,27 @@
/* { dg-set-target-env-var OMP_ALLOCATOR " omp_default_mem_space:alignment=512,pinned=false,access=all " } */
/* { dg-set-target-env-var OMP_DISPLAY_ENV "true" } */
/* We copied the environment string; hence, it may contain white space. */
/* { dg-output ".\\\[host\\\] OMP_ALLOCATOR = ' omp_default_mem_space:alignment=512,pinned=false,access=all '.*" } */
#include <stdint.h>
#include <omp.h>
int
main ()
{
int *a, *b;
a = omp_alloc (sizeof (int) * 1024, omp_null_allocator);
omp_allocator_handle_t m = omp_get_default_allocator ();
b = omp_alloc (sizeof (int) * 1024, m);
if ((uintptr_t) a % 512 != 0)
__builtin_abort ();
if ((uintptr_t) b % 512 != 0)
__builtin_abort ();
omp_free (a, omp_null_allocator);
omp_free (b, m);
return 0;
}

View file

@ -0,0 +1,15 @@
/* { dg-set-target-env-var OMP_ALLOCATOR "omp_const_mem_space:alignment=3,pinned=" } */
/* { dg-output ".*libgomp: Missing value at the end of environment variable OMP_ALLOCATOR=omp_const_mem_space:alignment=3,pinned=.*" } */
/* OMP_ALLOCATOR syntax error -> use omp_default_mem_alloc. */
#include <omp.h>
int
main ()
{
omp_allocator_handle_t m = omp_get_default_allocator ();
if (m != omp_default_mem_alloc)
__builtin_abort ();
return 0;
}

View file

@ -0,0 +1,15 @@
/* { dg-set-target-env-var OMP_ALLOCATOR "omp_const_mem_space:access=none,pinned=false" } */
/* { dg-output ".*libgomp: Invalid value for environment variable OMP_ALLOCATOR when parsing: none,pinned=false.*" } */
/* OMP_ALLOCATOR syntax error -> use omp_default_mem_alloc. */
#include <omp.h>
int
main ()
{
omp_allocator_handle_t m = omp_get_default_allocator ();
if (m != omp_default_mem_alloc)
__builtin_abort ();
return 0;
}

View file

@ -0,0 +1,15 @@
/* { dg-set-target-env-var OMP_ALLOCATOR "omp_default_mem_space:alignment=3" } */
/* { dg-output ".*libgomp: Allocator of environment variable OMP_ALLOCATOR cannot be created, using omp_default_mem_alloc instead.*" } */
/* OMP_ALLOCATOR's alignment is not power of 2 -> use omp_default_mem_alloc. */
#include <omp.h>
int
main ()
{
omp_allocator_handle_t m = omp_get_default_allocator ();
if (m != omp_default_mem_alloc)
__builtin_abort ();
return 0;
}