From 29b999df643e8ad52f90f07c11755dfe710f2e5c Mon Sep 17 00:00:00 2001 From: "Chao Li (Evan)" Date: Fri, 19 Sep 2025 06:58:29 +0800 Subject: [PATCH v1] Optimize multiplications/divisions by 2 using bit shifts in hot paths Replace occurrences of "* 2" with "<< 1" and "/ 2" with ">> 1" in functions along critical execution paths. These changes are safe because: - For unsigned types, left/right shifts by 1 are defined to behave exactly like multiply/divide by 2, modulo wraparound semantics that already apply to unsigned arithmetic. - For signed integer types, only non-negative values are affected by these operations, ensuring that "x >> 1" is equivalent to "x / 2". Negative values are not encountered in these code paths. This avoids unnecessary arithmetic instructions and makes the intent explicit, while preserving correctness. Author: Chao Li --- src/backend/access/gin/ginbulk.c | 2 +- src/backend/access/gin/ginfast.c | 2 +- src/backend/access/gin/ginpostinglist.c | 4 ++-- src/backend/access/gin/ginscan.c | 2 +- src/backend/access/gist/gistbuildbuffers.c | 4 ++-- src/backend/access/nbtree/nbtinsert.c | 2 +- src/backend/access/nbtree/nbtutils.c | 4 ++-- src/backend/executor/nodeHash.c | 12 ++++++------ 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/backend/access/gin/ginbulk.c b/src/backend/access/gin/ginbulk.c index 302cb2092a9..22bed52de5b 100644 --- a/src/backend/access/gin/ginbulk.c +++ b/src/backend/access/gin/ginbulk.c @@ -45,7 +45,7 @@ ginCombineData(RBTNode *existing, const RBTNode *newdata, void *arg) errhint("Reduce \"maintenance_work_mem\"."))); accum->allocatedMemory -= GetMemoryChunkSpace(eo->list); - eo->maxcount *= 2; + eo->maxcount <<= 1; eo->list = (ItemPointerData *) repalloc_huge(eo->list, sizeof(ItemPointerData) * eo->maxcount); accum->allocatedMemory += GetMemoryChunkSpace(eo->list); diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c index a6d88572cc2..6020aedaf67 100644 --- a/src/backend/access/gin/ginfast.c +++ b/src/backend/access/gin/ginfast.c @@ -686,7 +686,7 @@ addDatum(KeyArray *keys, Datum datum, GinNullCategory category) { if (keys->nvalues >= keys->maxvalues) { - keys->maxvalues *= 2; + keys->maxvalues <<= 1; keys->keys = repalloc_array(keys->keys, Datum, keys->maxvalues); keys->categories = repalloc_array(keys->categories, GinNullCategory, keys->maxvalues); } diff --git a/src/backend/access/gin/ginpostinglist.c b/src/backend/access/gin/ginpostinglist.c index 48eadec87b0..89f0f2eeeed 100644 --- a/src/backend/access/gin/ginpostinglist.c +++ b/src/backend/access/gin/ginpostinglist.c @@ -316,7 +316,7 @@ ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_ /* enlarge output array if needed */ if (ndecoded >= nallocated) { - nallocated *= 2; + nallocated <<= 1; result = repalloc(result, nallocated * sizeof(ItemPointerData)); } @@ -334,7 +334,7 @@ ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_ /* enlarge output array if needed */ if (ndecoded >= nallocated) { - nallocated *= 2; + nallocated <<= 1; result = repalloc(result, nallocated * sizeof(ItemPointerData)); } diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index 26081693383..5b21d3e89f3 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -122,7 +122,7 @@ ginFillScanEntry(GinScanOpaque so, OffsetNumber attnum, /* Add it to so's array */ if (so->totalentries >= so->allocentries) { - so->allocentries *= 2; + so->allocentries <<= 1; so->entries = (GinScanEntry *) repalloc(so->entries, so->allocentries * sizeof(GinScanEntry)); } diff --git a/src/backend/access/gist/gistbuildbuffers.c b/src/backend/access/gist/gistbuildbuffers.c index 0707254d18e..9a62110a1b2 100644 --- a/src/backend/access/gist/gistbuildbuffers.c +++ b/src/backend/access/gist/gistbuildbuffers.c @@ -204,7 +204,7 @@ gistAddLoadedBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer) /* Enlarge the array if needed */ if (gfbb->loadedBuffersCount >= gfbb->loadedBuffersLen) { - gfbb->loadedBuffersLen *= 2; + gfbb->loadedBuffersLen <<= 1; gfbb->loadedBuffers = (GISTNodeBuffer **) repalloc(gfbb->loadedBuffers, gfbb->loadedBuffersLen * sizeof(GISTNodeBuffer *)); @@ -489,7 +489,7 @@ gistBuffersReleaseBlock(GISTBuildBuffers *gfbb, long blocknum) /* Enlarge freeBlocks array if full. */ if (gfbb->nFreeBlocks >= gfbb->freeBlocksLen) { - gfbb->freeBlocksLen *= 2; + gfbb->freeBlocksLen <<= 1; gfbb->freeBlocks = (long *) repalloc(gfbb->freeBlocks, gfbb->freeBlocksLen * sizeof(long)); diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index be60781fc98..85d1ee26553 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -2972,7 +2972,7 @@ _bt_deadblocks(Page page, OffsetNumber *deletable, int ndeletable, { if (ntids + 1 > spacentids) { - spacentids *= 2; + spacentids <<= 1; tidblocks = (BlockNumber *) repalloc(tidblocks, sizeof(BlockNumber) * spacentids); } diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 41b4fbd1c37..6a33c2652d4 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -3289,8 +3289,8 @@ _bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate, */ if (!pstate->targetdistance) pstate->targetdistance = LOOK_AHEAD_DEFAULT_DISTANCE; - else if (pstate->targetdistance < MaxIndexTuplesPerPage / 2) - pstate->targetdistance *= 2; + else if (pstate->targetdistance < MaxIndexTuplesPerPage >> 1) + pstate->targetdistance <<= 1; /* Don't read past the end (or before the start) of the page, though */ if (ScanDirectionIsForward(dir)) diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index a3415db4e20..b34de4e8ce4 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -925,10 +925,10 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, * It's better to use half the batches, so do that and adjust the * nbucket in the opposite direction, and double the allowance. */ - nbatch /= 2; - nbuckets *= 2; + nbatch >>= 1; + nbuckets <<= 1; - *space_allowed = (*space_allowed) * 2; + *space_allowed = (*space_allowed) << 1; } Assert(nbuckets > 0); @@ -1791,10 +1791,10 @@ ExecHashTableInsert(HashJoinTable hashtable, ntuples > (hashtable->nbuckets_optimal * NTUP_PER_BUCKET)) { /* Guard against integer overflow and alloc size overflow */ - if (hashtable->nbuckets_optimal <= INT_MAX / 2 && - hashtable->nbuckets_optimal * 2 <= MaxAllocSize / sizeof(HashJoinTuple)) + if (hashtable->nbuckets_optimal <= INT_MAX >> 1 && + hashtable->nbuckets_optimal << 1 <= MaxAllocSize / sizeof(HashJoinTuple)) { - hashtable->nbuckets_optimal *= 2; + hashtable->nbuckets_optimal <<= 1; hashtable->log2_nbuckets_optimal += 1; } } -- 2.39.5 (Apple Git-154)