public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
From: Iain Sandoe <iain@sandoe.co.uk>
To: "Nicolas König" <koenigni@student.ethz.ch>,
	"Thomas Koenig" <tkoenig@netcologne.de>
Cc: Fortran List <fortran@gcc.gnu.org>, dhumieres.dominique@free.fr
Subject: Re: Update on shared memory coarrays
Date: Tue, 5 Jan 2021 13:11:13 +0000	[thread overview]
Message-ID: <816E309C-4983-4159-973D-F1A46AD8CB3C@sandoe.co.uk> (raw)
In-Reply-To: <c0bad300-01a8-ad97-f9ad-672b914405a7@student.ethz.ch>

[-- Attachment #1: Type: text/plain, Size: 4112 bytes --]

Hi folks,

Nicolas König <koenigni@student.ethz.ch> wrote:
> On 04/01/2021 03:34, Iain Sandoe wrote:
>> Thomas Koenig via Fortran <fortran@gcc.gnu.org> wrote:
>>> Am 03.01.21 um 16:42 schrieb Iain Sandoe:

>> It seems shm is not a favoured IPC mechanism for Darwin (it’s possibly  
>> disallowed for GUI apps, according to search results - I didn’t check  
>> that)
>>>> (we can file a radar, and maybe it gets fixed at some point - but  
>>>> that’s no help to all the existing system versions)
>>>
>>> Makes sense to file a bug report with Apple.  And yes, we'll have to
>>> deal with this some other way.
>> [for command line apps] Either mechanism for accessing shm works;
>> [1] shm_open / fd / mmap / munmap
>> [2] shmget / shmat / shmdt <= allocation is rounded up to the nearest  
>> page boundary.
>> Both have the constraint [on Darwin] that the size of the allocation  
>> cannot be increased after it is set (by ftruncate() [1] or shmget() [2]).
>> It can be decreased (by [2] only), but it’s not clear if that actually  
>> has any physical effect.
>
> That's a problem, since coarrays can be allocated at runtime, and we  
> can't possibly precompute their size.

OK.

> To get coarrays to work, we would probably need to create new shared  
> memory objects (with predictable names, so they can be opened from other  
> images), but that would be a significant time investment.

How does it work between different images with shared memory unless the  
name to shm_open () is predictable between images?

(there has to be some shared key of some form, right?)

> It also doesn't bring my hopes up that other things like  
> pthread_{mutex,cond}attr_setpshared() will work.

Darwin is Posix SUSv3 (actually, AFAICT the majority of the certified  
platforms are; there only seems to be one certified to UNIX7).

- so pthreads stuff that’s mandated in SUSv3 is definitely present on Darwin.

(in practice some of the optional stuff is also present - you can look at  
what libstdc++ does to get an idea of what works in a cross-platform manner)

> I think it's probably better to focus the attention on getting it to work  
> on Linux/BSD.

Well, I can understand making progress in that way - but it’s a bit of a  
slippery slope towards an “x86 Linux only” compiler (if we keep taking that  
route until a significant portion of the useful features don’t work  
elsewhere).

Of course, this particular case is not so exclusive [it appears from  
previous mails that Darwin is the only one with an issue], but as a general  
rule it would be good to pick an impl that works on at least the regularly  
used/tested targets.

>> I guess that one ought to consider that a change in allocation could  
>> trigger a copy on any system (since there might not be contiguous memory  
>> pages available for an arbitrary increase) - so a strategy which either  
>> allocates separae fragments for each need - or waits until the size is  
>> known before allocation is likely to perform better on average,
>
> There's no need to have the continuous virtual memory backed by  
> continuous physical memory, so nothing here should trigger a relocation  
> of the actual physical memory. There are just some entries in the page  
> table pointing to the same pages.

I guess if everything is done on page boundaries & sizes, that can work -  
providing one doesn’t mind the base pointer changing across resizes.

====

Update:

three codes attached.

1. Posix shm implementation; works fine but is not resizeable.

2. Darwin shm implementation : works fine but is only resizable downwards  
and it’s not clear if the resources are actually released.

3. mmapped shared file : This works [on Darwin at least] and is resizable.   
I would assume that, in reality, all accesses would be to the buffer cache  
[unless something actually forces the cache to be flushed] and therefore  
that the performance ought to be similar to shm.

Worst case, one could point /tmp at a ramdisk ..
(I tend to do that anyway, I don’t want my sshds getting hammered by  
toolchain builds).

Thoughts?
Iain


[-- Attachment #2: shm-posix.c --]
[-- Type: application/octet-stream, Size: 3252 bytes --]

/* shared memory IPC using Posix shm_open/ftruncate/mmap.
   The Darwin implementation does not appear to allow a shared memory segment
   to be resized once the initial size is set.
*/

#include <stdbool.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

#define NAME "/tmp/random_namexxx"

typedef struct shared_res
{
  void *ptr;
  size_t size;
  int fd;
  int status;
} shared_res_t;

shared_res_t
get_shared_resource (size_t size, bool master)
{
  shared_res_t res = {0};

  int fd;
  if (master)
    /* Create the segment.  */
   fd = shm_open (NAME, O_CREAT | O_RDWR,  S_IRUSR | S_IWUSR);
  else
    /* Wait for the segment to be created.  */
    while ((fd = shm_open (NAME, O_RDWR,  S_IRUSR | S_IWUSR)) < 0 
	   && errno == ENOENT) usleep (100000);

  if (fd < 0)
    {
      perror ("get_shared_resource: open failed");
      goto fatal_err;
    }
  else
    printf ("get_shared_resource: fd = %d\n", fd);

  if (master)
    {
      if (ftruncate (fd, size) < 0)
	{
	  perror ("get_shared_resource: ftruncate failed");
  	  goto fatal_err;
	}
    }

  void *p1 = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (p1 == MAP_FAILED)
    {
      perror ("get_shared_resource : mmap failed");
      goto fatal_err;
    }
  res.fd = fd;
  res.ptr = p1;
  res.size = size;
  res.status = 0;
  return res;

fatal_err:
  if (fd >= 0)
    close (fd);
  shm_unlink (NAME);
  exit (EXIT_FAILURE);  
}

void
resize_shared_resource (shared_res_t *r, size_t new_size)
{
  if (r->status != 0)
    {
      perror ("resize_shared_resource : bad shared resource status");
      goto fatal_err;
    }

  if (ftruncate (r->fd, new_size) < 0)
    {
      perror ("resize_shared_resource: ftruncate failed");
      goto fatal_err;
    }

  /* TODO: remap this if we succeeded ... but we do not*/
  return;

fatal_err:
  if (r->fd >= 0)
    close (r->fd);
  shm_unlink (NAME);
  exit (EXIT_FAILURE);  
}

void release_shared_resource (shared_res_t r)
{
  if (munmap (r.ptr, r.size) < 0 )
    {
      perror ("release_shared_resource : unmap failed");
    }
  shm_unlink (NAME);
  close (r.fd);
}

#if SENDER

int main()
{
  size_t pagesize = sysconf (_SC_PAGE_SIZE);
  if (pagesize == -1)
    {
      perror ("sysconf failed");
      exit (EXIT_FAILURE);
    }
  printf ("sender page size = %ld\n", pagesize);

  shared_res_t shared = get_shared_resource (pagesize, true);
  printf ("sender shared = 0x%p\n", shared.ptr);
  int *ip = shared.ptr;
  *ip = 42;

  while (*ip == 42)
    usleep (100000);

  /* Any attempt to re-size this (increase or decrease) fails.
  resize_shared_resource (&shared, pagesize * 2);
  */
  release_shared_resource (shared);
  return 0;
}

#else

int main()
{
  size_t pagesize = sysconf (_SC_PAGE_SIZE);
  if (pagesize == -1)
    {
      perror ("sysconf failed");
      exit (EXIT_FAILURE);
    }
  printf ("client page size = %ld\n", pagesize);

  shared_res_t shared = get_shared_resource (pagesize, false);
  printf ("client shared = 0x%p\n", shared.ptr);

  int *ip = shared.ptr;

  while (*ip != 42)
    usleep (100000);

  *ip = 6174;

  release_shared_resource (shared);
  return 0;
}

#endif

[-- Attachment #3: shm-darwin.c --]
[-- Type: application/octet-stream, Size: 3892 bytes --]

/* shared memory IPC using shmget/shmat/shmdt.
   There doesn't appear to be any mechanism to re-size such a segment
   (although re-getting with a smaller size produces no error, it doesn't
    make the segment size contained in the status any smaller).
*/

#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

typedef struct shared_res
{
  void *ptr;
  size_t size;
  int smid;
  int status;
  key_t savedKey;
} shared_res_t;

shared_res_t
get_shared_resource (size_t size)
{
  shared_res_t res = {0};

  key_t myKey = ftok ("/dev/null", 6174);
  if (myKey < 0)
    {
      perror ("ftok failed");
      exit (EXIT_FAILURE);
    }

  int smid = shmget (myKey, size, IPC_CREAT | SHM_R | SHM_W);
  if (smid < 0)
    {
      perror ("shmget failed");
      exit (EXIT_FAILURE);
    }
  printf ("smid = %d\n", smid);

  void *p1 = shmat (smid, NULL, SHM_R | SHM_W);
  if (p1 == MAP_FAILED)
    {
      perror ("get_shared_resource : shmat failed");
      exit (EXIT_FAILURE);
    }
  res.smid = smid;
  res.ptr = p1;
  res.size = size;
  res.status = 0;
  res.savedKey = myKey;
  return res;
}

void
resize_shared_resource (shared_res_t *r, size_t new_size)
{
  struct shmid_ds sb;
  int res = shmctl(r->smid, IPC_STAT, &sb);
  if (res < 0)
    {
      perror ("shmctl (1) failed");
      exit (EXIT_FAILURE);
    }
  printf ("size in shm = %zu\n", sb.shm_segsz);

  /* An attempt to get the same segment with a different size fails.
     detach and start again.  */
  if (shmdt (r->ptr) < 0 )
    {
      perror ("resize_shared_resource : shmdt failed");
    }

  int smid1 = shmget (r->savedKey, new_size, IPC_CREAT | SHM_R | SHM_W);
  if (smid1 < 0)
    {
      perror ("shmget (2) failed");
    }
  printf ("smid1 = %d\n", smid1);
  void *p1 = shmat (smid1, NULL, SHM_R | SHM_W);
  if (p1 == MAP_FAILED)
    {
      perror ("get_shared_resource : shmat failed");
      exit (EXIT_FAILURE);
    }
  r->smid = smid1;
  r->ptr = p1;
  r->size = new_size;  
}

void release_shared_resource (shared_res_t r)
{
  /* detach.  */
  if (shmdt (r.ptr) < 0 )
    perror ("release_shared_resource : shmdt failed");

  struct shmid_ds sb;
  int res = shmctl(r.smid, IPC_STAT, &sb);
  if (res < 0)
    {
      perror ("release_shared_resource : shmctl failed");
      return;
    }

  printf ("release_shared_resource : size in shm = %zu\n", sb.shm_segsz);
  /* If this is the last use, then remove the shm segment.  */
  if (sb.shm_nattch == 0)
    {
      res = shmctl(r.smid, IPC_RMID, &sb);
      if (res < 0)
	{
	  perror ("release_shared_resource : shmctl (IPC_RMID) failed");
	}
    } 
}

#if SENDER

int main()
{
  size_t pagesize = sysconf (_SC_PAGE_SIZE);
  if (pagesize == -1)
    {
      perror ("sysconf failed");
      exit (EXIT_FAILURE);
    }
  printf ("sender page size = %ld\n", pagesize);

  shared_res_t shared = get_shared_resource (pagesize * 2);
  printf ("sender shared = 0x%p\n", shared.ptr);
  int *ip = shared.ptr;
  *ip = 42;

  while (*ip == 42)
    usleep (100000);

  /* A resize to a smaller segment proceeds without error, but the actual
     reported size from the shm segment is not changed.  */

  printf ("sender attempting resize to %zu\n", pagesize);
  resize_shared_resource (&shared, pagesize);
  printf ("sender releasing\n");
  release_shared_resource (shared);
  return 0;
}

#else

int main()
{
  size_t pagesize = sysconf (_SC_PAGE_SIZE);
  if (pagesize == -1)
    {
      perror ("sysconf failed");
      exit (EXIT_FAILURE);
    }
  printf ("client page size = %ld\n", pagesize);

  shared_res_t shared = get_shared_resource (pagesize * 2);
  printf ("client shared = 0x%p\n", shared.ptr);

  int *ip = shared.ptr;

  while (*ip != 42)
    usleep (100000);

  *ip = 6174;

  printf ("client releasing\n");
  release_shared_resource (shared);
  return 0;
}

#endif

[-- Attachment #4: ram-file.c --]
[-- Type: application/octet-stream, Size: 3545 bytes --]

/* shared resource IPC using mmapped file.
   This allows resizing.
*/

#include <stdbool.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdlib.h>

#define NAME "/tmp/gfortran-xxxxxxx"

typedef struct shared_res
{
  void *ptr;
  size_t size;
  int fd;
  int status;
} shared_res_t;

shared_res_t
get_shared_resource (size_t size, bool master)
{
  shared_res_t res = {0};
  int fd = -1;
  if (master)
    fd = open (NAME, O_CREAT | O_RDWR,  S_IRUSR | S_IWUSR);
  else
    while ((fd = open (NAME, O_RDWR,  S_IRUSR | S_IWUSR)) < 0 
	   && errno == ENOENT) usleep (100000);

  if (fd == -1)
    {
      perror ("get_shared_resource: open failed");
      goto fatal_err;
    }
  else
    printf ("get_shared_resource: fd = %d\n", fd);

  if (master)
    if (ftruncate (fd, size) < 0)
      {
	perror ("get_shared_resource: ftruncate failed");
        goto fatal_err;
      }

  void *p1 = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (p1 == MAP_FAILED)
    {
      perror ("get_shared_resource : mmap failed");
      goto fatal_err;
    }
  res.fd = fd;
  res.ptr = p1;
  res.size = size;
  res.status = 0;
  return res;

fatal_err:
  if (fd >= 0)
    close (fd);
  shm_unlink (NAME);
  exit (EXIT_FAILURE);  
}

void
resize_shared_resource (shared_res_t *r, size_t new_size)
{
  if (r->status != 0)
    {
      perror ("resize_shared_resource : bad shared resource status");
      return;
    }

  if (munmap (r->ptr, r->size) < 0 )
    perror ("resize_shared_resource : unmap failed");

  if (ftruncate (r->fd, new_size) < 0)
    {
      perror ("resize_shared_resource: ftruncate failed");
      return;
    }

  /* remap this */
  void *p1 = mmap (NULL, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, r->fd, 0);
  if (p1 == MAP_FAILED)
    perror ("resize_shared_resource : mmap failed");
  else
    {
      r->ptr = p1;
      r->size = new_size;
    }
}

void release_shared_resource (shared_res_t r)
{
  if (munmap (r.ptr, r.size) < 0 )
    {
      perror ("release_shared_resource : unmap failed");
    }
  close (r.fd);
  unlink (NAME);
}

#if SENDER

int main()
{
  size_t pagesize = sysconf (_SC_PAGE_SIZE);
  if (pagesize == -1)
    {
      perror ("sysconf failed");
      exit (EXIT_FAILURE);
    }
  printf ("sender page size = %ld\n", pagesize);

  shared_res_t shared = get_shared_resource (pagesize, true);
  printf ("sender resource pointer = 0x%p\n", shared.ptr);
  int *ip = shared.ptr;
  *ip = 42;

  while (*ip == 42)
    usleep (100000);

  printf ("sender saw %d, resizing now\n", *ip);
  resize_shared_resource (&shared, 2 * pagesize);
  printf ("sender resized resource pointer = 0x%p\n", shared.ptr);

  ip = shared.ptr;
  ip += (pagesize/sizeof(int));
  printf ("sender sees %d\n", *ip);

  release_shared_resource (shared);
  return 0;
}

#else

int main()
{
  size_t pagesize = sysconf (_SC_PAGE_SIZE);
  if (pagesize == -1)
    {
      perror ("sysconf failed");
      exit (EXIT_FAILURE);
    }
  printf ("client page size = %ld\n", pagesize);

  shared_res_t shared = get_shared_resource (pagesize, false);
  printf ("client resource pointer = 0x%p\n", shared.ptr);

  int *ip = shared.ptr;

  while (*ip != 42)
    usleep (100000);

  printf ("client saw %d, resizing now\n", *ip);
  resize_shared_resource (&shared, 2 * pagesize);
  printf ("client resized resource pointer = 0x%p\n", shared.ptr);

  ip = shared.ptr;
  ip[(pagesize/sizeof(int))] = 6174;
  *ip = -42;

  release_shared_resource (shared);
  return 0;
}

#endif


[-- Attachment #5: Type: text/plain, Size: 3 bytes --]





  reply	other threads:[~2021-01-05 13:11 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-29 19:09 dhumieres.dominique
2020-11-30  6:21 ` Thomas Koenig
2020-11-30 15:41   ` dhumieres.dominique
2020-11-30 22:13     ` Thomas Koenig
2020-12-02 17:41       ` dhumieres.dominique
2020-12-03  7:27         ` Thomas Koenig
2020-12-21 12:24           ` dhumieres.dominique
2020-12-21 13:04             ` Thomas Koenig
2020-12-22 12:28               ` dhumieres.dominique
2020-12-22 15:10                 ` Thomas Koenig
2020-12-22 16:12                   ` Paul Richard Thomas
2020-12-23  9:09                     ` Thomas Koenig
2020-12-23  9:38                       ` Paul Richard Thomas
2020-12-23 10:47                         ` Thomas Koenig
2020-12-26 12:10                           ` Paul Richard Thomas
2020-12-26 13:01                             ` Thomas Koenig
2020-12-27 15:38                             ` Thomas Koenig
2020-12-23 16:42                         ` Nicolas König
2020-12-23 17:25                   ` dhumieres.dominique
2020-12-27 17:10                     ` Nicolas König
2021-01-01 13:51                       ` dhumieres.dominique
2021-01-01 16:16                         ` Thomas Koenig
2021-01-01 16:41                           ` dhumieres.dominique
2021-01-02 20:45                             ` Thomas Koenig
2021-01-02 20:55                               ` Iain Sandoe
2021-01-02 21:43                                 ` Thomas Koenig
2021-01-02 22:37                                 ` Nicolas König
2021-01-02 21:44                                   ` Iain Sandoe
2021-01-02 22:09                                     ` Iain Sandoe
2021-01-03 10:46                                       ` Iain Sandoe
2021-01-03 14:54                                         ` Iain Sandoe
2021-01-03 15:42                                           ` Iain Sandoe
2021-01-03 21:53                                             ` Thomas Koenig
2021-01-04  2:34                                               ` Iain Sandoe
2021-01-04 18:54                                                 ` Nicolas König
2021-01-05 13:11                                                   ` Iain Sandoe [this message]
2021-01-05 13:23                                                     ` Iain Sandoe
2021-01-05 13:27                                                     ` Thomas Koenig
2021-01-05 13:34                                                       ` Iain Sandoe
2021-01-05 14:54                                                     ` Nicolas König
2021-01-05 14:28                                                       ` Iain Sandoe
2021-01-05 15:45                                                         ` Nicolas König
     [not found]                                                           ` <BAD6EA1D-BB9F-4905-ADD1-76FA1D6B9591@sandoe.co.uk>
2021-01-05 17:11                                                             ` Nicolas König
2021-01-06 16:56                                                               ` Iain Sandoe
  -- strict thread matches above, loose matches on Subject: below --
2020-11-29 13:10 Nicolas König

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=816E309C-4983-4159-973D-F1A46AD8CB3C@sandoe.co.uk \
    --to=iain@sandoe.co.uk \
    --cc=dhumieres.dominique@free.fr \
    --cc=fortran@gcc.gnu.org \
    --cc=koenigni@student.ethz.ch \
    --cc=tkoenig@netcologne.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).