diff options
author | antirez <antirez@gmail.com> | 2015-02-09 11:06:44 +0100 |
---|---|---|
committer | antirez <antirez@gmail.com> | 2015-02-10 14:55:17 +0100 |
commit | 9e83d2d26f9e1def7e4c1ffc9dc7f969cc4b8b49 (patch) | |
tree | 6200cd1b07cca4acce49e6465c0979f36a580c2f | |
parent | ccbec34fad509ae773753aa65f5d9d75452c7a90 (diff) | |
download | redis-9e83d2d26f9e1def7e4c1ffc9dc7f969cc4b8b49.tar.gz |
redis-cli --lru-test implemented (cache workload simulator).
-rw-r--r-- | src/redis-cli.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/redis-cli.c b/src/redis-cli.c index be9485756..a80ec319c 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -77,6 +77,8 @@ static struct config { int latency_mode; int latency_dist_mode; int latency_history; + int lru_test_mode; + long long lru_test_sample_size; int cluster_mode; int cluster_reissue_command; int slave_mode; @@ -752,6 +754,9 @@ static int parseOptions(int argc, char **argv) { } else if (!strcmp(argv[i],"--latency-history")) { config.latency_mode = 1; config.latency_history = 1; + } else if (!strcmp(argv[i],"--lru-test") && !lastarg) { + config.lru_test_mode = 1; + config.lru_test_sample_size = strtoll(argv[++i],NULL,10); } else if (!strcmp(argv[i],"--slave")) { config.slave_mode = 1; } else if (!strcmp(argv[i],"--stat")) { @@ -843,6 +848,7 @@ static void usage(void) { " Default time interval is 15 sec. Change it using -i.\n" " --latency-dist Shows latency as a spectrum, requires xterm 256 colors.\n" " Default time interval is 1 sec. Change it using -i.\n" +" --lru-test <keys> Simulate a cache workload with an 80-20 distribution.\n" " --slave Simulate a slave showing commands received from the master.\n" " --rdb <filename> Transfer an RDB dump from remote server to local file.\n" " --pipe Transfer raw Redis protocol from stdin to server.\n" @@ -1956,6 +1962,94 @@ static void scanMode(void) { } /*------------------------------------------------------------------------------ + * LRU test mode + *--------------------------------------------------------------------------- */ + +/* Return an integer from min to max (both inclusive) using a power-law + * distribution, depending on the value of alpha: the greater the alpha + * the more bias towards lower values. + * + * With alpha = 6.2 the output follows the 80-20 rule where 20% of + * the returned numbers will account for 80% of the frequency. */ +long long powerLawRand(long long min, long long max, double alpha) { + double pl, r; + + max += 1; + r = ((double)rand()) / RAND_MAX; + pl = pow( + ((pow(max,alpha+1) - pow(min,alpha+1))*r + pow(min,alpha+1)), + (1.0/(alpha+1))); + return (max-1-(long long)pl)+min; +} + +/* Generates a key name among a set of lru_test_sample_size keys, using + * an 80-20 distribution. */ +void LRUTestGenKey(char *buf, size_t buflen) { + snprintf(buf, buflen, "lru:%lld\n", + powerLawRand(1, config.lru_test_sample_size, 6.2)); +} + +#define LRU_CYCLE_PERIOD 1000 /* 1000 milliseconds. */ +#define LRU_CYCLE_PIPELINE_SIZE 250 +static void LRUTestMode(void) { + redisReply *reply; + char key[128]; + long long start_cycle; + int j; + + srand(time(NULL)^getpid()); + while(1) { + /* Perform cycles of 1 second with 50% writes and 50% reads. + * We use pipelining batching writes / reads N times per cycle in order + * to fill the target instance easily. */ + start_cycle = mstime(); + long long hits = 0, misses = 0; + while(mstime() - start_cycle < 1000) { + /* Write cycle. */ + for (j = 0; j < LRU_CYCLE_PIPELINE_SIZE; j++) { + LRUTestGenKey(key,sizeof(key)); + redisAppendCommand(context, "SET %s val",key); + } + for (j = 0; j < LRU_CYCLE_PIPELINE_SIZE; j++) + redisGetReply(context, (void**)&reply); + + /* Read cycle. */ + for (j = 0; j < LRU_CYCLE_PIPELINE_SIZE; j++) { + LRUTestGenKey(key,sizeof(key)); + redisAppendCommand(context, "GET %s",key); + } + for (j = 0; j < LRU_CYCLE_PIPELINE_SIZE; j++) { + if (redisGetReply(context, (void**)&reply) == REDIS_OK) { + switch(reply->type) { + case REDIS_REPLY_ERROR: + printf("%s\n", reply->str); + break; + case REDIS_REPLY_NIL: + misses++; + break; + default: + hits++; + break; + } + } + } + + if (context->err) { + fprintf(stderr,"I/O error during LRU test\n"); + exit(1); + } + } + /* Print stats. */ + printf( + "%lld Gets/sec | Hits: %lld (%.2f%%) | Misses: %lld (%.2f%%)\n", + hits+misses, + hits, (double)hits/(hits+misses)*100, + misses, (double)misses/(hits+misses)*100); + } + exit(0); +} + +/*------------------------------------------------------------------------------ * Intrisic latency mode. * * Measure max latency of a running process that does not result from @@ -2048,6 +2142,8 @@ int main(int argc, char **argv) { config.latency_mode = 0; config.latency_dist_mode = 0; config.latency_history = 0; + config.lru_test_mode = 0; + config.lru_test_sample_size = 0; config.cluster_mode = 0; config.slave_mode = 0; config.getrdb_mode = 0; @@ -2124,6 +2220,12 @@ int main(int argc, char **argv) { scanMode(); } + /* LRU test mode */ + if (config.lru_test_mode) { + if (cliConnect(0) == REDIS_ERR) exit(1); + LRUTestMode(); + } + /* Intrinsic latency mode */ if (config.intrinsic_latency_mode) intrinsicLatencyMode(); |