From 35da660200be20cb4f08e5599807ada8c34f0d0a Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 23 Jul 2025 13:39:32 +0300 Subject: [PATCH] more work on exposing LFC stats --- .../communicator/src/backend_interface.rs | 8 +++ .../neon/communicator/src/integrated_cache.rs | 4 ++ pgxn/neon/communicator_new.c | 52 +++++++++++++++++-- pgxn/neon/neon.c | 1 + 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/pgxn/neon/communicator/src/backend_interface.rs b/pgxn/neon/communicator/src/backend_interface.rs index aa054785ee..6b2748750f 100644 --- a/pgxn/neon/communicator/src/backend_interface.rs +++ b/pgxn/neon/communicator/src/backend_interface.rs @@ -252,6 +252,14 @@ pub unsafe extern "C" fn bcomm_cache_iterate_next( } } +#[allow(clippy::missing_safety_doc)] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn bcomm_cache_get_num_pages_used( + bs: &mut CommunicatorBackendStruct, +) -> u64 { + bs.integrated_cache.get_num_buckets_in_use() as u64 +} + impl<'t> CommunicatorBackendStruct<'t> { /// The slot must be free, or this panics. pub(crate) fn start_neon_io_request(&mut self, request_slot_idx: i32, request: &NeonIORequest) { diff --git a/pgxn/neon/communicator/src/integrated_cache.rs b/pgxn/neon/communicator/src/integrated_cache.rs index c2850dd961..92a96e3456 100644 --- a/pgxn/neon/communicator/src/integrated_cache.rs +++ b/pgxn/neon/communicator/src/integrated_cache.rs @@ -759,6 +759,10 @@ impl<'t> IntegratedCacheReadAccess<'t> { Some((key, _)) => GetBucketResult::Occupied(key.rel, key.block_number), } } + + pub fn get_num_buckets_in_use(&self) -> usize { + self.block_map.get_num_buckets_in_use() + } } pub struct BackendCacheReadOp<'t> { diff --git a/pgxn/neon/communicator_new.c b/pgxn/neon/communicator_new.c index a38d7a1ae5..c4b7263e19 100644 --- a/pgxn/neon/communicator_new.c +++ b/pgxn/neon/communicator_new.c @@ -86,6 +86,10 @@ typedef struct CommunicatorShmemPerBackendData */ uint64 request_counter; + /* Counters, for metrics. */ + uint64 cache_misses; + uint64 cache_hits; + /* * Normally, when reading or writing pages from shared buffer cache, the * worker process can operate directly on the shared buffer. But when @@ -122,7 +126,8 @@ typedef struct CommunicatorShmemData static CommunicatorShmemData *communicator_shmem_ptr; -#define MyIOCompletionLatch (&communicator_shmem_ptr->backends[MyProcNumber].io_completion_latch) +static CommunicatorShmemPerBackendData *my_per_backend_data; +#define MyIOCompletionLatch (&my_per_backend_data->io_completion_latch) #define MAX_INFLIGHT_ASYNC_REQUESTS 5 @@ -308,6 +313,8 @@ communicator_new_init(void) if (MyBgworkerEntry && strcmp(MyBgworkerEntry->bgw_function_name, "communicator_new_bgworker_main") == 0) return; + my_per_backend_data = &communicator_shmem_ptr->backends[MyProcNumber]; + OwnLatch(MyIOCompletionLatch); my_bs = rcommunicator_backend_init(cis, MyProcNumber); @@ -753,6 +760,7 @@ retry: } pgBufferUsage.file_cache.hits += nblocks; + my_per_backend_data->cache_hits += nblocks; return; } @@ -768,6 +776,7 @@ retry: * as a cache miss. */ pgBufferUsage.file_cache.misses += nblocks; + my_per_backend_data->cache_misses += nblocks; wait_request_completion(request_idx, &result); Assert(num_inflight_requests == 1); @@ -1363,7 +1372,42 @@ communicator_new_approximate_working_set_size_seconds(time_t duration, bool rese LfcStatsEntry * communicator_new_get_lfc_stats(uint32 *num_entries) { - // TODO - *num_entries = 0; - return NULL; + LfcStatsEntry *entries; + int n = 0; + uint64 cache_misses = 0; + uint64 cache_hits = 0; + + for (int i = 0; i < MaxProcs; i++) + { + cache_misses += communicator_shmem_ptr->backends[i].cache_misses; + cache_hits += communicator_shmem_ptr->backends[i].cache_hits; + } + +#define NUM_ENTRIES 10 + entries = palloc(sizeof(LfcStatsEntry) * NUM_ENTRIES); + + entries[n++] = (LfcStatsEntry) {"file_cache_misses", false, cache_misses}; + entries[n++] = (LfcStatsEntry) {"file_cache_hits", false, cache_hits }; + + entries[n++] = (LfcStatsEntry) {"file_cache_used_pages", false, + bcomm_cache_get_num_pages_used(my_bs) }; + + /* TODO: these stats are exposed by the legacy LFC implementation */ +#if 0 + entries[n++] = (LfcStatsEntry) {"file_cache_used", lfc_ctl == NULL, + lfc_ctl ? lfc_ctl->used : 0 }; + entries[n++] = (LfcStatsEntry) {"file_cache_writes", lfc_ctl == NULL, + lfc_ctl ? lfc_ctl->writes : 0 }; + entries[n++] = (LfcStatsEntry) {"file_cache_size", lfc_ctl == NULL, + lfc_ctl ? lfc_ctl->size : 0 }; + entries[n++] = (LfcStatsEntry) {"file_cache_evicted_pages", lfc_ctl == NULL, + lfc_ctl ? lfc_ctl->evicted_pages : 0 }; + entries[n++] = (LfcStatsEntry) {"file_cache_limit", lfc_ctl == NULL, + lfc_ctl ? lfc_ctl->limit : 0 }; +#endif + + Assert(n <= NUM_ENTRIES); + + *num_entries = n; + return entries; } diff --git a/pgxn/neon/neon.c b/pgxn/neon/neon.c index d28aeed879..faf4b1d13b 100644 --- a/pgxn/neon/neon.c +++ b/pgxn/neon/neon.c @@ -735,6 +735,7 @@ neon_get_lfc_stats(PG_FUNCTION_ARGS) Datum values[NUM_NEON_GET_STATS_COLS]; bool nulls[NUM_NEON_GET_STATS_COLS]; + nulls[0] = false; values[0] = CStringGetTextDatum(entry->metric_name); nulls[1] = entry->isnull; values[1] = Int64GetDatum(entry->isnull ? 0 : entry->value);