Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7b5ef8f

Browse files
committed
Limit the verbosity of memory context statistics dumps.
We had a report from Stefan Kaltenbrunner of a case in which postmasterlog files overran available disk space because multiple backends spewedenormous context stats dumps upon hitting an out-of-memory condition.Given the lack of similar reports, this isn't a common problem, but itstill seems worth doing something about. However, we don't want to justblindly truncate the output, because that might prevent diagnosis of OOMproblems. What seems like a workable compromise is to limit the dump to100 child contexts per parent, and summarize the space used within anyadditional child contexts. That should help because practical cases wherethe dump gets long will typically be huge numbers of siblings under thesame parent context; while the additional debugging value from seeingdetails about individual siblings beyond 100 will not be large, we hope.Anyway it doesn't take much code or memory space to do this, so let's tryit like this and see how things go.Since the summarization mechanism requires passing totals back up anyway,I took the opportunity to add a "grand total" line to the end of theprintout.
1 parente39c4af commit7b5ef8f

File tree

4 files changed

+142
-21
lines changed

4 files changed

+142
-21
lines changed

‎src/backend/utils/mmgr/aset.c

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ static void AllocSetReset(MemoryContext context);
253253
staticvoidAllocSetDelete(MemoryContextcontext);
254254
staticSizeAllocSetGetChunkSpace(MemoryContextcontext,void*pointer);
255255
staticboolAllocSetIsEmpty(MemoryContextcontext);
256-
staticvoidAllocSetStats(MemoryContextcontext,intlevel);
256+
staticvoidAllocSetStats(MemoryContextcontext,intlevel,boolprint,
257+
MemoryContextCounters*totals);
257258

258259
#ifdefMEMORY_CONTEXT_CHECKING
259260
staticvoidAllocSetCheck(MemoryContextcontext);
@@ -1228,20 +1229,23 @@ AllocSetIsEmpty(MemoryContext context)
12281229

12291230
/*
12301231
* AllocSetStats
1231-
*Displays stats about memory consumption of an allocset.
1232+
*Compute stats about memory consumption of an allocset.
1233+
*
1234+
* level: recursion level (0 at top level); used for print indentation.
1235+
* print: true to print stats to stderr.
1236+
* totals: if not NULL, add stats about this allocset into *totals.
12321237
*/
12331238
staticvoid
1234-
AllocSetStats(MemoryContextcontext,intlevel)
1239+
AllocSetStats(MemoryContextcontext,intlevel,boolprint,
1240+
MemoryContextCounters*totals)
12351241
{
12361242
AllocSetset= (AllocSet)context;
12371243
Sizenblocks=0;
1238-
Sizenchunks=0;
1244+
Sizefreechunks=0;
12391245
Sizetotalspace=0;
12401246
Sizefreespace=0;
12411247
AllocBlockblock;
1242-
AllocChunkchunk;
12431248
intfidx;
1244-
inti;
12451249

12461250
for (block=set->blocks;block!=NULL;block=block->next)
12471251
{
@@ -1251,21 +1255,35 @@ AllocSetStats(MemoryContext context, int level)
12511255
}
12521256
for (fidx=0;fidx<ALLOCSET_NUM_FREELISTS;fidx++)
12531257
{
1258+
AllocChunkchunk;
1259+
12541260
for (chunk=set->freelist[fidx];chunk!=NULL;
12551261
chunk= (AllocChunk)chunk->aset)
12561262
{
1257-
nchunks++;
1263+
freechunks++;
12581264
freespace+=chunk->size+ALLOC_CHUNKHDRSZ;
12591265
}
12601266
}
12611267

1262-
for (i=0;i<level;i++)
1263-
fprintf(stderr," ");
1268+
if (print)
1269+
{
1270+
inti;
12641271

1265-
fprintf(stderr,
1272+
for (i=0;i<level;i++)
1273+
fprintf(stderr," ");
1274+
fprintf(stderr,
12661275
"%s: %zu total in %zd blocks; %zu free (%zd chunks); %zu used\n",
1267-
set->header.name,totalspace,nblocks,freespace,nchunks,
1268-
totalspace-freespace);
1276+
set->header.name,totalspace,nblocks,freespace,freechunks,
1277+
totalspace-freespace);
1278+
}
1279+
1280+
if (totals)
1281+
{
1282+
totals->nblocks+=nblocks;
1283+
totals->freechunks+=freechunks;
1284+
totals->totalspace+=totalspace;
1285+
totals->freespace+=freespace;
1286+
}
12691287
}
12701288

12711289

‎src/backend/utils/mmgr/mcxt.c

Lines changed: 91 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ MemoryContext CurTransactionContext = NULL;
5252
MemoryContextPortalContext=NULL;
5353

5454
staticvoidMemoryContextCallResetCallbacks(MemoryContextcontext);
55-
staticvoidMemoryContextStatsInternal(MemoryContextcontext,intlevel);
55+
staticvoidMemoryContextStatsInternal(MemoryContextcontext,intlevel,
56+
boolprint,intmax_children,
57+
MemoryContextCounters*totals);
5658

5759
/*
5860
* You should not do memory allocations within a critical section, because
@@ -477,25 +479,106 @@ MemoryContextIsEmpty(MemoryContext context)
477479
* MemoryContextStats
478480
*Print statistics about the named context and all its descendants.
479481
*
480-
* This is just a debugging utility, so it's not fancy. The statistics
481-
* are merely sent to stderr.
482+
* This is just a debugging utility, so it's not very fancy. However, we do
483+
* make some effort to summarize when the output would otherwise be very long.
484+
* The statistics are sent to stderr.
482485
*/
483486
void
484487
MemoryContextStats(MemoryContextcontext)
485488
{
486-
MemoryContextStatsInternal(context,0);
489+
/* A hard-wired limit on the number of children is usually good enough */
490+
MemoryContextStatsDetail(context,100);
487491
}
488492

493+
/*
494+
* MemoryContextStatsDetail
495+
*
496+
* Entry point for use if you want to vary the number of child contexts shown.
497+
*/
498+
void
499+
MemoryContextStatsDetail(MemoryContextcontext,intmax_children)
500+
{
501+
MemoryContextCountersgrand_totals;
502+
503+
memset(&grand_totals,0,sizeof(grand_totals));
504+
505+
MemoryContextStatsInternal(context,0, true,max_children,&grand_totals);
506+
507+
fprintf(stderr,
508+
"Grand total: %zu bytes in %zd blocks; %zu free (%zd chunks); %zu used\n",
509+
grand_totals.totalspace,grand_totals.nblocks,
510+
grand_totals.freespace,grand_totals.freechunks,
511+
grand_totals.totalspace-grand_totals.freespace);
512+
}
513+
514+
/*
515+
* MemoryContextStatsInternal
516+
*One recursion level for MemoryContextStats
517+
*
518+
* Print this context if print is true, but in any case accumulate counts into
519+
* *totals (if given).
520+
*/
489521
staticvoid
490-
MemoryContextStatsInternal(MemoryContextcontext,intlevel)
522+
MemoryContextStatsInternal(MemoryContextcontext,intlevel,
523+
boolprint,intmax_children,
524+
MemoryContextCounters*totals)
491525
{
526+
MemoryContextCounterslocal_totals;
492527
MemoryContextchild;
528+
intichild;
493529

494530
AssertArg(MemoryContextIsValid(context));
495531

496-
(*context->methods->stats) (context,level);
497-
for (child=context->firstchild;child!=NULL;child=child->nextchild)
498-
MemoryContextStatsInternal(child,level+1);
532+
/* Examine the context itself */
533+
(*context->methods->stats) (context,level,print,totals);
534+
535+
/*
536+
* Examine children. If there are more than max_children of them, we do
537+
* not print the rest explicitly, but just summarize them.
538+
*/
539+
memset(&local_totals,0,sizeof(local_totals));
540+
541+
for (child=context->firstchild,ichild=0;
542+
child!=NULL;
543+
child=child->nextchild,ichild++)
544+
{
545+
if (ichild<max_children)
546+
MemoryContextStatsInternal(child,level+1,
547+
print,max_children,
548+
totals);
549+
else
550+
MemoryContextStatsInternal(child,level+1,
551+
false,max_children,
552+
&local_totals);
553+
}
554+
555+
/* Deal with excess children */
556+
if (ichild>max_children)
557+
{
558+
if (print)
559+
{
560+
inti;
561+
562+
for (i=0;i <=level;i++)
563+
fprintf(stderr," ");
564+
fprintf(stderr,
565+
"%d more child contexts containing %zu total in %zd blocks; %zu free (%zd chunks); %zu used\n",
566+
ichild-max_children,
567+
local_totals.totalspace,
568+
local_totals.nblocks,
569+
local_totals.freespace,
570+
local_totals.freechunks,
571+
local_totals.totalspace-local_totals.freespace);
572+
}
573+
574+
if (totals)
575+
{
576+
totals->nblocks+=local_totals.nblocks;
577+
totals->freechunks+=local_totals.freechunks;
578+
totals->totalspace+=local_totals.totalspace;
579+
totals->freespace+=local_totals.freespace;
580+
}
581+
}
499582
}
500583

501584
/*

‎src/include/nodes/memnodes.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@
1616

1717
#include"nodes/nodes.h"
1818

19+
/*
20+
* MemoryContextCounters
21+
*Summarization state for MemoryContextStats collection.
22+
*
23+
* The set of counters in this struct is biased towards AllocSet; if we ever
24+
* add any context types that are based on fundamentally different approaches,
25+
* we might need more or different counters here. A possible API spec then
26+
* would be to print only nonzero counters, but for now we just summarize in
27+
* the format historically used by AllocSet.
28+
*/
29+
typedefstructMemoryContextCounters
30+
{
31+
Sizenblocks;/* Total number of malloc blocks */
32+
Sizefreechunks;/* Total number of free chunks */
33+
Sizetotalspace;/* Total bytes requested from malloc */
34+
Sizefreespace;/* The unused portion of totalspace */
35+
}MemoryContextCounters;
36+
1937
/*
2038
* MemoryContext
2139
*A logical context in which memory allocations occur.
@@ -44,7 +62,8 @@ typedef struct MemoryContextMethods
4462
void(*delete_context) (MemoryContextcontext);
4563
Size(*get_chunk_space) (MemoryContextcontext,void*pointer);
4664
bool(*is_empty) (MemoryContextcontext);
47-
void(*stats) (MemoryContextcontext,intlevel);
65+
void(*stats) (MemoryContextcontext,intlevel,boolprint,
66+
MemoryContextCounters*totals);
4867
#ifdefMEMORY_CONTEXT_CHECKING
4968
void(*check) (MemoryContextcontext);
5069
#endif

‎src/include/utils/memutils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ extern MemoryContext GetMemoryChunkContext(void *pointer);
104104
externMemoryContextMemoryContextGetParent(MemoryContextcontext);
105105
externboolMemoryContextIsEmpty(MemoryContextcontext);
106106
externvoidMemoryContextStats(MemoryContextcontext);
107+
externvoidMemoryContextStatsDetail(MemoryContextcontext,intmax_children);
107108
externvoidMemoryContextAllowInCriticalSection(MemoryContextcontext,
108109
boolallow);
109110

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp