From 9e8f60faa69c59a8668a6e81efda9562962a4d31 Mon Sep 17 00:00:00 2001 From: charsyam Date: Sat, 28 Mar 2026 09:47:33 +0900 Subject: [PATCH] Optimize infoCommand with SDS pre-allocation and getrusage caching Pre-allocate 4KB for the INFO SDS buffer to reduce realloc overhead during string building. Cache getrusage(RUSAGE_SELF) and getrusage(RUSAGE_CHILDREN) in serverCron (every 100ms) instead of calling them per INFO request, eliminating 2 syscalls per invocation. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/server.c | 16 +++++++++------- src/server.h | 3 +++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/server.c b/src/server.c index 3e216568b..a5769971e 100644 --- a/src/server.c +++ b/src/server.c @@ -1452,6 +1452,8 @@ void cronUpdateMemoryStats(void) { NULL, &server.cron_malloc_stats.allocator_muzzy, &server.cron_malloc_stats.allocator_frag_smallbins_bytes); + getrusage(RUSAGE_SELF, &server.cron_rusage_self); + getrusage(RUSAGE_CHILDREN, &server.cron_rusage_children); if (server.lua_arena != UINT_MAX) { zmalloc_get_allocator_info_by_arena(server.lua_arena, 0, @@ -6274,6 +6276,7 @@ static sds sdscatHistograms(sds info, int dbnum, keysizesHist histogram, const c * on memory corruption problems. */ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { sds info = sdsempty(); + info = sdsMakeRoomFor(info, 4096); time_t uptime = server.unixtime-server.stat_starttime; int j; int sections = 0; @@ -6834,19 +6837,18 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { if (all_sections || (dictFind(section_dict,"cpu") != NULL)) { if (sections++) info = sdscat(info,"\r\n"); - struct rusage self_ru, c_ru; - getrusage(RUSAGE_SELF, &self_ru); - getrusage(RUSAGE_CHILDREN, &c_ru); + struct rusage *self_ru = &server.cron_rusage_self; + struct rusage *c_ru = &server.cron_rusage_children; info = sdscatprintf(info, "# CPU\r\n" "used_cpu_sys:%ld.%06ld\r\n" "used_cpu_user:%ld.%06ld\r\n" "used_cpu_sys_children:%ld.%06ld\r\n" "used_cpu_user_children:%ld.%06ld\r\n", - (long)self_ru.ru_stime.tv_sec, (long)self_ru.ru_stime.tv_usec, - (long)self_ru.ru_utime.tv_sec, (long)self_ru.ru_utime.tv_usec, - (long)c_ru.ru_stime.tv_sec, (long)c_ru.ru_stime.tv_usec, - (long)c_ru.ru_utime.tv_sec, (long)c_ru.ru_utime.tv_usec); + (long)self_ru->ru_stime.tv_sec, (long)self_ru->ru_stime.tv_usec, + (long)self_ru->ru_utime.tv_sec, (long)self_ru->ru_utime.tv_usec, + (long)c_ru->ru_stime.tv_sec, (long)c_ru->ru_stime.tv_usec, + (long)c_ru->ru_utime.tv_sec, (long)c_ru->ru_utime.tv_usec); #ifdef RUSAGE_THREAD struct rusage m_ru; getrusage(RUSAGE_THREAD, &m_ru); diff --git a/src/server.h b/src/server.h index 6848230ec..d4f0f20cb 100644 --- a/src/server.h +++ b/src/server.h @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef HAVE_LIBSYSTEMD #include @@ -2094,6 +2095,8 @@ struct redisServer { long long stat_slowlog_time_us_sum; /* Sum of all slowlog entry durations (usec) */ long long stat_slowlog_time_us_max; /* Max slowlog entry duration (usec) */ struct malloc_stats cron_malloc_stats; /* sampled in serverCron(). */ + struct rusage cron_rusage_self; /* sampled in serverCron(). */ + struct rusage cron_rusage_children; /* sampled in serverCron(). */ redisAtomic long long stat_net_input_bytes; /* Bytes read from network. */ redisAtomic long long stat_net_output_bytes; /* Bytes written to network. */ redisAtomic long long stat_net_repl_input_bytes; /* Bytes read during replication, added to stat_net_input_bytes in 'info'. */