Hi, Thanks for looking into this!
On Thu, 28 Nov 2024 at 16:39, Bertrand Drouvot <bertranddrouvot...@gmail.com> wrote: > > Hi, > > On Wed, Nov 27, 2024 at 11:08:01AM -0500, Melanie Plageman wrote: > > On Wed, Sep 11, 2024 at 7:19 AM Nazir Bilal Yavuz <byavu...@gmail.com> > > wrote: > > > > > > Currently, in the pg_stat_io view, IOs are counted as blocks. However, > > > there are two issues with this approach: > > > > > > 1- The actual number of IO requests to the kernel is lower because IO > > > requests can be merged before sending the final request. Additionally, it > > > appears that all IOs are counted in block size. > > > > I think this is a great idea. It will allow people to tune > > io_combine_limit as you mention below. > > > > > 2- Some IOs may not align with block size. For example, WAL read IOs are > > > done in variable bytes and it is not possible to correctly show these IOs > > > in the pg_stat_io view [1]. > > > > Yep, this makes a lot of sense as a solution. > > Thanks for the patch! I also think it makes sense. > > A few random comments: > > === 1 > > + /* > + * If IO done in bytes and byte is <= 0, this means there is an error > + * while doing an IO. Don't count these IOs. > + */ > > s/byte/bytes/? This is removed, please look below for the explanation. > also: > > The pgstat_io_count_checks() parameter is uint64. Does it mean it has to be > changed to int64? > > Also from what I can see the calls are done with those values: > > - 0 > - io_buffers_len * BLCKSZ > - extend_by * BLCKSZ > - BLCKSZ > > could io_buffers_len and extend_by be < 0? If not, is the comment correct? You are right, no need to have this check; it can not be less than 0. I completely removed the function now. > === 2 > > + Assert((io_op == IOOP_READ || io_op == IOOP_WRITE || io_op == > IOOP_EXTEND > > and > > + if ((io_op == IOOP_READ || io_op == IOOP_WRITE || io_op == > IOOP_EXTEND) && > > What about ordering the enum in IOOp (no bytes/bytes) so that we could check > that io_op >= "our firt bytes enum" instead? > > Also we could create a macro on top of that to make it clear. And a comment > would be needed around the IOOp definition. > > I think that would be simpler to maintain should we add no bytes or bytes op > in > the future. I think this is a good idea. I applied all the comments. Created an inline function instead of macro and added this 'Assert((unsigned int) io_object < IOOBJECT_NUM_TYPES);' to function. > === 3 > > +pgstat_io_count_checks(IOObject io_object, IOContext io_context, IOOp io_op, > uint64 bytes) > +{ > + Assert((unsigned int) io_object < IOOBJECT_NUM_TYPES); > + Assert((unsigned int) io_context < IOCONTEXT_NUM_TYPES); > + Assert((unsigned int) io_op < IOOP_NUM_TYPES); > + Assert(pgstat_tracks_io_op(MyBackendType, io_object, io_context, > io_op)); > > IOObject and IOContext are passed only for the assertions. What about removing > them from there and put the asserts in other places? Done. I moved these checks to the pgstat_count_io_op_n() function. The code looks more like its previous version now. > === 4 > > + /* Only IOOP_READ, IOOP_WRITE and IOOP_EXTEND can do IO in bytes. */ > > Not sure about "can do IO in bytes" (same wording is used in multiple places). I changed it to 'measured in bytes' but I am not sure if this is better, open to suggestions. > === 5 > > /* Convert to numeric. */ > > "convert to numeric"? to be consistent with others single line comments > around. Done. -- Regards, Nazir Bilal Yavuz Microsoft
From f4d67aa4de695bcb97f4043bf7bf6ea1962feb17 Mon Sep 17 00:00:00 2001 From: Nazir Bilal Yavuz <byavu...@gmail.com> Date: Wed, 4 Dec 2024 14:37:30 +0300 Subject: [PATCH v2] Make pg_stat_io count IOs as bytes instead of blocks Currently in pg_stat_io view, IOs are counted as blocks. There are two problems with this approach: 1- The actual number of I/O requests sent to the kernel is lower because I/O requests may be merged before being sent. Additionally, it gives the impression that all I/Os are done in block size, which shadows the benefits of merging I/O requests. 2- There may be some IOs which are not done in block size in the future. For example, WAL read IOs are done in variable bytes and it is not possible to correctly show these IOs in pg_stat_io view. Because of these problems, now show the total number of IO requests to the kernel (as smgr function calls) and total number of bytes in the IO. Also, remove op_bytes column from the pg_stat_io view. --- src/include/catalog/pg_proc.dat | 6 +- src/include/pgstat.h | 38 ++++++++--- src/backend/catalog/system_views.sql | 4 +- src/backend/storage/buffer/bufmgr.c | 14 ++--- src/backend/storage/buffer/localbuf.c | 6 +- src/backend/storage/smgr/md.c | 4 +- src/backend/utils/activity/pgstat_io.c | 17 +++-- src/backend/utils/adt/pgstatfuncs.c | 87 +++++++++++++++++++------- src/test/regress/expected/rules.out | 6 +- doc/src/sgml/monitoring.sgml | 61 +++++++++++------- 10 files changed, 167 insertions(+), 76 deletions(-) diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 9575524007f..a9f4d33205f 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5908,9 +5908,9 @@ proname => 'pg_stat_get_io', prorows => '30', proretset => 't', provolatile => 'v', proparallel => 'r', prorettype => 'record', proargtypes => '', - proallargtypes => '{text,text,text,int8,float8,int8,float8,int8,float8,int8,float8,int8,int8,int8,int8,int8,float8,timestamptz}', - proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', - proargnames => '{backend_type,object,context,reads,read_time,writes,write_time,writebacks,writeback_time,extends,extend_time,op_bytes,hits,evictions,reuses,fsyncs,fsync_time,stats_reset}', + proallargtypes => '{text,text,text,int8,numeric,float8,int8,numeric,float8,int8,float8,int8,numeric,float8,int8,int8,int8,int8,float8,timestamptz}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{backend_type,object,context,reads,read_bytes,read_time,writes,write_bytes,write_time,writebacks,writeback_time,extends,extend_bytes,extend_time,hits,evictions,reuses,fsyncs,fsync_time,stats_reset}', prosrc => 'pg_stat_get_io' }, { oid => '1136', descr => 'statistics: information about WAL activity', diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 59c28b4aca8..e8148adbc03 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -327,22 +327,44 @@ typedef enum IOContext #define IOCONTEXT_NUM_TYPES (IOCONTEXT_VACUUM + 1) +/* + * Enumeration of IO operations. + * + * This enum categorizes IO operations into two groups: + * non-byte-measured and byte-measured operations. So, that makes is easier + * to check whether IO is measured in bytes. + * + * Note: If this enum is modified, ensure that both `IOOP_NUM_TYPES` macro + * and the `ioop_measured_in_bytes` function are updated accordingly. + */ typedef enum IOOp { + /* IOs not measured in bytes */ IOOP_EVICT, - IOOP_EXTEND, IOOP_FSYNC, IOOP_HIT, - IOOP_READ, IOOP_REUSE, - IOOP_WRITE, IOOP_WRITEBACK, + + /* IOs measured in bytes */ + IOOP_EXTEND, + IOOP_READ, + IOOP_WRITE, } IOOp; -#define IOOP_NUM_TYPES (IOOP_WRITEBACK + 1) +#define IOOP_NUM_TYPES (IOOP_WRITE + 1) + +static inline bool +ioop_measured_in_bytes(IOOp io_op) +{ + Assert((unsigned int) io_op < IOOP_NUM_TYPES); + return io_op >= IOOP_EXTEND; +} + typedef struct PgStat_BktypeIO { + uint64 bytes[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]; PgStat_Counter counts[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]; PgStat_Counter times[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]; } PgStat_BktypeIO; @@ -557,11 +579,13 @@ extern PgStat_CheckpointerStats *pgstat_fetch_stat_checkpointer(void); extern bool pgstat_bktype_io_stats_valid(PgStat_BktypeIO *backend_io, BackendType bktype); -extern void pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op); -extern void pgstat_count_io_op_n(IOObject io_object, IOContext io_context, IOOp io_op, uint32 cnt); +extern void pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op, uint64 bytes); +extern void pgstat_count_io_op_n(IOObject io_object, IOContext io_context, + IOOp io_op, uint32 cnt, uint64 bytes); extern instr_time pgstat_prepare_io_time(bool track_io_guc); extern void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, - IOOp io_op, instr_time start_time, uint32 cnt); + IOOp io_op, instr_time start_time, + uint32 cnt, uint64 bytes); extern PgStat_IO *pgstat_fetch_stat_io(void); extern const char *pgstat_get_io_context_name(IOContext io_context); diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index da9a8fe99f2..801ea02e13f 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1156,14 +1156,16 @@ SELECT b.object, b.context, b.reads, + b.read_bytes, b.read_time, b.writes, + b.write_bytes, b.write_time, b.writebacks, b.writeback_time, b.extends, + b.extend_bytes, b.extend_time, - b.op_bytes, b.hits, b.evictions, b.reuses, diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index cc9782b7132..a42d5c3c262 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -1165,7 +1165,7 @@ PinBufferForBlock(Relation rel, } if (*foundPtr) { - pgstat_count_io_op(io_object, io_context, IOOP_HIT); + pgstat_count_io_op(io_object, io_context, IOOP_HIT, 0); if (VacuumCostActive) VacuumCostBalance += VacuumCostPageHit; @@ -1515,7 +1515,7 @@ WaitReadBuffers(ReadBuffersOperation *operation) io_start = pgstat_prepare_io_time(track_io_timing); smgrreadv(operation->smgr, forknum, io_first_block, io_pages, io_buffers_len); pgstat_count_io_op_time(io_object, io_context, IOOP_READ, io_start, - io_buffers_len); + 1, io_buffers_len * BLCKSZ); /* Verify each block we read, and terminate the I/O. */ for (int j = 0; j < io_buffers_len; ++j) @@ -2073,7 +2073,7 @@ again: * pinners or erroring out. */ pgstat_count_io_op(IOOBJECT_RELATION, io_context, - from_ring ? IOOP_REUSE : IOOP_EVICT); + from_ring ? IOOP_REUSE : IOOP_EVICT, 0); } /* @@ -2429,7 +2429,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, UnlockRelationForExtension(bmr.rel, ExclusiveLock); pgstat_count_io_op_time(IOOBJECT_RELATION, io_context, IOOP_EXTEND, - io_start, extend_by); + io_start, 1, extend_by * BLCKSZ); /* Set BM_VALID, terminate IO, and wake up any waiters */ for (uint32 i = 0; i < extend_by; i++) @@ -3891,7 +3891,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, * of a dirty shared buffer (IOCONTEXT_NORMAL IOOP_WRITE). */ pgstat_count_io_op_time(IOOBJECT_RELATION, io_context, - IOOP_WRITE, io_start, 1); + IOOP_WRITE, io_start, 1, BLCKSZ); pgBufferUsage.shared_blks_written++; @@ -4530,7 +4530,7 @@ FlushRelationBuffers(Relation rel) pgstat_count_io_op_time(IOOBJECT_TEMP_RELATION, IOCONTEXT_NORMAL, IOOP_WRITE, - io_start, 1); + io_start, 1, BLCKSZ); buf_state &= ~(BM_DIRTY | BM_JUST_DIRTIED); pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); @@ -6037,7 +6037,7 @@ IssuePendingWritebacks(WritebackContext *wb_context, IOContext io_context) * blocks of permanent relations. */ pgstat_count_io_op_time(IOOBJECT_RELATION, io_context, - IOOP_WRITEBACK, io_start, wb_context->nr_pending); + IOOP_WRITEBACK, io_start, wb_context->nr_pending, 0); wb_context->nr_pending = 0; } diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 6fd1a6418d2..f2ff7ab5ab1 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -255,7 +255,7 @@ GetLocalVictimBuffer(void) /* Temporary table I/O does not use Buffer Access Strategies */ pgstat_count_io_op_time(IOOBJECT_TEMP_RELATION, IOCONTEXT_NORMAL, - IOOP_WRITE, io_start, 1); + IOOP_WRITE, io_start, 1, BLCKSZ); /* Mark not-dirty now in case we error out below */ buf_state &= ~BM_DIRTY; @@ -279,7 +279,7 @@ GetLocalVictimBuffer(void) ClearBufferTag(&bufHdr->tag); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); - pgstat_count_io_op(IOOBJECT_TEMP_RELATION, IOCONTEXT_NORMAL, IOOP_EVICT); + pgstat_count_io_op(IOOBJECT_TEMP_RELATION, IOCONTEXT_NORMAL, IOOP_EVICT, 0); } return BufferDescriptorGetBuffer(bufHdr); @@ -419,7 +419,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, smgrzeroextend(bmr.smgr, fork, first_block, extend_by, false); pgstat_count_io_op_time(IOOBJECT_TEMP_RELATION, IOCONTEXT_NORMAL, IOOP_EXTEND, - io_start, extend_by); + io_start, 1, extend_by * BLCKSZ); for (uint32 i = 0; i < extend_by; i++) { diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index cc8a80ee961..6b275d67e12 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -1407,7 +1407,7 @@ register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg) * backend fsyncs. */ pgstat_count_io_op_time(IOOBJECT_RELATION, IOCONTEXT_NORMAL, - IOOP_FSYNC, io_start, 1); + IOOP_FSYNC, io_start, 1, 0); } } @@ -1794,7 +1794,7 @@ mdsyncfiletag(const FileTag *ftag, char *path) FileClose(file); pgstat_count_io_op_time(IOOBJECT_RELATION, IOCONTEXT_NORMAL, - IOOP_FSYNC, io_start, 1); + IOOP_FSYNC, io_start, 1, 0); errno = save_errno; return result; diff --git a/src/backend/utils/activity/pgstat_io.c b/src/backend/utils/activity/pgstat_io.c index f9883af2b3c..1e6235e088d 100644 --- a/src/backend/utils/activity/pgstat_io.c +++ b/src/backend/utils/activity/pgstat_io.c @@ -23,6 +23,7 @@ typedef struct PgStat_PendingIO { + uint64 bytes[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]; PgStat_Counter counts[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]; instr_time pending_times[IOOBJECT_NUM_TYPES][IOCONTEXT_NUM_TYPES][IOOP_NUM_TYPES]; } PgStat_PendingIO; @@ -31,7 +32,6 @@ typedef struct PgStat_PendingIO static PgStat_PendingIO PendingIOStats; static bool have_iostats = false; - /* * Check that stats have not been counted for any combination of IOObject, * IOContext, and IOOp which are not tracked for the passed-in BackendType. If @@ -74,20 +74,22 @@ pgstat_bktype_io_stats_valid(PgStat_BktypeIO *backend_io, } void -pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op) +pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op, uint64 bytes) { - pgstat_count_io_op_n(io_object, io_context, io_op, 1); + pgstat_count_io_op_n(io_object, io_context, io_op, 1, bytes); } void -pgstat_count_io_op_n(IOObject io_object, IOContext io_context, IOOp io_op, uint32 cnt) +pgstat_count_io_op_n(IOObject io_object, IOContext io_context, IOOp io_op, uint32 cnt, uint64 bytes) { Assert((unsigned int) io_object < IOOBJECT_NUM_TYPES); Assert((unsigned int) io_context < IOCONTEXT_NUM_TYPES); Assert((unsigned int) io_op < IOOP_NUM_TYPES); + Assert(ioop_measured_in_bytes(io_op) || bytes == 0); Assert(pgstat_tracks_io_op(MyBackendType, io_object, io_context, io_op)); PendingIOStats.counts[io_object][io_context][io_op] += cnt; + PendingIOStats.bytes[io_object][io_context][io_op] += bytes; have_iostats = true; } @@ -120,7 +122,7 @@ pgstat_prepare_io_time(bool track_io_guc) */ void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, - instr_time start_time, uint32 cnt) + instr_time start_time, uint32 cnt, uint64 bytes) { if (track_io_timing) { @@ -150,7 +152,7 @@ pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, io_time); } - pgstat_count_io_op_n(io_object, io_context, io_op, cnt); + pgstat_count_io_op_n(io_object, io_context, io_op, cnt, bytes); } PgStat_IO * @@ -216,6 +218,9 @@ pgstat_io_flush_cb(bool nowait) bktype_shstats->counts[io_object][io_context][io_op] += PendingIOStats.counts[io_object][io_context][io_op]; + bktype_shstats->bytes[io_object][io_context][io_op] += + PendingIOStats.bytes[io_object][io_context][io_op]; + time = PendingIOStats.pending_times[io_object][io_context][io_op]; bktype_shstats->times[io_object][io_context][io_op] += diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 60a397dc561..81adc51a47a 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -1290,14 +1290,16 @@ typedef enum io_stat_col IO_COL_OBJECT, IO_COL_CONTEXT, IO_COL_READS, + IO_COL_READ_BYTES, IO_COL_READ_TIME, IO_COL_WRITES, + IO_COL_WRITE_BYTES, IO_COL_WRITE_TIME, IO_COL_WRITEBACKS, IO_COL_WRITEBACK_TIME, IO_COL_EXTENDS, + IO_COL_EXTEND_BYTES, IO_COL_EXTEND_TIME, - IO_COL_CONVERSION, IO_COL_HITS, IO_COL_EVICTIONS, IO_COL_REUSES, @@ -1338,11 +1340,36 @@ pgstat_get_io_op_index(IOOp io_op) pg_unreachable(); } +/* + * Get the number of the column containing IO bytes for the specified IOOp. + * If an op does not do IO in bytes, IO_COL_INVALID is returned. + */ +static io_stat_col +pgstat_get_io_byte_index(IOOp io_op) +{ + switch (io_op) + { + case IOOP_EXTEND: + return IO_COL_EXTEND_BYTES; + case IOOP_READ: + return IO_COL_READ_BYTES; + case IOOP_WRITE: + return IO_COL_WRITE_BYTES; + case IOOP_EVICT: + case IOOP_FSYNC: + case IOOP_HIT: + case IOOP_REUSE: + case IOOP_WRITEBACK: + return IO_COL_INVALID; + } + + elog(ERROR, "unrecognized IOOp value: %d", io_op); + pg_unreachable(); +} + /* * Get the number of the column containing IO times for the specified IOOp. - * This function encodes our assumption that IO time for an IOOp is displayed - * in the view in the column directly after the IOOp counts. If an op has no - * associated time, IO_COL_INVALID is returned. + * If an op has no associated time, IO_COL_INVALID is returned. */ static io_stat_col pgstat_get_io_time_index(IOOp io_op) @@ -1350,11 +1377,15 @@ pgstat_get_io_time_index(IOOp io_op) switch (io_op) { case IOOP_READ: + return IO_COL_READ_TIME; case IOOP_WRITE: + return IO_COL_WRITE_TIME; case IOOP_WRITEBACK: + return IO_COL_WRITEBACK_TIME; case IOOP_EXTEND: + return IO_COL_EXTEND_TIME; case IOOP_FSYNC: - return pgstat_get_io_op_index(io_op) + 1; + return IO_COL_FSYNC_TIME; case IOOP_EVICT: case IOOP_HIT: case IOOP_REUSE: @@ -1428,17 +1459,10 @@ pg_stat_get_io(PG_FUNCTION_ARGS) values[IO_COL_OBJECT] = CStringGetTextDatum(obj_name); values[IO_COL_RESET_TIME] = reset_time; - /* - * Hard-code this to the value of BLCKSZ for now. Future - * values could include XLOG_BLCKSZ, once WAL IO is tracked, - * and constant multipliers, once non-block-oriented IO (e.g. - * temporary file IO) is tracked. - */ - values[IO_COL_CONVERSION] = Int64GetDatum(BLCKSZ); - for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++) { int op_idx = pgstat_get_io_op_index(io_op); + int byte_idx = pgstat_get_io_byte_index(io_op); int time_idx = pgstat_get_io_time_index(io_op); /* @@ -1456,19 +1480,40 @@ pg_stat_get_io(PG_FUNCTION_ARGS) else nulls[op_idx] = true; - /* not every operation is timed */ - if (time_idx == IO_COL_INVALID) - continue; - if (!nulls[op_idx]) { - PgStat_Counter time = - bktype_stats->times[io_obj][io_context][io_op]; + /* not every operation is timed */ + if (time_idx != IO_COL_INVALID) + { + PgStat_Counter time = + bktype_stats->times[io_obj][io_context][io_op]; - values[time_idx] = Float8GetDatum(pg_stat_us_to_ms(time)); + values[time_idx] = Float8GetDatum(pg_stat_us_to_ms(time)); + } + + /* not every IO measured in bytes */ + if (byte_idx != IO_COL_INVALID) + { + char buf[256]; + PgStat_Counter byte = + bktype_stats->bytes[io_obj][io_context][io_op]; + + /* Convert to numeric */ + snprintf(buf, sizeof buf, UINT64_FORMAT, byte); + values[byte_idx] = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + } } else - nulls[time_idx] = true; + { + if (time_idx != IO_COL_INVALID) + nulls[time_idx] = true; + if (byte_idx != IO_COL_INVALID) + nulls[byte_idx] = true; + } + } tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 3014d047fef..29580c90710 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1892,21 +1892,23 @@ pg_stat_io| SELECT backend_type, object, context, reads, + read_bytes, read_time, writes, + write_bytes, write_time, writebacks, writeback_time, extends, + extend_bytes, extend_time, - op_bytes, hits, evictions, reuses, fsyncs, fsync_time, stats_reset - FROM pg_stat_get_io() b(backend_type, object, context, reads, read_time, writes, write_time, writebacks, writeback_time, extends, extend_time, op_bytes, hits, evictions, reuses, fsyncs, fsync_time, stats_reset); + FROM pg_stat_get_io() b(backend_type, object, context, reads, read_bytes, read_time, writes, write_bytes, write_time, writebacks, writeback_time, extends, extend_bytes, extend_time, hits, evictions, reuses, fsyncs, fsync_time, stats_reset); pg_stat_progress_analyze| SELECT s.pid, s.datid, d.datname, diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 840d7f81615..d36433065c6 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -2692,8 +2692,18 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>reads</structfield> <type>bigint</type> </para> <para> - Number of read operations, each of the size specified in - <varname>op_bytes</varname>. + Number of read operations. + </para> + </entry> + </row> + + <row> + <entry role="catalog_table_entry"> + <para role="column_definition"> + <structfield>read_bytes</structfield> <type>bigint</type> + </para> + <para> + The total size of read operations in bytes. </para> </entry> </row> @@ -2716,8 +2726,18 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>writes</structfield> <type>bigint</type> </para> <para> - Number of write operations, each of the size specified in - <varname>op_bytes</varname>. + Number of write operations. + </para> + </entry> + </row> + + <row> + <entry role="catalog_table_entry"> + <para role="column_definition"> + <structfield>write_bytes</structfield> <type>bigint</type> + </para> + <para> + The total size of write operations in bytes. </para> </entry> </row> @@ -2740,7 +2760,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>writebacks</structfield> <type>bigint</type> </para> <para> - Number of units of size <varname>op_bytes</varname> which the process + Number of units of size <symbol>BLCKSZ</symbol> which the process requested the kernel write out to permanent storage. </para> </entry> @@ -2766,8 +2786,18 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>extends</structfield> <type>bigint</type> </para> <para> - Number of relation extend operations, each of the size specified in - <varname>op_bytes</varname>. + Number of relation extend operations. + </para> + </entry> + </row> + + <row> + <entry role="catalog_table_entry"> + <para role="column_definition"> + <structfield>extend_bytes</structfield> <type>bigint</type> + </para> + <para> + The total size of relation extend operations in bytes. </para> </entry> </row> @@ -2784,23 +2814,6 @@ description | Waiting for a newly initialized WAL file to reach durable storage </entry> </row> - <row> - <entry role="catalog_table_entry"> - <para role="column_definition"> - <structfield>op_bytes</structfield> <type>bigint</type> - </para> - <para> - The number of bytes per unit of I/O read, written, or extended. - </para> - <para> - Relation data reads, writes, and extends are done in - <varname>block_size</varname> units, derived from the build-time - parameter <symbol>BLCKSZ</symbol>, which is <literal>8192</literal> by - default. - </para> - </entry> - </row> - <row> <entry role="catalog_table_entry"> <para role="column_definition"> -- 2.45.2