Skip to content

Commit 31f781e

Browse files
author
Sergey Dudoladov
committed
Add pg_stat_session
Author: Sergey Dudoladov Adds pg_stat_session view to track statistics accumulated during lifetime of a session. Reviewed-by: Aleksander Alekseev, Bertrand Drouvot, and Atsushi Torikoshi Discussion: https://www.postgresql.org/message-id/flat/CA%2BFpmFcJF0vwi-SWW0wYO-c-FbhyawLq4tCpRDCJJ8Bq%3Dja-gA%40mail.gmail.com
1 parent a4a9c4e commit 31f781e

File tree

7 files changed

+345
-9
lines changed

7 files changed

+345
-9
lines changed

doc/src/sgml/monitoring.sgml

Lines changed: 153 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>
@@ -5315,6 +5329,129 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
53155329
</tgroup>
53165330
</table>
53175331

5332+
<table id="monitoring-pg-stat-session-view" xreflabel="pg_stat_session">
5333+
<title><structname>pg_stat_session</structname> View</title>
5334+
<tgroup cols="1">
5335+
<thead>
5336+
<row>
5337+
<entry role="catalog_table_entry"><para role="column_definition">
5338+
Column Type
5339+
</para>
5340+
<para>
5341+
Description
5342+
</para></entry>
5343+
</row>
5344+
</thead>
5345+
5346+
<tbody>
5347+
<row>
5348+
<entry role="catalog_table_entry"><para role="column_definition">
5349+
<structfield>pid</structfield> <type>integer</type>
5350+
</para>
5351+
<para>
5352+
Process ID of this backend.
5353+
</para></entry>
5354+
</row>
5355+
5356+
<row>
5357+
<entry role="catalog_table_entry"><para role="column_definition">
5358+
<structfield>total_running_time</structfield> <type>double precision</type>
5359+
</para>
5360+
<para>
5361+
Time in milliseconds this backend spent in the <literal>running</literal> state.
5362+
</para></entry>
5363+
</row>
5364+
5365+
<row>
5366+
<entry role="catalog_table_entry"><para role="column_definition">
5367+
<structfield>total_running_count</structfield> <type>bigint</type>
5368+
</para>
5369+
<para>
5370+
Number of times this backend switched to the <literal>running</literal> state.
5371+
</para></entry>
5372+
</row>
5373+
5374+
<row>
5375+
<entry role="catalog_table_entry"><para role="column_definition">
5376+
<structfield>total_idle_time</structfield> <type>double precision</type>
5377+
</para>
5378+
<para>
5379+
Time in milliseconds this backend spent in the <literal>idle</literal> state.
5380+
</para></entry>
5381+
</row>
5382+
5383+
<row>
5384+
<entry role="catalog_table_entry"><para role="column_definition">
5385+
<structfield>total_idle_count</structfield> <type>bigint</type>
5386+
</para>
5387+
<para>
5388+
Number of times this backend switched to the <literal>idle</literal> state.
5389+
</para></entry>
5390+
</row>
5391+
5392+
<row>
5393+
<entry role="catalog_table_entry"><para role="column_definition">
5394+
<structfield>total_transaction_idle_time</structfield> <type>double precision</type>
5395+
</para>
5396+
<para>
5397+
Time in milliseconds this backend spent in the <literal>idle in transaction</literal>
5398+
state.
5399+
</para></entry>
5400+
</row>
5401+
5402+
<row>
5403+
<entry role="catalog_table_entry"><para role="column_definition">
5404+
<structfield>total_transaction_idle_count</structfield> <type>bigint</type>
5405+
</para>
5406+
<para>
5407+
Number of times this backend switched to the <literal>idle in transaction</literal>
5408+
state.
5409+
</para></entry>
5410+
</row>
5411+
5412+
<row>
5413+
<entry role="catalog_table_entry"><para role="column_definition">
5414+
<structfield>total_transaction_idle_aborted_time</structfield> <type>double precision</type>
5415+
</para>
5416+
<para>
5417+
Time in milliseconds this backend spent in the <literal>idle in transaction (aborted)</literal>
5418+
state.
5419+
</para></entry>
5420+
</row>
5421+
5422+
<row>
5423+
<entry role="catalog_table_entry"><para role="column_definition">
5424+
<structfield>total_transaction_idle_aborted_count</structfield> <type>bigint</type>
5425+
</para>
5426+
<para>
5427+
Number of times this backend switched to the <literal>idle in transaction (aborted)</literal>
5428+
state.
5429+
</para></entry>
5430+
</row>
5431+
5432+
<row>
5433+
<entry role="catalog_table_entry"><para role="column_definition">
5434+
<structfield>total_fastpath_time</structfield> <type>double precision</type>
5435+
</para>
5436+
<para>
5437+
Time in milliseconds this backend spent in the <literal>fastpath</literal> state.
5438+
</para></entry>
5439+
</row>
5440+
5441+
<row>
5442+
<entry role="catalog_table_entry"><para role="column_definition">
5443+
<structfield>total_fastpath_count</structfield> <type>bigint</type>
5444+
</para>
5445+
<para>
5446+
Number of times this backend switched to the <literal>fastpath</literal>
5447+
state.
5448+
</para></entry>
5449+
</row>
5450+
5451+
</tbody>
5452+
</tgroup>
5453+
</table>
5454+
53185455
</sect2>
53195456

53205457
<sect2 id="monitoring-stats-functions">
@@ -5382,6 +5519,22 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
53825519
</para></entry>
53835520
</row>
53845521

5522+
<row>
5523+
<entry role="func_table_entry"><para role="func_signature">
5524+
<indexterm>
5525+
<primary>pg_stat_get_session</primary>
5526+
</indexterm>
5527+
<function>pg_stat_get_session</function> ( <type>integer</type> )
5528+
<returnvalue>setof record</returnvalue>
5529+
</para>
5530+
<para>
5531+
Returns a record of information about the backend with the specified
5532+
process ID, or one record for each active backend in the system
5533+
if <literal>NULL</literal> is specified. The fields returned are a
5534+
subset of those in the <structname>pg_stat_session</structname> view.
5535+
</para></entry>
5536+
</row>
5537+
53855538
<row>
53865539
<entry role="func_table_entry"><para role="func_signature">
53875540
<indexterm>

src/backend/catalog/system_views.sql

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

873+
CREATE VIEW pg_stat_session AS
874+
SELECT
875+
s.pid,
876+
s.total_running_time,
877+
s.total_running_count,
878+
s.total_idle_time,
879+
s.total_idle_count,
880+
s.total_transaction_idle_time,
881+
s.total_transaction_idle_count,
882+
s.total_transaction_idle_aborted_time,
883+
s.total_transaction_idle_aborted_count,
884+
s.total_fastpath_time,
885+
s.total_fastpath_count
886+
FROM pg_stat_get_session(NULL) as s;
887+
873888
CREATE VIEW pg_stat_replication AS
874889
SELECT
875890
S.pid,

src/backend/utils/activity/backend_status.c

Lines changed: 49 additions & 9 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,7 @@ 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+
MemSet(&beentry->st_session, 0, sizeof(beentry->st_session));
553559
PGSTAT_END_WRITE_ACTIVITY(beentry);
554560
}
555561
return;
@@ -572,27 +578,46 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
572578
current_timestamp = GetCurrentTimestamp();
573579

574580
/*
575-
* If the state has changed from "active" or "idle in transaction",
576-
* calculate the duration.
581+
* If the state has changed, update per-database and per-session counters.
577582
*/
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) &&
583+
if ((PGSTAT_IS_ACTIVE(beentry) ||
584+
PGSTAT_IS_IDLEINTRANSACTION(beentry) ||
585+
PGSTAT_IS_IDLEINTRANSACTION_ABORTED(beentry) ||
586+
PGSTAT_IS_IDLE(beentry)) &&
582587
state != beentry->st_state)
583588
{
584589
long secs;
585590
int usecs;
591+
int64 usecs_diff;
586592

587593
TimestampDifference(beentry->st_state_start_timestamp,
588594
current_timestamp,
589595
&secs, &usecs);
596+
usecs_diff = secs * 1000000 + usecs;
590597

591-
if (beentry->st_state == STATE_RUNNING ||
592-
beentry->st_state == STATE_FASTPATH)
598+
/* Keep statistics for pg_stat_database intact */
599+
if (PGSTAT_IS_ACTIVE(beentry))
593600
pgstat_count_conn_active_time((PgStat_Counter) secs * 1000000 + usecs);
594-
else
601+
else if (PGSTAT_IS_IDLEINTRANSACTION(beentry) ||
602+
PGSTAT_IS_IDLEINTRANSACTION_ABORTED(beentry))
595603
pgstat_count_conn_txn_idle_time((PgStat_Counter) secs * 1000000 + usecs);
604+
605+
if (PGSTAT_IS_RUNNING(beentry)) {
606+
st_session_diff.total_running_time = usecs_diff;
607+
st_session_diff.total_running_count += 1;
608+
} else if (PGSTAT_IS_IDLE(beentry)){
609+
st_session_diff.total_idle_time = usecs_diff;
610+
st_session_diff.total_idle_count += 1;
611+
} else if (PGSTAT_IS_IDLEINTRANSACTION(beentry)){
612+
st_session_diff.total_transaction_idle_time = usecs_diff;
613+
st_session_diff.total_transaction_idle_count += 1;
614+
} else if (PGSTAT_IS_IDLEINTRANSACTION_ABORTED(beentry)){
615+
st_session_diff.total_transaction_idle_aborted_time = usecs_diff;
616+
st_session_diff.total_transaction_idle_aborted_count += 1;
617+
} else if (PGSTAT_IS_FASTPATH(beentry)){
618+
st_session_diff.total_fastpath_time = usecs_diff;
619+
st_session_diff.total_fastpath_count += 1;
620+
}
596621
}
597622

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

646+
beentry->st_session.total_running_time += st_session_diff.total_running_time;
647+
beentry->st_session.total_running_count += st_session_diff.total_running_count;
648+
649+
beentry->st_session.total_idle_time += st_session_diff.total_idle_time;
650+
beentry->st_session.total_idle_count += st_session_diff.total_idle_count;
651+
652+
beentry->st_session.total_transaction_idle_time += st_session_diff.total_transaction_idle_time;
653+
beentry->st_session.total_transaction_idle_count += st_session_diff.total_transaction_idle_count;
654+
655+
beentry->st_session.total_transaction_idle_aborted_time += st_session_diff.total_transaction_idle_aborted_time;
656+
beentry->st_session.total_transaction_idle_aborted_count += st_session_diff.total_transaction_idle_aborted_count;
657+
658+
beentry->st_session.total_fastpath_time += st_session_diff.total_fastpath_time;
659+
beentry->st_session.total_fastpath_count += st_session_diff.total_fastpath_count;
660+
621661
PGSTAT_END_WRITE_ACTIVITY(beentry);
622662
}
623663

src/backend/utils/adt/pgstatfuncs.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,76 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
297297
return (Datum) 0;
298298
}
299299

300+
/*
301+
* Returns accumulated statistics of current PG backends.
302+
*/
303+
Datum
304+
pg_stat_get_session(PG_FUNCTION_ARGS)
305+
{
306+
#define PG_STAT_GET_SESSION_COLS 11
307+
int num_backends = pgstat_fetch_stat_numbackends();
308+
int curr_backend;
309+
int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
310+
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
311+
312+
InitMaterializedSRF(fcinfo, 0);
313+
314+
/* 1-based index */
315+
for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
316+
{
317+
/* for each row */
318+
Datum values[PG_STAT_GET_SESSION_COLS] = {0};
319+
bool nulls[PG_STAT_GET_SESSION_COLS] = {0};
320+
LocalPgBackendStatus *local_beentry;
321+
PgBackendStatus *beentry;
322+
323+
/* Get the next one in the list */
324+
local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
325+
beentry = &local_beentry->backendStatus;
326+
327+
/* If looking for specific PID, ignore all the others */
328+
if (pid != -1 && beentry->st_procpid != pid)
329+
continue;
330+
331+
/* Values available to all callers */
332+
values[0] = Int32GetDatum(beentry->st_procpid);
333+
334+
/* Values only available to role member or pg_read_all_stats */
335+
if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid)){
336+
/* convert to msec */
337+
values[1] = Float8GetDatum(beentry->st_session.total_running_time / 1000.0);
338+
values[2] = Int64GetDatum(beentry->st_session.total_running_count);
339+
values[3] = Float8GetDatum(beentry->st_session.total_idle_time / 1000.0);
340+
values[4] = Int64GetDatum(beentry->st_session.total_idle_count);
341+
values[5] = Float8GetDatum(beentry->st_session.total_transaction_idle_time / 1000.0);
342+
values[6] = Int64GetDatum(beentry->st_session.total_transaction_idle_count);
343+
values[7] = Float8GetDatum(beentry->st_session.total_transaction_idle_aborted_time / 1000.0);
344+
values[8] = Int64GetDatum(beentry->st_session.total_transaction_idle_aborted_count);
345+
values[9] = Float8GetDatum(beentry->st_session.total_fastpath_time / 1000.0);
346+
values[10] = Int64GetDatum(beentry->st_session.total_fastpath_count);
347+
} else {
348+
nulls[1] = true;
349+
nulls[2] = true;
350+
nulls[3] = true;
351+
nulls[4] = true;
352+
nulls[5] = true;
353+
nulls[6] = true;
354+
nulls[7] = true;
355+
nulls[8] = true;
356+
nulls[9] = true;
357+
nulls[10] = true;
358+
}
359+
360+
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
361+
362+
/* If only a single backend was requested, and we found it, break. */
363+
if (pid != -1)
364+
break;
365+
}
366+
367+
return (Datum) 0;
368+
}
369+
300370
/*
301371
* Returns activity of PG backends.
302372
*/

src/include/catalog/pg_proc.dat

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5408,6 +5408,15 @@
54085408
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}',
54095409
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}',
54105410
prosrc => 'pg_stat_get_activity' },
5411+
{ oid => '2173',
5412+
descr => 'statistics: cumulative information about currently active backends',
5413+
proname => 'pg_stat_get_session', prorows => '100', proisstrict => 'f',
5414+
proretset => 't', provolatile => 's', proparallel => 'r',
5415+
prorettype => 'record', proargtypes => 'int4',
5416+
proallargtypes => '{int4,int4,float8,int8,float8,int8,float8,int8,float8,int8,float8,int8}',
5417+
proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o}',
5418+
proargnames => '{pid,pid,total_running_time,total_running_count,total_idle_time,total_idle_count,total_transaction_idle_time,total_transaction_idle_count,total_transaction_idle_aborted_time,total_transaction_idle_aborted_count,total_fastpath_time,total_fastpath_count}',
5419+
prosrc => 'pg_stat_get_session' },
54115420
{ oid => '3318',
54125421
descr => 'statistics: information about progress of backends running maintenance command',
54135422
proname => 'pg_stat_get_progress_info', prorows => '100', proretset => 't',

0 commit comments

Comments
 (0)