From a31b516e255cbee7cf1eea147f20de96469aa9f9 Mon Sep 17 00:00:00 2001 From: "Filipe Oliveira (Redis)" Date: Tue, 3 Sep 2024 10:27:35 +0100 Subject: [PATCH] Optimize the HELLO command reply (#13490) # Overall improvement TBD ( current is approximately 6% on the achievable ops/sec), coming from: - In case of no module we can skip 1.3% CPU cycles on dict Iterator creation/deletion - Use addReplyBulkCBuffer instead of addReplyBulkCString to avoid runtime strlen overhead within HELLO reply on string constants. ## Optimization 1: In case of no module we can skip 1.3% CPU cycles on dict Iterator creation/deletion. ## Optimization 2: Use addReplyBulkCBuffer instead of addReplyBulkCString to avoid runtime strlen overhead within HELLO reply on string constants. --- src/module.c | 7 ++++++- src/networking.c | 19 ++++++++++--------- src/server.h | 2 ++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/module.c b/src/module.c index c639e1515..b917a28a4 100644 --- a/src/module.c +++ b/src/module.c @@ -12463,10 +12463,15 @@ void modulePipeReadable(aeEventLoop *el, int fd, void *privdata, int mask) { /* Helper function for the MODULE and HELLO command: send the list of the * loaded modules to the client. */ void addReplyLoadedModules(client *c) { + const long ln = dictSize(modules); + /* In case no module is load we avoid iterator creation */ + addReplyArrayLen(c,ln); + if (ln == 0) { + return; + } dictIterator *di = dictGetIterator(modules); dictEntry *de; - addReplyArrayLen(c,dictSize(modules)); while ((de = dictNext(di)) != NULL) { sds name = dictGetKey(de); struct RedisModule *module = dictGetVal(de); diff --git a/src/networking.c b/src/networking.c index d3d925664..13ac603da 100644 --- a/src/networking.c +++ b/src/networking.c @@ -3662,29 +3662,30 @@ void helloCommand(client *c) { if (ver) c->resp = ver; addReplyMapLen(c,6 + !server.sentinel_mode); - addReplyBulkCString(c,"server"); - addReplyBulkCString(c,"redis"); + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,"server"); + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,"redis"); - addReplyBulkCString(c,"version"); - addReplyBulkCString(c,REDIS_VERSION); + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,"version"); + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,REDIS_VERSION); + + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,"proto"); - addReplyBulkCString(c,"proto"); addReplyLongLong(c,c->resp); - addReplyBulkCString(c,"id"); + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,"id"); addReplyLongLong(c,c->id); - addReplyBulkCString(c,"mode"); + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,"mode"); if (server.sentinel_mode) addReplyBulkCString(c,"sentinel"); else if (server.cluster_enabled) addReplyBulkCString(c,"cluster"); else addReplyBulkCString(c,"standalone"); if (!server.sentinel_mode) { - addReplyBulkCString(c,"role"); + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,"role"); addReplyBulkCString(c,server.masterhost ? "replica" : "master"); } - addReplyBulkCString(c,"modules"); + ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c,"modules"); addReplyLoadedModules(c); } diff --git a/src/server.h b/src/server.h index e83d28f61..79cbafde5 100644 --- a/src/server.h +++ b/src/server.h @@ -2690,6 +2690,8 @@ void initThreadedIO(void); client *lookupClientByID(uint64_t id); int authRequired(client *c); void putClientInPendingWriteQueue(client *c); +/* reply macros */ +#define ADD_REPLY_BULK_CBUFFER_STRING_CONSTANT(c, str) addReplyBulkCBuffer(c, str, strlen(str)) /* logreqres.c - logging of requests and responses */ void reqresReset(client *c, int free_buf);