On Sun, 4 Jun 2023, László Böszörményi wrote:

Hi,

On Sat, Jun 3, 2023 at 8:30 PM Bob Friesenhahn
<bfrie...@simple.dallas.tx.us> wrote:
I am definitely able to confirm that memory consumption builds due to
invoking GetImageDepth() via a POSIX thread.  The rate that it builds
is image sensitive since some images cause GetImageDepth() to perform
more OpenMP loops.
Unfortunately I can not reproduce. My processor is an Intel K variant
CPU, six cores and twelve threads, 64 Gb of RAM.
GM is 1.3.40 with two security fixes backported, compiled with GCC
v12.2.0. Tried with three PNG images, all memory consumption is static
from the beginning. Do I need some special case of PNG files to
experience this issue?

Using PNG is not important. The nature of the input image is important. Prepare a test image like

  gm convert infile.png -depth 4 testfile.pnm

and then use testfile.pnm as input.

The PNM reader is now also also threaded (in very recent versions). PNG should work as well to reproduce the bug.

My own testing is under Ubuntu 20.04 using GCC 10.
Do you think it might be a problem with another system component, a
GCC optimization or this is fixed meanwhile? At least I do wonder why
this issue is CPU / machine dependent.

That of course is the question. It seems like some small bit of state is being added to (presumably) many thread stacks, I see the number of 'anon' mappings increasing, and the "heap" similarly grows and, but is released before the program exits.

It is possible that doing some OpenMP thing prior to using POSIX threads (so OpenMP teams are already created) might change the outcome. I have not tried that yet.

I have attached a version of threadarena.c which loops 1024 times and then quits.

Bob
--
Bob Friesenhahn
bfrie...@simple.dallas.tx.us, http://www.simplesystems.org/users/bfriesen/
GraphicsMagick Maintainer,    http://www.GraphicsMagick.org/
Public Key,     http://www.simplesystems.org/users/bfriesen/public-key.txt
/*
 * gcc -o threadarena threadarena.c \
 *    `GraphicsMagick-config --cppflags --ldflags --libs`
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <pthread.h>
#include <magick/api.h>

static void* readimage(void* arg)
{
  ImageInfo *imageInfo;
  ExceptionInfo exception;
  const char* filename = (const char*) arg;
  /* ImageCharacteristics chars; */
  unsigned long depth;

  imageInfo=CloneImageInfo(0);
  GetExceptionInfo(&exception);

  (void) strncpy(imageInfo->filename, arg, MaxTextExtent-1 );

  Image *image = ReadImage(imageInfo, &exception);
  if (image == (Image *) NULL)
    {
      CatchException(&exception);
      perror("ReadImage");
    }

  depth=GetImageDepth(image,&exception);
  if (exception.severity != UndefinedException)
    CatchException(&exception);
  else
    fprintf(stdout,"Depth: %lu\n", depth);

  DestroyImage(image);
  DestroyImageInfo(imageInfo);
  DestroyExceptionInfo( &exception );
  return NULL;
}

int main ( int argc, char **argv )
{
  unsigned int count = 1024;
  const char* file = argv[1];
  if ( file == NULL )
    {
      fprintf(stderr,"usage: %s <imagefile>\n", argv[0]);
      return 1;
    }

  InitializeMagick(NULL);

  while (count)
    {
      pid_t myp = getpid();
      char s[PATH_MAX];
#if 1
      /* this code path has a thread arena leak */
      pthread_t thread_id;
      pthread_create(&thread_id, NULL, readimage, argv[1]);

      /* pthread_detach(thread_id); also shows the problem */
      pthread_join(thread_id, NULL);
#else
      /* this code path doesn't have a thread arena leak */
      readimage(argv[1]);
#endif

      sleep(1);

      fprintf(stderr,"%u : %lld\n", count, (long long)time(0));
      snprintf(s,sizeof(s),
               "ps -o vsz -o rss -o user -o command -p %lld", (long long)myp);
      system(s);
      snprintf(s,sizeof(s),
               "pmap -x %lld | grep anon | wc -l", (long long)myp);
      system(s);
      count--;
    }

  DestroyMagick();

  return 0;
}

Reply via email to