X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/57172ffb316b5e681c4f515927894f5129739237..ccb5332c5e6644a56b2af1ba3248f882d4f1bb60:/benchmark.c diff --git a/benchmark.c b/benchmark.c index bdf324bb..bf8e2834 100644 --- a/benchmark.c +++ b/benchmark.c @@ -28,6 +28,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "fmacros.h" + #include #include #include @@ -46,6 +48,7 @@ #define REPLY_INT 0 #define REPLY_RETCODE 1 #define REPLY_BULK 2 +#define REPLY_MBULK 3 #define CLIENT_CONNECTING 0 #define CLIENT_SENDQUERY 1 @@ -63,6 +66,7 @@ static struct config { int keysize; int datasize; int randomkeys; + int randomkeys_keyspacelen; aeEventLoop *el; char *hostip; int hostport; @@ -80,6 +84,7 @@ typedef struct _client { int fd; sds obuf; sds ibuf; + int mbulk; /* Number of elements in an mbulk reply */ int readlen; /* readlen == -1 means read a single line */ unsigned int written; /* bytes of 'obuf' already written */ int replytype; @@ -133,9 +138,38 @@ static void resetClient(client c) { sdsfree(c->ibuf); c->ibuf = sdsempty(); c->readlen = (c->replytype == REPLY_BULK) ? -1 : 0; + c->mbulk = -1; c->written = 0; c->state = CLIENT_SENDQUERY; c->start = mstime(); + createMissingClients(c); +} + +static void randomizeClientKey(client c) { + char *p; + char buf[32]; + long r; + + p = strstr(c->obuf, "_rand"); + if (!p) return; + p += 5; + r = random() % config.randomkeys_keyspacelen; + sprintf(buf,"%ld",r); + memcpy(p,buf,strlen(buf)); +} + +static void prepareClientForReply(client c, int type) { + if (type == REPLY_BULK) { + c->replytype = REPLY_BULK; + c->readlen = -1; + } else if (type == REPLY_MBULK) { + c->replytype = REPLY_MBULK; + c->readlen = -1; + c->mbulk = -1; + } else { + c->replytype = type; + c->readlen = 0; + } } static void clientDone(client c) { @@ -152,6 +186,7 @@ static void clientDone(client c) { } if (config.keepalive) { resetClient(c); + if (config.randomkeys) randomizeClientKey(c); } else { config.liveclients--; createMissingClients(c); @@ -182,21 +217,50 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) } 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)) { + (c->replytype == REPLY_BULK && c->readlen == -1) || + (c->replytype == REPLY_MBULK && c->readlen == -1) || + (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) { + 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; - if (c->readlen == -1) { + /* Handle null bulk reply "$-1" */ + if (c->readlen-2 == -1) { + clientDone(c); + return; + } + /* 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); + /* Handle null bulk reply "*-1" */ + if (c->mbulk == -1) { clientDone(c); return; } + /* Leave all the rest in the input buffer */ c->ibuf = sdsrange(c->ibuf,(p-c->ibuf)+1,-1); + goto processdata; } else { c->ibuf = sdstrim(c->ibuf,"\r\n"); clientDone(c); @@ -204,9 +268,23 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) } } } - /* bulk read */ - if ((unsigned)c->readlen == sdslen(c->ibuf)) - clientDone(c); + /* bulk read, did we read everything? */ + if (((c->replytype == REPLY_MBULK && c->mbulk != -1) || + (c->replytype == REPLY_BULK)) && c->readlen != -1 && + (unsigned)c->readlen <= sdslen(c->ibuf)) + { + if (c->replytype == REPLY_BULK) { + clientDone(c); + } else if (c->replytype == REPLY_MBULK) { + if (--c->mbulk == 0) { + clientDone(c); + } else { + c->ibuf = sdsrange(c->ibuf,c->readlen,-1); + c->readlen = -1; + goto processdata; + } + } + } } static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) @@ -251,6 +329,7 @@ static client createClient(void) { anetTcpNoDelay(NULL,c->fd); c->obuf = sdsempty(); c->ibuf = sdsempty(); + c->mbulk = -1; c->readlen = 0; c->written = 0; c->state = CLIENT_CONNECTING; @@ -266,6 +345,7 @@ static void createMissingClients(client c) { if (!new) continue; 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; @@ -342,8 +422,12 @@ void parseOptions(int argc, char **argv) { i++; if (config.datasize < 1) config.datasize=1; if (config.datasize > 1024*1024) config.datasize = 1024*1024; - } else if (!strcmp(argv[i],"-r")) { + } else if (!strcmp(argv[i],"-r") && !lastarg) { config.randomkeys = 1; + config.randomkeys_keyspacelen = atoi(argv[i+1]); + if (config.randomkeys_keyspacelen < 0) + config.randomkeys_keyspacelen = 0; + i++; } else if (!strcmp(argv[i],"-q")) { config.quiet = 1; } else if (!strcmp(argv[i],"-l")) { @@ -357,7 +441,13 @@ void parseOptions(int argc, char **argv) { printf(" -n Total number of requests (default 10000)\n"); printf(" -d Data size of SET/GET value in bytes (default 2)\n"); printf(" -k 1=keep alive 0=reconnect (default 1)\n"); - printf(" -r Use random keys for SET/GET/INCR\n"); + printf(" -r Use random keys for SET/GET/INCR\n"); + printf(" Using this option the benchmark will get/set keys\n"); + printf(" in the form mykey_rand000000012456 instead of constant\n"); + printf(" keys, the argument determines the max\n"); + printf(" number of values for the random number. For instance\n"); + printf(" if set to 10 only rand000000000000 - rand000000000009\n"); + printf(" range will be allowed.\n"); printf(" -q Quiet. Just show query/sec values\n"); printf(" -l Loop. Run the tests forever\n"); exit(1); @@ -379,6 +469,7 @@ int main(int argc, char **argv) { config.donerequests = 0; config.datasize = 3; config.randomkeys = 0; + config.randomkeys_keyspacelen = 0; config.quiet = 0; config.loop = 0; config.latency = NULL; @@ -391,19 +482,10 @@ int main(int argc, char **argv) { parseOptions(argc,argv); if (config.keepalive == 0) { - printf("WARNING: keepalive disabled, you probably need 'echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse' in order to use a lot of clients/requests\n"); + 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"); } do { - prepareForBenchmark(); - c = createClient(); - if (!c) exit(1); - c->obuf = sdscat(c->obuf,"PING\r\n"); - c->replytype = REPLY_RETCODE; - createMissingClients(c); - aeMain(config.el); - endBenchmark("PING"); - prepareForBenchmark(); c = createClient(); if (!c) exit(1); @@ -415,7 +497,7 @@ int main(int argc, char **argv) { data[config.datasize+1] = '\n'; c->obuf = sdscatlen(c->obuf,data,config.datasize+2); } - c->replytype = REPLY_RETCODE; + prepareClientForReply(c,REPLY_RETCODE); createMissingClients(c); aeMain(config.el); endBenchmark("SET"); @@ -424,8 +506,7 @@ int main(int argc, char **argv) { c = createClient(); if (!c) exit(1); c->obuf = sdscat(c->obuf,"GET foo_rand000000000000\r\n"); - c->replytype = REPLY_BULK; - c->readlen = -1; + prepareClientForReply(c,REPLY_BULK); createMissingClients(c); aeMain(config.el); endBenchmark("GET"); @@ -434,7 +515,7 @@ int main(int argc, char **argv) { c = createClient(); if (!c) exit(1); c->obuf = sdscat(c->obuf,"INCR counter_rand000000000000\r\n"); - c->replytype = REPLY_INT; + prepareClientForReply(c,REPLY_INT); createMissingClients(c); aeMain(config.el); endBenchmark("INCR"); @@ -443,7 +524,7 @@ int main(int argc, char **argv) { c = createClient(); if (!c) exit(1); c->obuf = sdscat(c->obuf,"LPUSH mylist 3\r\nbar\r\n"); - c->replytype = REPLY_INT; + prepareClientForReply(c,REPLY_INT); createMissingClients(c); aeMain(config.el); endBenchmark("LPUSH"); @@ -452,12 +533,47 @@ int main(int argc, char **argv) { c = createClient(); if (!c) exit(1); c->obuf = sdscat(c->obuf,"LPOP mylist\r\n"); - c->replytype = REPLY_BULK; - c->readlen = -1; + prepareClientForReply(c,REPLY_BULK); createMissingClients(c); aeMain(config.el); endBenchmark("LPOP"); + prepareForBenchmark(); + c = createClient(); + if (!c) exit(1); + c->obuf = sdscat(c->obuf,"PING\r\n"); + prepareClientForReply(c,REPLY_RETCODE); + createMissingClients(c); + aeMain(config.el); + endBenchmark("PING"); + + prepareForBenchmark(); + c = createClient(); + if (!c) exit(1); + c->obuf = sdscat(c->obuf,"LPUSH mylist 3\r\nbar\r\n"); + prepareClientForReply(c,REPLY_RETCODE); + createMissingClients(c); + aeMain(config.el); + endBenchmark("LPUSH (again, in order to bench LRANGE)"); + + prepareForBenchmark(); + c = createClient(); + if (!c) exit(1); + c->obuf = sdscat(c->obuf,"LRANGE mylist 0 99\r\n"); + prepareClientForReply(c,REPLY_MBULK); + createMissingClients(c); + 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)"); + printf("\n"); } while(config.loop);