X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/2fd309522d22ea518a496cf203e77505ec35aaf1..a51dcb8b7f63637f83e48f55c327e46ae6ac9269:/benchmark.c diff --git a/benchmark.c b/benchmark.c index 29fc7f32..fd949ea3 100644 --- a/benchmark.c +++ b/benchmark.c @@ -48,7 +48,7 @@ #define REPLY_INT 0 #define REPLY_RETCODE 1 #define REPLY_BULK 2 -#define REPLY_MBULK 2 +#define REPLY_MBULK 3 #define CLIENT_CONNECTING 0 #define CLIENT_SENDQUERY 1 @@ -59,6 +59,7 @@ #define REDIS_NOTUSED(V) ((void) V) static struct config { + int debug; int numclients; int requests; int liveclients; @@ -77,6 +78,7 @@ static struct config { list *clients; int quiet; int loop; + int idlemode; } config; typedef struct _client { @@ -86,6 +88,7 @@ typedef struct _client { sds ibuf; int mbulk; /* Number of elements in an mbulk reply */ int readlen; /* readlen == -1 means read a single line */ + int totreceived; unsigned int written; /* bytes of 'obuf' already written */ int replytype; long long start; /* start time in milliseconds */ @@ -134,12 +137,14 @@ static void freeAllClients(void) { static void resetClient(client c) { aeDeleteFileEvent(config.el,c->fd,AE_WRITABLE); aeDeleteFileEvent(config.el,c->fd,AE_READABLE); - aeCreateFileEvent(config.el,c->fd, AE_WRITABLE,writeHandler,c,NULL); + aeCreateFileEvent(config.el,c->fd, AE_WRITABLE,writeHandler,c); sdsfree(c->ibuf); c->ibuf = sdsempty(); - c->readlen = (c->replytype == REPLY_BULK) ? -1 : 0; + c->readlen = (c->replytype == REPLY_BULK || + c->replytype == REPLY_MBULK) ? -1 : 0; c->mbulk = -1; c->written = 0; + c->totreceived = 0; c->state = CLIENT_SENDQUERY; c->start = mstime(); createMissingClients(c); @@ -173,12 +178,18 @@ static void prepareClientForReply(client c, int type) { } static void clientDone(client c) { + static int last_tot_received = 1; + long long latency; config.donerequests ++; latency = mstime() - c->start; if (latency > MAX_LATENCY) latency = MAX_LATENCY; config.latency[latency]++; + if (config.debug && last_tot_received != c->totreceived) { + printf("Tot bytes received: %d\n", c->totreceived); + last_tot_received = c->totreceived; + } if (config.donerequests == config.requests) { freeClient(c); aeStop(config.el); @@ -215,9 +226,12 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) freeClient(c); return; } + c->totreceived += nread; c->ibuf = sdscatlen(c->ibuf,buf,nread); processdata: + /* Are we waiting for the first line of the command of for sdf + * count in bulk or multi bulk operations? */ if (c->replytype == REPLY_INT || c->replytype == REPLY_RETCODE || (c->replytype == REPLY_BULK && c->readlen == -1) || @@ -225,13 +239,18 @@ processdata: (c->replytype == REPLY_MBULK && c->mbulk == -1)) { char *p; + /* Check if the first line is complete. This is only true if + * there is a newline inside the buffer. */ if ((p = strchr(c->ibuf,'\n')) != NULL) { if (c->replytype == REPLY_BULK || (c->replytype == REPLY_MBULK && c->mbulk != -1)) { + /* Read the count of a bulk reply (being it a single bulk or + * a multi bulk reply). "$" for the protocol spec. */ *p = '\0'; *(p-1) = '\0'; c->readlen = atoi(c->ibuf+1)+2; + // printf("BULK ATOI: %s\n", c->ibuf+1); /* Handle null bulk reply "$-1" */ if (c->readlen-2 == -1) { clientDone(c); @@ -239,7 +258,11 @@ processdata: } /* Leave all the rest in the input buffer */ c->ibuf = sdsrange(c->ibuf,(p-c->ibuf)+1,-1); + /* fall through to reach the point where the code will try + * to check if the bulk reply is complete. */ } else if (c->replytype == REPLY_MBULK && c->mbulk == -1) { + /* Read the count of a multi bulk reply. That is, how many + * bulk replies we have to read next. "*" protocol. */ *p = '\0'; *(p-1) = '\0'; c->mbulk = atoi(c->ibuf+1); @@ -248,6 +271,7 @@ processdata: clientDone(c); return; } + // printf("%p) %d elements list\n", c, c->mbulk); /* Leave all the rest in the input buffer */ c->ibuf = sdsrange(c->ibuf,(p-c->ibuf)+1,-1); goto processdata; @@ -259,12 +283,18 @@ processdata: } } /* bulk read, did we read everything? */ - if ((c->replytype == REPLY_BULK || c->replytype == REPLY_MBULK) && - (unsigned)c->readlen <= sdslen(c->ibuf)) + if (((c->replytype == REPLY_MBULK && c->mbulk != -1) || + (c->replytype == REPLY_BULK)) && c->readlen != -1 && + (unsigned)c->readlen <= sdslen(c->ibuf)) { + // printf("BULKSTATUS mbulk:%d readlen:%d sdslen:%d\n", + // c->mbulk,c->readlen,sdslen(c->ibuf)); if (c->replytype == REPLY_BULK) { clientDone(c); } else if (c->replytype == REPLY_MBULK) { + // printf("%p) %d (%d)) ",c, c->mbulk, c->readlen); + // fwrite(c->ibuf,c->readlen,1,stdout); + // printf("\n"); if (--c->mbulk == 0) { clientDone(c); } else { @@ -299,7 +329,7 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) c->written += nwritten; if (sdslen(c->obuf) == c->written) { aeDeleteFileEvent(config.el,c->fd,AE_WRITABLE); - aeCreateFileEvent(config.el,c->fd,AE_READABLE,readHandler,c,NULL); + aeCreateFileEvent(config.el,c->fd,AE_READABLE,readHandler,c); c->state = CLIENT_READREPLY; } } @@ -321,8 +351,9 @@ static client createClient(void) { c->mbulk = -1; c->readlen = 0; c->written = 0; + c->totreceived = 0; c->state = CLIENT_CONNECTING; - aeCreateFileEvent(config.el, c->fd, AE_WRITABLE, writeHandler, c, NULL); + aeCreateFileEvent(config.el, c->fd, AE_WRITABLE, writeHandler, c); config.liveclients++; listAddNodeTail(config.clients,c); return c; @@ -335,9 +366,7 @@ static void createMissingClients(client c) { sdsfree(new->obuf); new->obuf = sdsdup(c->obuf); if (config.randomkeys) randomizeClientKey(c); - new->replytype = c->replytype; - if (c->replytype == REPLY_BULK) - new->readlen = -1; + prepareClientForReply(new,c->replytype); } } @@ -421,6 +450,10 @@ void parseOptions(int argc, char **argv) { config.quiet = 1; } else if (!strcmp(argv[i],"-l")) { config.loop = 1; + } else if (!strcmp(argv[i],"-D")) { + config.debug = 1; + } else if (!strcmp(argv[i],"-I")) { + config.idlemode = 1; } else { printf("Wrong option '%s' or option argument missing\n\n",argv[i]); printf("Usage: redis-benchmark [-h ] [-p ] [-c ] [-n [-k ]\n\n"); @@ -439,6 +472,8 @@ void parseOptions(int argc, char **argv) { printf(" range will be allowed.\n"); printf(" -q Quiet. Just show query/sec values\n"); printf(" -l Loop. Run the tests forever\n"); + printf(" -I Idle mode. Just open N idle connections and wait.\n"); + printf(" -D Debug mode. more verbose.\n"); exit(1); } } @@ -450,6 +485,7 @@ int main(int argc, char **argv) { signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); + config.debug = 0; config.numclients = 50; config.requests = 10000; config.liveclients = 0; @@ -461,6 +497,7 @@ int main(int argc, char **argv) { config.randomkeys_keyspacelen = 0; config.quiet = 0; config.loop = 0; + config.idlemode = 0; config.latency = NULL; config.clients = listCreate(); config.latency = zmalloc(sizeof(int)*(MAX_LATENCY+1)); @@ -474,6 +511,18 @@ int main(int argc, char **argv) { printf("WARNING: keepalive disabled, you probably need 'echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse' for Linux and 'sudo sysctl -w net.inet.tcp.msl=1000' for Mac OS X in order to use a lot of clients/requests\n"); } + if (config.idlemode) { + printf("Creating %d idle connections and waiting forever (Ctrl+C when done)\n", config.numclients); + prepareForBenchmark(); + c = createClient(); + if (!c) exit(1); + c->obuf = sdsempty(); + prepareClientForReply(c,REPLY_RETCODE); /* will never receive it */ + createMissingClients(c); + aeMain(config.el); + /* and will wait for every */ + } + do { prepareForBenchmark(); c = createClient(); @@ -554,6 +603,33 @@ int main(int argc, char **argv) { aeMain(config.el); endBenchmark("LRANGE (first 100 elements)"); + prepareForBenchmark(); + c = createClient(); + if (!c) exit(1); + c->obuf = sdscat(c->obuf,"LRANGE mylist 0 299\r\n"); + prepareClientForReply(c,REPLY_MBULK); + createMissingClients(c); + aeMain(config.el); + endBenchmark("LRANGE (first 300 elements)"); + + prepareForBenchmark(); + c = createClient(); + if (!c) exit(1); + c->obuf = sdscat(c->obuf,"LRANGE mylist 0 449\r\n"); + prepareClientForReply(c,REPLY_MBULK); + createMissingClients(c); + aeMain(config.el); + endBenchmark("LRANGE (first 450 elements)"); + + prepareForBenchmark(); + c = createClient(); + if (!c) exit(1); + c->obuf = sdscat(c->obuf,"LRANGE mylist 0 599\r\n"); + prepareClientForReply(c,REPLY_MBULK); + createMissingClients(c); + aeMain(config.el); + endBenchmark("LRANGE (first 600 elements)"); + printf("\n"); } while(config.loop);