aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2020-01-09 10:59:07 -0500
committerRobert Haas <rhaas@postgresql.org>2020-01-09 10:59:07 -0500
commited10f32e37e9a16814c25e400d7826745ae3c797 (patch)
treeee16979e46a05e2c6ffc03d92e20a9d8f9ac3732 /src
parent5acf6d8bb4ec23349604c7c15111959e657ff294 (diff)
downloadpostgresql-ed10f32e37e9a16814c25e400d7826745ae3c797.tar.gz
postgresql-ed10f32e37e9a16814c25e400d7826745ae3c797.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/system_views.sql6
-rw-r--r--src/backend/storage/ipc/shmem.c106
-rw-r--r--src/include/catalog/pg_proc.dat9
-rw-r--r--src/include/storage/shmem.h3
-rw-r--r--src/test/regress/expected/rules.out5
5 files changed, 126 insertions, 3 deletions
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2fc3e3ff90a..773edf85e78 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -547,6 +547,12 @@ CREATE VIEW pg_config AS
REVOKE ALL on pg_config FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION pg_config() FROM PUBLIC;
+CREATE VIEW pg_shmem_allocations AS
+ SELECT * FROM pg_get_shmem_allocations();
+
+REVOKE ALL ON pg_shmem_allocations FROM PUBLIC;
+REVOKE EXECUTE ON FUNCTION pg_get_shmem_allocations() FROM PUBLIC;
+
-- Statistics views
CREATE VIEW pg_stat_all_tables AS
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index a4f0ec1a673..2892a573e4a 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -66,12 +66,16 @@
#include "postgres.h"
#include "access/transam.h"
+#include "fmgr.h"
+#include "funcapi.h"
#include "miscadmin.h"
#include "storage/lwlock.h"
#include "storage/pg_shmem.h"
#include "storage/shmem.h"
#include "storage/spin.h"
+#include "utils/builtins.h"
+static void *ShmemAllocRaw(Size size, Size *allocated_size);
/* shared memory global variables */
@@ -157,8 +161,9 @@ void *
ShmemAlloc(Size size)
{
void *newSpace;
+ Size allocated_size;
- newSpace = ShmemAllocNoError(size);
+ newSpace = ShmemAllocRaw(size, &allocated_size);
if (!newSpace)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
@@ -175,6 +180,20 @@ ShmemAlloc(Size size)
void *
ShmemAllocNoError(Size size)
{
+ Size allocated_size;
+
+ return ShmemAllocRaw(size, &allocated_size);
+}
+
+/*
+ * ShmemAllocRaw -- allocate align chunk and return allocated size
+ *
+ * Also sets *allocated_size to the number of bytes allocated, which will
+ * be equal to the number requested plus any padding we choose to add.
+ */
+static void *
+ShmemAllocRaw(Size size, Size *allocated_size)
+{
Size newStart;
Size newFree;
void *newSpace;
@@ -191,6 +210,7 @@ ShmemAllocNoError(Size size)
* won't be sufficient.
*/
size = CACHELINEALIGN(size);
+ *allocated_size = size;
Assert(ShmemSegHdr != NULL);
@@ -441,8 +461,10 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
}
else
{
+ Size allocated_size;
+
/* It isn't in the table yet. allocate and initialize it */
- structPtr = ShmemAllocNoError(size);
+ structPtr = ShmemAllocRaw(size, &allocated_size);
if (structPtr == NULL)
{
/* out of memory; remove the failed ShmemIndex entry */
@@ -455,6 +477,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
name, size)));
}
result->size = size;
+ result->allocated_size = allocated_size;
result->location = structPtr;
}
@@ -503,3 +526,82 @@ mul_size(Size s1, Size s2)
errmsg("requested shared memory size overflows size_t")));
return result;
}
+
+/* SQL SRF showing allocated shared memory */
+Datum
+pg_get_shmem_allocations(PG_FUNCTION_ARGS)
+{
+#define PG_GET_SHMEM_SIZES_COLS 4
+ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ TupleDesc tupdesc;
+ Tuplestorestate *tupstore;
+ MemoryContext per_query_ctx;
+ MemoryContext oldcontext;
+ HASH_SEQ_STATUS hstat;
+ ShmemIndexEnt *ent;
+ Size named_allocated = 0;
+ Datum values[PG_GET_SHMEM_SIZES_COLS];
+ bool nulls[PG_GET_SHMEM_SIZES_COLS];
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not allowed in this context")));
+
+ /* Build a tuple descriptor for our result type */
+ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+ elog(ERROR, "return type must be a row type");
+
+ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+ oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+ tupstore = tuplestore_begin_heap(true, false, work_mem);
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ MemoryContextSwitchTo(oldcontext);
+
+ LWLockAcquire(ShmemIndexLock, LW_SHARED);
+
+ hash_seq_init(&hstat, ShmemIndex);
+
+ /* output all allocated entries */
+ memset(nulls, 0, sizeof(nulls));
+ while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
+ {
+ values[0] = CStringGetTextDatum(ent->key);
+ values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
+ values[2] = Int64GetDatum(ent->size);
+ values[3] = Int64GetDatum(ent->allocated_size);
+ named_allocated += ent->allocated_size;
+
+ tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+ }
+
+ /* output shared memory allocated but not counted via the shmem index */
+ values[0] = CStringGetTextDatum("<anonymous>");
+ nulls[1] = true;
+ values[2] = Int64GetDatum(ShmemSegHdr->freeoffset - named_allocated);
+ values[3] = values[2];
+ tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+
+ /* output as-of-yet unused shared memory */
+ nulls[0] = true;
+ values[1] = Int64GetDatum(ShmemSegHdr->freeoffset);
+ nulls[1] = false;
+ values[2] = Int64GetDatum(ShmemSegHdr->totalsize - ShmemSegHdr->freeoffset);
+ values[3] = values[2];
+ tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+
+ LWLockRelease(ShmemIndexLock);
+
+ tuplestore_donestoring(tupstore);
+
+ return (Datum) 0;
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 59f1ff01ab8..427faa3c3b6 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7663,6 +7663,15 @@
proparallel => 'r', prorettype => 'float8', proargtypes => '',
prosrc => 'pg_notification_queue_usage' },
+# shared memory usage
+{ oid => '8613',
+ descr => 'allocations from the main shared memory segment',
+ proname => 'pg_get_shmem_allocations', 'prorows' => 50, 'proretset' => 't',
+ provolatile => 'v', 'prorettype' => 'record', 'proargtypes' => '',
+ proallargtypes => '{text,int8,int8,int8}', proargmodes => '{o,o,o,o}',
+ proargnames => '{name,off,size,allocated_size}',
+ prosrc => 'pg_get_shmem_allocations' },
+
# non-persistent series generator
{ oid => '1066', descr => 'non-persistent series generator',
proname => 'generate_series', prorows => '1000',
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 243b73f8bbd..0c1af892062 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -59,7 +59,8 @@ typedef struct
{
char key[SHMEM_INDEX_KEYSIZE]; /* string name */
void *location; /* location in shared mem */
- Size size; /* # bytes allocated for the structure */
+ Size size; /* # bytes requested for the structure */
+ Size allocated_size; /* # bytes actually allocated */
} ShmemIndexEnt;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 80a07825b95..62eaf90a0f2 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1721,6 +1721,11 @@ pg_shadow| SELECT pg_authid.rolname AS usename,
FROM (pg_authid
LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid))))
WHERE pg_authid.rolcanlogin;
+pg_shmem_allocations| SELECT pg_get_shmem_allocations.name,
+ pg_get_shmem_allocations.off,
+ pg_get_shmem_allocations.size,
+ pg_get_shmem_allocations.allocated_size
+ FROM pg_get_shmem_allocations() pg_get_shmem_allocations(name, off, size, allocated_size);
pg_stat_activity| SELECT s.datid,
d.datname,
s.pid,