X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/66d8818cb751ab23e70e82fc5ab1017399f49109..ecd82f59fe5296de2733154bfcf1a4b95d4547aa:/src/redis-benchmark.c?ds=inline diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index b22322f4..d95bfd8e 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -62,6 +62,7 @@ static struct config { int randomkeys; int randomkeys_keyspacelen; int keepalive; + int pipeline; long long start; long long totlatency; long long *latency; @@ -77,11 +78,12 @@ static struct config { typedef struct _client { redisContext *context; sds obuf; - char *randptr[10]; /* needed for MSET against 10 keys */ + char *randptr[32]; /* needed for MSET against 10 keys */ size_t randlen; unsigned int written; /* bytes of 'obuf' already written */ long long start; /* start time of a request */ long long latency; /* request latency */ + int pending; /* Number of pending requests (sent but no reply received) */ } *client; /* Prototypes */ @@ -137,6 +139,7 @@ static void resetClient(client c) { aeDeleteFileEvent(config.el,c->context->fd,AE_READABLE); aeCreateFileEvent(config.el,c->context->fd,AE_WRITABLE,writeHandler,c); c->written = 0; + c->pending = config.pipeline; } static void randomizeClientKey(client c) { @@ -182,19 +185,29 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) { fprintf(stderr,"Error: %s\n",c->context->errstr); exit(1); } else { - if (redisGetReply(c->context,&reply) != REDIS_OK) { - fprintf(stderr,"Error: %s\n",c->context->errstr); - exit(1); - } - if (reply != NULL) { - if (reply == (void*)REDIS_REPLY_ERROR) { - fprintf(stderr,"Unexpected error reply, exiting...\n"); + while(c->pending) { + if (redisGetReply(c->context,&reply) != REDIS_OK) { + fprintf(stderr,"Error: %s\n",c->context->errstr); exit(1); } - - if (config.requests_finished < config.requests) - config.latency[config.requests_finished++] = c->latency; - clientDone(c); + if (reply != NULL) { + if (reply == (void*)REDIS_REPLY_ERROR) { + fprintf(stderr,"Unexpected error reply, exiting...\n"); + exit(1); + } + + freeReplyObject(reply); + + if (config.requests_finished < config.requests) + config.latency[config.requests_finished++] = c->latency; + c->pending--; + if (c->pending == 0) { + clientDone(c); + break; + } + } else { + break; + } } } } @@ -236,8 +249,10 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) { } } -static client createClient(const char *cmd, size_t len) { +static client createClient(char *cmd, size_t len) { + int j; client c = zmalloc(sizeof(struct _client)); + if (config.hostsocket == NULL) { c->context = redisConnectNonBlock(config.hostip,config.hostport); } else { @@ -251,23 +266,27 @@ static client createClient(const char *cmd, size_t len) { fprintf(stderr,"%s: %s\n",config.hostsocket,c->context->errstr); exit(1); } - c->obuf = sdsnewlen(cmd,len); + /* Suppress hiredis cleanup of unused buffers for max speed. */ + c->context->reader->maxbuf = 0; + /* Queue N requests accordingly to the pipeline size. */ + c->obuf = sdsempty(); + for (j = 0; j < config.pipeline; j++) + c->obuf = sdscatlen(c->obuf,cmd,len); c->randlen = 0; c->written = 0; + c->pending = config.pipeline; /* Find substrings in the output buffer that need to be randomized. */ if (config.randomkeys) { - char *p = c->obuf, *newline; + char *p = c->obuf; while ((p = strstr(p,":rand:")) != NULL) { - newline = strstr(p,"\r\n"); - assert(newline-(p+6) == 12); /* 12 chars for randomness */ assert(c->randlen < (signed)(sizeof(c->randptr)/sizeof(char*))); c->randptr[c->randlen++] = p+6; - p = newline+2; + p += 6; } } - redisSetReplyObjectFunctions(c->context,NULL); +/* redisSetReplyObjectFunctions(c->context,NULL); */ aeCreateFileEvent(config.el,c->context->fd,AE_WRITABLE,writeHandler,c); listAddNodeTail(config.clients,c); config.liveclients++; @@ -278,7 +297,7 @@ static void createMissingClients(client c) { int n = 0; while(config.liveclients < config.numclients) { - createClient(c->obuf,sdslen(c->obuf)); + createClient(c->obuf,sdslen(c->obuf)/config.pipeline); /* Listen backlog is quite limited on most systems */ if (++n > 64) { @@ -322,7 +341,7 @@ static void showLatencyReport(void) { } } -static void benchmark(const char *title, const char *cmd, int len) { +static void benchmark(char *title, char *cmd, int len) { client c; config.title = title; @@ -372,6 +391,10 @@ int parseOptions(int argc, const char **argv) { config.datasize = atoi(argv[++i]); if (config.datasize < 1) config.datasize=1; if (config.datasize > 1024*1024*1024) config.datasize = 1024*1024*1024; + } else if (!strcmp(argv[i],"-P")) { + if (lastarg) goto invalid; + config.pipeline = atoi(argv[++i]); + if (config.pipeline <= 0) config.pipeline=1; } else if (!strcmp(argv[i],"-r")) { if (lastarg) goto invalid; config.randomkeys = 1; @@ -426,11 +449,12 @@ usage: " -k 1=keep alive 0=reconnect (default 1)\n" " -r Use random keys for SET/GET/INCR, random values for SADD\n" " Using this option the benchmark will get/set keys\n" -" in the form mykey_rand000000012456 instead of constant\n" +" in the form mykey_rand:000000012456 instead of constant\n" " keys, the argument determines the max\n" " number of values for the random number. For instance\n" -" if set to 10 only rand000000000000 - rand000000000009\n" +" if set to 10 only rand:000000000000 - rand:000000000009\n" " range will be allowed.\n" +" -P Pipeline requests. Default 1 (no pipeline).\n" " -q Quiet. Just show query/sec values\n" " --csv Output in CSV format\n" " -l Loop. Run the tests forever\n" @@ -446,6 +470,8 @@ usage: " $ redis-benchmark -t set -n 1000000 -r 100000000\n\n" " Benchmark 127.0.0.1:6379 for a few commands producing CSV output:\n" " $ redis-benchmark -t ping,set,get -n 100000 --csv\n\n" +" Fill a list with 10000 random elements:\n" +" $ redis-benchmark -r 10000 -n 10000 lpush mylist ele:rand:000000000000\n\n" ); exit(exit_status); } @@ -490,10 +516,11 @@ int main(int argc, const char **argv) { config.numclients = 50; config.requests = 10000; config.liveclients = 0; - config.el = aeCreateEventLoop(); + config.el = aeCreateEventLoop(1024*10); aeCreateTimeEvent(config.el,1,showThroughput,NULL,NULL); config.keepalive = 1; config.datasize = 3; + config.pipeline = 1; config.randomkeys = 0; config.randomkeys_keyspacelen = 0; config.quiet = 0;