1/* -------------------------------------------------------------------------
4 * Implementation of IO statistics.
6 * This file contains the implementation of IO statistics. It is kept separate
7 * from pgstat.c to enforce the line between the statistics access / storage
8 * implementation and the details about individual types of statistics.
10 * Copyright (c) 2021-2025, PostgreSQL Global Development Group
13 * src/backend/utils/activity/pgstat_io.c
14 * -------------------------------------------------------------------------
27 * Check that stats have not been counted for any combination of IOObject,
28 * IOContext, and IOOp which are not tracked for the passed-in BackendType. If
29 * stats are tracked for this combination and IO times are non-zero, counts
32 * The passed-in PgStat_BktypeIO must contain stats from the BackendType
33 * specified by the second parameter. Caller is responsible for locking the
34 * passed-in PgStat_BktypeIO, if needed.
49 /* ensure that if IO times are non-zero, counts are > 0 */
50 if (backend_io->
times[io_object][io_context][io_op] != 0 &&
51 backend_io->
counts[io_object][io_context][io_op] <= 0)
57 /* we don't track it, and it is not 0 */
58 if (backend_io->
counts[io_object][io_context][io_op] != 0)
79 /* Add the per-backend counts */
87 * Initialize the internal timing for an IO operation, depending on an
100 * There is no need to set io_start when an IO timing GUC is disabled.
101 * Initialize it to zero to avoid compiler warnings and to let
102 * pgstat_count_io_op_time() know that timings should be ignored.
111 * Like pgstat_count_io_op() except it also accumulates time.
113 * The calls related to pgstat_count_buffer_*() are for pgstat_database. As
114 * pg_stat_database only counts block read and write times, these are done for
115 * IOOP_READ, IOOP_WRITE and IOOP_EXTEND.
117 * pgBufferUsage is used for EXPLAIN. pgBufferUsage has write and read stats
118 * for shared, local and temporary blocks. pg_stat_io does not track the
119 * activity of temporary blocks, so these are ignored here.
155 /* Add the per-backend count */
172 * Simpler wrapper of pgstat_io_flush_cb()
181 * Flush out locally pending IO statistics
183 * If no stats have been recorded, this function returns false.
185 * If nowait is true, this function returns true if the lock could not be
186 * acquired. Otherwise, return false.
214 bktype_shstats->
counts[io_object][io_context][io_op] +=
217 bktype_shstats->
bytes[io_object][io_context][io_op] +=
222 bktype_shstats->
times[io_object][io_context][io_op] +=
256 elog(
ERROR,
"unrecognized IOContext value: %d", io_context);
268 return "temp relation";
273 elog(
ERROR,
"unrecognized IOObject value: %d", io_object);
297 * Use the lock in the first BackendType's PgStat_BktypeIO to protect
298 * the reset timestamp as well.
303 memset(bktype_shstats, 0,
sizeof(*bktype_shstats));
320 * Use the lock in the first BackendType's PgStat_BktypeIO to protect
321 * the reset timestamp as well.
327 /* using struct assignment due to better type safety */
328 *bktype_snap = *bktype_shstats;
334* IO statistics are not collected for all BackendTypes.
336* The following BackendTypes do not participate in the cumulative stats
337* subsystem or do not perform IO on which we currently track:
338* - Dead-end backend because it is not connected to shared memory and
340* - Syslogger because it is not connected to shared memory
341* - Archiver because most relevant archiving IO is delegated to a
342* specialized command or module
344* Function returns true if BackendType participates in the cumulative stats
345* subsystem for IO and false if it does not.
347* When adding a new BackendType, also consider adding relevant restrictions to
348* pgstat_tracks_io_object() and pgstat_tracks_io_op().
354 * List every type so that new backend types trigger a warning about
355 * needing to adjust this switch.
386 * Some BackendTypes do not perform IO on certain IOObjects or in certain
387 * IOContexts. Some IOObjects are never operated on in some IOContexts. Check
388 * that the given BackendType is expected to do IO in the given IOContext and
389 * on the given IOObject and that the given IOObject is expected to be operated
390 * on in the given IOContext.
399 * Some BackendTypes should never track IO statistics.
405 * Currently, IO on IOOBJECT_WAL objects can only occur in the
406 * IOCONTEXT_NORMAL and IOCONTEXT_INIT IOContexts.
414 * Currently, IO on temporary relations can only occur in the
415 * IOCONTEXT_NORMAL IOContext.
422 * In core Postgres, only regular backends and WAL Sender processes
423 * executing queries will use local buffers and operate on temporary
424 * relations. Parallel workers will not use local buffers (see
425 * InitLocalBuffers()); however, extensions leveraging background workers
426 * have no such limitation, so track IO on IOOBJECT_TEMP_RELATION for
427 * BackendType B_BG_WORKER.
440 * Some BackendTypes only perform IO under IOOBJECT_WAL, hence exclude all
441 * rows for all the other objects for these.
448 * Some BackendTypes do not currently perform any IO in certain
449 * IOContexts, and, while it may not be inherently incorrect for them to
450 * do so, excluding those rows from the view makes the view easier to use.
469 * Some BackendTypes will never do certain IOOps and some IOOps should not
470 * occur in certain IOContexts or on certain IOObjects. Check that the given
471 * IOOp is valid for the given BackendType in the given IOContext and on the
472 * given IOObject. Note that there are currently no cases of an IOOp being
473 * invalid for a particular BackendType only within a certain IOContext and/or
474 * only on a certain IOObject.
480 bool strategy_io_context;
482 /* if (io_context, io_object) will never collect stats, we're done */
487 * Some BackendTypes will not do certain IOOps.
503 * Some BackendTypes do not perform reads with IOOBJECT_WAL.
512 * Temporary tables are not logged and thus do not require fsync'ing.
513 * Writeback is not requested for temporary tables.
520 * Some IOOps are not valid in certain IOContexts and some IOOps are only
521 * valid in certain contexts.
530 * IOOP_REUSE is only relevant when a BufferAccessStrategy is in use.
532 if (!strategy_io_context && io_op ==
IOOP_REUSE)
536 * IOOBJECT_WAL IOObject will not do certain IOOps depending on IOContext.
547 * IOOP_FSYNC IOOps done by a backend using a BufferAccessStrategy are
548 * counted in the IOCONTEXT_NORMAL IOContext. See comment in
549 * register_dirty_segment() for more details.
551 if (strategy_io_context && io_op ==
IOOP_FSYNC)
Assert(PointerIsAligned(start, uint64))
#define INSTR_TIME_SET_CURRENT(t)
#define INSTR_TIME_ADD(x, y)
#define INSTR_TIME_IS_ZERO(t)
#define INSTR_TIME_SUBTRACT(x, y)
#define INSTR_TIME_GET_MICROSEC(t)
#define INSTR_TIME_SET_ZERO(t)
BufferUsage pgBufferUsage
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void LWLockRelease(LWLock *lock)
void LWLockInitialize(LWLock *lock, int tranche_id)
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
#define BACKEND_NUM_TYPES
BackendType MyBackendType
void pgstat_snapshot_fixed(PgStat_Kind kind)
PgStat_LocalState pgStatLocal
#define pgstat_count_buffer_read_time(n)
#define pgstat_is_ioop_tracked_in_bytes(io_op)
#define pgstat_count_buffer_write_time(n)
#define IOCONTEXT_NUM_TYPES
#define IOOBJECT_NUM_TYPES
void pgstat_count_backend_io_op(IOObject io_object, IOContext io_context, IOOp io_op, uint32 cnt, uint64 bytes)
void pgstat_count_backend_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, instr_time io_time)
instr_time pgstat_prepare_io_time(bool track_io_guc)
void pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op, uint32 cnt, uint64 bytes)
void pgstat_flush_io(bool nowait)
void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, instr_time start_time, uint32 cnt, uint64 bytes)
PgStat_IO * pgstat_fetch_stat_io(void)
const char * pgstat_get_io_context_name(IOContext io_context)
bool pgstat_tracks_io_bktype(BackendType bktype)
const char * pgstat_get_io_object_name(IOObject io_object)
bool pgstat_io_flush_cb(bool nowait)
void pgstat_io_reset_all_cb(TimestampTz ts)
bool pgstat_bktype_io_stats_valid(PgStat_BktypeIO *backend_io, BackendType bktype)
static PgStat_PendingIO PendingIOStats
bool pgstat_tracks_io_op(BackendType bktype, IOObject io_object, IOContext io_context, IOOp io_op)
void pgstat_io_snapshot_cb(void)
void pgstat_io_init_shmem_cb(void *stats)
bool pgstat_tracks_io_object(BackendType bktype, IOObject io_object, IOContext io_context)
instr_time local_blk_read_time
instr_time shared_blk_read_time
instr_time shared_blk_write_time
instr_time local_blk_write_time
LWLock locks[BACKEND_NUM_TYPES]
PgStat_Counter times[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]
uint64 bytes[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]
PgStat_Counter counts[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]
PgStat_BktypeIO stats[BACKEND_NUM_TYPES]
TimestampTz stat_reset_timestamp
PgStat_ShmemControl * shmem
PgStat_Counter counts[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]
uint64 bytes[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]
instr_time pending_times[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]