/
static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
client c = privdata;
void *reply = NULL;
REDIS_NOTUSED(el);
REDIS_NOTUSED(fd);
REDIS_NOTUSED(mask);
/* Calculate latency only for the first read event. This means that the
* server already sent the reply and we need to parse it. Parsing overhead
* is not part of the latency, so calculate it only once, here. */
//计算延时,然后比较延时,取得第一个read 的event事件
if (c->latency < 0) c->latency = ustime()-(c->start);
if (redisBufferRead(c->context) != REDIS_OK) {
//首先判断能否读
fprintf(stderr,"Error: %s\n",c->context->errstr);
exit(1);
} else {
while(c->pending) {
if (redisGetReply(c->context,&reply) != REDIS_OK) {
fprintf(stderr,"Error: %s\n",c->context->errstr);
exit(1);
}
if (reply != NULL) {
//获取reply回复,如果这里出错,也会直接退出
if (reply == (void*)REDIS_REPLY_ERROR) {
fprintf(stderr,"Unexpected error reply, exiting...\n");
exit(1);
}
freeReplyObject(reply);
if (c->selectlen) {
size_t j;
/* This is the OK from SELECT. Just discard the SELECT
* from the buffer. */
//执行到这里,请求已经执行成功,等待的请求数减1
c->pending--;
sdsrange(c->obuf,c->selectlen,-1);
/* We also need to fix the pointers to the strings
* we need to randomize. */
for (j = 0; j < c->randlen; j++)
c->randptr[j] -= c->selectlen;
c->selectlen = 0;
continue;
}
if (config.requests_finished < config.requests)
config.latency[config.requests_finished++] = c->latency;
c->pending--;
if (c->pending == 0) {
//调用客户端done完成后的方法
clientDone(c);
break;
}
} else {
break;
}
}
}
} 这个方法其实是一个回调方法,会作为参数传入另一个函数中,redis的函数式
编程的思想又再次体现了,在这些操作都执行好了之后,会有个延时报告,针对各种操作的延时统计,这时我们就能知道,性能之间的比较了:
/* 输出请求延时 */
static void showLatencyReport(void) {
int i, curlat = 0;
float perc, reqpersec;
reqpersec = (float)config.requests_finished/((float)config.totlatency/1000);
if (!config.quiet && !config.csv) {
printf("====== %s ======\n", config.title);
printf(" %d requests completed in %.2f seconds\n", config.requests_finished,
(float)config.totlatency/1000);
printf(" %d parallel clients\n", config.numclients);
printf(" %d bytes payload\n", config.datasize);
printf(" keep alive: %d\n", config.keepalive);
printf("\n");
//将请求按延时排序
qsort(config.latency,config.requests,sizeof(long long),compareLatency);
for (i = 0; i < config.requests; i++) {
if (config.latency[i]/1000 != curlat || i == (config.requests-1)) {
curlat = config.latency[i]/1000;
perc = ((float)(i+1)*100)/config.requests;
printf("%.2f%% <= %d milliseconds\n", perc, curlat);
}
}
printf("%.2f requests per second\n\n", reqpersec);
} else if (config.csv) {
printf("\"%s\",\"%.2f\"\n", config.title, reqpersec);
} else {
printf("%s: %.2f requests per second\n", config.title, reqpersec);
}
} 当然你能更改配置文件,做你想做的性能测试,不过这里我想吐槽一点,这么多个if判断语句不是很好吧,换成switch也比这简洁啊:
/* Returns number of consumed options. */
/* 根据读入的参数,设置config配置文件 */
int parseOptions(int argc, const char **argv) {
int i;
int lastarg;
int exit_status = 1;
for (i = 1; i < argc; i++) {
lastarg = (i == (argc-1));
//通过多重if判断,但个人感觉不够优美,稳定性略差
if (!strcmp(argv[i],"-c")) {
if (lastarg) goto invalid;
config.numclients = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-n")) {
if (lastarg) goto invalid;
config.requests = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-k")) {
if (lastarg) goto invalid;
config.keepalive = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-h")) {
if (lastarg) goto invalid;
config.hostip = strdup(argv[++i]);
} else if (!strcmp(argv[i],"-p")) {
if (lastarg) goto invalid;
config.hostport = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-s")) {
if (lastarg) goto invalid;
config.hostsocket = strdup(argv[++i]);
} else if (!strcmp(argv[i],"-a") ) {
if (lastarg) goto invalid;
config.auth = strdup(argv[++i]);
} else if (!strcmp(argv[i],"-d")) {
if (lastarg) goto invalid;
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]);
//......省略 redis的性能测试还能支持本地测试和指定Ip,端口测试,挺方便的。下面列出全部的API:
/* Prototypes */
/* 方法原型 */
static void createMissingClients(client c); /* 创建没有Command命令要求的clint */
static long long ustime(void) /* 返回当期时间的单位为微秒的格式 */
static long long mstime(void) /* 返回当期时间的单位为毫秒的格式 */
static void freeClient(client c) /* 释放Client */
static void freeAllClients(void) /* 释放所有的Client */
static void resetClient(client c) /* 重置Client */
static void randomizeClientKey(client c) /* 随机填充client里的randptr中的key值 */
static void clientDone(client c) /* Client完成后的调用方法 */
static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) /* 读事件的处理方法 */
static void writeHandler(aeEv