Skip to content

Commit 52acfe4

Browse files
author
Sergey Dudoladov
committed
1 parent 61f1fc6 commit 52acfe4

File tree

7 files changed

+214
-6
lines changed

7 files changed

+214
-6
lines changed

doc/src/sgml/monitoring.sgml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,20 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
414414
See <xref linkend='copy-progress-reporting'/>.
415415
</entry>
416416
</row>
417+
418+
<row>
419+
<entry>
420+
<structname>pg_stat_session</structname>
421+
<indexterm><primary>pg_stat_session</primary></indexterm>
422+
</entry>
423+
<entry>
424+
One row per server process, showing information related to
425+
the currently accumulated activity of that process, such as time spent in
426+
a certain state.
427+
See <link linkend="monitoring-pg-stat-session-view">
428+
<structname>pg_stat_session</structname></link> for details.
429+
</entry>
430+
</row>
417431
</tbody>
418432
</tgroup>
419433
</table>
@@ -5261,6 +5275,53 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
52615275
</tgroup>
52625276
</table>
52635277

5278+
<table id="pg-stat-session-view" xreflabel="pg_stat_session">
5279+
<title><structname>pg_stat_session</structname> View</title>
5280+
<tgroup cols="1">
5281+
<thead>
5282+
<row>
5283+
<entry role="catalog_table_entry"><para role="column_definition">
5284+
Column Type
5285+
</para>
5286+
<para>
5287+
Description
5288+
</para></entry>
5289+
</row>
5290+
</thead>
5291+
5292+
<tbody>
5293+
<row>
5294+
<entry role="catalog_table_entry"><para role="column_definition">
5295+
<structfield>pid</structfield> <type>integer</type>
5296+
</para>
5297+
<para>
5298+
Process ID of this backend
5299+
</para></entry>
5300+
</row>
5301+
5302+
<row>
5303+
<entry role="catalog_table_entry"><para role="column_definition">
5304+
<structfield>total_active_time</structfield> <type>double precision</type>
5305+
</para>
5306+
<para>
5307+
Time in milliseconds this backend spent in <literal>active</literal> and
5308+
<literal>fastpath function call</literal> states.
5309+
</para></entry>
5310+
</row>
5311+
5312+
<row>
5313+
<entry role="catalog_table_entry"><para role="column_definition">
5314+
<structfield>total_idle_in_transaction_time</structfield> <type>double precision</type>
5315+
</para>
5316+
<para>
5317+
Time in milliseconds this backend spent in <literal>idle in transaction</literal>
5318+
and <literal>idle in transaction (aborted)</literal> states.
5319+
</para></entry>
5320+
</row>
5321+
</tbody>
5322+
</tgroup>
5323+
</table>
5324+
52645325
</sect2>
52655326

52665327
<sect2 id="monitoring-stats-functions">
@@ -5328,6 +5389,22 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
53285389
</para></entry>
53295390
</row>
53305391

5392+
<row>
5393+
<entry role="func_table_entry"><para role="func_signature">
5394+
<indexterm>
5395+
<primary>pg_stat_get_session</primary>
5396+
</indexterm>
5397+
<function>pg_stat_get_session</function> ( <type>integer</type> )
5398+
<returnvalue>setof record</returnvalue>
5399+
</para>
5400+
<para>
5401+
Returns a record of information about the backend with the specified
5402+
process ID, or one record for each active backend in the system
5403+
if <literal>NULL</literal> is specified. The fields returned are a
5404+
subset of those in the <structname>pg_stat_session</structname> view.
5405+
</para></entry>
5406+
</row>
5407+
53315408
<row>
53325409
<entry role="func_table_entry"><para role="func_signature">
53335410
<indexterm>

src/backend/catalog/system_views.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,15 @@ CREATE VIEW pg_stat_activity AS
871871
LEFT JOIN pg_database AS D ON (S.datid = D.oid)
872872
LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid);
873873

874+
--CREATE VIEW pg_stat_session AS
875+
-- SELECT
876+
-- S.pid,
877+
-- S.total_active_time,
878+
-- S.total_transaction_idle_time,
879+
-- S.total_transaction_idle_count
880+
-- S.total_active_count,
881+
-- FROM pg_stat_get_session(NULL) as S;
882+
874883
CREATE VIEW pg_stat_replication AS
875884
SELECT
876885
S.pid,

src/backend/utils/activity/backend_status.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ pgstat_bestart(void)
338338
lbeentry.st_xact_start_timestamp = 0;
339339
lbeentry.st_databaseid = MyDatabaseId;
340340

341+
MemSet(&lbeentry.st_session, 0, sizeof(lbeentry.st_session));
342+
341343
/* We have userid for client-backends, wal-sender and bgworker processes */
342344
if (lbeentry.st_backendType == B_BACKEND
343345
|| lbeentry.st_backendType == B_WAL_SENDER
@@ -525,6 +527,9 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
525527
TimestampTz current_timestamp;
526528
int len = 0;
527529

530+
PgBackendSessionStatus st_session_diff;
531+
MemSet(&st_session_diff, 0, sizeof(st_session_diff));
532+
528533
TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
529534

530535
if (!beentry)
@@ -550,6 +555,10 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
550555
beentry->st_xact_start_timestamp = 0;
551556
beentry->st_query_id = UINT64CONST(0);
552557
proc->wait_event_info = 0;
558+
beentry->st_session.total_active_time = 0;
559+
beentry->st_session.total_active_count = 0;
560+
beentry->st_session.total_transaction_idle_time = 0;
561+
beentry->st_session.total_transaction_idle_count = 0;
553562
PGSTAT_END_WRITE_ACTIVITY(beentry);
554563
}
555564
return;
@@ -575,24 +584,40 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
575584
* If the state has changed from "active" or "idle in transaction",
576585
* calculate the duration.
577586
*/
578-
if ((beentry->st_state == STATE_RUNNING ||
579-
beentry->st_state == STATE_FASTPATH ||
580-
beentry->st_state == STATE_IDLEINTRANSACTION ||
581-
beentry->st_state == STATE_IDLEINTRANSACTION_ABORTED) &&
587+
if ((PGSTAT_IS_ACTIVE(beentry) || PGSTAT_IS_IDLEINTRANSACTION(beentry)) &&
582588
state != beentry->st_state)
583589
{
584590
long secs;
585591
int usecs;
592+
int64 usecs_diff;
586593

587594
TimestampDifference(beentry->st_state_start_timestamp,
588595
current_timestamp,
589596
&secs, &usecs);
597+
usecs_diff = secs * 1000000 + usecs;
590598

591-
if (beentry->st_state == STATE_RUNNING ||
592-
beentry->st_state == STATE_FASTPATH)
599+
if (PGSTAT_IS_ACTIVE(beentry))
593600
pgstat_count_conn_active_time((PgStat_Counter) secs * 1000000 + usecs);
594601
else
595602
pgstat_count_conn_txn_idle_time((PgStat_Counter) secs * 1000000 + usecs);
603+
604+
/*
605+
* We update per-backend st_total_active_time and st_total_transaction_idle_time
606+
* separately from pgStatActiveTime and pgStatTransactionIdleTime
607+
* used in pg_stat_database to provide per-DB statistics because
608+
* 1. Changing the former values implies modifying beentry and thus
609+
* have to be wrapped into PGSTAT_*_WRITE_ACTIVITY macros (see below).
610+
* 2. The latter values are reset to 0 once the data has been sent
611+
* to the statistics collector.
612+
*/
613+
if (PGSTAT_IS_ACTIVE(beentry)) {
614+
st_session_diff.total_active_time = usecs_diff;
615+
st_session_diff.total_active_count += 1;
616+
}
617+
else {
618+
st_session_diff.total_transaction_idle_time = usecs_diff;
619+
st_session_diff.total_transaction_idle_count += 1;
620+
}
596621
}
597622

598623
/*
@@ -618,6 +643,12 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
618643
beentry->st_activity_start_timestamp = start_timestamp;
619644
}
620645

646+
beentry->st_session.total_active_time += st_session_diff.total_active_time;
647+
beentry->st_session.total_active_count += st_session_diff.total_active_count;
648+
649+
beentry->st_session.total_transaction_idle_time += st_session_diff.total_transaction_idle_time;
650+
beentry->st_session.total_transaction_idle_count += st_session_diff.total_transaction_idle_count;
651+
621652
PGSTAT_END_WRITE_ACTIVITY(beentry);
622653
}
623654

src/backend/utils/adt/pgstatfuncs.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,55 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
553553
return (Datum) 0;
554554
}
555555

556+
/*
557+
* Returns accumulated statistics of currently active PG backends.
558+
*/
559+
Datum
560+
pg_stat_get_session(PG_FUNCTION_ARGS)
561+
{
562+
#define PG_STAT_GET_SESSION_COLS 5
563+
int num_backends = pgstat_fetch_stat_numbackends();
564+
int curr_backend;
565+
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
566+
567+
InitMaterializedSRF(fcinfo, 0);
568+
569+
/* 1-based index */
570+
for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
571+
{
572+
/* for each row */
573+
Datum values[PG_STAT_GET_SESSION_COLS] = {0};
574+
bool nulls[PG_STAT_GET_SESSION_COLS] = {0};
575+
LocalPgBackendStatus *local_beentry;
576+
PgBackendStatus *beentry;
577+
578+
/* Get the next one in the list */
579+
local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
580+
beentry = &local_beentry->backendStatus;
581+
582+
/* Values available to all callers */
583+
values[0] = Int32GetDatum(beentry->st_procpid);
584+
585+
/* Values only available to role member or pg_read_all_stats */
586+
if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid)){
587+
/* convert to msec */
588+
values[1] = Float8GetDatum(beentry->st_session.total_active_time / 1000.0);
589+
values[2] = Int64GetDatum(beentry->st_session.total_active_count);
590+
values[3] = Float8GetDatum(beentry->st_session.total_transaction_idle_time / 1000.0);
591+
values[4] = Int64GetDatum(beentry->st_session.total_transaction_idle_count);
592+
} else {
593+
nulls[1] = true;
594+
nulls[2] = true;
595+
nulls[3] = true;
596+
nulls[4] = true;
597+
}
598+
599+
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
600+
}
601+
602+
return (Datum) 0;
603+
}
604+
556605
/*
557606
* Returns activity of PG backends.
558607
*/

src/include/catalog/pg_proc.dat

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5351,6 +5351,15 @@
53515351
proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
53525352
proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,leader_pid,query_id}',
53535353
prosrc => 'pg_stat_get_activity' },
5354+
{ oid => '2173',
5355+
descr => 'statistics: cumulative information about currently active backends',
5356+
proname => 'pg_stat_get_session', prorows => '100', proisstrict => 'f',
5357+
proretset => 't', provolatile => 's', proparallel => 'r',
5358+
prorettype => 'record', proargtypes => 'int4',
5359+
proallargtypes => '{int4,float8,int8,float8,int8}',
5360+
proargmodes => '{i,o,o,o,o}',
5361+
proargnames => '{pid,total_active_time,total_active_count,total_transaction_idle_time,total_transaction_idle_count}',
5362+
prosrc => 'pg_stat_get_session' },
53545363
{ oid => '3318',
53555364
descr => 'statistics: information about progress of backends running maintenance command',
53565365
proname => 'pg_stat_get_progress_info', prorows => '100', proretset => 't',

src/include/utils/backend_status.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,22 @@ typedef struct PgBackendGSSStatus
8080

8181
} PgBackendGSSStatus;
8282

83+
/*
84+
* PgBackendSessionStatus
85+
*
86+
* For each backend, we keep per-session cumulative counters in a within
87+
* PgBackendStatus struct. The struct is always filled.
88+
*
89+
* All char arrays must be null-terminated.
90+
*/
91+
typedef struct PgBackendSessionStatus
92+
{
93+
/* Counters accumulated since the start of the session */
94+
int64 total_active_time;
95+
int64 total_active_count;
96+
int64 total_transaction_idle_time;
97+
int64 total_transaction_idle_count;
98+
} PgBackendSessionStatus;
8399

84100
/* ----------
85101
* PgBackendStatus
@@ -169,6 +185,9 @@ typedef struct PgBackendStatus
169185

170186
/* query identifier, optionally computed using post_parse_analyze_hook */
171187
uint64 st_query_id;
188+
189+
/* Counters accumulated since the start of the session */
190+
PgBackendSessionStatus st_session;
172191
} PgBackendStatus;
173192

174193

@@ -233,6 +252,14 @@ typedef struct PgBackendStatus
233252
((before_changecount) & 1) == 0)
234253

235254

255+
/* Macros to identify the states for time accounting */
256+
#define PGSTAT_IS_ACTIVE(s) \
257+
((s)->st_state == STATE_RUNNING || (s)->st_state == STATE_FASTPATH)
258+
#define PGSTAT_IS_IDLEINTRANSACTION(s) \
259+
((s)->st_state == STATE_IDLEINTRANSACTION || \
260+
(s)->st_state == STATE_IDLEINTRANSACTION_ABORTED)
261+
262+
236263
/* ----------
237264
* LocalPgBackendStatus
238265
*

src/test/regress/expected/rules.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,12 @@ pg_stat_replication_slots| SELECT s.slot_name,
20682068
FROM pg_replication_slots r,
20692069
LATERAL pg_stat_get_replication_slot((r.slot_name)::text) s(slot_name, spill_txns, spill_count, spill_bytes, stream_txns, stream_count, stream_bytes, total_txns, total_bytes, stats_reset)
20702070
WHERE (r.datoid IS NOT NULL);
2071+
pg_stat_session| SELECT s.pid,
2072+
s.total_active_time,
2073+
s.total_active_count,
2074+
s.total_transaction_idle_time,
2075+
s.total_transaction_idle_count
2076+
FROM pg_stat_get_session(NULL::integer) s(pid integer, total_active_time double precision, total_active_count integer, total_transaction_idle_time double precision, total_transaction_idle_count integer);
20712077
pg_stat_slru| SELECT s.name,
20722078
s.blks_zeroed,
20732079
s.blks_hit,

0 commit comments

Comments
 (0)