Skip to content

Commit 6448289

Browse files
committed
Expose track_iotiming data via the statistics collector.
Ants Aasma's original patch to add timing information for buffer I/O requests exposed this data at the relation level, which was judged too costly. I've here exposed it at the database level instead.
1 parent 05dbd4a commit 6448289

File tree

10 files changed

+99
-9
lines changed

10 files changed

+99
-9
lines changed

doc/src/sgml/config.sgml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4295,8 +4295,11 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
42954295
default, because it will repeatedly query the operating system for
42964296
the current time, which may cause significant overhead on some
42974297
platforms. You can use the <xref linkend="pgtesttiming"> tool to
4298-
measure the overhead of timing on your system. Only superusers can
4299-
change this setting.
4298+
measure the overhead of timing on your system. Timing information is
4299+
displayed in <xref linkend="pg-stat-database-view">, in the output of
4300+
<xref linkend="sql-explain"> when the <literal>BUFFERS</> option is
4301+
used, and by <xref linkend="pgstatstatements">. Only superusers can
4302+
change this setting.
43004303
</para>
43014304
</listitem>
43024305
</varlistentry>

doc/src/sgml/monitoring.sgml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
144144
statistics are collected about table and index accesses.
145145
</para>
146146

147+
<para>
148+
The parameter <xref linkend="guc-track-iotiming"> enables monitoring
149+
of block read and write times.
150+
</para>
151+
147152
<para>
148153
The parameter <xref linkend="guc-track-functions"> enables tracking of
149154
usage of user-defined functions.
@@ -961,6 +966,20 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
961966
This value can also be returned by directly calling
962967
the <function>pg_stat_get_db_deadlocks</function> function.</entry>
963968
</row>
969+
<row>
970+
<entry>block_read_time</entry>
971+
<entry><type>bigint</></entry>
972+
<entry>Time spent by backends reading data file blocks, in milliseconds.
973+
The same value can be returned in microseconds by directly calling
974+
the <function>pg_stat_get_db_block_time_read</function> function.</entry>
975+
</row>
976+
<row>
977+
<entry>block_write_time</entry>
978+
<entry><type>bigint</></entry>
979+
<entry>Time spent by backends writing data file blocks, in milliseconds.
980+
The same value can be returned in microseconds by directly calling
981+
the <function>pg_stat_get_db_block_time_write</function> function.</entry>
982+
</row>
964983
<row>
965984
<entry>stats_reset</entry>
966985
<entry><type>timestamptz</></entry>

src/backend/catalog/system_views.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,8 @@ CREATE VIEW pg_stat_database AS
604604
pg_stat_get_db_temp_files(D.oid) AS temp_files,
605605
pg_stat_get_db_temp_bytes(D.oid) AS temp_bytes,
606606
pg_stat_get_db_deadlocks(D.oid) AS deadlocks,
607+
pg_stat_get_db_block_time_read(D.oid) / 1000 AS block_read_time,
608+
pg_stat_get_db_block_time_write(D.oid) / 1000 AS block_write_time,
607609
pg_stat_get_db_stat_reset_time(D.oid) AS stats_reset
608610
FROM pg_database D;
609611

src/backend/postmaster/pgstat.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ static PgStat_SubXactStatus *pgStatXactStack = NULL;
197197

198198
static int pgStatXactCommit = 0;
199199
static int pgStatXactRollback = 0;
200+
PgStat_Counter pgStatBlockTimeRead = 0;
201+
PgStat_Counter pgStatBlockTimeWrite = 0;
200202

201203
/* Record that's written to 2PC state file when pgstat state is persisted */
202204
typedef struct TwoPhasePgStatRecord
@@ -782,20 +784,24 @@ pgstat_send_tabstat(PgStat_MsgTabstat *tsmsg)
782784
return;
783785

784786
/*
785-
* Report accumulated xact commit/rollback whenever we send a normal
786-
* tabstat message
787+
* Report accumulated xact commit/rollback and I/O timings whenever we send
788+
* a normal tabstat message
787789
*/
788790
if (OidIsValid(tsmsg->m_databaseid))
789791
{
790792
tsmsg->m_xact_commit = pgStatXactCommit;
791793
tsmsg->m_xact_rollback = pgStatXactRollback;
794+
tsmsg->m_block_time_read = pgStatBlockTimeRead;
795+
tsmsg->m_block_time_write = pgStatBlockTimeWrite;
792796
pgStatXactCommit = 0;
793797
pgStatXactRollback = 0;
794798
}
795799
else
796800
{
797801
tsmsg->m_xact_commit = 0;
798802
tsmsg->m_xact_rollback = 0;
803+
tsmsg->m_block_time_read = 0;
804+
tsmsg->m_block_time_write = 0;
799805
}
800806

801807
n = tsmsg->m_nentries;
@@ -3352,6 +3358,8 @@ pgstat_get_db_entry(Oid databaseid, bool create)
33523358
result->n_temp_files = 0;
33533359
result->n_temp_bytes = 0;
33543360
result->n_deadlocks = 0;
3361+
result->n_block_time_read = 0;
3362+
result->n_block_time_write = 0;
33553363

33563364
result->stat_reset_timestamp = GetCurrentTimestamp();
33573365

@@ -4070,6 +4078,8 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
40704078
*/
40714079
dbentry->n_xact_commit += (PgStat_Counter) (msg->m_xact_commit);
40724080
dbentry->n_xact_rollback += (PgStat_Counter) (msg->m_xact_rollback);
4081+
dbentry->n_block_time_read += msg->m_block_time_read;
4082+
dbentry->n_block_time_write += msg->m_block_time_write;
40734083

40744084
/*
40754085
* Process all table entries in the message.
@@ -4266,6 +4276,8 @@ pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
42664276
dbentry->n_temp_bytes = 0;
42674277
dbentry->n_temp_files = 0;
42684278
dbentry->n_deadlocks = 0;
4279+
dbentry->n_block_time_read = 0;
4280+
dbentry->n_block_time_write = 0;
42694281

42704282
dbentry->stat_reset_timestamp = GetCurrentTimestamp();
42714283

src/backend/storage/buffer/bufmgr.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
450450
{
451451
INSTR_TIME_SET_CURRENT(io_time);
452452
INSTR_TIME_SUBTRACT(io_time, io_start);
453+
pgstat_count_buffer_read_time(INSTR_TIME_GET_MICROSEC(io_time));
453454
INSTR_TIME_ADD(pgBufferUsage.time_read, io_time);
454455
}
455456

@@ -1888,7 +1889,8 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
18881889
{
18891890
XLogRecPtr recptr;
18901891
ErrorContextCallback errcontext;
1891-
instr_time io_start, io_end;
1892+
instr_time io_start,
1893+
io_time;
18921894

18931895
/*
18941896
* Acquire the buffer's io_in_progress lock. If StartBufferIO returns
@@ -1947,8 +1949,10 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
19471949

19481950
if (track_iotiming)
19491951
{
1950-
INSTR_TIME_SET_CURRENT(io_end);
1951-
INSTR_TIME_ACCUM_DIFF(pgBufferUsage.time_write, io_end, io_start);
1952+
INSTR_TIME_SET_CURRENT(io_time);
1953+
INSTR_TIME_SUBTRACT(io_time, io_start);
1954+
pgstat_count_buffer_write_time(INSTR_TIME_GET_MICROSEC(io_time));
1955+
INSTR_TIME_ADD(pgBufferUsage.time_write, io_time);
19521956
}
19531957

19541958
pgBufferUsage.shared_blks_written++;

src/backend/utils/adt/pgstatfuncs.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ extern Datum pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS);
8282
extern Datum pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS);
8383
extern Datum pg_stat_get_db_temp_files(PG_FUNCTION_ARGS);
8484
extern Datum pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS);
85+
extern Datum pg_stat_get_db_block_time_read(PG_FUNCTION_ARGS);
86+
extern Datum pg_stat_get_db_block_time_write(PG_FUNCTION_ARGS);
8587

8688
extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS);
8789
extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS);
@@ -1357,6 +1359,36 @@ pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS)
13571359
PG_RETURN_INT64(result);
13581360
}
13591361

1362+
Datum
1363+
pg_stat_get_db_block_time_read(PG_FUNCTION_ARGS)
1364+
{
1365+
Oid dbid = PG_GETARG_OID(0);
1366+
int64 result;
1367+
PgStat_StatDBEntry *dbentry;
1368+
1369+
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1370+
result = 0;
1371+
else
1372+
result = (int64) (dbentry->n_block_time_read);
1373+
1374+
PG_RETURN_INT64(result);
1375+
}
1376+
1377+
Datum
1378+
pg_stat_get_db_block_time_write(PG_FUNCTION_ARGS)
1379+
{
1380+
Oid dbid = PG_GETARG_OID(0);
1381+
int64 result;
1382+
PgStat_StatDBEntry *dbentry;
1383+
1384+
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1385+
result = 0;
1386+
else
1387+
result = (int64) (dbentry->n_block_time_write);
1388+
1389+
PG_RETURN_INT64(result);
1390+
}
1391+
13601392
Datum
13611393
pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
13621394
{

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201203191
56+
#define CATALOG_VERSION_NO 201204051
5757

5858
#endif

src/include/catalog/pg_proc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2662,6 +2662,10 @@ DATA(insert OID = 3150 ( pg_stat_get_db_temp_files PGNSP PGUID 12 1 0 0 0 f f f
26622662
DESCR("statistics: number of temporary files written");
26632663
DATA(insert OID = 3151 ( pg_stat_get_db_temp_bytes PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_temp_bytes _null_ _null_ _null_ ));
26642664
DESCR("statistics: number of bytes in temporary files written");
2665+
DATA(insert OID = 2844 ( pg_stat_get_db_block_time_read PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_block_time_read _null_ _null_ _null_ ));
2666+
DESCR("statistics: block read time in microseconds");
2667+
DATA(insert OID = 2845 ( pg_stat_get_db_block_time_write PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_block_time_write _null_ _null_ _null_ ));
2668+
DESCR("statistics: block write time in microseconds");
26652669
DATA(insert OID = 2769 ( pg_stat_get_bgwriter_timed_checkpoints PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_timed_checkpoints _null_ _null_ _null_ ));
26662670
DESCR("statistics: number of timed checkpoints started by the bgwriter");
26672671
DATA(insert OID = 2770 ( pg_stat_get_bgwriter_requested_checkpoints PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_requested_checkpoints _null_ _null_ _null_ ));

src/include/pgstat.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ typedef struct PgStat_MsgTabstat
233233
int m_nentries;
234234
int m_xact_commit;
235235
int m_xact_rollback;
236+
PgStat_Counter m_block_time_read;
237+
PgStat_Counter m_block_time_write;
236238
PgStat_TableEntry m_entry[PGSTAT_NUM_TABENTRIES];
237239
} PgStat_MsgTabstat;
238240

@@ -536,6 +538,8 @@ typedef struct PgStat_StatDBEntry
536538
PgStat_Counter n_temp_files;
537539
PgStat_Counter n_temp_bytes;
538540
PgStat_Counter n_deadlocks;
541+
PgStat_Counter n_block_time_read; /* times in microseconds */
542+
PgStat_Counter n_block_time_write;
539543

540544
TimestampTz stat_reset_timestamp;
541545

@@ -721,6 +725,12 @@ extern char *pgstat_stat_filename;
721725
*/
722726
extern PgStat_MsgBgWriter BgWriterStats;
723727

728+
/*
729+
* Updated by pgstat_count_time_* macros.
730+
*/
731+
extern PgStat_Counter pgStatBlockTimeRead;
732+
extern PgStat_Counter pgStatBlockTimeWrite;
733+
724734
/* ----------
725735
* Functions called from postmaster
726736
* ----------
@@ -816,6 +826,10 @@ extern void pgstat_initstats(Relation rel);
816826
if ((rel)->pgstat_info != NULL) \
817827
(rel)->pgstat_info->t_counts.t_blocks_hit++; \
818828
} while (0)
829+
#define pgstat_count_buffer_read_time(n) \
830+
pgStatBlockTimeRead += (n);
831+
#define pgstat_count_buffer_write_time(n) \
832+
pgStatBlockTimeWrite += (n);
819833

820834
extern void pgstat_count_heap_insert(Relation rel, int n);
821835
extern void pgstat_count_heap_update(Relation rel, bool hot);

src/test/regress/expected/rules.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
12961296
pg_stat_all_indexes | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
12971297
pg_stat_all_tables | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze, pg_stat_get_vacuum_count(c.oid) AS vacuum_count, pg_stat_get_autovacuum_count(c.oid) AS autovacuum_count, pg_stat_get_analyze_count(c.oid) AS analyze_count, pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
12981298
pg_stat_bgwriter | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_buf_written_backend() AS buffers_backend, pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync, pg_stat_get_buf_alloc() AS buffers_alloc, pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
1299-
pg_stat_database | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted, pg_stat_get_db_conflict_all(d.oid) AS conflicts, pg_stat_get_db_temp_files(d.oid) AS temp_files, pg_stat_get_db_temp_bytes(d.oid) AS temp_bytes, pg_stat_get_db_deadlocks(d.oid) AS deadlocks, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM pg_database d;
1299+
pg_stat_database | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted, pg_stat_get_db_conflict_all(d.oid) AS conflicts, pg_stat_get_db_temp_files(d.oid) AS temp_files, pg_stat_get_db_temp_bytes(d.oid) AS temp_bytes, pg_stat_get_db_deadlocks(d.oid) AS deadlocks, (pg_stat_get_db_block_time_read(d.oid) / 1000) AS block_read_time, (pg_stat_get_db_block_time_write(d.oid) / 1000) AS block_write_time, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM pg_database d;
13001300
pg_stat_database_conflicts | SELECT d.oid AS datid, d.datname, pg_stat_get_db_conflict_tablespace(d.oid) AS confl_tablespace, pg_stat_get_db_conflict_lock(d.oid) AS confl_lock, pg_stat_get_db_conflict_snapshot(d.oid) AS confl_snapshot, pg_stat_get_db_conflict_bufferpin(d.oid) AS confl_bufferpin, pg_stat_get_db_conflict_startup_deadlock(d.oid) AS confl_deadlock FROM pg_database d;
13011301
pg_stat_replication | SELECT s.pid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, w.state, w.sent_location, w.write_location, w.flush_location, w.replay_location, w.sync_priority, w.sync_state FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port), pg_authid u, pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) WHERE ((s.usesysid = u.oid) AND (s.pid = w.pid));
13021302
pg_stat_sys_indexes | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE ((pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_indexes.schemaname ~ '^pg_toast'::text));

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