Skip to content

Commit 13eb6bb

Browse files
committed
Fix performance regression with flush of pending fixed-numbered stats
The callback added in fc415ed used to check if there is any pending data to flush for fixed-numbered statistics, done by looping across all the builtin and custom stats kinds with a call to have_fixed_pending_cb, is proving to able to show in workloads that do not report any stats (read-only, no function calls, no WAL, no IO, etc). The code used in v17 was cheaper than that what HEAD has introduced, relying on three boolean checks for WAL, SLRU and IO stats. This commit switches the code to use a more efficient approach than fc415ed, with a single boolean flag that can be switched to "true" by any fixed-numbered stats kinds to force pgstat_report_stat() to go through one round of reports. The flag is reset by pgstat_report_stat() once a full round of reports is done. The flag being false means that fixed-numbered stats kinds saw no activity, and that there is no pending data to flush. ac000fc took one step in improving the performance by reducing the number of stats kinds that the backend can hold. This commit takes a more drastic step by bringing back the code efficiency to what it was before v18 with a cheap check at the beginning of pgstat_report_stat() for its fast-exit path. The callback have_static_pending_cb is removed as an effect of all that. Reported-by: Andres Freund <andres@anarazel.de> Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Discussion: https://postgr.es/m/eb224uegsga2hgq7dfq3ps5cduhpqej7ir2hjxzzozjthrekx5@dysei6buqthe Backpatch-through: 18
1 parent bae5078 commit 13eb6bb

File tree

7 files changed

+62
-88
lines changed

7 files changed

+62
-88
lines changed

src/backend/access/transam/xlog.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
#include "utils/guc_hooks.h"
9797
#include "utils/guc_tables.h"
9898
#include "utils/injection_point.h"
99+
#include "utils/pgstat_internal.h"
99100
#include "utils/ps_status.h"
100101
#include "utils/relmapper.h"
101102
#include "utils/snapmgr.h"
@@ -1092,6 +1093,9 @@ XLogInsertRecord(XLogRecData *rdata,
10921093
pgWalUsage.wal_bytes += rechdr->xl_tot_len;
10931094
pgWalUsage.wal_records++;
10941095
pgWalUsage.wal_fpi += num_fpi;
1096+
1097+
/* Required for the flush of pending stats WAL data */
1098+
pgstat_report_fixed = true;
10951099
}
10961100

10971101
return EndPos;
@@ -2109,6 +2113,12 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
21092113
LWLockRelease(WALWriteLock);
21102114
pgWalUsage.wal_buffers_full++;
21112115
TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_DONE();
2116+
2117+
/*
2118+
* Required for the flush of pending stats WAL data, per
2119+
* update of pgWalUsage.
2120+
*/
2121+
pgstat_report_fixed = true;
21122122
}
21132123
}
21142124
}

src/backend/utils/activity/pgstat.c

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ int pgstat_fetch_consistency = PGSTAT_FETCH_CONSISTENCY_CACHE;
212212

213213
PgStat_LocalState pgStatLocal;
214214

215+
/*
216+
* Track pending reports for fixed-numbered stats, used by
217+
* pgstat_report_stat().
218+
*/
219+
bool pgstat_report_fixed = false;
215220

216221
/* ----------
217222
* Local data
@@ -370,7 +375,6 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE]
370375
.shared_data_off = offsetof(PgStatShared_Backend, stats),
371376
.shared_data_len = sizeof(((PgStatShared_Backend *) 0)->stats),
372377

373-
.have_static_pending_cb = pgstat_backend_have_pending_cb,
374378
.flush_static_cb = pgstat_backend_flush_cb,
375379
.reset_timestamp_cb = pgstat_backend_reset_timestamp_cb,
376380
},
@@ -437,7 +441,6 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE]
437441
.shared_data_len = sizeof(((PgStatShared_IO *) 0)->stats),
438442

439443
.flush_static_cb = pgstat_io_flush_cb,
440-
.have_static_pending_cb = pgstat_io_have_pending_cb,
441444
.init_shmem_cb = pgstat_io_init_shmem_cb,
442445
.reset_all_cb = pgstat_io_reset_all_cb,
443446
.snapshot_cb = pgstat_io_snapshot_cb,
@@ -455,7 +458,6 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE]
455458
.shared_data_len = sizeof(((PgStatShared_SLRU *) 0)->stats),
456459

457460
.flush_static_cb = pgstat_slru_flush_cb,
458-
.have_static_pending_cb = pgstat_slru_have_pending_cb,
459461
.init_shmem_cb = pgstat_slru_init_shmem_cb,
460462
.reset_all_cb = pgstat_slru_reset_all_cb,
461463
.snapshot_cb = pgstat_slru_snapshot_cb,
@@ -474,7 +476,6 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE]
474476

475477
.init_backend_cb = pgstat_wal_init_backend_cb,
476478
.flush_static_cb = pgstat_wal_flush_cb,
477-
.have_static_pending_cb = pgstat_wal_have_pending_cb,
478479
.init_shmem_cb = pgstat_wal_init_shmem_cb,
479480
.reset_all_cb = pgstat_wal_reset_all_cb,
480481
.snapshot_cb = pgstat_wal_snapshot_cb,
@@ -708,29 +709,10 @@ pgstat_report_stat(bool force)
708709
}
709710

710711
/* Don't expend a clock check if nothing to do */
711-
if (dlist_is_empty(&pgStatPending))
712+
if (dlist_is_empty(&pgStatPending) &&
713+
!pgstat_report_fixed)
712714
{
713-
bool do_flush = false;
714-
715-
/* Check for pending stats */
716-
for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
717-
{
718-
const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
719-
720-
if (!kind_info)
721-
continue;
722-
if (!kind_info->have_static_pending_cb)
723-
continue;
724-
725-
if (kind_info->have_static_pending_cb())
726-
{
727-
do_flush = true;
728-
break;
729-
}
730-
}
731-
732-
if (!do_flush)
733-
return 0;
715+
return 0;
734716
}
735717

736718
/*
@@ -784,16 +766,19 @@ pgstat_report_stat(bool force)
784766
partial_flush |= pgstat_flush_pending_entries(nowait);
785767

786768
/* flush of other stats kinds */
787-
for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
769+
if (pgstat_report_fixed)
788770
{
789-
const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
771+
for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
772+
{
773+
const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
790774

791-
if (!kind_info)
792-
continue;
793-
if (!kind_info->flush_static_cb)
794-
continue;
775+
if (!kind_info)
776+
continue;
777+
if (!kind_info->flush_static_cb)
778+
continue;
795779

796-
partial_flush |= kind_info->flush_static_cb(nowait);
780+
partial_flush |= kind_info->flush_static_cb(nowait);
781+
}
797782
}
798783

799784
last_flush = now;
@@ -815,6 +800,7 @@ pgstat_report_stat(bool force)
815800
}
816801

817802
pending_since = 0;
803+
pgstat_report_fixed = false;
818804

819805
return 0;
820806
}

src/backend/utils/activity/pgstat_backend.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pgstat_count_backend_io_op_time(IOObject io_object, IOContext io_context,
6666
io_time);
6767

6868
backend_has_iostats = true;
69+
pgstat_report_fixed = true;
6970
}
7071

7172
void
@@ -81,6 +82,7 @@ pgstat_count_backend_io_op(IOObject io_object, IOContext io_context,
8182
PendingBackendStats.pending_io.bytes[io_object][io_context][io_op] += bytes;
8283

8384
backend_has_iostats = true;
85+
pgstat_report_fixed = true;
8486
}
8587

8688
/*
@@ -301,18 +303,6 @@ pgstat_flush_backend(bool nowait, bits32 flags)
301303
return false;
302304
}
303305

304-
/*
305-
* Check if there are any backend stats waiting for flush.
306-
*/
307-
bool
308-
pgstat_backend_have_pending_cb(void)
309-
{
310-
if (!pgstat_tracks_backend_bktype(MyBackendType))
311-
return false;
312-
313-
return (backend_has_iostats || pgstat_backend_wal_have_pending());
314-
}
315-
316306
/*
317307
* Callback to flush out locally pending backend statistics.
318308
*

src/backend/utils/activity/pgstat_io.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op,
8080
pgstat_count_backend_io_op(io_object, io_context, io_op, cnt, bytes);
8181

8282
have_iostats = true;
83+
pgstat_report_fixed = true;
8384
}
8485

8586
/*
@@ -167,15 +168,6 @@ pgstat_fetch_stat_io(void)
167168
return &pgStatLocal.snapshot.io;
168169
}
169170

170-
/*
171-
* Check if there any IO stats waiting for flush.
172-
*/
173-
bool
174-
pgstat_io_have_pending_cb(void)
175-
{
176-
return have_iostats;
177-
}
178-
179171
/*
180172
* Simpler wrapper of pgstat_io_flush_cb()
181173
*/

src/backend/utils/activity/pgstat_slru.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,6 @@ pgstat_get_slru_index(const char *name)
143143
return (SLRU_NUM_ELEMENTS - 1);
144144
}
145145

146-
/*
147-
* Check if there are any SLRU stats entries waiting for flush.
148-
*/
149-
bool
150-
pgstat_slru_have_pending_cb(void)
151-
{
152-
return have_slrustats;
153-
}
154-
155146
/*
156147
* Flush out locally pending SLRU stats entries
157148
*
@@ -247,6 +238,7 @@ get_slru_entry(int slru_idx)
247238
Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS));
248239

249240
have_slrustats = true;
241+
pgstat_report_fixed = true;
250242

251243
return &pending_SLRUStats[slru_idx];
252244
}

src/backend/utils/activity/pgstat_wal.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ pgstat_fetch_stat_wal(void)
7171
return &pgStatLocal.snapshot.wal;
7272
}
7373

74+
/*
75+
* To determine whether WAL usage happened.
76+
*/
77+
static inline bool
78+
pgstat_wal_have_pending(void)
79+
{
80+
return pgWalUsage.wal_records != prevWalUsage.wal_records;
81+
}
82+
7483
/*
7584
* Calculate how much WAL usage counters have increased by subtracting the
7685
* previous counters from the current ones.
@@ -92,7 +101,7 @@ pgstat_wal_flush_cb(bool nowait)
92101
* This function can be called even if nothing at all has happened. Avoid
93102
* taking lock for nothing in that case.
94103
*/
95-
if (!pgstat_wal_have_pending_cb())
104+
if (!pgstat_wal_have_pending())
96105
return false;
97106

98107
/*
@@ -136,15 +145,6 @@ pgstat_wal_init_backend_cb(void)
136145
prevWalUsage = pgWalUsage;
137146
}
138147

139-
/*
140-
* To determine whether WAL usage happened.
141-
*/
142-
bool
143-
pgstat_wal_have_pending_cb(void)
144-
{
145-
return pgWalUsage.wal_records != prevWalUsage.wal_records;
146-
}
147-
148148
void
149149
pgstat_wal_init_shmem_cb(void *stats)
150150
{

src/include/utils/pgstat_internal.h

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -295,18 +295,11 @@ typedef struct PgStat_KindInfo
295295
*
296296
* Returns true if some of the stats could not be flushed, due to lock
297297
* contention for example. Optional.
298-
*/
299-
bool (*flush_static_cb) (bool nowait);
300-
301-
/*
302-
* For fixed-numbered or variable-numbered statistics: Check for pending
303-
* stats in need of flush with flush_static_cb, when these do not use
304-
* PgStat_EntryRef->pending.
305298
*
306-
* Returns true if there are any stats pending for flush, triggering
307-
* flush_static_cb. Optional.
299+
* "pgstat_report_fixed" needs to be set to trigger the flush of pending
300+
* stats.
308301
*/
309-
bool (*have_static_pending_cb) (void);
302+
bool (*flush_static_cb) (bool nowait);
310303

311304
/*
312305
* For fixed-numbered statistics: Reset All.
@@ -627,7 +620,6 @@ extern void pgstat_archiver_snapshot_cb(void);
627620

628621
extern bool pgstat_flush_backend(bool nowait, bits32 flags);
629622
extern bool pgstat_backend_flush_cb(bool nowait);
630-
extern bool pgstat_backend_have_pending_cb(void);
631623
extern void pgstat_backend_reset_timestamp_cb(PgStatShared_Common *header,
632624
TimestampTz ts);
633625

@@ -676,7 +668,6 @@ extern bool pgstat_function_flush_cb(PgStat_EntryRef *entry_ref, bool nowait);
676668

677669
extern void pgstat_flush_io(bool nowait);
678670

679-
extern bool pgstat_io_have_pending_cb(void);
680671
extern bool pgstat_io_flush_cb(bool nowait);
681672
extern void pgstat_io_init_shmem_cb(void *stats);
682673
extern void pgstat_io_reset_all_cb(TimestampTz ts);
@@ -738,7 +729,6 @@ extern PgStatShared_Common *pgstat_init_entry(PgStat_Kind kind,
738729
* Functions in pgstat_slru.c
739730
*/
740731

741-
extern bool pgstat_slru_have_pending_cb(void);
742732
extern bool pgstat_slru_flush_cb(bool nowait);
743733
extern void pgstat_slru_init_shmem_cb(void *stats);
744734
extern void pgstat_slru_reset_all_cb(TimestampTz ts);
@@ -750,7 +740,6 @@ extern void pgstat_slru_snapshot_cb(void);
750740
*/
751741

752742
extern void pgstat_wal_init_backend_cb(void);
753-
extern bool pgstat_wal_have_pending_cb(void);
754743
extern bool pgstat_wal_flush_cb(bool nowait);
755744
extern void pgstat_wal_init_shmem_cb(void *stats);
756745
extern void pgstat_wal_reset_all_cb(TimestampTz ts);
@@ -778,8 +767,23 @@ extern void pgstat_create_transactional(PgStat_Kind kind, Oid dboid, uint64 obji
778767
* Variables in pgstat.c
779768
*/
780769

781-
extern PGDLLIMPORT PgStat_LocalState pgStatLocal;
770+
/*
771+
* Track if *any* pending fixed-numbered statistics should be flushed to
772+
* shared memory.
773+
*
774+
* This flag can be switched to true by fixed-numbered statistics to let
775+
* pgstat_report_stat() know if it needs to go through one round of
776+
* reports, calling flush_static_cb for each fixed-numbered statistics
777+
* kind. When this flag is not set, pgstat_report_stat() is able to do
778+
* a fast exit, knowing that there are no pending fixed-numbered statistics.
779+
*
780+
* Statistics callbacks should never reset this flag; pgstat_report_stat()
781+
* is in charge of doing that.
782+
*/
783+
extern PGDLLIMPORT bool pgstat_report_fixed;
782784

785+
/* Backend-local stats state */
786+
extern PGDLLIMPORT PgStat_LocalState pgStatLocal;
783787

784788
/*
785789
* Implementation of inline functions declared above.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy