From da6fd9a04613c9a2aafb30ef238cfbdc6ed7d6c7 Mon Sep 17 00:00:00 2001 From: jeffchen Date: Wed, 5 Aug 2026 13:29:06 +0000 Subject: [PATCH] Avoid an integer divide on the page-cache lookup fast path. The hash table size in pcache1 is always a power of two, so the bucket index in pcache1FetchNoMutex() can be computed with a mask instead of a modulo. An assert() verifies the power-of-two invariant in debug builds. FossilOrigin-Name: 750c37d4044c0957b81a12448293c0f85bab0b9f981d8e6f573ffe27eeb8f16d --- manifest | 17 ++++++++++------- manifest.tags | 4 ++-- manifest.uuid | 2 +- src/pcache1.c | 7 +++++-- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 6155b6a5ce..f904b1911a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\ssorter\senhancement\sat\s[bdc841de10fef65b]\scontains\sa\sbug\swhere\sit\nmight\ssort\s64-bit\sintegers\sin\sthe\swrong\sorder\sdue\sto\sthe\slimited\nprecision\sof\sdouble.\s\sFixed\shere. -D 2026-08-04T20:40:10.440 +C Avoid\san\sinteger\sdivide\son\sthe\spage-cache\slookup\sfast\spath.\s\sThe\shash\ntable\ssize\sin\spcache1\sis\salways\sa\spower\sof\stwo,\sso\sthe\sbucket\sindex\sin\npcache1FetchNoMutex()\scan\sbe\scomputed\swith\sa\smask\sinstead\sof\sa\smodulo.\nAn\sassert()\sverifies\sthe\spower-of-two\sinvariant\sin\sdebug\sbuilds. +D 2026-08-05T13:29:06.472 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -735,7 +735,7 @@ F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8 F src/parse.y d5a3c5b0277a441c38b35071c05e2b61ff5fc918a63309c809f4b6706179c320 F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba -F src/pcache1.c d7ee0f95992501a65379f620b3de1430b64e52e397769938668a9fd9dd1c8145 +F src/pcache1.c c5725cfc6043c33b1343fc848176b8cfceacd6bc5102423c8b61f9ba62b21a9d F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d F src/prepare.c 8954bb69defe377cd6a926f8c61d8215ea4f1974838d3ec6f22681a2c0a2939f F src/printf.c b480176bd0aaed9d64e804cfa3ca27fc585f65a73e7c7ca2fe9b9016db2cf6d5 @@ -2218,8 +2218,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P bdc841de10fef65b627deb8b770702c976174a66af847c96ebecf24d91798744 -R 0db8bad880544fadd75c136d6d89db37 -U drh -Z c0254d132a18aeae6d54aba80ce46af2 +P 6bdfff7ddb63d0b4f28f6c174a36e81486a652056a4e21644378a22feda780fd +R 696eb69ee5490c1498ca703ebfcb71e1 +T *branch * jeffchen-opt-page-cache-lookup +T *sym-jeffchen-opt-page-cache-lookup * +T -sym-trunk * +U jeffchen +Z a5d3f5cff3167f880dcc229921fa0798 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..7267642b50 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch jeffchen-opt-page-cache-lookup +tag jeffchen-opt-page-cache-lookup diff --git a/manifest.uuid b/manifest.uuid index fd3459d4bf..b0f123a5cc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6bdfff7ddb63d0b4f28f6c174a36e81486a652056a4e21644378a22feda780fd +750c37d4044c0957b81a12448293c0f85bab0b9f981d8e6f573ffe27eeb8f16d diff --git a/src/pcache1.c b/src/pcache1.c index 39a37062e8..d36e83dc11 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -1007,8 +1007,11 @@ static PgHdr1 *pcache1FetchNoMutex( PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = 0; - /* Step 1: Search the hash table for an existing entry. */ - pPage = pCache->apHash[iKey % pCache->nHash]; + /* Step 1: Search the hash table for an existing entry. nHash is always + ** a power of two when the cache is in use (see pcache1ResizeHash()), so + ** the modulo reduces to a mask, avoiding a hardware divide. */ + assert( pCache->nHash>0 && (pCache->nHash & (pCache->nHash-1))==0 ); + pPage = pCache->apHash[iKey & (pCache->nHash-1u)]; while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } /* Step 2: If the page was found in the hash table, then return it.