From 4b6145cc9b68e0a210db88d79b5d01f1207060d3 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 1 Aug 2014 20:14:14 -0600 Subject: [PATCH] String: performance improvement converting uint64_t to string (4x) Based on the trick given by A. Alexandrescu on Facebook Engineering blog, this patch replace the old mk_str_itop() with the faster algorithm proposed. More details about the implementation here: https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920 Signed-off-by: Eduardo Silva --- include/monkey/mk_plugin.h | 2 +- include/monkey/mk_string.h | 9 ++--- src/mk_signals.c | 8 ++--- src/mk_string.c | 72 ++++++++++++++++++++++++++++---------- 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/include/monkey/mk_plugin.h b/include/monkey/mk_plugin.h index 9f5901b08..fa999000e 100644 --- a/include/monkey/mk_plugin.h +++ b/include/monkey/mk_plugin.h @@ -208,7 +208,7 @@ struct plugin_api char *(*pointer_to_buf) (mk_ptr_t); /* string functions */ - int (*str_itop) (int, mk_ptr_t *); + int (*str_itop) (uint64_t, mk_ptr_t *); int (*str_search) (const char *, const char *, int); int (*str_search_n) (const char *, const char *, int, int); char *(*str_build) (char **, unsigned long *, const char *, ...) PRINTF_WARNINGS(3,4); diff --git a/include/monkey/mk_string.h b/include/monkey/mk_string.h index e1ae25449..2c659664c 100644 --- a/include/monkey/mk_string.h +++ b/include/monkey/mk_string.h @@ -20,9 +20,10 @@ #ifndef MK_STR_H #define MK_STR_H -#include "mk_memory.h" -#include "mk_list.h" -#include "mk_macros.h" +#include +#include +#include +#include /* Case sensitive OFF */ #define MK_STR_SENSITIVE 0 @@ -58,7 +59,7 @@ void mk_string_split_free(struct mk_list *list); int mk_string_trim(char **str); char *mk_string_build(char **buffer, unsigned long *len, const char *format, ...) PRINTF_WARNINGS(3,4); -int mk_string_itop(int n, mk_ptr_t *p); +int mk_string_itop(uint64_t value, mk_ptr_t *p); char *mk_string_copy_substr(const char *string, int pos_init, int pos_end); char *mk_string_tolower(const char *in); diff --git a/src/mk_signals.c b/src/mk_signals.c index a048bba07..4580b72c5 100644 --- a/src/mk_signals.c +++ b/src/mk_signals.c @@ -117,13 +117,9 @@ static void mk_signal_handler(int signo, siginfo_t *si, void *context UNUSED_PAR #endif mk_err("%s (%d), code=%d, addr=%p", strsignal(signo), signo, si->si_code, si->si_addr); - - struct sched_list_node *sched; - sched = mk_sched_get_thread_conf(); - printf("sched=%p\n", sched); //close(sched->server_fd); - pthread_exit(NULL); - //abort(); + //pthread_exit(NULL); + abort(); default: /* let the kernel handle it */ kill(getpid(), signo); diff --git a/src/mk_string.c b/src/mk_string.c index 2b5b8fda6..ed15df612 100644 --- a/src/mk_string.c +++ b/src/mk_string.c @@ -327,30 +327,64 @@ int mk_string_trim(char **str) return 0; } -int mk_string_itop(int value, mk_ptr_t *p) -{ - char aux; - char *wstr = p->data; - char *begin, *end; - unsigned int uvalue = (value < 0) ? -value : value; - - do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10); - if (value < 0) *wstr++ = '-'; - *wstr='\0'; +uint32_t digits10(uint64_t v) { + if (v < 10) return 1; + if (v < 100) return 2; + if (v < 1000) return 3; + if (v < 1000000000000UL) { + if (v < 100000000UL) { + if (v < 1000000) { + if (v < 10000) return 4; + return 5 + (v >= 100000); + } + return 7 + (v >= 10000000UL); + } + if (v < 10000000000UL) { + return 9 + (v >= 1000000000UL); + } + return 11 + (v >= 100000000000UL); + } + return 12 + digits10(v / 1000000000000UL); +} - begin = p->data; - end = wstr - 1; +int mk_string_itop(uint64_t value, mk_ptr_t *p) +{ + static const char digits[201] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + + uint32_t const length = digits10(value); + uint32_t next = length - 1; + char *dst = p->data; + + while (value >= 100) { + int const i = (value % 100) * 2; + value /= 100; + dst[next] = digits[i + 1]; + dst[next - 1] = digits[i]; + next -= 2; + } - while (end > begin) { - aux = *end, *end-- = *begin, *begin++ = aux; + /* Handle last 1-2 digits */ + if (value < 10) { + dst[next] = '0' + (uint32_t) value; + } + else { + int i = (uint32_t) value * 2; + dst[next] = digits[i + 1]; + dst[next - 1] = digits[i]; } - *wstr++ = '\r'; - *wstr++ = '\n'; - *wstr++ = '\0'; + dst = p->data + length; + *dst++ = '\r'; + *dst++ = '\n'; + *dst++ = '\0'; - p->len = (wstr - p->data - 1); - return 0; + p->len = (dst - p->data - 1); + return p->len; } /* Return a buffer with a new string from string */