[Mesa-dev] [PATCH 05/12] ralloc: Avoid calling vsnprintf() twice

Vladislav Egorov vegorov180 at gmail.com
Sat Jan 7 19:02:06 UTC 2017


Typical perf output of ralloc's printf-like functions looks like that:

   0,14% ralloc_vasprintf_rewrite_tail
     0,06% printf_length
     0,05% __vsnprintf_chk
     0,02% resize
     0,01% __vsnprintf_chk at plt

They spend most of the time inside of libc's formatted i/o functions
they call twice -- first inside of printf_length() to calculate
resulting string length, then resize the buffer, then to actually
print the string to the resized buffer.

Try to avoid double vsnprintf() printing the string to a large enough
temporary buffer. If the string wasn't trimmed, just memcpy() it to
the output without printing it again.
---
 src/util/ralloc.c | 57 ++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 42 insertions(+), 15 deletions(-)

diff --git a/src/util/ralloc.c b/src/util/ralloc.c
index 980e4e4..df2b1d8 100644
--- a/src/util/ralloc.c
+++ b/src/util/ralloc.c
@@ -429,14 +429,18 @@ ralloc_asprintf(const void *ctx, const char *fmt, ...)
    return ptr;
 }
 
+#define PRINTF_BUF_SIZE 128
+
 /* Return the length of the string that would be generated by a printf-style
- * format and argument list, not including the \0 byte.
+ * format and argument list, not including the \0 byte. Print the string to
+ * PRINTF_BUF_SIZE-sized buffer and set fully_printed to true, if the entire
+ * string was printed to the buf.
  */
 static size_t
-printf_length(const char *fmt, va_list untouched_args)
+printf_length(const char *fmt, char* buf, bool *fully_printed,
+              va_list untouched_args)
 {
    int size;
-   char junk;
 
    /* Make a copy of the va_list so the original caller can still use it */
    va_list args;
@@ -447,9 +451,10 @@ printf_length(const char *fmt, va_list untouched_args)
     * if the number of characters to write is greater than count.
     */
    size = _vscprintf(fmt, args);
-   (void)junk;
+   *fully_printed = false;
 #else
-   size = vsnprintf(&junk, 1, fmt, args);
+   size = vsnprintf(buf, PRINTF_BUF_SIZE, fmt, args);
+   *fully_printed = size <= (PRINTF_BUF_SIZE - 1);
 #endif
    assert(size >= 0);
 
@@ -461,11 +466,17 @@ printf_length(const char *fmt, va_list untouched_args)
 char *
 ralloc_vasprintf(const void *ctx, const char *fmt, va_list args)
 {
-   size_t size = printf_length(fmt, args) + 1;
+   char buf[PRINTF_BUF_SIZE];
+   bool fully_printed;
+   size_t size = printf_length(fmt, buf, &fully_printed, args) + 1;
 
    char *ptr = ralloc_size(ctx, size);
-   if (ptr != NULL)
-      vsnprintf(ptr, size, fmt, args);
+   if (ptr != NULL) {
+      if (fully_printed)
+         memcpy(ptr, buf, size);
+      else
+         vsnprintf(ptr, size, fmt, args);
+   }
 
    return ptr;
 }
@@ -507,6 +518,8 @@ ralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
 {
    size_t new_length;
    char *ptr;
+   char buf[PRINTF_BUF_SIZE];
+   bool fully_printed;
 
    assert(str != NULL);
 
@@ -517,13 +530,16 @@ ralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
       return true;
    }
 
-   new_length = printf_length(fmt, args);
+   new_length = printf_length(fmt, buf, &fully_printed, args);
 
    ptr = resize(*str, *start + new_length + 1);
    if (unlikely(ptr == NULL))
       return false;
 
-   vsnprintf(ptr + *start, new_length + 1, fmt, args);
+   if (fully_printed)
+      memcpy(ptr + *start, buf, new_length + 1);
+   else
+      vsnprintf(ptr + *start, new_length + 1, fmt, args);
    *str = ptr;
    *start += new_length;
    return true;
@@ -788,11 +804,17 @@ linear_asprintf(void *parent, const char *fmt, ...)
 char *
 linear_vasprintf(void *parent, const char *fmt, va_list args)
 {
-   unsigned size = printf_length(fmt, args) + 1;
+   char buf[PRINTF_BUF_SIZE];
+   bool fully_printed;
+   unsigned size = printf_length(fmt, buf, &fully_printed, args) + 1;
 
    char *ptr = linear_alloc_child(parent, size);
-   if (ptr != NULL)
-      vsnprintf(ptr, size, fmt, args);
+   if (ptr != NULL) {
+      if (fully_printed)
+         memcpy(ptr, buf, size);
+      else
+         vsnprintf(ptr, size, fmt, args);
+   }
 
    return ptr;
 }
@@ -835,6 +857,8 @@ linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start,
 {
    size_t new_length;
    char *ptr;
+   char buf[PRINTF_BUF_SIZE];
+   bool fully_printed;
 
    assert(str != NULL);
 
@@ -844,13 +868,16 @@ linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start,
       return true;
    }
 
-   new_length = printf_length(fmt, args);
+   new_length = printf_length(fmt, buf, &fully_printed, args);
 
    ptr = linear_realloc(parent, *str, *start + new_length + 1);
    if (unlikely(ptr == NULL))
       return false;
 
-   vsnprintf(ptr + *start, new_length + 1, fmt, args);
+   if (fully_printed)
+      memcpy(ptr + *start, buf, new_length + 1);
+   else
+      vsnprintf(ptr + *start, new_length + 1, fmt, args);
    *str = ptr;
    *start += new_length;
    return true;
-- 
2.7.4



More information about the mesa-dev mailing list