libgompd: Add ompd_get/rel_display_control_vars

Message ID CAPFh8N+cBM8m3auD7cYN+=DznMzV3mNA9+3=YPLNa56SWws0OA@mail.gmail.com
State New
Headers
Series libgompd: Add ompd_get/rel_display_control_vars |

Commit Message

Mohamed Atef May 27, 2022, 12:04 a.m. UTC
  libgomp/ChangeLog

2022-05-27  Mohamed Atef  <mohamedatef1698@gmail.com>

* libgompd.map (ompd_get_display_control_vars,
ompd_rel_display_control_vars): New global symbol versions.
* env.c: (gompd_buffer, gompd_env_buff_size): New Variables.
(dump_icvs): New function.
(initialize_env): call dump_icvs.
* ompd-icv.c: (ompd_get_display_control_vars): New function.
(ompd_rel_display_control_vars): New function.
  

Comments

Jakub Jelinek May 30, 2022, 4:10 p.m. UTC | #1
On Fri, May 27, 2022 at 02:04:11AM +0200, Mohamed Atef wrote:
> libgomp/ChangeLog
> 
> 2022-05-27  Mohamed Atef  <mohamedatef1698@gmail.com>
> 
> * libgompd.map (ompd_get_display_control_vars,
> ompd_rel_display_control_vars): New global symbol versions.
> * env.c: (gompd_buffer, gompd_env_buff_size): New Variables.
> (dump_icvs): New function.
> (initialize_env): call dump_icvs.
> * ompd-icv.c: (ompd_get_display_control_vars): New function.
> (ompd_rel_display_control_vars): New function.

I don't like this solution, I know LLVM libomp does it this way,
but that adds complexity to the libgomp library to make it easier
for libgompd, and even worse further bloats .data section of
every OpenMP program even when debugging isn't enabled (and not just a tiny
bit, but by sizeof (char *) + sizeof (unsigned long) + 500 bytes, which is
significant).

This really should be done on the libgompd side, instead of copying
the gompd_buffer you've added, it should instead copy
gomp_global_icv and whatever else is necessary to print it, then
do that in libgompd.

> diff --git a/libgomp/env.c b/libgomp/env.c
> index 243c6267ef9..173c9271303 100644
> --- a/libgomp/env.c
> +++ b/libgomp/env.c
> @@ -91,6 +91,8 @@ unsigned long gomp_places_list_len;
>  uintptr_t gomp_def_allocator = omp_default_mem_alloc;
>  int gomp_debug_var;
>  int gompd_enabled;
> +char *gompd_buffer;
> +unsigned long gompd_env_buff_size;
>  unsigned int gomp_num_teams_var;
>  int gomp_nteams_var;
>  int gomp_teams_thread_limit_var;
> @@ -1453,6 +1455,187 @@ omp_display_env (int verbose)
>  }
>  ialias (omp_display_env)
>  
> +/* This function dumps all global ICVs into a buffer
> +   in the form "icv-name=icv-value\n", so that OMPD can read the
> +   buffer and display all icvs.  */
> +
> +static void
> +dump_icvs (void)
> +{
> +  static char temp_buffer[500];
> +  char temp_num_str[20];
> +  strcat (temp_buffer, "OMP_DYNAMIC=");
> +  strcat (temp_buffer, gomp_global_icv.dyn_var ? "TRUE\n" : "FALSE\n");
> +  strcat (temp_buffer, "OMP_NESTED=");
> +  strcat (temp_buffer,
> +          gomp_global_icv.max_active_levels_var > 1 ? "TRUE\n" : "FALSE\n");
> +  strcat (temp_buffer, "OMP_NUM_THREADS=");
> +  sprintf (temp_num_str, "%lu\n", gomp_global_icv.nthreads_var);
> +  strcat (temp_buffer, temp_num_str);
> +  strcat (temp_buffer, "OMP_SCHEDULE=");

This is terribly inefficient even when done that way on the libgompd side.
You really don't want every further strcat to walk all the already
previously stored bytes to find the end, and you don't want to hardcode
the size of the buffer, see
https://www.gnu.org/prep/standards/standards.html#Writing-Robust-Programs

So, the buffer should be dynamically allocated, and you should at all times
know how many bytes have been already stored.  One possibility is to
call a printing function twice, once with say NULL as the buffer which will
be a mode in which it just computes the length of each addition and just
returns the total length, then allocate and then pass non-NULL buffer
into which it will actually store it.
Or you could allocate keep some extra bytes in the buffer (longer than
say longest name of an env variable name, = char, largest representable
long long number, \n char plus a few bytes extra) and keep checking before
adding any var that is guaranteed to fit into those extra bytes whether
there are at least those number of bytes left in the buffer and reallocate
otherwise.  But for vars that can have arbitrarily long results (e.g. vars
with various lists), such checking needs to be done before adding any
partial result that can fit).

	Jakub
  

Patch

diff --git a/libgomp/env.c b/libgomp/env.c
index 243c6267ef9..173c9271303 100644
--- a/libgomp/env.c
+++ b/libgomp/env.c
@@ -91,6 +91,8 @@  unsigned long gomp_places_list_len;
 uintptr_t gomp_def_allocator = omp_default_mem_alloc;
 int gomp_debug_var;
 int gompd_enabled;
+char *gompd_buffer;
+unsigned long gompd_env_buff_size;
 unsigned int gomp_num_teams_var;
 int gomp_nteams_var;
 int gomp_teams_thread_limit_var;
@@ -1453,6 +1455,187 @@  omp_display_env (int verbose)
 }
 ialias (omp_display_env)
 
+/* This function dumps all global ICVs into a buffer
+   in the form "icv-name=icv-value\n", so that OMPD can read the
+   buffer and display all icvs.  */
+
+static void
+dump_icvs (void)
+{
+  static char temp_buffer[500];
+  char temp_num_str[20];
+  strcat (temp_buffer, "OMP_DYNAMIC=");
+  strcat (temp_buffer, gomp_global_icv.dyn_var ? "TRUE\n" : "FALSE\n");
+  strcat (temp_buffer, "OMP_NESTED=");
+  strcat (temp_buffer,
+          gomp_global_icv.max_active_levels_var > 1 ? "TRUE\n" : "FALSE\n");
+  strcat (temp_buffer, "OMP_NUM_THREADS=");
+  sprintf (temp_num_str, "%lu\n", gomp_global_icv.nthreads_var);
+  strcat (temp_buffer, temp_num_str);
+  strcat (temp_buffer, "OMP_SCHEDULE=");
+  if ((gomp_global_icv.run_sched_var & GFS_MONOTONIC))
+    {
+      if (gomp_global_icv.run_sched_var != (GFS_MONOTONIC | GFS_STATIC))
+        strcat (temp_buffer, "MONOTONIC\n");
+    }
+  else if (gomp_global_icv.run_sched_var == GFS_STATIC)
+    strcat (temp_buffer, "NONMONOTONIC\n");
+  switch (gomp_global_icv.run_sched_var & ~GFS_MONOTONIC)
+    {
+    case GFS_RUNTIME:
+      strcat (temp_buffer, "RUNTIME");
+      if (gomp_global_icv.run_sched_chunk_size != 1)
+        {
+          sprintf (temp_num_str, ",%d", gomp_global_icv.run_sched_chunk_size);
+          strcat (temp_buffer, temp_num_str);
+        }
+      break;
+    case GFS_STATIC:
+      strcat (temp_buffer, "STATIC");
+      if (gomp_global_icv.run_sched_chunk_size != 0)
+        {
+          sprintf (temp_num_str, ",%d", gomp_global_icv.run_sched_chunk_size);
+          strcat (temp_buffer, temp_num_str);
+        }
+      break;
+    case GFS_DYNAMIC:
+      strcat (temp_buffer, "DYNAMIC");
+      if (gomp_global_icv.run_sched_chunk_size != 1)
+        {
+          sprintf (temp_num_str, ",%d", gomp_global_icv.run_sched_chunk_size);
+          strcat (temp_buffer, temp_num_str);
+        }
+      break;
+    case GFS_GUIDED:
+      strcat (temp_buffer, "GUIDED");
+      if (gomp_global_icv.run_sched_chunk_size != 1)
+        {
+          sprintf (temp_num_str, ",%d", gomp_global_icv.run_sched_chunk_size);
+          strcat (temp_buffer, temp_num_str);
+        }
+      break;
+    case GFS_AUTO:
+      strcat (temp_buffer, "AUTO");
+      break;
+    }
+  strcat (temp_buffer, "\n");
+
+  strcat (temp_buffer, "OMP_PROC_BIND=");
+  switch (gomp_global_icv.bind_var)
+    {
+    case omp_proc_bind_false:
+      strcat (temp_buffer, "FALSE");
+      break;
+    case omp_proc_bind_true:
+      strcat (temp_buffer, "TRUE");
+      break;
+    case omp_proc_bind_master:
+      strcat (temp_buffer, "MASTER"); /* TODO: Change to PRIMARY for OpenMP 5.1.  */
+      break;
+    case omp_proc_bind_close:
+      strcat (temp_buffer, "CLOSE");
+      break;
+    case omp_proc_bind_spread:
+      strcat (temp_buffer, "SPREAD");
+      break;
+    }
+  for (int i = 1; i < gomp_bind_var_list_len; i++)
+    switch (gomp_bind_var_list[i])
+      {
+      case omp_proc_bind_master:
+        strcat (temp_buffer, ",MASTER"); /* TODO: Change to PRIMARY for OpenMP 5.1. */
+        break;
+      case omp_proc_bind_close:
+        strcat (temp_buffer, ",CLOSE");
+        break;
+      case omp_proc_bind_spread:
+        strcat (temp_buffer, ",SPREAD");
+        break;
+      }
+  strcat (temp_buffer, "\n");
+
+  strcat (temp_buffer, "OMP_STACKSIZE=");
+  sprintf (temp_num_str, "%lu\n", stacksize);
+  strcat (temp_buffer, temp_num_str);
+
+  /* GOMP's default value is actually neither active nor passive.  */
+  strcat (temp_buffer, "OMP_WAIT_POLICY=");
+  strcat (temp_buffer, wait_policy > 0 ? "ACTIVE\n" : "PASSIVE\n");
+  strcat (temp_buffer, "OMP_THREAD_LIMIT=");
+  sprintf (temp_num_str, "%u\n", gomp_global_icv.thread_limit_var);
+  strcat (temp_buffer, temp_num_str);
+  strcat (temp_buffer, "OMP_MAX_ACTIVE_LEVELS=");
+  sprintf (temp_num_str, "%u\n", gomp_global_icv.max_active_levels_var);
+  strcat (temp_buffer, temp_num_str);
+  strcat (temp_buffer, "OMP_NUM_TEAMS=");
+  sprintf (temp_num_str, "%u\n", gomp_nteams_var);
+  strcat (temp_buffer, temp_num_str);
+  strcat (temp_buffer, "OMP_TEAMS_THREAD_LIMIT=");
+  sprintf (temp_num_str, "%u\n", gomp_teams_thread_limit_var);
+  strcat (temp_buffer, temp_num_str);
+
+  strcat (temp_buffer, "OMP_CANCELLATION=");
+  strcat (temp_buffer, gomp_cancel_var ? "TRUE\n" : "FALSE\n");
+  strcat (temp_buffer, "OMP_DEFAULT_DEVICE=");
+  sprintf (temp_num_str, "%d\n", gomp_global_icv.default_device_var);
+  strcat (temp_buffer, temp_num_str);
+  strcat (temp_buffer, "OMP_MAX_TASK_PRIORITY=");
+  sprintf (temp_num_str, "%d\n", gomp_max_task_priority_var);
+  strcat (temp_buffer, temp_num_str);
+  strcat (temp_buffer, "OMP_DISPLAY_AFFINITY=");
+  strcat (temp_buffer, gomp_display_affinity_var ? "TRUE\n" : "FALSE\n");
+  strcat (temp_buffer, "OMP_AFFINITY_FORMAT=");
+  strcat (temp_buffer, gomp_affinity_format_var);
+  strcat (temp_buffer, "\n");
+  strcat (temp_buffer, "OMP_ALLOCATOR=");
+  switch (gomp_def_allocator)
+    {
+#define C(v) case v: strcat (temp_buffer, #v); 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;
+    }
+  strcat (temp_buffer, "\n");
+
+  strcat (temp_buffer, "OMP_TARGET_OFFLOAD=");
+  switch (gomp_target_offload_var)
+    {
+    case GOMP_TARGET_OFFLOAD_DEFAULT:
+      strcat (temp_buffer, "DEFAULT");
+      break;
+    case GOMP_TARGET_OFFLOAD_MANDATORY:
+      strcat (temp_buffer, "MANDATORY");
+      break;
+    case GOMP_TARGET_OFFLOAD_DISABLED:
+      strcat (temp_buffer, "DISABLED");
+      break;
+    }
+  strcat (temp_buffer, "\n");
+
+  strcat (temp_buffer, "GOMP_CPU_AFFINITY=\n");
+  strcat (temp_buffer, "GOMP_STACKSIZE=");
+  sprintf (temp_num_str, "%lu\n", stacksize);
+  strcat (temp_buffer, temp_num_str);
+#ifdef HAVE_INTTYPES_H
+  strcat (temp_buffer, "GOMP_SPINCOUNT=");
+  sprintf (temp_num_str, "%"PRIu64"\n", (uint64_t) gomp_spin_count_var);
+  strcat (temp_buffer, temp_num_str);
+#else
+  strcat (temp_buffer, "GOMP_SPINCOUNT=");
+  sprintf (temp_num_str, "%lu\n", (unsigned long) gomp_spin_count_var);
+  strcat (temp_buffer, temp_num_str);
+#endif
+  gompd_buffer = temp_buffer;
+  gompd_env_buff_size = (__UINT64_TYPE__) strlen (temp_buffer);
+}
+
 static void
 handle_omp_display_env (void)
 {
@@ -1519,7 +1702,10 @@  initialize_env (void)
   parse_int_secure ("GOMP_DEBUG", &gomp_debug_var, true);
   parse_debug ("OMP_DEBUG", &gompd_enabled);
   if (gompd_enabled == 1)
-    gompd_load ();
+    {
+      gompd_load ();
+      dump_icvs ();
+    }
 #ifndef HAVE_SYNC_BUILTINS
   gomp_mutex_init (&gomp_managed_threads_lock);
 #endif
diff --git a/libgomp/libgompd.map b/libgomp/libgompd.map
index 85bdc3695f6..439e5c313eb 100644
--- a/libgomp/libgompd.map
+++ b/libgomp/libgompd.map
@@ -16,6 +16,8 @@  OMPD_5.1 {
     ompd_thread_handle_compare;
     ompd_get_thread_id;
     ompd_get_device_from_thread;
+    ompd_get_display_control_vars;
+    ompd_rel_display_control_vars;
   local:
     *;
 };
diff --git a/libgomp/ompd-icv.c b/libgomp/ompd-icv.c
index 7f198d1638d..a0a2bec98dd 100644
--- a/libgomp/ompd-icv.c
+++ b/libgomp/ompd-icv.c
@@ -182,3 +182,76 @@  ompd_get_icv_string_from_scope (void *handle, ompd_scope_t scope,
     }
   return ompd_rc_error;
 }
+
+ompd_rc_t
+ompd_get_display_control_vars (ompd_address_space_handle_t *ah,
+                               const char *const **control_vars)
+{
+  CHECK (ah);
+  if (control_vars == NULL)
+    return ompd_rc_error;
+  /* GET the buffer size.  */
+  ompd_word_t buff_size = 0;
+  ompd_address_t symbol_addr = {OMPD_SEGMENT_UNSPECIFIED, 0};
+  ompd_rc_t ret;
+  GET_VALUE (ah->context, NULL, "gompd_env_buff_size", buff_size, buff_size,
+             target_sizes.sizeof_long, 1, ret, symbol_addr);
+  /* GET the buffer that has all environment variables.  */
+  ret = callbacks->symbol_addr_lookup (ah->context, NULL, "gompd_buffer",
+                                       &symbol_addr, NULL);
+  CHECK_RET (ret);
+  ompd_word_t addr = 0;
+  ret = callbacks->read_memory (ah->context, NULL, &symbol_addr,
+                                target_sizes.sizeof_pointer, &addr);
+  symbol_addr.address = addr;
+  char *env;
+  ret = callbacks->alloc_memory (buff_size, (void **) &env);
+  CHECK_RET (ret);
+  ret = callbacks->read_memory (ah->context, NULL, &symbol_addr,
+                                target_sizes.sizeof_char * buff_size,
+                                env);
+  CHECK_RET (ret);
+  ret = callbacks->device_to_host (ah->context, &env,
+                                   target_sizes.sizeof_char, buff_size, &env);
+  CHECK_RET (ret);
+  /* Count the number of variables.  */
+  int cntr = 1;  /* Take also the last NULL string.  */
+  for (int i = 0; i < buff_size; i++)
+    {
+      if (env[i] == '\n')
+        {
+          env[i] = '\0';
+          cntr++;
+        }
+    }
+  const char **temp_control_vars;
+  ret = callbacks->alloc_memory (cntr * sizeof (char *),
+                                 (void **) (&temp_control_vars));
+  CHECK_RET (ret);
+  char *idx = env;
+  temp_control_vars[0] = idx;
+  for (int i = 1; i < cntr - 1; i++)
+    {
+      while (*idx != '\0')
+        idx++;
+      if (idx > env + buff_size)
+        return ompd_rc_error;
+      temp_control_vars[i] = idx;
+    }
+  temp_control_vars[cntr - 1] = NULL;
+  *control_vars = temp_control_vars;
+  return ompd_rc_ok;
+}
+
+ompd_rc_t
+ompd_rel_display_control_vars (const char *const **control_vars)
+{
+  if (control_vars == NULL)
+    return ompd_rc_bad_input;
+  ompd_rc_t ret;
+  ret = callbacks->free_memory ((void *) control_vars[0]);
+  CHECK_RET (ret);
+  ret = callbacks->free_memory ((void *) control_vars);
+  CHECK_RET (ret);
+  return ompd_rc_ok;  
+}