]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libgomp, openmp: Add ompx_pinned_mem_alloc
authorAndrew Stubbs <ams@codesourcery.com>
Fri, 11 Mar 2022 12:33:06 +0000 (12:33 +0000)
committerHafiz Abid Qadeer <abidh@codesourcery.com>
Fri, 11 Mar 2022 23:03:58 +0000 (23:03 +0000)
This creates a new predefined allocator as a shortcut for using pinned
memory with OpenMP.  The name uses the OpenMP extension space and is
intended to be consistent with other OpenMP implementations currently in
development.

The allocator is equivalent to using a custom allocator with the pinned
trait and the null fallback trait.

Backport of a patch posted at
https://gcc.gnu.org/pipermail/gcc-patches/2022-January/588951.html

* allocator.c (omp_max_predefined_alloc): Update.
(omp_aligned_alloc): Support ompx_pinned_mem_alloc.
(omp_free): Likewise.
(omp_aligned_calloc): Likewise.
(omp_realloc): Likewise.
* omp.h.in (omp_allocator_handle_t): Add ompx_pinned_mem_alloc.
* omp_lib.f90.in: Add ompx_pinned_mem_alloc.
* testsuite/libgomp.c/alloc-pinned-5.c: New test.
* testsuite/libgomp.c/alloc-pinned-6.c: New test.
* testsuite/libgomp.fortran/alloc-pinned-1.f90: New test.

libgomp/ChangeLog.omp
libgomp/allocator.c
libgomp/omp.h.in
libgomp/omp_lib.f90.in
libgomp/testsuite/libgomp.c/alloc-pinned-5.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c/alloc-pinned-6.c [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/alloc-pinned-1.f90 [new file with mode: 0644]

index 42a6c2841272e3237fc08148fc279e9eb4a1903b..6f7004bcc4b6f443eda33cbd301fbddca61a82ea 100644 (file)
@@ -1,3 +1,19 @@
+2022-03-11  Andrew Stubbs <ams@codesourcery.com>
+
+       Backport of a patch posted at
+       https://gcc.gnu.org/pipermail/gcc-patches/2022-January/588951.html
+
+       * allocator.c (omp_max_predefined_alloc): Update.
+       (omp_aligned_alloc): Support ompx_pinned_mem_alloc.
+       (omp_free): Likewise.
+       (omp_aligned_calloc): Likewise.
+       (omp_realloc): Likewise.
+       * omp.h.in (omp_allocator_handle_t): Add ompx_pinned_mem_alloc.
+       * omp_lib.f90.in: Add ompx_pinned_mem_alloc.
+       * testsuite/libgomp.c/alloc-pinned-5.c: New test.
+       * testsuite/libgomp.c/alloc-pinned-6.c: New test.
+       * testsuite/libgomp.fortran/alloc-pinned-1.f90: New test.
+
 2022-03-10  Andrew Stubbs <ams@codesourcery.com>
 
        Backport of a patch posted at
index db534c5fd18a1419fcd41f09a26d78d528669391..a84b36a9942576d9577431d8ada8f48bd3179169 100644 (file)
@@ -32,7 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define omp_max_predefined_alloc omp_thread_mem_alloc
+#define omp_max_predefined_alloc ompx_pinned_mem_alloc
 
 /* These macros may be overridden in config/<target>/allocator.c.  */
 #ifndef MEMSPACE_ALLOC
@@ -64,6 +64,7 @@ static const omp_memspace_handle_t predefined_alloc_mapping[] = {
   omp_low_lat_mem_space,   /* omp_cgroup_mem_alloc. */
   omp_low_lat_mem_space,   /* omp_pteam_mem_alloc. */
   omp_low_lat_mem_space,   /* omp_thread_mem_alloc. */
+  omp_default_mem_space,   /* ompx_pinned_mem_alloc. */
 };
 
 struct omp_allocator_data
@@ -330,11 +331,15 @@ retry:
     }
   else
     {
-      omp_memspace_handle_t memspace = (allocator_data
-                                       ? allocator_data->memspace
-                                       : predefined_alloc_mapping[allocator]);
-      ptr = MEMSPACE_ALLOC (memspace, new_size,
-                           allocator_data && allocator_data->pinned);
+      omp_memspace_handle_t memspace __attribute__((unused))
+       = (allocator_data
+          ? allocator_data->memspace
+          : predefined_alloc_mapping[allocator]);
+      int pinned __attribute__((unused))
+       = (allocator_data
+          ? allocator_data->pinned
+          : allocator == ompx_pinned_mem_alloc);
+      ptr = MEMSPACE_ALLOC (memspace, new_size, pinned);
       if (ptr == NULL)
        goto fail;
     }
@@ -354,7 +359,8 @@ retry:
 fail:
   int fallback = (allocator_data
                  ? allocator_data->fallback
-                 : allocator == omp_default_mem_alloc
+                 : (allocator == omp_default_mem_alloc
+                    || allocator == ompx_pinned_mem_alloc)
                  ? omp_atv_null_fb
                  : omp_atv_default_mem_fb);
   switch (fallback)
@@ -413,7 +419,8 @@ void
 omp_free (void *ptr, omp_allocator_handle_t allocator)
 {
   struct omp_mem_header *data;
-  omp_memspace_handle_t memspace = omp_default_mem_space;
+  omp_memspace_handle_t memspace __attribute__((unused))
+    = omp_default_mem_space;
   int pinned __attribute__((unused)) = false;
 
   if (ptr == NULL)
@@ -440,7 +447,10 @@ omp_free (void *ptr, omp_allocator_handle_t allocator)
       pinned = allocator_data->pinned;
     }
   else
-    memspace = predefined_alloc_mapping[data->allocator];
+    {
+      memspace = predefined_alloc_mapping[data->allocator];
+      pinned = (data->allocator == ompx_pinned_mem_alloc);
+    }
 
   MEMSPACE_FREE (memspace, data->ptr, data->size, pinned);
 }
@@ -530,8 +540,11 @@ retry:
       allocator_data->used_pool_size = used_pool_size;
       gomp_mutex_unlock (&allocator_data->lock);
 #endif
-      ptr = MEMSPACE_CALLOC (allocator_data->memspace, new_size,
-                            allocator_data->pinned);
+      int pinned __attribute__((unused))
+       = (allocator_data
+          ? allocator_data->pinned
+          : allocator == ompx_pinned_mem_alloc);
+      ptr = MEMSPACE_CALLOC (allocator_data->memspace, new_size, pinned);
       if (ptr == NULL)
        {
 #ifdef HAVE_SYNC_BUILTINS
@@ -547,11 +560,15 @@ retry:
     }
   else
     {
-      omp_memspace_handle_t memspace = (allocator_data
-                                       ? allocator_data->memspace
-                                       : predefined_alloc_mapping[allocator]);
-      ptr = MEMSPACE_ALLOC (memspace, new_size,
-                           allocator_data && allocator_data->pinned);
+      omp_memspace_handle_t memspace __attribute__((unused))
+       = (allocator_data
+          ? allocator_data->memspace
+          : predefined_alloc_mapping[allocator]);
+      int pinned __attribute__((unused))
+       = (allocator_data
+          ? allocator_data->pinned
+          : allocator == ompx_pinned_mem_alloc);
+      ptr = MEMSPACE_CALLOC (memspace, new_size, pinned);
       if (ptr == NULL)
        goto fail;
     }
@@ -571,7 +588,8 @@ retry:
 fail:
   int fallback = (allocator_data
                  ? allocator_data->fallback
-                 : allocator == omp_default_mem_alloc
+                 : (allocator == omp_default_mem_alloc
+                    || allocator == ompx_pinned_mem_alloc)
                  ? omp_atv_null_fb
                  : omp_atv_default_mem_fb);
   switch (fallback)
@@ -716,11 +734,15 @@ retry:
       gomp_mutex_unlock (&allocator_data->lock);
 #endif
       if (prev_size)
-       new_ptr = MEMSPACE_REALLOC (allocator_data->memspace, data->ptr,
-                                   data->size, new_size,
-                                   (free_allocator_data
-                                    && free_allocator_data->pinned),
-                                   allocator_data->pinned);
+       {
+         int was_pinned __attribute__((unused))
+           = (free_allocator_data
+              ? free_allocator_data->pinned
+              : free_allocator == ompx_pinned_mem_alloc);
+         new_ptr = MEMSPACE_REALLOC (allocator_data->memspace, data->ptr,
+                                     data->size, new_size, was_pinned,
+                                     allocator_data->pinned);
+       }
       else
        new_ptr = MEMSPACE_ALLOC (allocator_data->memspace, new_size,
                                  allocator_data->pinned);
@@ -751,13 +773,20 @@ retry:
           && (free_allocator_data == NULL
               || free_allocator_data->pool_size == ~(uintptr_t) 0))
     {
-      omp_memspace_handle_t memspace = (allocator_data
-                                       ? allocator_data->memspace
-                                       : predefined_alloc_mapping[allocator]);
+      omp_memspace_handle_t memspace __attribute__((unused))
+       = (allocator_data
+          ? allocator_data->memspace
+          : predefined_alloc_mapping[allocator]);
+      int was_pinned __attribute__((unused))
+       = (free_allocator_data
+          ? free_allocator_data->pinned
+          : free_allocator == ompx_pinned_mem_alloc);
+      int pinned __attribute__((unused))
+       = (allocator_data
+          ? allocator_data->pinned
+          : allocator == ompx_pinned_mem_alloc);
       new_ptr = MEMSPACE_REALLOC (memspace, data->ptr, data->size, new_size,
-                                 (free_allocator_data
-                                  && free_allocator_data->pinned),
-                                 allocator_data && allocator_data->pinned);
+                                 was_pinned, pinned);
       if (new_ptr == NULL)
        goto fail;
       ret = (char *) new_ptr + sizeof (struct omp_mem_header);
@@ -768,12 +797,15 @@ retry:
     }
   else
     {
-      omp_memspace_handle_t memspace
+      omp_memspace_handle_t memspace __attribute__((unused))
        = (allocator_data
           ? allocator_data->memspace
           : predefined_alloc_mapping[allocator]);
-      new_ptr = MEMSPACE_ALLOC (memspace, new_size,
-                               allocator_data && allocator_data->pinned);
+      int pinned __attribute__((unused))
+       = (allocator_data
+          ? allocator_data->pinned
+          : allocator == ompx_pinned_mem_alloc);
+      new_ptr = MEMSPACE_ALLOC (memspace, new_size, pinned);
       if (new_ptr == NULL)
        goto fail;
     }
@@ -809,7 +841,8 @@ retry:
 fail:
   int fallback = (allocator_data
                  ? allocator_data->fallback
-                 : allocator == omp_default_mem_alloc
+                 : (allocator == omp_default_mem_alloc
+                    || allocator == ompx_pinned_mem_alloc)
                  ? omp_atv_null_fb
                  : omp_atv_default_mem_fb);
   switch (fallback)
index 6b9ac96cff63ee7b9471384dad422698cc77720d..63c2d00799ec9bee1f527934f7fda0107a51a4fa 100644 (file)
@@ -134,6 +134,7 @@ typedef enum omp_allocator_handle_t __GOMP_UINTPTR_T_ENUM
   omp_cgroup_mem_alloc = 6,
   omp_pteam_mem_alloc = 7,
   omp_thread_mem_alloc = 8,
+  ompx_pinned_mem_alloc = 9,
   __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
 } omp_allocator_handle_t;
 
index e870755891ce8ecbf03263a9606cf95c392c4fe8..d04cd646ebcd5596eafc3ab195d9ea20b34a0928 100644 (file)
                  parameter :: omp_pteam_mem_alloc = 7
         integer (kind=omp_allocator_handle_kind), &
                  parameter :: omp_thread_mem_alloc = 8
+        integer (kind=omp_allocator_handle_kind), &
+                 parameter :: ompx_pinned_mem_alloc = 9
         integer (omp_memspace_handle_kind), &
                  parameter :: omp_default_mem_space = 0
         integer (omp_memspace_handle_kind), &
diff --git a/libgomp/testsuite/libgomp.c/alloc-pinned-5.c b/libgomp/testsuite/libgomp.c/alloc-pinned-5.c
new file mode 100644 (file)
index 0000000..8355ca8
--- /dev/null
@@ -0,0 +1,76 @@
+/* { dg-do run } */
+
+/* { dg-xfail-run-if "Pinning not implemented on this host" { ! *-*-linux-gnu } } */
+
+/* Test that ompx_pinned_mem_alloc works.  */
+
+#ifdef __linux__
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/mman.h>
+
+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 ();
+}
+#else
+int
+get_pinned_mem ()
+{
+  return 0;
+}
+#endif
+
+#include <omp.h>
+
+/* Allocate more than a page each time, but stay within the ulimit.  */
+#define SIZE 10*1024
+
+int
+main ()
+{
+  // Sanity check
+  if (get_pinned_mem () != 0)
+    abort ();
+
+  void *p = omp_alloc (SIZE, ompx_pinned_mem_alloc);
+  if (!p)
+    abort ();
+
+  int amount = get_pinned_mem ();
+  if (amount == 0)
+    abort ();
+
+  p = omp_realloc (p, SIZE*2, ompx_pinned_mem_alloc, ompx_pinned_mem_alloc);
+
+  int amount2 = get_pinned_mem ();
+  if (amount2 <= amount)
+    abort ();
+
+  p = omp_calloc (1, SIZE, ompx_pinned_mem_alloc);
+
+  if (get_pinned_mem () <= amount2)
+    abort ();
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/alloc-pinned-6.c b/libgomp/testsuite/libgomp.c/alloc-pinned-6.c
new file mode 100644 (file)
index 0000000..80fd37a
--- /dev/null
@@ -0,0 +1,96 @@
+/* { dg-do run } */
+
+/* Test that ompx_pinned_mem_alloc fails correctly.  */
+
+#ifdef __linux__
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/mman.h>
+#include <sys/resource.h>
+
+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
+int
+get_pinned_mem ()
+{
+  return 0;
+}
+
+void
+set_pin_limit ()
+{
+}
+#endif
+
+#include <omp.h>
+
+/* This should be large enough to cover multiple pages.  */
+#define SIZE 10000*1024
+
+int
+main ()
+{
+  /* 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, ompx_pinned_mem_alloc);
+  if (p)
+    abort ();
+
+  // Should fail
+  p = omp_calloc (1, SIZE, ompx_pinned_mem_alloc);
+  if (p)
+    abort ();
+
+  // Should fail to realloc
+  void *notpinned = omp_alloc (SIZE, omp_default_mem_alloc);
+  p = omp_realloc (notpinned, SIZE, ompx_pinned_mem_alloc, omp_default_mem_alloc);
+  if (!notpinned || p)
+    abort ();
+
+  // No memory should have been pinned
+  int amount = get_pinned_mem ();
+  if (amount != 0)
+    abort ();
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.fortran/alloc-pinned-1.f90 b/libgomp/testsuite/libgomp.fortran/alloc-pinned-1.f90
new file mode 100644 (file)
index 0000000..798dc3d
--- /dev/null
@@ -0,0 +1,16 @@
+! Ensure that the ompx_pinned_mem_alloc predefined allocator is present and
+! accepted.  The majority of the functionality testing lives in the C tests.
+!
+! { dg-xfail-run-if "Pinning not implemented on this host" { ! *-*-linux-gnu } }
+
+program main
+  use omp_lib
+  use ISO_C_Binding
+  implicit none (external, type)
+
+  type(c_ptr) :: p
+
+  p = omp_alloc (10_c_size_t, ompx_pinned_mem_alloc);
+  if (.not. c_associated (p)) stop 1
+  call omp_free (p, ompx_pinned_mem_alloc);
+end program main