emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Old topic(s) again [was: Re: Aligned blocks management: obsolete?]


From: Stefan Monnier
Subject: Re: Old topic(s) again [was: Re: Aligned blocks management: obsolete?]
Date: Wed, 04 Jul 2012 09:11:43 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1.50 (gnu/linux)

> Likewise.

Similarly, I'm not convinced it's an improvement.
Overall, it doesn't seem to simplify the code and I don't see any
evidence that it will have a non-negligible effect on CPU/memory use.


        Stefan


> Dmitry
> === modified file 'configure.in'
> --- configure.in      2012-07-04 08:07:26 +0000
> +++ configure.in      2012-07-04 08:28:33 +0000
> @@ -2704,12 +2704,106 @@
>  __fpending strsignal setitimer \
>  sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
>  gai_strerror mkstemp getline getdelim fsync sync \
> -difftime posix_memalign \
> +difftime memalign posix_memalign \
>  getpwent endpwent getgrent endgrent \
>  touchlock \
>  strcasecmp strncasecmp \
>  cfmakeraw cfsetspeed copysign __executable_start)
 
> +dnl Check whether posix_memalign can allocate blocks consecutively.
> +if test "$ac_cv_func_posix_memalign" = yes; then
> +  AC_MSG_CHECKING([for block padding size to use with posix_memalign])
> +  AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdlib.h>
> +int
> +main ()
> +{
> +  int i, bad;
> +  void *p, *prev;
> +  size_t padsz, blksz = 1024;
> +
> +  for (padsz = 0; padsz <= 64; padsz += sizeof (long))
> +    {
> +      bad = 0;
> +
> +      /* Test asks for BLKSZ - PADSZ bytes aligned at BLKSZ boundary.  */
> +      for (i = 0, prev = NULL; i < 16; i++)
> +        {
> +          if (posix_memalign (&p, blksz, blksz - padsz))
> +            bad++;
> +          else if (prev && p - prev > blksz)
> +            bad++;
> +          prev = p;
> +        }
> +
> +      /* Zero means posix_memalign looks good enough with this PADSZ.  */
> +      if (!bad)
> +        return padsz;
> +    }
> +
> +  /* No suitable PADSZ was found, posix_memalign isn't good enough for us.  
> */
> +  return 255;
> +}]])], emacs_cv_posix_memalign_pad=255, emacs_cv_posix_memalign_pad=$?,
> +  emacs_cv_posix_memalign_pad=255)
> +  if test $emacs_cv_posix_memalign_pad -le 64; then
> +      AC_MSG_RESULT($emacs_cv_posix_memalign_pad)
> +      AC_DEFINE(POSIX_MEMALIGN_WORKS, 1,
> +        [Define to 1 if you have good enough `posix_memalign' function.])
> +      AC_DEFINE_UNQUOTED(BLOCK_PADDING, $emacs_cv_posix_memalign_pad,
> +        [Block padding used to allocate aligned blocks.])
> +  else
> +      AC_MSG_RESULT([not detected, posix_memalign will not be used])
> +  fi
> +fi
> +
> +dnl If posix_memalign isn't available or tends to create holes
> +dnl between blocks, check whether memalign performs better.
> +if test "$emacs_cv_posix_memalign_pad" -gt 64; then
> +  if test "$ac_cv_func_memalign" = yes; then
> +    AC_MSG_CHECKING([for block padding size for memalign])
> +    AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <malloc.h>
> +int
> +main ()
> +{
> +  int i, bad;
> +  void *p, *prev;
> +  size_t padsz, blksz = 1024;
> +
> +  for (padsz = 0; padsz <= 64; padsz += sizeof (long))
> +    {
> +      bad = 0;
> +
> +      /* Test asks for BLKSZ - PADSZ bytes aligned at BLKSZ boundary.  */
> +      for (i = 0, prev = NULL; i < 16; i++)
> +        {
> +          p = memalign (blksz, blksz - padsz);
> +          if (!p)
> +            bad++;
> +          else if (prev && p - prev > blksz)
> +            bad++;
> +          prev = p;
> +        }
> +  
> +      /* Zero means memalign looks good enough with this PADSZ.  */
> +      if (!bad)
> +        return padsz;
> +    }
> +
> +  /* No suitable PADSZ was found, memalign isn't good enough for us.  */
> +  return 255;
> +}]])], emacs_cv_memalign_pad=255, emacs_cv_memalign_pad=$?,
> +    emacs_cv_memalign_pad=255)
> +    if test $emacs_cv_memalign_pad -le 64; then
> +      AC_MSG_RESULT($emacs_cv_memalign_pad)
> +      AC_DEFINE(MEMALIGN_WORKS, 1,
> +        [Define to 1 if you have good enough `memalign' function.])
> +      AC_DEFINE_UNQUOTED(BLOCK_PADDING, $emacs_cv_memalign_pad,
> +        [Block padding used to allocate aligned blocks.])
> +    else
> +      AC_MSG_RESULT([not detected, memalign will not be used])
> +    fi
> +  fi
> +fi
> +
>  dnl Cannot use AC_CHECK_FUNCS
>  AC_CACHE_CHECK([for __builtin_unwind_init],
>              emacs_cv_func___builtin_unwind_init,

> === modified file 'src/alloc.c'
> --- src/alloc.c       2012-07-03 16:35:53 +0000
> +++ src/alloc.c       2012-07-04 08:33:52 +0000
> @@ -308,9 +308,6 @@
>    MEM_TYPE_VECTOR_BLOCK
>  };
 
> -static void *lisp_malloc (size_t, enum mem_type);
> -
> -
>  #if GC_MARK_STACK || defined GC_MALLOC_CHECK
 
>  #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
> @@ -390,7 +387,6 @@
>  #define MEM_NIL &mem_z
 
>  static struct Lisp_Vector *allocate_vectorlike (ptrdiff_t);
> -static void lisp_free (void *);
>  static void mark_stack (void);
>  static int live_vector_p (struct mem_node *, void *);
>  static int live_buffer_p (struct mem_node *, void *);
> @@ -887,15 +883,33 @@
>    return Qnil;
>  }
 
> +#if ! USE_LSB_TAG
> +
> +/* Used to catch invalid address when debugging.  */
> +
> +void *lisp_malloc_loser EXTERNALLY_VISIBLE;
> +
> +/* Nonzero if the memory at ADDR can be
> +   addressed thru a Lisp object's pointer.  */
> +
> +static inline int
> +verify_address (char *addr)
> +{
> +  Lisp_Object obj;
> +
> +  XSETCONS (obj, addr);
> +  if ((char *) XCONS (obj) == addr)
> +    return 1;
> +  lisp_malloc_loser = addr;
> +  return 0;
> +}
> +
> +#endif /* not USE_LSB_TAG */
 
>  /* Like malloc but used for allocating Lisp data.  NBYTES is the
>     number of bytes to allocate, TYPE describes the intended use of the
>     allocated memory block (for strings, for conses, ...).  */
 
> -#if ! USE_LSB_TAG
> -void *lisp_malloc_loser EXTERNALLY_VISIBLE;
> -#endif
> -
>  static void *
>  lisp_malloc (size_t nbytes, enum mem_type type)
>  {
> @@ -907,24 +921,33 @@
>    allocated_mem_type = type;
>  #endif
 
> +#ifdef DOUG_LEA_MALLOC
> +  /* Prevent mmap'ing the chunk.  Lisp data may not be mmap'ed
> +     because mapped region contents are not preserved in
> +     a dumped Emacs.  */
> +  mallopt (M_MMAP_MAX, 0);
> +#endif
>    val = (void *) malloc (nbytes);
> +#ifdef DOUG_LEA_MALLOC
> +  /* Back to a reasonable maximum of mmap'ed areas.  */
> +  mallopt (M_MMAP_MAX, MMAP_MAX_AREAS);
> +#endif
> +
> +  if (!val && nbytes)
> +    {
> +      MALLOC_UNBLOCK_INPUT;
> +      memory_full (nbytes);
> +    }
 
>  #if ! USE_LSB_TAG
> -  /* If the memory just allocated cannot be addressed thru a Lisp
> -     object's pointer, and it needs to be,
> -     that's equivalent to running out of memory.  */
> -  if (val && type != MEM_TYPE_NON_LISP)
> +  if (val && type != MEM_TYPE_NON_LISP
> +      && !verify_address ((char *) val + nbytes - 1))
>      {
> -      Lisp_Object tem;
> -      XSETCONS (tem, (char *) val + nbytes - 1);
> -      if ((char *) XCONS (tem) != (char *) val + nbytes - 1)
> -     {
> -       lisp_malloc_loser = val;
> -       free (val);
> -       val = 0;
> -     }
> +      free (val);
> +      MALLOC_UNBLOCK_INPUT;
> +      memory_full (SIZE_MAX);
>      }
> -#endif
> +#endif /* not USE_LSB_TAG */
 
>  #if GC_MARK_STACK && !defined GC_MALLOC_CHECK
>    if (val && type != MEM_TYPE_NON_LISP)
> @@ -932,8 +955,6 @@
>  #endif
 
>    MALLOC_UNBLOCK_INPUT;
> -  if (!val && nbytes)
> -    memory_full (nbytes);
>    return val;
>  }
 
> @@ -951,30 +972,33 @@
>    MALLOC_UNBLOCK_INPUT;
>  }
 
> -/*****  Allocation of aligned blocks of memory to store Lisp data.  *****/
> -
> -/* The entry point is lisp_align_malloc which returns blocks of at most
> -   BLOCK_BYTES and guarantees they are aligned on a BLOCK_ALIGN boundary.  */
> -
> -#if defined (HAVE_POSIX_MEMALIGN) && defined (SYSTEM_MALLOC)
> -#define USE_POSIX_MEMALIGN 1
> -#endif
> +/* Allocation of aligned blocks is somewhat tricky.  If posix_memalign is
> +   available, configure tries to determine the block padding value to help
> +   posix_memalign allocate blocks of (1024 - padding) bytes without holes
> +   between them.  If suitable padding is found, we define 
> POSIX_MEMALIGN_WORKS,
> +   BLOCK_PADDING to padding value and use posix_memalign and free.  Some
> +   systems lacks posix_memalign, but provides memalign; for such a system,
> +   configure performs similar check for memalign.  If suitable padding is
> +   found, we define MEMALIGN_WORKS, BLOCK_PADDING to padding value and use
> +   memalign and free.  If none of the above, we use internal_align_alloc and
> +   internal_align_free.  */
 
>  /* BLOCK_ALIGN has to be a power of 2.  */
> +
>  #define BLOCK_ALIGN (1 << 10)
 
> -/* Padding to leave at the end of a malloc'd block.  This is to give
> -   malloc a chance to minimize the amount of memory wasted to alignment.
> -   It should be tuned to the particular malloc library used.
> -   On glibc-2.3.2, malloc never tries to align, so a padding of 0 is best.
> -   posix_memalign on the other hand would ideally prefer a value of 4
> -   because otherwise, there's 1020 bytes wasted between each ablocks.
> -   In Emacs, testing shows that those 1020 can most of the time be
> -   efficiently used by malloc to place other objects, so a value of 0 can
> -   still preferable unless you have a lot of aligned blocks and virtually
> -   nothing else.  */
> +#if ! POSIX_MEMALIGN_WORKS && ! MEMALIGN_WORKS
> +
> +/* Here we assume that malloc implementation has
> +   nothing about aligned blocks management.  */
> +
> +/* Padding to leave at the end of a malloc'd block.  */
> +
>  #define BLOCK_PADDING 0
> -#define BLOCK_BYTES \
> +
> +/* Maximum amount of memory in aligned block.  */
> +
> +#define BLOCK_BYTES                                          \
>    (BLOCK_ALIGN - sizeof (struct ablocks *) - BLOCK_PADDING)
 
>  /* Internal data structures and constants.  */
> @@ -982,6 +1006,7 @@
>  #define ABLOCKS_SIZE 16
 
>  /* An aligned block of memory.  */
> +
>  struct ablock
>  {
>    union
> @@ -1007,12 +1032,14 @@
>  };
 
>  /* A bunch of consecutive aligned blocks.  */
> +
>  struct ablocks
>  {
>    struct ablock blocks[ABLOCKS_SIZE];
>  };
 
> -/* Size of the block requested from malloc or posix_memalign.  */
> +/* Size of the block requested from underlying malloc.  */
> +
>  #define ABLOCKS_BYTES (sizeof (struct ablocks) - BLOCK_PADDING)
 
>  #define ABLOCK_ABASE(block) \
> @@ -1021,94 +1048,43 @@
>     : (block)->abase)
 
>  /* Virtual `busy' field.  */
> +
>  #define ABLOCKS_BUSY(abase) ((abase)->blocks[0].abase)
 
>  /* Pointer to the (not necessarily aligned) malloc block.  */
> -#ifdef USE_POSIX_MEMALIGN
> -#define ABLOCKS_BASE(abase) (abase)
> -#else
> -#define ABLOCKS_BASE(abase) \
> +
> +#define ABLOCKS_BASE(abase)                                          \
>    (1 & (intptr_t) ABLOCKS_BUSY (abase) ? abase : ((void**)abase)[-1])
> -#endif
 
>  /* The list of free ablock.   */
> +
>  static struct ablock *free_ablock;
 
> -/* Allocate an aligned block of nbytes.
> -   Alignment is on a multiple of BLOCK_ALIGN and `nbytes' has to be
> -   smaller or equal to BLOCK_BYTES.  */
> +/* Allocate an aligned block of NBYTES.  */
> +
>  static void *
> -lisp_align_malloc (size_t nbytes, enum mem_type type)
> +internal_align_alloc (size_t nbytes)
>  {
>    void *base, *val;
>    struct ablocks *abase;
 
>    eassert (nbytes <= BLOCK_BYTES);
 
> -  MALLOC_BLOCK_INPUT;
> -
> -#ifdef GC_MALLOC_CHECK
> -  allocated_mem_type = type;
> -#endif
> -
>    if (!free_ablock)
>      {
>        int i;
>        intptr_t aligned; /* int gets warning casting to 64-bit pointer.  */
 
> -#ifdef DOUG_LEA_MALLOC
> -      /* Prevent mmap'ing the chunk.  Lisp data may not be mmap'ed
> -      because mapped region contents are not preserved in
> -      a dumped Emacs.  */
> -      mallopt (M_MMAP_MAX, 0);
> -#endif
> -
> -#ifdef USE_POSIX_MEMALIGN
> -      {
> -     int err = posix_memalign (&base, BLOCK_ALIGN, ABLOCKS_BYTES);
> -     if (err)
> -       base = NULL;
> -     abase = base;
> -      }
> -#else
>        base = malloc (ABLOCKS_BYTES);
>        abase = ALIGN (base, BLOCK_ALIGN);
> -#endif
 
> -      if (base == 0)
> -     {
> -       MALLOC_UNBLOCK_INPUT;
> -       memory_full (ABLOCKS_BYTES);
> -     }
> +      if (base == NULL)
> +     return base;
 
>        aligned = (base == abase);
>        if (!aligned)
>       ((void**)abase)[-1] = base;
 
> -#ifdef DOUG_LEA_MALLOC
> -      /* Back to a reasonable maximum of mmap'ed areas.  */
> -      mallopt (M_MMAP_MAX, MMAP_MAX_AREAS);
> -#endif
> -
> -#if ! USE_LSB_TAG
> -      /* If the memory just allocated cannot be addressed thru a Lisp
> -      object's pointer, and it needs to be, that's equivalent to
> -      running out of memory.  */
> -      if (type != MEM_TYPE_NON_LISP)
> -     {
> -       Lisp_Object tem;
> -       char *end = (char *) base + ABLOCKS_BYTES - 1;
> -       XSETCONS (tem, end);
> -       if ((char *) XCONS (tem) != end)
> -         {
> -           lisp_malloc_loser = base;
> -           free (base);
> -           MALLOC_UNBLOCK_INPUT;
> -           memory_full (SIZE_MAX);
> -         }
> -     }
> -#endif
> -
>        /* Initialize the blocks and put them on the free list.
>        If `base' was not properly aligned, we can't use the last block.  */
>        for (i = 0; i < (aligned ? ABLOCKS_SIZE : ABLOCKS_SIZE - 1); i++)
> @@ -1132,27 +1108,15 @@
>    val = free_ablock;
>    free_ablock = free_ablock->x.next_free;
 
> -#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
> -  if (type != MEM_TYPE_NON_LISP)
> -    mem_insert (val, (char *) val + nbytes, type);
> -#endif
> -
> -  MALLOC_UNBLOCK_INPUT;
> -
> -  eassert (0 == ((uintptr_t) val) % BLOCK_ALIGN);
>    return val;
>  }
 
>  static void
> -lisp_align_free (void *block)
> +internal_align_free (void *block)
>  {
>    struct ablock *ablock = block;
>    struct ablocks *abase = ABLOCK_ABASE (ablock);
 
> -  MALLOC_BLOCK_INPUT;
> -#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
> -  mem_delete (mem_find (block));
> -#endif
>    /* Put on free list.  */
ablock-> x.next_free = free_ablock;
>    free_ablock = ablock;
> @@ -1178,11 +1142,103 @@
>       }
>        eassert ((aligned & 1) == aligned);
>        eassert (i == (aligned ? ABLOCKS_SIZE : ABLOCKS_SIZE - 1));
> -#ifdef USE_POSIX_MEMALIGN
> -      eassert ((uintptr_t) ABLOCKS_BASE (abase) % BLOCK_ALIGN == 0);
> -#endif
>        free (ABLOCKS_BASE (abase));
>      }
> +}
> +
> +#else /* ! POSIX_MEMALIGN_WORKS && ! MEMALIGN_WORKS */
> +
> +/* Here we assume that malloc implementation has either posix_memalign or
> +   memalign, and suitable BLOCK_PADDING value was detected by configure.  */
> +
> +#ifndef BLOCK_PADDING
> +#error "unknown BLOCK_PADDING"
> +#endif
> +
> +/* Maximum amount of memory in aligned block.  */
> +
> +#define BLOCK_BYTES (BLOCK_ALIGN - BLOCK_PADDING)
> +
> +#endif /* ! POSIX_MEMALIGN_WORKS && ! MEMALIGN_WORKS */
> +
> +/* Like lisp_malloc, but allocates aligned block of at
> +   most BLOCK_BYTES aligned on a BLOCK_ALIGN boundary.  */
> +
> +static void *
> +lisp_align_malloc (size_t nbytes, enum mem_type type)
> +{
> +  void *val;
> +
> +  eassert (nbytes <= BLOCK_BYTES);
> +
> +  MALLOC_BLOCK_INPUT;
> +
> +#ifdef GC_MALLOC_CHECK
> +  allocated_mem_type = type;
> +#endif
> +
> +#ifdef DOUG_LEA_MALLOC
> +  /* Prevent mmap'ing the chunk.  Lisp data may not be mmap'ed
> +     because mapped region contents are not preserved in
> +     a dumped Emacs.  */
> +  mallopt (M_MMAP_MAX, 0);
> +#endif
> +
> +#ifdef POSIX_MEMALIGN_WORKS
> +  if (posix_memalign (&val, BLOCK_ALIGN, nbytes))
> +    val = NULL;
> +#elif MEMALIGN_WORKS
> +  val = memalign (BLOCK_ALIGN, nbytes);
> +#else
> +  val = internal_align_alloc (nbytes);
> +#endif
> +
> +#ifdef DOUG_LEA_MALLOC
> +  /* Back to a reasonable maximum of mmap'ed areas.  */
> +  mallopt (M_MMAP_MAX, MMAP_MAX_AREAS);
> +#endif
> +
> +  if (!val && nbytes)
> +    {
> +      MALLOC_UNBLOCK_INPUT;
> +      memory_full (nbytes);
> +    }
> +
> +#if ! USE_LSB_TAG
> +  if (type != MEM_TYPE_NON_LISP 
> +      && !verify_address ((char *) val + nbytes - 1))
> +    {
> +      free (val);
> +      MALLOC_UNBLOCK_INPUT;
> +      memory_full (SIZE_MAX);
> +    }
> +#endif /* not USE_LSB_TAG */
> +
> +#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
> +  if (type != MEM_TYPE_NON_LISP)
> +    mem_insert (val, (char *) val + nbytes, type);
> +#endif
> +
> +  MALLOC_UNBLOCK_INPUT;
> +  eassert (0 == ((uintptr_t) val) % BLOCK_ALIGN);
> +  return val;
> +}
> +
> +/* Free aligned BLOCK.  This must be called to free
> +   memory allocated with a call to lisp_align_malloc.  */
> +
> +static void
> +lisp_align_free (void *block)
> +{
> +  MALLOC_BLOCK_INPUT;
> +#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
> +  mem_delete (mem_find (block));
> +#endif
> +#if POSIX_MEMALIGN_WORKS || MEMALIGN_WORKS
> +  free (block);
> +#else
> +  internal_align_free (block);
> +#endif
>    MALLOC_UNBLOCK_INPUT;
>  }
 
> @@ -6661,8 +6717,10 @@
>    pure_bytes_used_lisp = pure_bytes_used_non_lisp = 0;
>    pure_bytes_used_before_overflow = 0;
 
> +#if ! POSIX_MEMALIGN_WORKS && ! MEMALIGN_WORKS
>    /* Initialize the list of free aligned blocks.  */
>    free_ablock = NULL;
> +#endif
 
>  #if GC_MARK_STACK || defined GC_MALLOC_CHECK
>    mem_init ();





reply via email to

[Prev in Thread] Current Thread [Next in Thread]