Skip to content

Commit

Permalink
String: performance improvement converting uint64_t to string (4x)
Browse files Browse the repository at this point in the history
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 <eduardo@monkey.io>
  • Loading branch information
edsiper committed Aug 2, 2014
1 parent 41d018e commit 4b6145c
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 30 deletions.
2 changes: 1 addition & 1 deletion include/monkey/mk_plugin.h
Expand Up @@ -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);
Expand Down
9 changes: 5 additions & 4 deletions include/monkey/mk_string.h
Expand Up @@ -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 <stdint.h>
#include <monkey/mk_memory.h>
#include <monkey/mk_list.h>
#include <monkey/mk_macros.h>

/* Case sensitive OFF */
#define MK_STR_SENSITIVE 0
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 2 additions & 6 deletions src/mk_signals.c
Expand Up @@ -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);
Expand Down
72 changes: 53 additions & 19 deletions src/mk_string.c
Expand Up @@ -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 */
Expand Down

0 comments on commit 4b6145c

Please sign in to comment.