提交 9d9be0e0 编写于 作者: A antirez

Initial implementation of redis-cli --latency-dist.

上级 d4047f72
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <assert.h> #include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <math.h>
#include "hiredis.h" #include "hiredis.h"
#include "sds.h" #include "sds.h"
...@@ -74,6 +75,7 @@ static struct config { ...@@ -74,6 +75,7 @@ static struct config {
int monitor_mode; int monitor_mode;
int pubsub_mode; int pubsub_mode;
int latency_mode; int latency_mode;
int latency_dist_mode;
int latency_history; int latency_history;
int cluster_mode; int cluster_mode;
int cluster_reissue_command; int cluster_reissue_command;
...@@ -741,6 +743,8 @@ static int parseOptions(int argc, char **argv) { ...@@ -741,6 +743,8 @@ static int parseOptions(int argc, char **argv) {
config.output = OUTPUT_CSV; config.output = OUTPUT_CSV;
} else if (!strcmp(argv[i],"--latency")) { } else if (!strcmp(argv[i],"--latency")) {
config.latency_mode = 1; config.latency_mode = 1;
} else if (!strcmp(argv[i],"--latency-dist")) {
config.latency_dist_mode = 1;
} else if (!strcmp(argv[i],"--latency-history")) { } else if (!strcmp(argv[i],"--latency-history")) {
config.latency_mode = 1; config.latency_mode = 1;
config.latency_history = 1; config.latency_history = 1;
...@@ -833,6 +837,8 @@ static void usage(void) { ...@@ -833,6 +837,8 @@ static void usage(void) {
" --latency Enter a special mode continuously sampling latency.\n" " --latency Enter a special mode continuously sampling latency.\n"
" --latency-history Like --latency but tracking latency changes over time.\n" " --latency-history Like --latency but tracking latency changes over time.\n"
" Default time interval is 15 sec. Change it using -i.\n" " 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"
" --slave Simulate a slave showing commands received from the master.\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" " --rdb <filename> Transfer an RDB dump from remote server to local file.\n"
" --pipe Transfer raw Redis protocol from stdin to server.\n" " --pipe Transfer raw Redis protocol from stdin to server.\n"
...@@ -1071,6 +1077,146 @@ static void latencyMode(void) { ...@@ -1071,6 +1077,146 @@ static void latencyMode(void) {
} }
} }
/*------------------------------------------------------------------------------
* Latency distribution mode -- requires 256 colors xterm
*--------------------------------------------------------------------------- */
#define LATENCY_DIST_DEFAULT_INTERVAL 1000 /* milliseconds. */
#define LATENCY_DIST_MIN_GRAY 233 /* Less than that is too hard to see gray. */
#define LATENCY_DIST_MAX_GRAY 255
#define LATENCY_DIST_GRAYS (LATENCY_DIST_MAX_GRAY-LATENCY_DIST_MIN_GRAY+1)
/* Structure to store samples distribution. */
struct distsamples {
long long max; /* Max latency to fit into this interval (usec). */
long long count; /* Number of samples in this interval. */
int character; /* Associated character in visualization. */
};
/* Helper function for latencyDistMode(). Performs the spectrum visualization
* of the collected samples targeting an xterm 256 terminal.
*
* Takes an array of distsamples structures, ordered from smaller to bigger
* 'max' value. Last sample max must be 0, to mean that it olds all the
* samples greater than the previous one, and is also the stop sentinel.
*
* "tot' is the total number of samples in the different buckets, so it
* is the SUM(samples[i].conut) for i to 0 up to the max sample.
*
* As a side effect the function sets all the buckets count to 0. */
void showLatencyDistSamples(struct distsamples *samples, long long tot) {
int j;
/* We convert samples into a number between 0 and DIST_GRAYS,
* proportional to the percentage a given bucket represents.
* This way intensity of the different parts of the spectrum
* don't change relative to the number of requests, which avoids to
* pollute the visualization with non-latency related info. */
printf("\033[38;5;0m"); /* Set foreground color to black. */
for (j = 0; ; j++) {
float color = (float) samples[j].count / tot * LATENCY_DIST_GRAYS;
color = ceil(color) + (LATENCY_DIST_MIN_GRAY-1);
if (color == LATENCY_DIST_MIN_GRAY-1) {
printf("\033[48;5;0m ");
} else {
printf("\033[48;5;%dm%c", (int)color, samples[j].character);
}
samples[j].count = 0;
if (samples[j].max == 0) break; /* Last sample. */
}
printf("\033[0m\n");
fflush(stdout);
}
/* Show the legend: different buckets values and colors meaning, so
* that the spectrum is more easily readable. */
void showLatencyDistLegend(void) {
printf(". - * 0.01 0.125 0.5 milliseconds\n");
printf("1,2,3,...,9 from 1 to 9 milliseconds\n");
printf("A,B,C,D,E 10,20,30,40,50 milliseconds\n");
printf("F,G,H,I,J .1,.2,.3,.4,.5 seconds\n");
printf("K,L,M,N,O,P,Q,? 1,2,4,8,16,30,60,>60 seconds\n");
printf("---------------------------------------------\n");
}
static void latencyDistMode(void) {
redisReply *reply;
long long start, latency, count = 0;
long long history_interval =
config.interval ? config.interval/1000 :
LATENCY_DIST_DEFAULT_INTERVAL;
long long history_start = ustime();
int j, outputs = 0;
struct distsamples samples[] = {
/* We use a mostly logarithmic scale, with certain linear intervals
* which are more interesting than others, like 1-10 milliseconds
* range. */
{10,0,'.'}, /* 0.01 ms */
{125,0,'-'}, /* 0.125 ms */
{250,0,'*'}, /* 0.25 ms */
{500,0,'#'}, /* 0.5 ms */
{1000,0,'1'}, /* 1 ms */
{2000,0,'2'}, /* 2 ms */
{3000,0,'3'}, /* 3 ms */
{4000,0,'4'}, /* 4 ms */
{5000,0,'5'}, /* 5 ms */
{6000,0,'6'}, /* 6 ms */
{7000,0,'7'}, /* 7 ms */
{8000,0,'8'}, /* 8 ms */
{9000,0,'9'}, /* 9 ms */
{10000,0,'A'}, /* 10 ms */
{20000,0,'B'}, /* 20 ms */
{30000,0,'C'}, /* 30 ms */
{40000,0,'D'}, /* 40 ms */
{50000,0,'E'}, /* 50 ms */
{100000,0,'F'}, /* 0.1 s */
{200000,0,'G'}, /* 0.2 s */
{300000,0,'H'}, /* 0.3 s */
{400000,0,'I'}, /* 0.4 s */
{500000,0,'J'}, /* 0.5 s */
{1000000,0,'K'}, /* 1 s */
{2000000,0,'L'}, /* 2 s */
{4000000,0,'M'}, /* 4 s */
{8000000,0,'N'}, /* 8 s */
{16000000,0,'O'}, /* 16 s */
{30000000,0,'P'}, /* 30 s */
{60000000,0,'Q'}, /* 1 minute */
{0,0,'?'}, /* > 1 minute */
};
if (!context) exit(1);
while(1) {
start = ustime();
reply = redisCommand(context,"PING");
if (reply == NULL) {
fprintf(stderr,"\nI/O error\n");
exit(1);
}
latency = ustime()-start;
freeReplyObject(reply);
count++;
/* Populate the relevant bucket. */
for (j = 0; ; j++) {
if (samples[j].max == 0 || latency <= samples[j].max) {
samples[j].count++;
break;
}
}
/* From time to time show the spectrum. */
if (count && (ustime()-history_start)/1000 > history_interval) {
if ((outputs++ % 20) == 0)
showLatencyDistLegend();
showLatencyDistSamples(samples,count);
history_start = ustime();
count = 0;
}
usleep(LATENCY_SAMPLE_RATE * 1000);
}
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Slave mode * Slave mode
*--------------------------------------------------------------------------- */ *--------------------------------------------------------------------------- */
...@@ -1887,6 +2033,7 @@ int main(int argc, char **argv) { ...@@ -1887,6 +2033,7 @@ int main(int argc, char **argv) {
config.monitor_mode = 0; config.monitor_mode = 0;
config.pubsub_mode = 0; config.pubsub_mode = 0;
config.latency_mode = 0; config.latency_mode = 0;
config.latency_dist_mode = 0;
config.latency_history = 0; config.latency_history = 0;
config.cluster_mode = 0; config.cluster_mode = 0;
config.slave_mode = 0; config.slave_mode = 0;
...@@ -1921,6 +2068,12 @@ int main(int argc, char **argv) { ...@@ -1921,6 +2068,12 @@ int main(int argc, char **argv) {
latencyMode(); latencyMode();
} }
/* Latency distribution mode */
if (config.latency_dist_mode) {
if (cliConnect(0) == REDIS_ERR) exit(1);
latencyDistMode();
}
/* Slave mode */ /* Slave mode */
if (config.slave_mode) { if (config.slave_mode) {
if (cliConnect(0) == REDIS_ERR) exit(1); if (cliConnect(0) == REDIS_ERR) exit(1);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册