detect full load + server threads (diagnostic tool)

Former-commit-id: fd4ed1e425e32b628c5850e83c9ea9411c471bbe
This commit is contained in:
christianEQ 2021-06-18 16:49:25 +00:00
parent ef3ba1699d
commit e6900c37c1

View File

@ -864,6 +864,16 @@ int extractPropertyFromInfo(const char *info, const char *key, double &val) {
return 0; return 0;
} }
int extractPropertyFromInfo(const char *info, const char *key, unsigned int &val) {
char *line = strstr((char*)info, key);
if (line == nullptr) return 1;
line += strlen(key) + 1; // Skip past key name and following colon
char *newline = strchr(line, '\n');
*newline = 0; // Terminate string after relevant line
val = atoi(line);
return 0;
}
double getSelfCpuTime(struct rusage *self_ru) { double getSelfCpuTime(struct rusage *self_ru) {
getrusage(RUSAGE_SELF, self_ru); getrusage(RUSAGE_SELF, self_ru);
double user_time = self_ru->ru_utime.tv_sec + (self_ru->ru_utime.tv_usec / (double)1000000); double user_time = self_ru->ru_utime.tv_sec + (self_ru->ru_utime.tv_usec / (double)1000000);
@ -872,7 +882,7 @@ double getSelfCpuTime(struct rusage *self_ru) {
} }
double getServerCpuTime(redisContext *ctx) { double getServerCpuTime(redisContext *ctx) {
redisReply *reply = (redisReply*)redisCommand(ctx, "INFO"); redisReply *reply = (redisReply*)redisCommand(ctx, "INFO CPU");
if (reply->type != REDIS_REPLY_STRING) { if (reply->type != REDIS_REPLY_STRING) {
freeReplyObject(reply); freeReplyObject(reply);
printf("Error executing INFO command. Exiting.\r\n"); printf("Error executing INFO command. Exiting.\r\n");
@ -892,6 +902,10 @@ double getServerCpuTime(redisContext *ctx) {
return used_cpu_user + used_cpu_sys; return used_cpu_user + used_cpu_sys;
} }
bool isAtFullLoad(double cpuPercent, unsigned int threads) {
return cpuPercent / threads >= 96;
}
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
int i; int i;
@ -926,7 +940,7 @@ int main(int argc, const char **argv) {
} }
const char *set_value = "abcdefghijklmnopqrstuvwxyz"; const char *set_value = "abcdefghijklmnopqrstuvwxyz";
int threads_used = 0; int self_threads = 0;
unsigned int period = 5; unsigned int period = 5;
char command[63]; char command[63];
@ -935,36 +949,66 @@ int main(int argc, const char **argv) {
double server_cpu_time, last_server_cpu_time = getServerCpuTime(ctx); double server_cpu_time, last_server_cpu_time = getServerCpuTime(ctx);
struct rusage self_ru; struct rusage self_ru;
double self_cpu_time, last_self_cpu_time = getSelfCpuTime(&self_ru); double self_cpu_time, last_self_cpu_time = getSelfCpuTime(&self_ru);
double server_cpu_load, last_server_cpu_load, self_cpu_load, server_cpu_gain, last_server_cpu_gain;
redisReply *reply = (redisReply*)redisCommand(ctx, "INFO CPU");
if (reply->type != REDIS_REPLY_STRING) {
freeReplyObject(reply);
printf("Error executing INFO command. Exiting.\r\n");
return 1;
}
unsigned int server_threads;
if (extractPropertyFromInfo(reply->str, "server_threads", server_threads)) {
printf("Error reading server threads from INFO command. Exiting.\r\n");
return 1;
}
freeReplyObject(reply);
printf("Server has %d threads.\n", server_threads);
while (threads_used < config.max_threads) { while (self_threads < config.max_threads) {
printf("Creating %d clients for thread %d...\n", config.numclients, threads_used); printf("Creating %d clients for thread %d...\n", config.numclients, self_threads);
for (int i = 0; i < config.numclients; i++) { for (int i = 0; i < config.numclients; i++) {
sprintf(command, "SET %d %s\r\n", threads_used * config.numclients + i, set_value); sprintf(command, "SET %d %s\r\n", self_threads * config.numclients + i, set_value);
createClient(command, strlen(command), NULL,threads_used); createClient(command, strlen(command), NULL,self_threads);
} }
printf("Starting thread %d\n", threads_used); printf("Starting thread %d\n", self_threads);
benchmarkThread *t = config.threads[threads_used]; benchmarkThread *t = config.threads[self_threads];
if (pthread_create(&(t->thread), NULL, execBenchmarkThread, t)){ if (pthread_create(&(t->thread), NULL, execBenchmarkThread, t)){
fprintf(stderr, "FATAL: Failed to start thread %d.\n", threads_used); fprintf(stderr, "FATAL: Failed to start thread %d.\n", self_threads);
exit(1); exit(1);
} }
threads_used++; self_threads++;
sleep(period); sleep(period);
server_cpu_time = getServerCpuTime(ctx); server_cpu_time = getServerCpuTime(ctx);
self_cpu_time = getSelfCpuTime(&self_ru); self_cpu_time = getSelfCpuTime(&self_ru);
server_cpu_load = (server_cpu_time - last_server_cpu_time) * 100 / period;
self_cpu_load = (self_cpu_time - last_self_cpu_time) * 100 / period;
if (server_cpu_time < 0) { if (server_cpu_time < 0) {
break; break;
} }
printf("CPU Usage Self: %.1f%%, Server: %.1f%%\r\n", printf("CPU Usage Self: %.1f%%, Server: %.1f%%\r\n", self_cpu_load, server_cpu_load);
(self_cpu_time - last_self_cpu_time) * 100 / period, server_cpu_gain = server_cpu_load - last_server_cpu_load;
(server_cpu_time - last_server_cpu_time) * 100 / period);
last_server_cpu_time = server_cpu_time; last_server_cpu_time = server_cpu_time;
last_self_cpu_time = self_cpu_time; last_self_cpu_time = self_cpu_time;
last_server_cpu_load = server_cpu_load;
if (isAtFullLoad(server_cpu_load, server_threads)) {
printf("Server is at full CPU load.\n");
break;
}
if (isAtFullLoad(self_cpu_load, self_threads)) {
printf("Diagnostic tool is at full CPU load.\n");
break;
}
} }
printf("Done.\n"); printf("Done.\n");