Hi Pádraig, > There was lots of heap interaction going on, > and by using the attached patch (only illustrative, may leak, > is not thread safe, ...) to cache the PRINTF_PARSE result > it increases the throughput to 5.8MB/s
Adding a global cache like this is hairy. Maybe we could get a speedup by letting the application allocate and manage a hash table that is used as a cache...? Anyway, the immediate need to malloc() should be reduced with this patch. It trades malloc() against a bit more room on the stack. With it, I see a performance improvement in my test case of a factor 1.75. How much does it help on yours? 2011-02-04 Bruno Haible <[email protected]> vasnprintf: Reduce use of malloc for small format strings. * lib/printf-args.h (N_DIRECT_ALLOC_ARGUMENTS): New macro. (arguments): Add room for the first 7 arguments. * lib/printf-parse.h (N_DIRECT_ALLOC_DIRECTIVES): New macro. (char_directives, u8_directives, u16_directives, u32_directives): Add room for the first 7 directives. * lib/printf-parse.c: Include <string.h>. (PRINTF_PARSE): Change memory handling code so that it uses the first 7 preallocated elements in an 'arguments' or 'DIRECTIVES' struct. * lib/vasnprintf.c (VASNPRINTF): Update memory handling code. Reported by Pádraig Brady <[email protected]>. --- lib/printf-args.h.orig Fri Feb 4 19:09:25 2011 +++ lib/printf-args.h Fri Feb 4 17:35:19 2011 @@ -1,5 +1,5 @@ /* Decomposed printf argument list. - Copyright (C) 1999, 2002-2003, 2006-2007, 2009-2011 Free Software + Copyright (C) 1999, 2002-2003, 2006-2007, 2011 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -136,10 +136,14 @@ } argument; +/* Number of directly allocated arguments (no malloc() needed). */ +#define N_DIRECT_ALLOC_ARGUMENTS 7 + typedef struct { size_t count; argument *arg; + argument direct_alloc_arg[N_DIRECT_ALLOC_ARGUMENTS]; } arguments; --- lib/printf-parse.h.orig Fri Feb 4 19:09:25 2011 +++ lib/printf-parse.h Fri Feb 4 17:36:35 2011 @@ -1,5 +1,5 @@ /* Parse printf format string. - Copyright (C) 1999, 2002-2003, 2005, 2007, 2009-2011 Free Software + Copyright (C) 1999, 2002-2003, 2005, 2007, 2010-2011 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -47,6 +47,9 @@ /* xxx_directive: A parsed directive. xxx_directives: A parsed format string. */ +/* Number of directly allocated directives (no malloc() needed). */ +#define N_DIRECT_ALLOC_DIRECTIVES 7 + /* A parsed directive. */ typedef struct { @@ -71,6 +74,7 @@ char_directive *dir; size_t max_width_length; size_t max_precision_length; + char_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES]; } char_directives; @@ -100,6 +104,7 @@ u8_directive *dir; size_t max_width_length; size_t max_precision_length; + u8_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES]; } u8_directives; @@ -127,6 +132,7 @@ u16_directive *dir; size_t max_width_length; size_t max_precision_length; + u16_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES]; } u16_directives; @@ -154,6 +160,7 @@ u32_directive *dir; size_t max_width_length; size_t max_precision_length; + u32_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES]; } u32_directives; --- lib/printf-parse.c.orig Fri Feb 4 19:09:25 2011 +++ lib/printf-parse.c Fri Feb 4 17:24:05 2011 @@ -63,6 +63,9 @@ /* malloc(), realloc(), free(). */ #include <stdlib.h> +/* memcpy(). */ +#include <string.h> + /* errno. */ #include <errno.h> @@ -80,23 +83,20 @@ int PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) { - const CHAR_T *cp = format; /* pointer into format */ + const CHAR_T *cp = format; /* pointer into format */ size_t arg_posn = 0; /* number of regular arguments consumed */ - size_t d_allocated; /* allocated elements of d->dir */ - size_t a_allocated; /* allocated elements of a->arg */ + size_t d_allocated; /* allocated elements of d->dir */ + size_t a_allocated; /* allocated elements of a->arg */ size_t max_width_length = 0; size_t max_precision_length = 0; d->count = 0; - d_allocated = 1; - d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE)); - if (d->dir == NULL) - /* Out of memory. */ - goto out_of_memory_1; + d_allocated = N_DIRECT_ALLOC_DIRECTIVES; + d->dir = d->direct_alloc_dir; a->count = 0; - a_allocated = 0; - a->arg = NULL; + a_allocated = N_DIRECT_ALLOC_ARGUMENTS; + a->arg = a->direct_alloc_arg; #define REGISTER_ARG(_index_,_type_) \ { \ @@ -113,12 +113,14 @@ if (size_overflow_p (memory_size)) \ /* Overflow, would lead to out of memory. */ \ goto out_of_memory; \ - memory = (argument *) (a->arg \ + memory = (argument *) (a->arg != a->direct_alloc_arg \ ? realloc (a->arg, memory_size) \ : malloc (memory_size)); \ if (memory == NULL) \ /* Out of memory. */ \ goto out_of_memory; \ + if (a->arg == a->direct_alloc_arg) \ + memcpy (memory, a->arg, a->count * sizeof (argument)); \ a->arg = memory; \ } \ while (a->count <= n) \ @@ -588,10 +590,14 @@ if (size_overflow_p (memory_size)) /* Overflow, would lead to out of memory. */ goto out_of_memory; - memory = (DIRECTIVE *) realloc (d->dir, memory_size); + memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir + ? realloc (d->dir, memory_size) + : malloc (memory_size)); if (memory == NULL) /* Out of memory. */ goto out_of_memory; + if (d->dir == d->direct_alloc_dir) + memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE)); d->dir = memory; } } @@ -610,19 +616,18 @@ return 0; error: - if (a->arg) + if (a->arg != a->direct_alloc_arg) free (a->arg); - if (d->dir) + if (d->dir != d->direct_alloc_dir) free (d->dir); errno = EINVAL; return -1; out_of_memory: - if (a->arg) + if (a->arg != a->direct_alloc_arg) free (a->arg); - if (d->dir) + if (d->dir != d->direct_alloc_dir) free (d->dir); -out_of_memory_1: errno = ENOMEM; return -1; } --- lib/vasnprintf.c.orig Fri Feb 4 19:09:25 2011 +++ lib/vasnprintf.c Fri Feb 4 17:23:17 2011 @@ -1753,8 +1753,9 @@ return NULL; #define CLEANUP() \ - free (d.dir); \ - if (a.arg) \ + if (d.dir != d.direct_alloc_dir) \ + free (d.dir); \ + if (a.arg != a.direct_alloc_arg) \ free (a.arg); if (PRINTF_FETCHARGS (args, &a) < 0) -- In memoriam Amadou Diallo <http://en.wikipedia.org/wiki/Amadou_Diallo>
