Skip to content

Commit 18d56cb

Browse files
committed
EXPERIMENT: instrument current 3-patch bcs (ticks/victim + eviction counter)
1 parent 898e100 commit 18d56cb

4 files changed

Lines changed: 221 additions & 0 deletions

File tree

src/backend/storage/buffer/bufmgr.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,6 +2326,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
23262326
Assert(BUF_STATE_GET_REFCOUNT(victim_buf_state) == 1);
23272327
Assert(!(victim_buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY | BM_IO_IN_PROGRESS)));
23282328

2329+
if (BufTagGetForkNum(&newTag) == MAIN_FORKNUM)
2330+
BcsGhostProbeRead(newHash);
23292331
victim_buf_hdr->tag = newTag;
23302332

23312333
/*
@@ -2663,6 +2665,13 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context)
26632665
*/
26642666
pgstat_count_io_op(IOOBJECT_RELATION, io_context,
26652667
from_ring ? IOOP_REUSE : IOOP_EVICT, 1, 0);
2668+
2669+
/* EXPERIMENT: record real evictions of MAIN_FORKNUM by relfilenumber */
2670+
if (!from_ring && BufTagGetForkNum(&buf_hdr->tag) == MAIN_FORKNUM)
2671+
{
2672+
BcsRecordEviction(BufTagGetRelNumber(&buf_hdr->tag));
2673+
BcsGhostRecordEviction(BufTableHashCode(&buf_hdr->tag), (BUF_STATE_GET_COOLSTATE(buf_state) == BUF_COOLSTATE_COOL));
2674+
}
26662675
}
26672676

26682677
/*

src/backend/storage/buffer/freelist.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
*/
1616
#include "postgres.h"
1717

18+
#include "funcapi.h"
19+
#include "utils/tuplestore.h"
20+
#include "access/relation.h"
21+
#include "common/pg_prng.h"
22+
#include "utils/rel.h"
1823
#include "pgstat.h"
1924
#include "port/atomics.h"
2025
#include "storage/buf_internals.h"
@@ -64,6 +69,25 @@ typedef struct
6469
* StrategyNotifyBgWriter.
6570
*/
6671
int bgwprocno;
72+
73+
/*
74+
* EXPERIMENT INSTRUMENT (throwaway, never posted): clock-sweep work
75+
* counters + per-relation eviction counts. sweepTicks/sweepVictims give
76+
* ticks-per-victim (the 0..5-grind metric); evictRel/evictCnt classify the
77+
* eviction stream by relation offline. Exposed via bcs_sweepstats() and
78+
* bcs_evictions().
79+
*/
80+
#define BCS_EVICT_SLOTS 8192
81+
pg_atomic_uint64 sweepTicks;
82+
pg_atomic_uint64 sweepVictims;
83+
pg_atomic_uint64 evictRel[BCS_EVICT_SLOTS];
84+
pg_atomic_uint64 evictCnt[BCS_EVICT_SLOTS];
85+
/* ghost observer (measurement only) */
86+
#define BCS_GHOST_SLOTS (1<<20)
87+
pg_atomic_uint64 ghostReads;
88+
pg_atomic_uint64 ghostReloads;
89+
pg_atomic_uint64 ghostReloadsCold;
90+
pg_atomic_uint32 ghostTag[BCS_GHOST_SLOTS]; /* low 31 bits of taghash, bit31=cold */
6791
} BufferStrategyControl;
6892

6993
/* Pointers to shared state */
@@ -204,6 +228,8 @@ ClockSweepTick(void)
204228
victim = MyBatchPos % NBuffers;
205229
MyBatchPos++;
206230

231+
pg_atomic_fetch_add_u64(&StrategyControl->sweepTicks, 1); /* EXPERIMENT */
232+
207233
return victim;
208234
}
209235

@@ -366,6 +392,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_r
366392
AddBufferToRing(strategy, buf);
367393
*buf_state = local_buf_state;
368394

395+
pg_atomic_fetch_add_u64(&StrategyControl->sweepVictims, 1); /* EXPERIMENT */
396+
369397
TrackNewBufferPin(BufferDescriptorGetBuffer(buf));
370398

371399
return buf;
@@ -477,6 +505,15 @@ StrategyCtlShmemInit(void *arg)
477505
/* No pending notification */
478506
StrategyControl->bgwprocno = -1;
479507

508+
/* EXPERIMENT: instrument counters */
509+
pg_atomic_init_u64(&StrategyControl->sweepTicks, 0);
510+
pg_atomic_init_u64(&StrategyControl->sweepVictims, 0);
511+
for (int i = 0; i < BCS_EVICT_SLOTS; i++)
512+
{
513+
pg_atomic_init_u64(&StrategyControl->evictRel[i], 0);
514+
pg_atomic_init_u64(&StrategyControl->evictCnt[i], 0);
515+
}
516+
480517
/*
481518
* Decide whether to batch the clock sweep.
482519
*
@@ -499,6 +536,17 @@ StrategyCtlShmemInit(void *arg)
499536
(uint32) NBuffers);
500537
else
501538
StrategyControl->batchSize = 1;
539+
540+
/*
541+
* EXPERIMENT (throwaway): allow forcing the batch size via env, so a
542+
* single binary can be run at batch 1 / 16 / 64 to isolate the NUMA
543+
* batching effect. Not part of the proposed patch.
544+
*/
545+
{
546+
const char *ov = getenv("BCS_BATCH_OVERRIDE");
547+
if (ov != NULL && atoi(ov) >= 1)
548+
StrategyControl->batchSize = Min((uint32) atoi(ov), (uint32) NBuffers);
549+
}
502550
}
503551

504552

@@ -862,3 +910,143 @@ StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_r
862910

863911
return true;
864912
}
913+
914+
/* EXPERIMENT INSTRUMENT (throwaway, never posted). */
915+
void
916+
BcsRecordEviction(RelFileNumber relNumber)
917+
{
918+
uint32 h = ((uint32) relNumber) % BCS_EVICT_SLOTS;
919+
920+
for (int probe = 0; probe < 64; probe++)
921+
{
922+
uint32 i = (h + probe) % BCS_EVICT_SLOTS;
923+
uint64 cur = pg_atomic_read_u64(&StrategyControl->evictRel[i]);
924+
925+
if (cur == (uint64) relNumber)
926+
{ pg_atomic_fetch_add_u64(&StrategyControl->evictCnt[i], 1); return; }
927+
if (cur == 0)
928+
{
929+
uint64 expected = 0;
930+
if (pg_atomic_compare_exchange_u64(&StrategyControl->evictRel[i], &expected, (uint64) relNumber)
931+
|| pg_atomic_read_u64(&StrategyControl->evictRel[i]) == (uint64) relNumber)
932+
{ pg_atomic_fetch_add_u64(&StrategyControl->evictCnt[i], 1); return; }
933+
}
934+
}
935+
pg_atomic_fetch_add_u64(&StrategyControl->evictCnt[0], 1);
936+
}
937+
938+
PG_FUNCTION_INFO_V1(bcs_sweepstats);
939+
Datum
940+
bcs_sweepstats(PG_FUNCTION_ARGS)
941+
{
942+
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
943+
Datum values[2];
944+
bool nulls[2] = {false, false};
945+
946+
InitMaterializedSRF(fcinfo, 0);
947+
values[0] = Int64GetDatum((int64) pg_atomic_read_u64(&StrategyControl->sweepTicks));
948+
values[1] = Int64GetDatum((int64) pg_atomic_read_u64(&StrategyControl->sweepVictims));
949+
tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
950+
return (Datum) 0;
951+
}
952+
953+
PG_FUNCTION_INFO_V1(bcs_evictions);
954+
Datum
955+
bcs_evictions(PG_FUNCTION_ARGS)
956+
{
957+
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
958+
959+
InitMaterializedSRF(fcinfo, 0);
960+
for (int i = 0; i < BCS_EVICT_SLOTS; i++)
961+
{
962+
uint64 rel = pg_atomic_read_u64(&StrategyControl->evictRel[i]);
963+
uint64 cnt = pg_atomic_read_u64(&StrategyControl->evictCnt[i]);
964+
Datum values[2];
965+
bool nulls[2] = {false, false};
966+
967+
if (cnt == 0) continue;
968+
values[0] = Int64GetDatum((int64) rel);
969+
values[1] = Int64GetDatum((int64) cnt);
970+
tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
971+
}
972+
return (Datum) 0;
973+
}
974+
975+
/*
976+
* EXPERIMENT INSTRUMENT (throwaway, never posted).
977+
* bcs_thrash(rel, n): pin+release n random MAIN_FORKNUM blocks of rel with the
978+
* normal (global-sweep) strategy, forcing n buffer allocations with almost no
979+
* other work -- so StrategyGetBuffer / nextVictimBuffer dominates the cost.
980+
* Isolates the clock-sweep mechanism from executor/protocol overhead.
981+
*/
982+
PG_FUNCTION_INFO_V1(bcs_thrash);
983+
Datum
984+
bcs_thrash(PG_FUNCTION_ARGS)
985+
{
986+
Oid relid = PG_GETARG_OID(0);
987+
int64 n = PG_GETARG_INT64(1);
988+
Relation rel = relation_open(relid, AccessShareLock);
989+
BlockNumber nblocks = RelationGetNumberOfBlocks(rel);
990+
uint64 sum = 0;
991+
pg_prng_state prng;
992+
993+
pg_prng_seed(&prng, (uint64) MyProcPid ^ (uint64) n);
994+
for (int64 i = 0; i < n && nblocks > 0; i++)
995+
{
996+
BlockNumber blk = (BlockNumber) (pg_prng_uint64(&prng) % nblocks);
997+
Buffer buf = ReadBufferExtended(rel, MAIN_FORKNUM, blk,
998+
RBM_NORMAL, NULL);
999+
1000+
sum += blk;
1001+
ReleaseBuffer(buf);
1002+
CHECK_FOR_INTERRUPTS();
1003+
}
1004+
relation_close(rel, AccessShareLock);
1005+
PG_RETURN_INT64((int64) sum);
1006+
}
1007+
1008+
1009+
/* ---- ghost observer (measurement only, never posted) ---- */
1010+
/* Record that a block (identified by its buffer tag hash) was evicted, and
1011+
* whether it was cold at eviction. Stores low 31 bits of hash + cold bit. */
1012+
void
1013+
BcsGhostRecordEviction(uint32 taghash, bool cold)
1014+
{
1015+
uint32 slot = taghash & (BCS_GHOST_SLOTS - 1);
1016+
uint32 val = (taghash & 0x7fffffff) | (cold ? 0x80000000u : 0);
1017+
pg_atomic_write_u32(&StrategyControl->ghostTag[slot], val);
1018+
}
1019+
1020+
/* On a real read/alloc of a block, probe the ghost table: was this exact block
1021+
* recently evicted? If so it's a reload; note if it was cold when evicted. */
1022+
void
1023+
BcsGhostProbeRead(uint32 taghash)
1024+
{
1025+
uint32 slot = taghash & (BCS_GHOST_SLOTS - 1);
1026+
uint32 val = pg_atomic_read_u32(&StrategyControl->ghostTag[slot]);
1027+
pg_atomic_fetch_add_u64(&StrategyControl->ghostReads, 1);
1028+
if ((val & 0x7fffffff) == (taghash & 0x7fffffff) && val != 0)
1029+
{
1030+
pg_atomic_fetch_add_u64(&StrategyControl->ghostReloads, 1);
1031+
if (val & 0x80000000u)
1032+
pg_atomic_fetch_add_u64(&StrategyControl->ghostReloadsCold, 1);
1033+
/* clear so we don't double-count the same resurrection */
1034+
pg_atomic_write_u32(&StrategyControl->ghostTag[slot], 0);
1035+
}
1036+
}
1037+
1038+
PG_FUNCTION_INFO_V1(bcs_ghost);
1039+
Datum
1040+
bcs_ghost(PG_FUNCTION_ARGS)
1041+
{
1042+
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1043+
Datum v[3];
1044+
bool n[3] = {false, false, false};
1045+
1046+
InitMaterializedSRF(fcinfo, 0);
1047+
v[0] = Int64GetDatum((int64) pg_atomic_read_u64(&StrategyControl->ghostReads));
1048+
v[1] = Int64GetDatum((int64) pg_atomic_read_u64(&StrategyControl->ghostReloads));
1049+
v[2] = Int64GetDatum((int64) pg_atomic_read_u64(&StrategyControl->ghostReloadsCold));
1050+
tuplestore_putvalues(rsi->setResult, rsi->setDesc, v, n);
1051+
return (Datum) 0;
1052+
}

src/include/catalog/pg_proc.dat

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12715,4 +12715,25 @@
1271512715
proname => 'hashoid8extended', prorettype => 'int8',
1271612716
proargtypes => 'oid8 int8', prosrc => 'hashoid8extended' },
1271712717

12718+
# EXPERIMENT INSTRUMENT (throwaway, never posted)
12719+
{ oid => '8902', descr => 'bcs experiment: clock-sweep ticks and victims',
12720+
proname => 'bcs_sweepstats', prorows => '1', proretset => 't',
12721+
provolatile => 'v', proparallel => 'r', prorettype => 'record',
12722+
proargtypes => '', proallargtypes => '{int8,int8}', proargmodes => '{o,o}',
12723+
proargnames => '{ticks,victims}', prosrc => 'bcs_sweepstats' },
12724+
{ oid => '8901', descr => 'bcs experiment: per-relation eviction counts',
12725+
proname => 'bcs_evictions', prorows => '1000', proretset => 't',
12726+
provolatile => 'v', proparallel => 'r', prorettype => 'record',
12727+
proargtypes => '', proallargtypes => '{int8,int8}', proargmodes => '{o,o}',
12728+
proargnames => '{relfilenode,evictions}', prosrc => 'bcs_evictions' },
12729+
12730+
{ oid => '8903', descr => 'bcs experiment: thrash n random blocks (sweep isolation)',
12731+
proname => 'bcs_thrash', provolatile => 'v', proparallel => 'u',
12732+
prorettype => 'int8', proargtypes => 'regclass int8', prosrc => 'bcs_thrash' },
12733+
12734+
{ oid => '8905', descr => 'bcs exp: ghost observer',
12735+
proname => 'bcs_ghost', prorows => '1', proretset => 't', provolatile => 'v',
12736+
proparallel => 'r', prorettype => 'record', proargtypes => '',
12737+
proallargtypes => '{int8,int8,int8}', proargmodes => '{o,o,o}',
12738+
proargnames => '{reads,reloads,reloads_cold}', prosrc => 'bcs_ghost' },
1271812739
]

src/include/storage/buf_internals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,9 @@ extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy,
638638
extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
639639
BufferDesc *buf, bool from_ring);
640640

641+
extern void BcsRecordEviction(RelFileNumber relNumber);
642+
extern void BcsGhostRecordEviction(uint32 taghash, bool cold);
643+
extern void BcsGhostProbeRead(uint32 taghash);
641644
extern int StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc);
642645
extern void StrategyNotifyBgWriter(int bgwprocno);
643646

0 commit comments

Comments
 (0)