[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