Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qqyT7-001yPf-Bm for pgsql-hackers@arkaria.postgresql.org; Thu, 12 Oct 2023 16:23:26 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1qqyT4-009Apw-FG for pgsql-hackers@arkaria.postgresql.org; Thu, 12 Oct 2023 16:23:23 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qqyT2-009Apo-Kx for pgsql-hackers@lists.postgresql.org; Thu, 12 Oct 2023 16:23:22 +0000 Received: from out2-smtp.messagingengine.com ([66.111.4.26]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qqySv-0009Xe-Ky for pgsql-hackers@lists.postgresql.org; Thu, 12 Oct 2023 16:23:20 +0000 Received: from compute6.internal (compute6.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 7A1755C0226; Thu, 12 Oct 2023 12:23:11 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute6.internal (MEProxy); Thu, 12 Oct 2023 12:23:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=anarazel.de; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to; s=fm2; t= 1697127791; x=1697214191; bh=ORN/q0wk428Hl03d36K6GtkzuxIKf87TqBA 2TWnb9aY=; b=G7XnxYM1CfiN34qJcQ7oFhkijRTJyVCfERPHjNPe8zXu/KBj7Oh RHg7k0+ool8iKl11JPq1R3ko0rJcQGC5Kcf2zK5iJTeBb+0za4JWrpGH0sjJYisB 4DKAIcMt9Zw+rQdGsdh+tCzAhQUGpZcQ7QR3PnDJHaAp6N8ChN5E/Z8O7M92NI7H v7F0OzwfGnXTvCHU2PVmbg+pxZLYBikQxWf9rtof/IU1KIwMxvuoyYH7NI5ockWi 7DuL0A87+mxVDXNQbbKxfpEUXlfcegJFJeJDEsslh809KT/4Wlh5Po/JV9zMjlxd qGrRNyMmNIJLWE2w9sntLLhmwmOAXBOM2nw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1697127791; x=1697214191; bh=ORN/q0wk428Hl03d36K6GtkzuxIKf87TqBA 2TWnb9aY=; b=lZ9hEUejIhCTURw8Jdykt4XIIrlbj2O0iLHJHPPkYjDUjGeDpvw Pr2+RjX6EXbyzzPIirfaf8VCNjGI+r/qeDpDP3f8IGfCID9yZQ/ETN4sa+7FYWoT /9UKuCy8fkbuq4hmm+wzJV2Nkf5J2I4tDwQVlc1/fPW/w0w3yt0MN9s4VbSHeJX2 4slfLtFSf99ZOen8y/4jKr+81hSLi3l+di3vvTo1WVOcvtLAW4FEFgzc2UZzRO/s QN8SsymYfHKX4Mc8H1MfDtL+x46JUawZw3vUH6sBHg6v5ODPL/zHcmG8No3TRScW MNMjpG3iMhBUgcCZVsS/rlioIWu0/M9e0dg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvkedriedtgdeltdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpeffhffvvefukfhfgggtugfgjgesthekredttddtjeenucfhrhhomheptehnughr vghsucfhrhgvuhhnugcuoegrnhgurhgvshesrghnrghrrgiivghlrdguvgeqnecuggftrf grthhtvghrnhephfeitefgleevtedtffejvedujeekjedugfdtveffjeelvddtfeekgefg jefhgfegnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomh eprghnughrvghssegrnhgrrhgriigvlhdruggv X-ME-Proxy: Feedback-ID: id4a34324:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 12 Oct 2023 12:23:11 -0400 (EDT) Date: Thu, 12 Oct 2023 09:23:09 -0700 From: Andres Freund To: Melih Mutlu Cc: PostgreSQL Hackers Subject: Re: Parent/child context relation in pg_get_backend_memory_contexts() Message-ID: <20231012162309.4wmc2nb5tkt6pzml@awork3.anarazel.de> References: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, On 2023-08-04 21:16:49 +0300, Melih Mutlu wrote: > Melih Mutlu , 16 Haz 2023 Cum, 17:03 tarihinde şunu > yazdı: > > > With this change, here's a query to find how much space used by each > > context including its children: > > > > > WITH RECURSIVE cte AS ( > > > SELECT id, total_bytes, id as root, name as root_name > > > FROM memory_contexts > > > UNION ALL > > > SELECT r.id, r.total_bytes, cte.root, cte.root_name > > > FROM memory_contexts r > > > INNER JOIN cte ON r.parent_id = cte.id > > > ), > > > memory_contexts AS ( > > > SELECT * FROM pg_backend_memory_contexts > > > ) > > > SELECT root as id, root_name as name, sum(total_bytes) > > > FROM cte > > > GROUP BY root, root_name > > > ORDER BY sum DESC; > > > > Given that the above query to get total bytes including all children is > still a complex one, I decided to add an additional info in > pg_backend_memory_contexts. > The new "path" field displays an integer array that consists of ids of all > parents for the current context. This way it's easier to tell whether a > context is a child of another context, and we don't need to use recursive > queries to get this info. I think that does make it a good bit easier. Both to understand and to use. > Here how pg_backend_memory_contexts would look like with this patch: > > postgres=# SELECT name, id, parent, parent_id, path > FROM pg_backend_memory_contexts > ORDER BY total_bytes DESC LIMIT 10; > name | id | parent | parent_id | path > -------------------------+-----+------------------+-----------+-------------- > CacheMemoryContext | 27 | TopMemoryContext | 0 | {0} > Timezones | 124 | TopMemoryContext | 0 | {0} > TopMemoryContext | 0 | | | > MessageContext | 8 | TopMemoryContext | 0 | {0} > WAL record construction | 118 | TopMemoryContext | 0 | {0} > ExecutorState | 18 | PortalContext | 17 | {0,16,17} > TupleSort main | 19 | ExecutorState | 18 | {0,16,17,18} > TransactionAbortContext | 14 | TopMemoryContext | 0 | {0} > smgr relation table | 10 | TopMemoryContext | 0 | {0} > GUC hash table | 123 | GUCMemoryContext | 122 | {0,122} > (10 rows) Would we still need the parent_id column? > + > + > + > + context_id int4 > + > + > + Current context id > + > + I think the docs here need to warn that the id is ephemeral and will likely differ in the next invocation. > + > + > + parent_id int4 > + > + > + Parent context id > + > + > + > + > + > + path int4 > + > + > + Path to reach the current context from TopMemoryContext > + > + Perhaps we should include some hint here how it could be used? > > > > diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c > index 92ca5b2f72..81cb35dd47 100644 > --- a/src/backend/utils/adt/mcxtfuncs.c > +++ b/src/backend/utils/adt/mcxtfuncs.c > @@ -20,6 +20,7 @@ > #include "mb/pg_wchar.h" > #include "storage/proc.h" > #include "storage/procarray.h" > +#include "utils/array.h" > #include "utils/builtins.h" > > /* ---------- > @@ -28,6 +29,8 @@ > */ > #define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE 1024 > > +static Datum convert_path_to_datum(List *path); > + > /* > * PutMemoryContextsStatsTupleStore > * One recursion level for pg_get_backend_memory_contexts. > @@ -35,9 +38,10 @@ > static void > PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, > TupleDesc tupdesc, MemoryContext context, > - const char *parent, int level) > + const char *parent, int level, int *context_id, > + int parent_id, List *path) > { > -#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS 9 > +#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS 12 > > Datum values[PG_GET_BACKEND_MEMORY_CONTEXTS_COLS]; > bool nulls[PG_GET_BACKEND_MEMORY_CONTEXTS_COLS]; > @@ -45,6 +49,7 @@ PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, > MemoryContext child; > const char *name; > const char *ident; > + int current_context_id = (*context_id)++; > > Assert(MemoryContextIsValid(context)); > > @@ -103,13 +108,29 @@ PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, > values[6] = Int64GetDatum(stat.freespace); > values[7] = Int64GetDatum(stat.freechunks); > values[8] = Int64GetDatum(stat.totalspace - stat.freespace); > + values[9] = Int32GetDatum(current_context_id); > + > + if(parent_id < 0) > + /* TopMemoryContext has no parent context */ > + nulls[10] = true; > + else > + values[10] = Int32GetDatum(parent_id); > + > + if (path == NIL) > + nulls[11] = true; > + else > + values[11] = convert_path_to_datum(path); > + > tuplestore_putvalues(tupstore, tupdesc, values, nulls); > > + path = lappend_int(path, current_context_id); > for (child = context->firstchild; child != NULL; child = child->nextchild) > { > - PutMemoryContextsStatsTupleStore(tupstore, tupdesc, > - child, name, level + 1); > + PutMemoryContextsStatsTupleStore(tupstore, tupdesc, child, name, > + level+1, context_id, > + current_context_id, path); > } > + path = list_delete_last(path); > } > > /* > @@ -120,10 +141,15 @@ Datum > pg_get_backend_memory_contexts(PG_FUNCTION_ARGS) > { > ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; > + int context_id = 0; > + List *path = NIL; > + > + elog(LOG, "pg_get_backend_memory_contexts called"); > > InitMaterializedSRF(fcinfo, 0); > PutMemoryContextsStatsTupleStore(rsinfo->setResult, rsinfo->setDesc, > - TopMemoryContext, NULL, 0); > + TopMemoryContext, NULL, 0, &context_id, > + -1, path); > > return (Datum) 0; > } > @@ -193,3 +219,26 @@ pg_log_backend_memory_contexts(PG_FUNCTION_ARGS) > > PG_RETURN_BOOL(true); > } > + > +/* > + * Convert a list of context ids to a int[] Datum > + */ > +static Datum > +convert_path_to_datum(List *path) > +{ > + Datum *datum_array; > + int length; > + ArrayType *result_array; > + ListCell *lc; > + > + length = list_length(path); > + datum_array = (Datum *) palloc(length * sizeof(Datum)); > + length = 0; > + foreach(lc, path) > + { > + datum_array[length++] = Int32GetDatum((int) lfirst_int(lc)); The "(int)" in front of lfirst_int() seems redundant? I think it'd be good to have some minimal test for this. E.g. checking that there's multiple contexts below cache memory context or such. Greetings, Andres Freund