Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ed10f32

Browse files
committed
Add pg_shmem_allocations view.
This tells you about allocations that have been made from the main shared memory segment. The original patch also tried to show information about dynamic shared memory allocation as well, but I decided to leave that problem for another time. Andres Freund and Robert Haas, reviewed by Michael Paquier, Marti Raudsepp, Tom Lane, Álvaro Herrera, and Kyotaro Horiguchi. Discussion: http://postgr.es/m/20140504114417.GM12715@awork2.anarazel.de
1 parent 5acf6d8 commit ed10f32

File tree

7 files changed

+212
-4
lines changed

7 files changed

+212
-4
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8362,6 +8362,11 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
83628362
<entry>planner statistics</entry>
83638363
</row>
83648364

8365+
<row>
8366+
<entry><link linkend="view-pg-shmem-allocations"><structname>pg_shmem_allocations</structname></link></entry>
8367+
<entry>shared memory allocations</entry>
8368+
</row>
8369+
83658370
<row>
83668371
<entry><link linkend="view-pg-stats-ext"><structname>pg_stats_ext</structname></link></entry>
83678372
<entry>extended planner statistics</entry>
@@ -10748,6 +10753,86 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
1074810753

1074910754
</sect1>
1075010755

10756+
<sect1 id="view-pg-shmem-allocations">
10757+
<title><structname>pg_shmem_allocations</structname></title>
10758+
10759+
<indexterm zone="view-pg-shmem-allocations">
10760+
<primary>pg_shmem_allocations</primary>
10761+
</indexterm>
10762+
10763+
<para>
10764+
The <structname>pg_shmem_allocations</structname> view shows allocations
10765+
made from the server's main shared memory segment. This includes both
10766+
memory allocated by <productname>postgres</productname> itself and memory
10767+
allocated by extensions using the mechanisms detailed in
10768+
<xref linkend="xfunc-shared-addin" />.
10769+
</para>
10770+
10771+
<para>
10772+
Note that this view does not include memory allocated using the dynamic
10773+
shared memory infrastructure.
10774+
</para>
10775+
10776+
<table>
10777+
<title><structname>pg_shmem_allocations</structname> Columns</title>
10778+
10779+
<tgroup cols="3">
10780+
<thead>
10781+
<row>
10782+
<entry>Name</entry>
10783+
<entry>Type</entry>
10784+
<entry>Description</entry>
10785+
</row>
10786+
</thead>
10787+
10788+
<tbody>
10789+
<row>
10790+
<entry><structfield>name</structfield></entry>
10791+
<entry><type>text</type></entry>
10792+
<entry>The name of the shared memory allocation. NULL for unused memory
10793+
and <literal>&lt;anonymous&gt;</literal> for anonymous
10794+
allocations.</entry>
10795+
</row>
10796+
10797+
<row>
10798+
<entry><structfield>off</structfield></entry>
10799+
<entry><type>bigint</type></entry>
10800+
<entry>The offset at which the allocation starts. NULL for anonymous
10801+
allocations and unused memory.</entry>
10802+
</row>
10803+
10804+
<row>
10805+
<entry><structfield>size</structfield></entry>
10806+
<entry><type>bigint</type></entry>
10807+
<entry>Size of the allocation</entry>
10808+
</row>
10809+
10810+
<row>
10811+
<entry><structfield>allocated_size</structfield></entry>
10812+
<entry><type>bigint</type></entry>
10813+
<entry>Size of the allocation including padding. For anonymous
10814+
allocations, no information about padding is available, so the
10815+
<literal>size</literal> and <literal>allocated_size</literal> columns
10816+
will always be equal. Padding is not meaningful for free memory, so
10817+
the columns will be equal in that case also.</entry>
10818+
</row>
10819+
</tbody>
10820+
</tgroup>
10821+
</table>
10822+
10823+
<para>
10824+
Anonymous allocations are allocations that have been made
10825+
with <literal>ShmemAlloc()</literal> directly, rather than via
10826+
<literal>ShmemInitStruct()</literal> or
10827+
<literal>ShmemInitHash()</literal>.
10828+
</para>
10829+
10830+
<para>
10831+
By default, the <structname>pg_shmem_allocations</structname> view can be
10832+
read only by superusers.
10833+
</para>
10834+
</sect1>
10835+
1075110836
<sect1 id="view-pg-stats">
1075210837
<title><structname>pg_stats</structname></title>
1075310838

doc/src/sgml/xfunc.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3239,7 +3239,7 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
32393239
</para>
32403240
</sect2>
32413241

3242-
<sect2>
3242+
<sect2 id="xfunc-shared-addin">
32433243
<title>Shared Memory and LWLocks</title>
32443244

32453245
<para>

src/backend/catalog/system_views.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,12 @@ CREATE VIEW pg_config AS
547547
REVOKE ALL on pg_config FROM PUBLIC;
548548
REVOKE EXECUTE ON FUNCTION pg_config() FROM PUBLIC;
549549

550+
CREATE VIEW pg_shmem_allocations AS
551+
SELECT * FROM pg_get_shmem_allocations();
552+
553+
REVOKE ALL ON pg_shmem_allocations FROM PUBLIC;
554+
REVOKE EXECUTE ON FUNCTION pg_get_shmem_allocations() FROM PUBLIC;
555+
550556
-- Statistics views
551557

552558
CREATE VIEW pg_stat_all_tables AS

src/backend/storage/ipc/shmem.c

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,16 @@
6666
#include "postgres.h"
6767

6868
#include "access/transam.h"
69+
#include "fmgr.h"
70+
#include "funcapi.h"
6971
#include "miscadmin.h"
7072
#include "storage/lwlock.h"
7173
#include "storage/pg_shmem.h"
7274
#include "storage/shmem.h"
7375
#include "storage/spin.h"
76+
#include "utils/builtins.h"
7477

78+
static void *ShmemAllocRaw(Size size, Size *allocated_size);
7579

7680
/* shared memory global variables */
7781

@@ -157,8 +161,9 @@ void *
157161
ShmemAlloc(Size size)
158162
{
159163
void *newSpace;
164+
Size allocated_size;
160165

161-
newSpace = ShmemAllocNoError(size);
166+
newSpace = ShmemAllocRaw(size, &allocated_size);
162167
if (!newSpace)
163168
ereport(ERROR,
164169
(errcode(ERRCODE_OUT_OF_MEMORY),
@@ -174,6 +179,20 @@ ShmemAlloc(Size size)
174179
*/
175180
void *
176181
ShmemAllocNoError(Size size)
182+
{
183+
Size allocated_size;
184+
185+
return ShmemAllocRaw(size, &allocated_size);
186+
}
187+
188+
/*
189+
* ShmemAllocRaw -- allocate align chunk and return allocated size
190+
*
191+
* Also sets *allocated_size to the number of bytes allocated, which will
192+
* be equal to the number requested plus any padding we choose to add.
193+
*/
194+
static void *
195+
ShmemAllocRaw(Size size, Size *allocated_size)
177196
{
178197
Size newStart;
179198
Size newFree;
@@ -191,6 +210,7 @@ ShmemAllocNoError(Size size)
191210
* won't be sufficient.
192211
*/
193212
size = CACHELINEALIGN(size);
213+
*allocated_size = size;
194214

195215
Assert(ShmemSegHdr != NULL);
196216

@@ -441,8 +461,10 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
441461
}
442462
else
443463
{
464+
Size allocated_size;
465+
444466
/* It isn't in the table yet. allocate and initialize it */
445-
structPtr = ShmemAllocNoError(size);
467+
structPtr = ShmemAllocRaw(size, &allocated_size);
446468
if (structPtr == NULL)
447469
{
448470
/* out of memory; remove the failed ShmemIndex entry */
@@ -455,6 +477,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
455477
name, size)));
456478
}
457479
result->size = size;
480+
result->allocated_size = allocated_size;
458481
result->location = structPtr;
459482
}
460483

@@ -503,3 +526,82 @@ mul_size(Size s1, Size s2)
503526
errmsg("requested shared memory size overflows size_t")));
504527
return result;
505528
}
529+
530+
/* SQL SRF showing allocated shared memory */
531+
Datum
532+
pg_get_shmem_allocations(PG_FUNCTION_ARGS)
533+
{
534+
#define PG_GET_SHMEM_SIZES_COLS 4
535+
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
536+
TupleDesc tupdesc;
537+
Tuplestorestate *tupstore;
538+
MemoryContext per_query_ctx;
539+
MemoryContext oldcontext;
540+
HASH_SEQ_STATUS hstat;
541+
ShmemIndexEnt *ent;
542+
Size named_allocated = 0;
543+
Datum values[PG_GET_SHMEM_SIZES_COLS];
544+
bool nulls[PG_GET_SHMEM_SIZES_COLS];
545+
546+
/* check to see if caller supports us returning a tuplestore */
547+
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
548+
ereport(ERROR,
549+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
550+
errmsg("set-valued function called in context that cannot accept a set")));
551+
if (!(rsinfo->allowedModes & SFRM_Materialize))
552+
ereport(ERROR,
553+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
554+
errmsg("materialize mode required, but it is not allowed in this context")));
555+
556+
/* Build a tuple descriptor for our result type */
557+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
558+
elog(ERROR, "return type must be a row type");
559+
560+
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
561+
oldcontext = MemoryContextSwitchTo(per_query_ctx);
562+
563+
tupstore = tuplestore_begin_heap(true, false, work_mem);
564+
rsinfo->returnMode = SFRM_Materialize;
565+
rsinfo->setResult = tupstore;
566+
rsinfo->setDesc = tupdesc;
567+
568+
MemoryContextSwitchTo(oldcontext);
569+
570+
LWLockAcquire(ShmemIndexLock, LW_SHARED);
571+
572+
hash_seq_init(&hstat, ShmemIndex);
573+
574+
/* output all allocated entries */
575+
memset(nulls, 0, sizeof(nulls));
576+
while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
577+
{
578+
values[0] = CStringGetTextDatum(ent->key);
579+
values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
580+
values[2] = Int64GetDatum(ent->size);
581+
values[3] = Int64GetDatum(ent->allocated_size);
582+
named_allocated += ent->allocated_size;
583+
584+
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
585+
}
586+
587+
/* output shared memory allocated but not counted via the shmem index */
588+
values[0] = CStringGetTextDatum("<anonymous>");
589+
nulls[1] = true;
590+
values[2] = Int64GetDatum(ShmemSegHdr->freeoffset - named_allocated);
591+
values[3] = values[2];
592+
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
593+
594+
/* output as-of-yet unused shared memory */
595+
nulls[0] = true;
596+
values[1] = Int64GetDatum(ShmemSegHdr->freeoffset);
597+
nulls[1] = false;
598+
values[2] = Int64GetDatum(ShmemSegHdr->totalsize - ShmemSegHdr->freeoffset);
599+
values[3] = values[2];
600+
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
601+
602+
LWLockRelease(ShmemIndexLock);
603+
604+
tuplestore_donestoring(tupstore);
605+
606+
return (Datum) 0;
607+
}

src/include/catalog/pg_proc.dat

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7663,6 +7663,15 @@
76637663
proparallel => 'r', prorettype => 'float8', proargtypes => '',
76647664
prosrc => 'pg_notification_queue_usage' },
76657665

7666+
# shared memory usage
7667+
{ oid => '8613',
7668+
descr => 'allocations from the main shared memory segment',
7669+
proname => 'pg_get_shmem_allocations', 'prorows' => 50, 'proretset' => 't',
7670+
provolatile => 'v', 'prorettype' => 'record', 'proargtypes' => '',
7671+
proallargtypes => '{text,int8,int8,int8}', proargmodes => '{o,o,o,o}',
7672+
proargnames => '{name,off,size,allocated_size}',
7673+
prosrc => 'pg_get_shmem_allocations' },
7674+
76667675
# non-persistent series generator
76677676
{ oid => '1066', descr => 'non-persistent series generator',
76687677
proname => 'generate_series', prorows => '1000',

src/include/storage/shmem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ typedef struct
5959
{
6060
char key[SHMEM_INDEX_KEYSIZE]; /* string name */
6161
void *location; /* location in shared mem */
62-
Size size; /* # bytes allocated for the structure */
62+
Size size; /* # bytes requested for the structure */
63+
Size allocated_size; /* # bytes actually allocated */
6364
} ShmemIndexEnt;
6465

6566
/*

src/test/regress/expected/rules.out

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,6 +1721,11 @@ pg_shadow| SELECT pg_authid.rolname AS usename,
17211721
FROM (pg_authid
17221722
LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid))))
17231723
WHERE pg_authid.rolcanlogin;
1724+
pg_shmem_allocations| SELECT pg_get_shmem_allocations.name,
1725+
pg_get_shmem_allocations.off,
1726+
pg_get_shmem_allocations.size,
1727+
pg_get_shmem_allocations.allocated_size
1728+
FROM pg_get_shmem_allocations() pg_get_shmem_allocations(name, off, size, allocated_size);
17241729
pg_stat_activity| SELECT s.datid,
17251730
d.datname,
17261731
s.pid,

0 commit comments

Comments
 (0)