|
From: <sv...@va...> - 2008-09-06 19:12:33
|
Author: sewardj
Date: 2008-09-06 20:12:41 +0100 (Sat, 06 Sep 2008)
New Revision: 8570
Log:
Add a heap profiling facility the dynamic memory manager:
* all allocation requests must now supply a cost-center string,
an arbitrary "const HChar*", against which the allocation is
"billed"
* each block has its cost-center string stored with it
* the heap is periodically profiled. For each arena, the
number of blocks and bytes associated with each cost-center
string is printed out.
* the heap is profiled at system shutdown, and also when the
maximum size of an Arena increases by more than 10%.
* heap profiling is only done when --profile-heap=yes is given.
* there is an additional overheap of 8 bytes per allocated block,
needed to hold a pointer to the block's cost-center string.
Overhead is 8 bytes even on 32 bit platforms, because of
alignment constraints.
These changes make it much easier to make sense of what is going on
with Valgrind's internal dynamic memory management, and to find leaks
and excessive space use.
Modified:
branches/YARD/coregrind/m_mallocfree.c
branches/YARD/coregrind/pub_core_mallocfree.h
branches/YARD/include/pub_tool_mallocfree.h
Modified: branches/YARD/coregrind/m_mallocfree.c
===================================================================
--- branches/YARD/coregrind/m_mallocfree.c 2008-09-06 18:59:27 UTC (rev 8569)
+++ branches/YARD/coregrind/m_mallocfree.c 2008-09-06 19:12:41 UTC (rev 8570)
@@ -51,6 +51,8 @@
Long VG_(free_queue_volume) = 0;
Long VG_(free_queue_length) = 0;
+static void cc_analyse_alloc_arena ( ArenaId aid ); /* fwds */
+
/*------------------------------------------------------------*/
/*--- Main types ---*/
/*------------------------------------------------------------*/
@@ -68,6 +70,7 @@
/* Layout of an in-use block:
+ cost center (sizeof(ULong) bytes)
this block total szB (sizeof(SizeT) bytes)
red zone bytes (depends on Arena.rz_szB, but >= sizeof(void*))
(payload bytes)
@@ -76,6 +79,7 @@
Layout of a block on the free list:
+ cost center (sizeof(ULong) bytes)
this block total szB (sizeof(SizeT) bytes)
freelist previous ptr (sizeof(void*) bytes)
excess red zone bytes (if Arena.rz_szB > sizeof(void*))
@@ -87,13 +91,13 @@
Total size in bytes (bszB) and payload size in bytes (pszB)
are related by:
- bszB == pszB + 2*sizeof(SizeT) + 2*a->rz_szB
+ bszB == pszB + 2*sizeof(SizeT) + 2*a->rz_szB + sizeof(ULong)
The minimum overhead per heap block for arenas used by
the core is:
- 32-bit platforms: 2*4 + 2*4 == 16 bytes
- 64-bit platforms: 2*8 + 2*8 == 32 bytes
+ 32-bit platforms: 2*4 + 2*4 + 8 == 24 bytes
+ 64-bit platforms: 2*8 + 2*8 + 8 == 40 bytes
In both cases extra overhead may be incurred when rounding the payload
size up to VG_MIN_MALLOC_SZB.
@@ -111,6 +115,13 @@
- Superblock admin section lengths (due to elastic padding)
- Block admin section (low and high) lengths (due to elastic redzones)
- Block payload lengths (due to req_pszB rounding up)
+
+ The heap-profile cost-center field is 8 bytes even on 32 bit
+ platforms. This is so as to keep the payload field 8-aligned. On
+ a 64-bit platform, this cc-field contains a pointer to a const
+ HChar*, which is the cost center name. On 32-bit platforms, the
+ pointer lives in the lower-addressed half of the field, regardless
+ of the endianness of the host.
*/
typedef
struct {
@@ -169,6 +180,7 @@
SizeT bytes_on_loan;
SizeT bytes_mmaped;
SizeT bytes_on_loan_max;
+ SizeT next_profile_at;
}
Arena;
@@ -206,7 +218,7 @@
SizeT get_bszB_as_is ( Block* b )
{
UByte* b2 = (UByte*)b;
- SizeT bszB_lo = *(SizeT*)&b2[0];
+ SizeT bszB_lo = *(SizeT*)&b2[0 + sizeof(ULong)];
SizeT bszB_hi = *(SizeT*)&b2[mk_plain_bszB(bszB_lo) - sizeof(SizeT)];
vg_assert2(bszB_lo == bszB_hi,
"Heap block lo/hi size mismatch: lo = %llu, hi = %llu.\n"
@@ -227,7 +239,7 @@
void set_bszB ( Block* b, SizeT bszB )
{
UByte* b2 = (UByte*)b;
- *(SizeT*)&b2[0] = bszB;
+ *(SizeT*)&b2[0 + sizeof(ULong)] = bszB;
*(SizeT*)&b2[mk_plain_bszB(bszB) - sizeof(SizeT)] = bszB;
}
@@ -249,7 +261,7 @@
static __inline__
SizeT overhead_szB_lo ( Arena* a )
{
- return sizeof(SizeT) + a->rz_szB;
+ return sizeof(ULong) + sizeof(SizeT) + a->rz_szB;
}
static __inline__
SizeT overhead_szB_hi ( Arena* a )
@@ -319,7 +331,7 @@
void set_prev_b ( Block* b, Block* prev_p )
{
UByte* b2 = (UByte*)b;
- *(Block**)&b2[sizeof(SizeT)] = prev_p;
+ *(Block**)&b2[sizeof(ULong) + sizeof(SizeT)] = prev_p;
}
static __inline__
void set_next_b ( Block* b, Block* next_p )
@@ -331,7 +343,7 @@
Block* get_prev_b ( Block* b )
{
UByte* b2 = (UByte*)b;
- return *(Block**)&b2[sizeof(SizeT)];
+ return *(Block**)&b2[sizeof(ULong) + sizeof(SizeT)];
}
static __inline__
Block* get_next_b ( Block* b )
@@ -342,6 +354,22 @@
//---------------------------------------------------------------------------
+// Set and get the cost-center field of a block.
+static __inline__
+void set_cc ( Block* b, HChar* cc )
+{
+ UByte* b2 = (UByte*)b;
+ *(HChar**)&b2[0] = cc;
+}
+static __inline__
+HChar* get_cc ( Block* b )
+{
+ UByte* b2 = (UByte*)b;
+ return *(HChar**)&b2[0];
+}
+
+//---------------------------------------------------------------------------
+
// Get the block immediately preceding this one in the Superblock.
static __inline__
Block* get_predecessor_block ( Block* b )
@@ -358,7 +386,7 @@
void set_rz_lo_byte ( Arena* a, Block* b, UInt rz_byteno, UByte v )
{
UByte* b2 = (UByte*)b;
- b2[sizeof(SizeT) + rz_byteno] = v;
+ b2[sizeof(ULong) + sizeof(SizeT) + rz_byteno] = v;
}
static __inline__
void set_rz_hi_byte ( Arena* a, Block* b, UInt rz_byteno, UByte v )
@@ -370,7 +398,7 @@
UByte get_rz_lo_byte ( Arena* a, Block* b, UInt rz_byteno )
{
UByte* b2 = (UByte*)b;
- return b2[sizeof(SizeT) + rz_byteno];
+ return b2[sizeof(ULong) + sizeof(SizeT) + rz_byteno];
}
static __inline__
UByte get_rz_hi_byte ( Arena* a, Block* b, UInt rz_byteno )
@@ -420,7 +448,9 @@
// redzone size if necessary to achieve this.
a->rz_szB = rz_szB;
while (0 != overhead_szB_lo(a) % VG_MIN_MALLOC_SZB) a->rz_szB++;
- vg_assert(overhead_szB_lo(a) == overhead_szB_hi(a));
+ // vg_assert(overhead_szB_lo(a) == overhead_szB_hi(a));
+ vg_assert(0 == overhead_szB_lo(a) % VG_MIN_MALLOC_SZB);
+ vg_assert(0 == overhead_szB_hi(a) % VG_MIN_MALLOC_SZB);
a->min_sblock_szB = min_sblock_szB;
for (i = 0; i < N_MALLOC_LISTS; i++) a->freelist[i] = NULL;
@@ -431,6 +461,7 @@
a->bytes_on_loan = 0;
a->bytes_mmaped = 0;
a->bytes_on_loan_max = 0;
+ a->next_profile_at = 25 * 1000 * 1000;
vg_assert(sizeof(a->sblocks_initial)
== SBLOCKS_SIZE_INITIAL * sizeof(Superblock*));
}
@@ -448,6 +479,16 @@
}
}
+void VG_(print_arena_cc_analysis) ( void )
+{
+ UInt i;
+ vg_assert( VG_(clo_profile_heap) );
+ for (i = 0; i < VG_N_ARENAS; i++) {
+ cc_analyse_alloc_arena(i);
+ }
+}
+
+
/* This library is self-initialising, as it makes this more self-contained,
less coupled with the outside world. Hence VG_(arena_malloc)() and
VG_(arena_free)() below always call ensure_mm_init() to ensure things are
@@ -804,7 +845,7 @@
}
if (p_best < a->freelist[lno]) {
# ifdef VERBOSE_MALLOC
- VG_(printf)("retreat by %d\n", a->freelist[lno] - p_best);
+ VG_(printf)("retreat by %ld\n", (Word)(a->freelist[lno] - p_best));
# endif
a->freelist[lno] = p_best;
}
@@ -930,8 +971,8 @@
if (arena_bytes_on_loan != a->bytes_on_loan) {
# ifdef VERBOSE_MALLOC
- VG_(printf)( "sanity_check_malloc_arena: a->bytes_on_loan %d, "
- "arena_bytes_on_loan %d: "
+ VG_(printf)( "sanity_check_malloc_arena: a->bytes_on_loan %ld, "
+ "arena_bytes_on_loan %ld: "
"MISMATCH\n", a->bytes_on_loan, arena_bytes_on_loan);
# endif
ppSuperblocks(a);
@@ -991,6 +1032,110 @@
}
+#define N_AN_CCS 1000
+
+typedef struct { ULong nBytes; ULong nBlocks; HChar* cc; } AnCC;
+
+static AnCC anCCs[N_AN_CCS];
+
+static Int cmp_AnCC_by_vol ( void* v1, void* v2 ) {
+ AnCC* ancc1 = (AnCC*)v1;
+ AnCC* ancc2 = (AnCC*)v2;
+ if (ancc1->nBytes < ancc2->nBytes) return -1;
+ if (ancc1->nBytes > ancc2->nBytes) return 1;
+ return 0;
+}
+
+static void cc_analyse_alloc_arena ( ArenaId aid )
+{
+ Word i, j, k;
+ Arena* a;
+ Block* b;
+ Bool thisFree, lastWasFree;
+ SizeT b_bszB;
+
+ HChar* cc;
+ UInt n_ccs = 0;
+ //return;
+ a = arenaId_to_ArenaP(aid);
+ if (a->name == NULL) {
+ /* arena is not in use, is not initialised and will fail the
+ sanity check that follows. */
+ return;
+ }
+
+ sanity_check_malloc_arena(aid);
+
+ VG_(printf)(
+ "-------- Arena \"%s\": %ld mmap'd, %ld/%ld max/curr --------\n",
+ a->name, a->bytes_mmaped, a->bytes_on_loan_max, a->bytes_on_loan
+ );
+
+ for (j = 0; j < a->sblocks_used; ++j) {
+ Superblock * sb = a->sblocks[j];
+ lastWasFree = False;
+ for (i = 0; i < sb->n_payload_bytes; i += mk_plain_bszB(b_bszB)) {
+ b = (Block*)&sb->payload_bytes[i];
+ b_bszB = get_bszB_as_is(b);
+ if (!blockSane(a, b)) {
+ VG_(printf)("sanity_check_malloc_arena: sb %p, block %ld "
+ "(bszB %lu): BAD\n", sb, i, b_bszB );
+ tl_assert(0);
+ }
+ thisFree = !is_inuse_block(b);
+ if (thisFree && lastWasFree) {
+ VG_(printf)("sanity_check_malloc_arena: sb %p, block %ld "
+ "(bszB %lu): UNMERGED FREES\n", sb, i, b_bszB );
+ tl_assert(0);
+ }
+ lastWasFree = thisFree;
+
+ if (thisFree) continue;
+
+ if (0)
+ VG_(printf)("block: inUse=%d pszB=%d cc=%s\n",
+ (Int)(!thisFree),
+ (Int)bszB_to_pszB(a, b_bszB),
+ get_cc(b));
+ cc = get_cc(b);
+ tl_assert(cc);
+ for (k = 0; k < n_ccs; k++) {
+ tl_assert(anCCs[k].cc);
+ if (0 == VG_(strcmp)(cc, anCCs[k].cc))
+ break;
+ }
+ tl_assert(k >= 0 && k <= n_ccs);
+
+ if (k == n_ccs) {
+ tl_assert(n_ccs < N_AN_CCS-1);
+ n_ccs++;
+ anCCs[k].nBytes = 0;
+ anCCs[k].nBlocks = 0;
+ anCCs[k].cc = cc;
+ }
+
+ tl_assert(k >= 0 && k < n_ccs && k < N_AN_CCS);
+ anCCs[k].nBytes += (ULong)bszB_to_pszB(a, b_bszB);
+ anCCs[k].nBlocks++;
+ }
+ if (i > sb->n_payload_bytes) {
+ VG_(printf)( "sanity_check_malloc_arena: sb %p: last block "
+ "overshoots end\n", sb);
+ tl_assert(0);
+ }
+ }
+
+ VG_(ssort)( &anCCs[0], n_ccs, sizeof(anCCs[0]), cmp_AnCC_by_vol );
+
+ for (k = 0; k < n_ccs; k++) {
+ VG_(printf)("%'13llu in %'9llu: %s\n",
+ anCCs[k].nBytes, anCCs[k].nBlocks, anCCs[k].cc );
+ }
+
+ VG_(printf)("\n");
+}
+
+
void VG_(sanity_check_malloc_all) ( void )
{
UInt i;
@@ -1092,7 +1237,7 @@
return ((req_pszB + n) & (~n));
}
-void* VG_(arena_malloc) ( ArenaId aid, SizeT req_pszB )
+void* VG_(arena_malloc) ( ArenaId aid, HChar* cc, SizeT req_pszB )
{
SizeT req_bszB, frag_bszB, b_bszB;
UInt lno, i;
@@ -1108,6 +1253,10 @@
req_pszB = align_req_pszB(req_pszB);
req_bszB = pszB_to_bszB(a, req_pszB);
+ // You must provide a cost-center name against which to charge
+ // this allocation; it isn't optional.
+ vg_assert(cc);
+
// Scan through all the big-enough freelists for a block.
//
// Nb: this scanning might be expensive in some cases. Eg. if you
@@ -1185,6 +1334,7 @@
b = (Block*)&new_sb->payload_bytes[0];
lno = pszB_to_listNo(bszB_to_pszB(a, new_sb->n_payload_bytes));
mkFreeBlock ( a, b, new_sb->n_payload_bytes, lno);
+ set_cc(b, "admin.free-new-sb-1");
// fall through
obtained_block:
@@ -1205,19 +1355,31 @@
// printf( "split %dB into %dB and %dB\n", b_bszB, req_bszB, frag_bszB );
unlinkBlock(a, b, lno);
mkInuseBlock(a, b, req_bszB);
+ set_cc(b, cc);
mkFreeBlock(a, &b[req_bszB], frag_bszB,
pszB_to_listNo(bszB_to_pszB(a, frag_bszB)));
+ set_cc(&b[req_bszB], "admin.fragmentation-1");
b_bszB = get_bszB(b);
} else {
// No, mark as in use and use as-is.
unlinkBlock(a, b, lno);
mkInuseBlock(a, b, b_bszB);
+ set_cc(b, cc);
}
// Update stats
a->bytes_on_loan += bszB_to_pszB(a, b_bszB);
- if (a->bytes_on_loan > a->bytes_on_loan_max)
+ if (a->bytes_on_loan > a->bytes_on_loan_max) {
a->bytes_on_loan_max = a->bytes_on_loan;
+ if (a->bytes_on_loan_max >= a->next_profile_at) {
+ /* next profile after 10% more growth */
+ a->next_profile_at
+ = (SizeT)(
+ (((ULong)a->bytes_on_loan_max) * 110ULL) / 100ULL );
+ if (VG_(clo_profile_heap))
+ cc_analyse_alloc_arena(aid);
+ }
+ }
# ifdef DEBUG_MALLOC
sanity_check_malloc_arena(aid);
@@ -1286,6 +1448,7 @@
// Put this chunk back on a list somewhere.
b_listno = pszB_to_listNo(b_pszB);
mkFreeBlock( a, b, b_bszB, b_listno );
+ set_cc(b, "admin.free-1");
// See if this block can be merged with its successor.
// First test if we're far enough before the superblock's end to possibly
@@ -1304,6 +1467,7 @@
b_bszB += other_bszB;
b_listno = pszB_to_listNo(bszB_to_pszB(a, b_bszB));
mkFreeBlock( a, b, b_bszB, b_listno );
+ set_cc(b, "admin.free-2");
}
} else {
// Not enough space for successor: check that b is the last block
@@ -1326,6 +1490,7 @@
b_bszB += other_bszB;
b_listno = pszB_to_listNo(bszB_to_pszB(a, b_bszB));
mkFreeBlock( a, b, b_bszB, b_listno );
+ set_cc(b, "admin.free-3");
}
} else {
// Not enough space for predecessor: check that b is the first block,
@@ -1373,7 +1538,8 @@
. . . . . . .
*/
-void* VG_(arena_memalign) ( ArenaId aid, SizeT req_alignB, SizeT req_pszB )
+void* VG_(arena_memalign) ( ArenaId aid, HChar* cc,
+ SizeT req_alignB, SizeT req_pszB )
{
SizeT base_pszB_req, base_pszB_act, frag_bszB;
Block *base_b, *align_b;
@@ -1386,6 +1552,10 @@
vg_assert(req_pszB < MAX_PSZB);
+ // You must provide a cost-center name against which to charge
+ // this allocation; it isn't optional.
+ vg_assert(cc);
+
// Check that the requested alignment seems reasonable; that is, is
// a power of 2.
if (req_alignB < VG_MIN_MALLOC_SZB
@@ -1408,7 +1578,7 @@
/* Payload ptr for the block we are going to split. Note this
changes a->bytes_on_loan; we save and restore it ourselves. */
saved_bytes_on_loan = a->bytes_on_loan;
- base_p = VG_(arena_malloc) ( aid, base_pszB_req );
+ base_p = VG_(arena_malloc) ( aid, cc, base_pszB_req );
a->bytes_on_loan = saved_bytes_on_loan;
/* Give up if we couldn't allocate enough space */
@@ -1437,11 +1607,13 @@
/* Create the fragment block, and put it back on the relevant free list. */
mkFreeBlock ( a, base_b, frag_bszB,
pszB_to_listNo(bszB_to_pszB(a, frag_bszB)) );
+ set_cc(base_b, "admin.frag-memalign-1");
/* Create the aligned block. */
mkInuseBlock ( a, align_b,
base_p + base_pszB_act
+ overhead_szB_hi(a) - (UByte*)align_b );
+ set_cc(align_b, cc);
/* Final sanity checks. */
vg_assert( is_inuse_block(get_payload_block(a, align_p)) );
@@ -1538,7 +1710,8 @@
/*--- Services layered on top of malloc/free. ---*/
/*------------------------------------------------------------*/
-void* VG_(arena_calloc) ( ArenaId aid, SizeT nmemb, SizeT bytes_per_memb )
+void* VG_(arena_calloc) ( ArenaId aid, HChar* cc,
+ SizeT nmemb, SizeT bytes_per_memb )
{
SizeT size;
UChar* p;
@@ -1546,7 +1719,7 @@
size = nmemb * bytes_per_memb;
vg_assert(size >= nmemb && size >= bytes_per_memb);// check against overflow
- p = VG_(arena_malloc) ( aid, size );
+ p = VG_(arena_malloc) ( aid, cc, size );
VG_(memset)(p, 0, size);
@@ -1556,7 +1729,8 @@
}
-void* VG_(arena_realloc) ( ArenaId aid, void* ptr, SizeT req_pszB )
+void* VG_(arena_realloc) ( ArenaId aid, HChar* cc,
+ void* ptr, SizeT req_pszB )
{
Arena* a;
SizeT old_pszB;
@@ -1578,7 +1752,7 @@
return ptr;
}
- p_new = VG_(arena_malloc) ( aid, req_pszB );
+ p_new = VG_(arena_malloc) ( aid, cc, req_pszB );
VG_(memcpy)(p_new, ptr, old_pszB);
@@ -1589,7 +1763,8 @@
/* Inline just for the wrapper VG_(strdup) below */
-__inline__ Char* VG_(arena_strdup) ( ArenaId aid, const Char* s )
+__inline__ Char* VG_(arena_strdup) ( ArenaId aid, HChar* cc,
+ const Char* s )
{
Int i;
Int len;
@@ -1599,7 +1774,7 @@
return NULL;
len = VG_(strlen)(s) + 1;
- res = VG_(arena_malloc) (aid, len);
+ res = VG_(arena_malloc) (aid, cc, len);
for (i = 0; i < len; i++)
res[i] = s[i];
@@ -1613,9 +1788,9 @@
// All just wrappers to avoid exposing arenas to tools.
-void* VG_(malloc) ( SizeT nbytes )
+void* VG_(malloc) ( HChar* cc, SizeT nbytes )
{
- return VG_(arena_malloc) ( VG_AR_TOOL, nbytes );
+ return VG_(arena_malloc) ( VG_AR_TOOL, cc, nbytes );
}
void VG_(free) ( void* ptr )
@@ -1623,19 +1798,19 @@
VG_(arena_free) ( VG_AR_TOOL, ptr );
}
-void* VG_(calloc) ( SizeT nmemb, SizeT bytes_per_memb )
+void* VG_(calloc) ( HChar* cc, SizeT nmemb, SizeT bytes_per_memb )
{
- return VG_(arena_calloc) ( VG_AR_TOOL, nmemb, bytes_per_memb );
+ return VG_(arena_calloc) ( VG_AR_TOOL, cc, nmemb, bytes_per_memb );
}
-void* VG_(realloc) ( void* ptr, SizeT size )
+void* VG_(realloc) ( HChar* cc, void* ptr, SizeT size )
{
- return VG_(arena_realloc) ( VG_AR_TOOL, ptr, size );
+ return VG_(arena_realloc) ( VG_AR_TOOL, cc, ptr, size );
}
-Char* VG_(strdup) ( const Char* s )
+Char* VG_(strdup) ( HChar* cc, const Char* s )
{
- return VG_(arena_strdup) ( VG_AR_TOOL, s );
+ return VG_(arena_strdup) ( VG_AR_TOOL, cc, s );
}
// Useful for querying user blocks.
Modified: branches/YARD/coregrind/pub_core_mallocfree.h
===================================================================
--- branches/YARD/coregrind/pub_core_mallocfree.h 2008-09-06 18:59:27 UTC (rev 8569)
+++ branches/YARD/coregrind/pub_core_mallocfree.h 2008-09-06 19:12:41 UTC (rev 8570)
@@ -86,14 +86,16 @@
int keepcost; /* top-most, releasable (via malloc_trim) space */
};
-extern void* VG_(arena_malloc) ( ArenaId arena, SizeT nbytes );
+extern void* VG_(arena_malloc) ( ArenaId arena, HChar* cc, SizeT nbytes );
extern void VG_(arena_free) ( ArenaId arena, void* ptr );
-extern void* VG_(arena_calloc) ( ArenaId arena,
+extern void* VG_(arena_calloc) ( ArenaId arena, HChar* cc,
SizeT nmemb, SizeT bytes_per_memb );
-extern void* VG_(arena_realloc) ( ArenaId arena, void* ptr, SizeT size );
-extern void* VG_(arena_memalign)( ArenaId aid, SizeT req_alignB,
- SizeT req_pszB );
-extern Char* VG_(arena_strdup) ( ArenaId aid, const Char* s);
+extern void* VG_(arena_realloc) ( ArenaId arena, HChar* cc,
+ void* ptr, SizeT size );
+extern void* VG_(arena_memalign)( ArenaId aid, HChar* cc,
+ SizeT req_alignB, SizeT req_pszB );
+extern Char* VG_(arena_strdup) ( ArenaId aid, HChar* cc,
+ const Char* s);
// Nb: The ThreadId doesn't matter, it's not used.
extern SizeT VG_(arena_payload_szB) ( ThreadId tid, ArenaId aid, void* payload );
@@ -104,6 +106,8 @@
extern void VG_(print_all_arena_stats) ( void );
+extern void VG_(print_arena_cc_analysis) ( void );
+
#endif // __PUB_CORE_MALLOCFREE_H
/*--------------------------------------------------------------------*/
Modified: branches/YARD/include/pub_tool_mallocfree.h
===================================================================
--- branches/YARD/include/pub_tool_mallocfree.h 2008-09-06 18:59:27 UTC (rev 8569)
+++ branches/YARD/include/pub_tool_mallocfree.h 2008-09-06 19:12:41 UTC (rev 8570)
@@ -35,11 +35,11 @@
// These can be for allocating memory used by tools.
// Nb: the allocators *always succeed* -- they never return NULL (Valgrind
// will abort if they can't allocate the memory).
-extern void* VG_(malloc) ( SizeT nbytes );
+extern void* VG_(malloc) ( HChar* cc, SizeT nbytes );
extern void VG_(free) ( void* p );
-extern void* VG_(calloc) ( SizeT n, SizeT bytes_per_elem );
-extern void* VG_(realloc) ( void* p, SizeT size );
-extern Char* VG_(strdup) ( const Char* s );
+extern void* VG_(calloc) ( HChar* cc, SizeT n, SizeT bytes_per_elem );
+extern void* VG_(realloc) ( HChar* cc, void* p, SizeT size );
+extern Char* VG_(strdup) ( HChar* cc, const Char* s );
// Returns the usable size of a heap-block. It's the asked-for size plus
// possibly some more due to rounding up.
|
|
From: Nicholas N. <nj...@cs...> - 2008-09-17 05:20:22
|
On Sat, 6 Sep 2008 sv...@va... wrote: > * heap profiling is only done when --profile-heap=yes is given. > > * there is an additional overheap of 8 bytes per allocated block, > needed to hold a pointer to the block's cost-center string. > Overhead is 8 bytes even on 32 bit platforms, because of > alignment constraints. Is that overhead present when --profile-heap=no ? N |
|
From: Julian S. <js...@ac...> - 2008-09-17 08:05:40
|
> > * there is an additional overheap of 8 bytes per allocated block, > > needed to hold a pointer to the block's cost-center string. > > Overhead is 8 bytes even on 32 bit platforms, because of > > alignment constraints. > > Is that overhead present when --profile-heap=no ? Yes, which isn't good. When I merge this lot into the trunk I plan to add a configure time test, --enable-profile-heap, to avoid that. I guess it would be possible (and ideal) to not have a configure time test, and simply have the block layout chosen (with/without the extra overhead) chosen dynamically at startup. Sounds a bit complex, and requires parsing the command line args before m_mallocfree is started for the first time. J |