From 01fb2a99bd21c22921ca960c012a4d8fc889e920 Mon Sep 17 00:00:00 2001 From: John Sully Date: Fri, 26 Mar 2021 23:48:24 +0000 Subject: [PATCH] Prefetch keys even in pure RAM scenarios Former-commit-id: d7219de186d60a5a437c1828ac97117eaad34819 --- src/db.cpp | 25 ++++++++++++++++++++++++- src/networking.cpp | 4 ++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index 524cdb66c..9978a8ca5 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -35,6 +35,11 @@ #include #include +// Needed for prefetch +#if defined(__x86_64__) || defined(__i386__) +#include +#endif + /* Database backup. */ struct dbBackup { const redisDbPersistentDataSnapshot **dbarray; @@ -3002,8 +3007,26 @@ int dbnumFromDb(redisDb *db) void redisDbPersistentData::prefetchKeysAsync(client *c, parsed_command &command) { - if (m_spstorage == nullptr) + if (m_spstorage == nullptr) { +#if defined(__x86_64__) || defined(__i386__) + // We do a quick 'n dirty check for set & get. Anything else is too slow. + // Should the user do something weird like remap them then the worst that will + // happen is we don't prefetch or we prefetch wrong data. A mild perf hit, but + // not dangerous + const char *cmd = szFromObj(command.argv[0]); + if (!strcasecmp(cmd, "set") || !strcasecmp(cmd, "get")) { + auto h = dictSdsHash(szFromObj(command.argv[1])); + for (int iht = 0; iht < 2; ++iht) { + auto hT = h & c->db->m_pdict->ht[iht].sizemask; + if (c->db->m_pdict->ht[iht].table != nullptr) + _mm_prefetch(c->db->m_pdict->ht[iht].table[hT], _MM_HINT_T1); + if (!dictIsRehashing(c->db->m_pdict)) + break; + } + } +#endif return; + } AeLocker lock; diff --git a/src/networking.cpp b/src/networking.cpp index 15aa6f43a..2919750bc 100644 --- a/src/networking.cpp +++ b/src/networking.cpp @@ -2358,8 +2358,8 @@ void parseClientCommandBuffer(client *c) { serverAssert(c->vecqueuedcmd.back().reploff >= 0); } - /* Prefetch if we have a storage provider and we're not in the global lock */ - if (cqueries < c->vecqueuedcmd.size() && g_pserver->m_pstorageFactory != nullptr && !GlobalLocksAcquired()) { + /* Prefetch outside the lock for better perf */ + if (cqueries < c->vecqueuedcmd.size() && !GlobalLocksAcquired()) { auto &query = c->vecqueuedcmd.back(); if (query.argc > 0 && query.argc == query.argcMax) { c->db->prefetchKeysAsync(c, query);