forked from greenplum-db/gpdb-archive
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Port -DEXTRA_DYNAMIC_MEMORY_DEBUG to GPDB 7
This commit is a rework of the same macro from GPDB 6 (commit 1ddd6b0, #403) The patch enhances the output of MemoryContextStats() by including a list of memory allocations along with their locations for each memory context. To enable the feature, add -DEXTRA_DYNAMIC_MEMORY_DEBUG to CFLAGS during ./configure. At runtime, invoke MemoryContextStats(TopMemoryContext) or any other context as needed. The output will display the top allocations for each context following the default memory statistics. Co-authored-by: Evgeniy Ratkov <[email protected]>
- Loading branch information
Showing
13 changed files
with
625 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/* This file should be included into aset.c. */ | ||
|
||
#include "postgres.h" | ||
|
||
#include "utils/palloc_memory_debug.h" | ||
#include "access/hash.h" | ||
#include "utils/hsearch.h" | ||
|
||
/* Update individual chunk stats. */ | ||
static void | ||
AllocChunkUpdateStats(HTAB *chunk_table, AllocChunk chunk) | ||
{ | ||
bool found = false; | ||
MemoryContextChunkTableEntry *r = NULL; | ||
|
||
r = hash_search(chunk_table, &chunk->info.key, HASH_ENTER, &found); | ||
Assert(r != NULL); | ||
|
||
if (found) | ||
{ | ||
r->stat.count++; | ||
r->stat.bytes += chunk->size; | ||
} | ||
else | ||
{ | ||
r->info = chunk->info; | ||
r->stat.bytes = chunk->size; | ||
r->stat.count = 1; | ||
} | ||
} | ||
|
||
static uint32 | ||
MemoryContextChunkStatKeyHash(const void *key, Size keysize) | ||
{ | ||
Assert(keysize == sizeof(MemoryContextChunkStatKey)); | ||
return DatumGetUInt32(hash_any((const unsigned char *) key, | ||
keysize)); | ||
} | ||
|
||
static int | ||
MemoryContextChunkStatKeyCompare(const void *a, const void *b, | ||
Size keysize) | ||
{ | ||
Assert(keysize == sizeof(MemoryContextChunkStatKey)); | ||
|
||
MemoryContextChunkStatKey *lhs = (MemoryContextChunkStatKey *) a; | ||
MemoryContextChunkStatKey *rhs = (MemoryContextChunkStatKey *) b; | ||
|
||
return !(strcmp(lhs->parent_func, rhs->parent_func) == 0 && | ||
lhs->line == rhs->line); | ||
} | ||
|
||
static bool | ||
AllocSetChunkIsFree(AllocChunk chunk, AllocSet set) | ||
{ | ||
if (chunk->size > set->allocChunkLimit) | ||
return false; | ||
|
||
AllocChunk free_chunk = set->freelist[AllocSetFreeIndex(chunk->size)]; | ||
|
||
while (free_chunk != NULL) | ||
{ | ||
if (free_chunk == chunk) | ||
return true; | ||
|
||
free_chunk = (AllocChunk) free_chunk->aset; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/* Update every chunk's stats table inside an AllocSet. */ | ||
static void | ||
AllocSetUpdateAllocatedChunkStats(AllocSet set) | ||
{ | ||
if (set->chunkTable == NULL) | ||
{ | ||
HASHCTL hash_ctl = | ||
{ | ||
.keysize = sizeof(MemoryContextChunkStatKey), | ||
.entrysize = sizeof(MemoryContextChunkTableEntry), | ||
.hash = MemoryContextChunkStatKeyHash, | ||
.match = MemoryContextChunkStatKeyCompare, | ||
}; | ||
|
||
set->chunkTable = hash_create("AllocSetUpdateAllocatedChunkStats", | ||
DYN_MEM_HTABLE_SIZE, &hash_ctl, | ||
HASH_FUNCTION | HASH_ELEM | HASH_COMPARE); | ||
} | ||
|
||
for (AllocBlock block = set->blocks; block != NULL; block = block->next) | ||
{ | ||
AllocChunk chunk; | ||
|
||
for (chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ); | ||
(char *) chunk < (char *) block->freeptr; | ||
chunk = (AllocChunk) ((char *) chunk + chunk->size + ALLOC_CHUNKHDRSZ)) | ||
{ | ||
if (AllocSetChunkIsFree(chunk, set) || | ||
chunk->info.init != EXTRA_DYNAMIC_MEMORY_DEBUG_INIT_MAGIC) | ||
continue; | ||
if (!chunk->info.key.parent_func || !chunk->info.key.line || | ||
!chunk->info.filename || !chunk->info.func) | ||
continue; | ||
|
||
AllocChunkUpdateStats(set->chunkTable, chunk); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.