[Mesa-dev] [RFC] ralloc: use jemalloc for faster GLSL compilation

Nicolai Hähnle nhaehnle at gmail.com
Thu Sep 29 09:20:19 UTC 2016


On 28.09.2016 18:49, Marek Olšák wrote:
> From: Marek Olšák <marek.olsak at amd.com>
>
> More info about jemalloc:
>    https://github.com/jemalloc/jemalloc/wiki/History
>
> Average from 3 takes compiling Alien Isolation shaders from GLSL to GCN
> bytecode:
>    glibc:    17.183s
>    jemalloc: 15.558s
>    diff:     -9.5%
>
> The diff is -10.5% for a full shader-db run.
> ---
>
> TODO: The jemalloc dependency should be added to configure.ac before this.
>
> We can probably redirect all malloc/calloc/realloc/free calls in Mesa to
> jemalloc. We can either use _mesa_jemalloc, etc. everywhere or we can
> redirect calls to jemalloc using #define malloc _mesa_jemalloc, etc.
>
> Right now, I just use: export LDFLAGS=-ljemalloc

Sounds good to me. It should probably be a configurable option, 
defaulting to jemalloc and failing if not available unless explicitly 
disabled.

On the Gallium side of things, switching to jemalloc could be pretty 
straightforward via the macros in u_memory.h, once we know that they're 
actually used consistently (which we currently don't -- it would be nice 
to know how jemalloc and glibc malloc react when the calls are mixed).

Cheers,
Nicolai

>  src/util/jemalloc_wrapper.h | 95 +++++++++++++++++++++++++++++++++++++++++++++
>  src/util/ralloc.c           |  7 ++--
>  2 files changed, 99 insertions(+), 3 deletions(-)
>  create mode 100644 src/util/jemalloc_wrapper.h
>
> diff --git a/src/util/jemalloc_wrapper.h b/src/util/jemalloc_wrapper.h
> new file mode 100644
> index 0000000..d994576
> --- /dev/null
> +++ b/src/util/jemalloc_wrapper.h
> @@ -0,0 +1,95 @@
> +/*
> + * Copyright © 2016 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +#ifndef JEMALLOC_WRAPPER_H
> +#define JEMALLOC_WRAPPER_H
> +
> +#if defined(_WIN32) || defined(WIN32)
> +
> +/* Use a fallback on Windows. */
> +#include <stdlib.h>
> +#define _mesa_jemalloc malloc
> +#define _mesa_jezalloc(size) calloc(1, size)
> +#define _mesa_jecalloc calloc
> +#define _mesa_jerealloc realloc
> +#define _mesa_jefree free
> +
> +#else /* Linux, BSD, etc. */
> +
> +#include "macros.h"
> +#include <jemalloc/jemalloc.h>
> +
> +/* Standard function names (malloc, etc.) can't be used, because glibc is
> + * loaded first, so libjemalloc can't override them. Instead, alternative
> + * jemalloc functions are used, which do the same thing.
> + *
> + * - mallocx = like malloc
> + * - rallocx = like realloc
> + * - dallocx = like free
> + */
> +
> +static inline void *
> +_mesa_jemalloc(size_t size)
> +{
> +   if (unlikely(!size))
> +      size = 1;
> +
> +   return mallocx(size, 0);
> +}
> +
> +static inline void *
> +_mesa_jezalloc(size_t size)
> +{
> +   if (unlikely(!size))
> +      size = 1;
> +
> +   return mallocx(size, MALLOCX_ZERO);
> +}
> +
> +static inline void *
> +_mesa_jecalloc(size_t num, size_t size)
> +{
> +   /* TODO:
> +    *   Check for overflow if needed.
> +    *   See jemalloc, which seems to use a compatible license.
> +    */
> +   return _mesa_jezalloc(num * size);
> +}
> +
> +static inline void *
> +_mesa_jerealloc(void *ptr, size_t size)
> +{
> +   if (unlikely(!size))
> +      size = 1;
> +
> +   return rallocx(ptr, size, 0);
> +}
> +
> +static inline void
> +_mesa_jefree(void *ptr)
> +{
> +   dallocx(ptr, 0);
> +}
> +
> +#endif /* OS/Platform check */
> +#endif /* JEMALLOC_WRAPPER_H */
> diff --git a/src/util/ralloc.c b/src/util/ralloc.c
> index 9526011..d3897ed 100644
> --- a/src/util/ralloc.c
> +++ b/src/util/ralloc.c
> @@ -33,20 +33,21 @@
>  #include <limits.h>
>  #endif
>
>  /* Some versions of MinGW are missing _vscprintf's declaration, although they
>   * still provide the symbol in the import library. */
>  #ifdef __MINGW32__
>  _CRTIMP int _vscprintf(const char *format, va_list argptr);
>  #endif
>
>  #include "ralloc.h"
> +#include "jemalloc_wrapper.h"
>
>  #ifndef va_copy
>  #ifdef __va_copy
>  #define va_copy(dest, src) __va_copy((dest), (src))
>  #else
>  #define va_copy(dest, src) (dest) = (src)
>  #endif
>  #endif
>
>  #define CANARY 0x5A1106
> @@ -115,21 +116,21 @@ ralloc_size(const void *ctx, size_t size)
>      *
>      * TODO: Make ralloc_size not zero fill memory, and cleanup any code that
>      * should instead be using rzalloc.
>      */
>     return rzalloc_size(ctx, size);
>  }
>
>  void *
>  rzalloc_size(const void *ctx, size_t size)
>  {
> -   void *block = calloc(1, size + sizeof(ralloc_header));
> +   void *block = _mesa_jezalloc(size + sizeof(ralloc_header));
>     ralloc_header *info;
>     ralloc_header *parent;
>
>     if (unlikely(block == NULL))
>        return NULL;
>     info = (ralloc_header *) block;
>     parent = ctx != NULL ? get_header(ctx) : NULL;
>
>     add_child(parent, info);
>
> @@ -140,21 +141,21 @@ rzalloc_size(const void *ctx, size_t size)
>     return PTR_FROM_HEADER(info);
>  }
>
>  /* helper function - assumes ptr != NULL */
>  static void *
>  resize(void *ptr, size_t size)
>  {
>     ralloc_header *child, *old, *info;
>
>     old = get_header(ptr);
> -   info = realloc(old, size + sizeof(ralloc_header));
> +   info = _mesa_jerealloc(old, size + sizeof(ralloc_header));
>
>     if (info == NULL)
>        return NULL;
>
>     /* Update parent and sibling's links to the reallocated node. */
>     if (info != old && info->parent != NULL) {
>        if (info->parent->child == old)
>  	 info->parent->child = info;
>
>        if (info->prev != NULL)
> @@ -248,21 +249,21 @@ unsafe_free(ralloc_header *info)
>     while (info->child != NULL) {
>        temp = info->child;
>        info->child = temp->next;
>        unsafe_free(temp);
>     }
>
>     /* Free the block itself.  Call the destructor first, if any. */
>     if (info->destructor != NULL)
>        info->destructor(PTR_FROM_HEADER(info));
>
> -   free(info);
> +   _mesa_jefree(info);
>  }
>
>  void
>  ralloc_steal(const void *new_ctx, void *ptr)
>  {
>     ralloc_header *info, *parent;
>
>     if (unlikely(ptr == NULL))
>        return;
>
>


More information about the mesa-dev mailing list