From: Bart Van Assche Date: Mon, 21 Apr 2008 17:28:50 +0000 (+0000) Subject: Refined mallinfo() implementation (contributed by Eugene Toder). X-Git-Tag: svn/VALGRIND_3_4_0~715 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2497cadb853627500ad4e00c0795c046c7f269a7;p=thirdparty%2Fvalgrind.git Refined mallinfo() implementation (contributed by Eugene Toder). git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7901 --- diff --git a/coregrind/m_mallocfree.c b/coregrind/m_mallocfree.c index c1f01f8fb3..f78b18eac7 100644 --- a/coregrind/m_mallocfree.c +++ b/coregrind/m_mallocfree.c @@ -47,6 +47,10 @@ // #define DEBUG_MALLOC // turn on heavyweight debugging machinery // #define VERBOSE_MALLOC // make verbose, esp. in debugging machinery +/* Number and total size of blocks in free queue. Used by mallinfo(). */ +Long VG_(free_queue_volume) = 0; +Long VG_(free_queue_length) = 0; + /*------------------------------------------------------------*/ /*--- Main types ---*/ /*------------------------------------------------------------*/ @@ -1468,9 +1472,34 @@ SizeT VG_(arena_payload_szB) ( ThreadId tid, ArenaId aid, void* ptr ) return get_pszB(a, b); } -// We cannot return the whole struct as the library function does, -// because this is called by a client request. So instead we use -// a pointer to do call by reference. + +// Implementation of mallinfo(). There is no recent standard that defines +// the behavior of mallinfo(). The meaning of the fields in struct mallinfo +// is as follows: +// +// struct mallinfo { +// int arena; /* total space in arena */ +// int ordblks; /* number of ordinary blocks */ +// int smblks; /* number of small blocks */ +// int hblks; /* number of holding blocks */ +// int hblkhd; /* space in holding block headers */ +// int usmblks; /* space in small blocks in use */ +// int fsmblks; /* space in free small blocks */ +// int uordblks; /* space in ordinary blocks in use */ +// int fordblks; /* space in free ordinary blocks */ +// int keepcost; /* space penalty if keep option */ +// /* is used */ +// }; +// +// The glibc documentation about mallinfo (which is somewhat outdated) can +// be found here: +// http://www.gnu.org/software/libtool/manual/libc/Statistics-of-Malloc.html +// +// See also http://bugs.kde.org/show_bug.cgi?id=160956. +// +// Regarding the implementation of VG_(mallinfo)(): we cannot return the +// whole struct as the library function does, because this is called by a +// client request. So instead we use a pointer to do call by reference. void VG_(mallinfo) ( ThreadId tid, struct vg_mallinfo* mi ) { UInt i, free_blocks, free_blocks_size; @@ -1491,17 +1520,16 @@ void VG_(mallinfo) ( ThreadId tid, struct vg_mallinfo* mi ) } // We don't have fastbins so smblks & fsmblks are always 0. Also we don't - // have a separate mmap allocator so set hblks & hblkhd to 0. See also - // http://www.gnu.org/software/libtool/manual/libc/Statistics-of-Malloc.html + // have a separate mmap allocator so set hblks & hblkhd to 0. mi->arena = a->bytes_mmaped; - mi->ordblks = free_blocks; + mi->ordblks = free_blocks + VG_(free_queue_length); mi->smblks = 0; mi->hblks = 0; mi->hblkhd = 0; mi->usmblks = 0; mi->fsmblks = 0; - mi->uordblks = a->bytes_on_loan; - mi->fordblks = free_blocks_size; + mi->uordblks = a->bytes_on_loan - VG_(free_queue_volume); + mi->fordblks = free_blocks_size + VG_(free_queue_volume); mi->keepcost = 0; // may want some value in here } diff --git a/include/pub_tool_replacemalloc.h b/include/pub_tool_replacemalloc.h index 9b54f20439..dd8b23e30c 100644 --- a/include/pub_tool_replacemalloc.h +++ b/include/pub_tool_replacemalloc.h @@ -41,6 +41,13 @@ extern void* VG_(cli_malloc) ( SizeT align, SizeT nbytes ); extern void VG_(cli_free) ( void* p ); +/* If a tool uses deferred freeing (e.g. memcheck to catch accesses to + freed memory) it can maintain number and total size of queued blocks + in these variable to provide more accurate statistics about client + memory usage. Currently used by mallinfo(). */ +extern Long VG_(free_queue_volume); +extern Long VG_(free_queue_length); + /* Check if an address is within a range, allowing for redzones at edges */ extern Bool VG_(addr_is_in_block)( Addr a, Addr start, SizeT size, SizeT rz_szB ); diff --git a/memcheck/mc_malloc_wrappers.c b/memcheck/mc_malloc_wrappers.c index 06f568b6a7..0c2eb72d3f 100644 --- a/memcheck/mc_malloc_wrappers.c +++ b/memcheck/mc_malloc_wrappers.c @@ -71,7 +71,6 @@ VgHashTable MC_(mempool_list) = NULL; /* Records blocks after freeing. */ static MC_Chunk* freed_list_start = NULL; static MC_Chunk* freed_list_end = NULL; -static Long freed_list_volume = 0; /* Put a shadow chunk on the freed blocks queue, possibly freeing up some of the oldest blocks in the queue at the same time. */ @@ -83,33 +82,35 @@ static void add_to_freed_queue ( MC_Chunk* mc ) if (freed_list_end == NULL) { tl_assert(freed_list_start == NULL); freed_list_end = freed_list_start = mc; - freed_list_volume = (Long)mc->szB; + VG_(free_queue_volume) = (Long)mc->szB; } else { tl_assert(freed_list_end->next == NULL); freed_list_end->next = mc; freed_list_end = mc; - freed_list_volume += (Long)mc->szB; + VG_(free_queue_volume) += (Long)mc->szB; if (show) VG_(printf)("mc_freelist: acquire: volume now %lld\n", - freed_list_volume); + VG_(free_queue_volume)); } + VG_(free_queue_length)++; mc->next = NULL; /* Release enough of the oldest blocks to bring the free queue volume below vg_clo_freelist_vol. */ - while (freed_list_volume > MC_(clo_freelist_vol)) { + while (VG_(free_queue_volume) > MC_(clo_freelist_vol)) { MC_Chunk* mc1; tl_assert(freed_list_start != NULL); tl_assert(freed_list_end != NULL); mc1 = freed_list_start; - freed_list_volume -= (Long)mc1->szB; + VG_(free_queue_volume) -= (Long)mc1->szB; + VG_(free_queue_length)--; if (show) VG_(printf)("mc_freelist: discard: volume now %lld\n", - freed_list_volume); - tl_assert(freed_list_volume >= 0); + VG_(free_queue_volume)); + tl_assert(VG_(free_queue_volume) >= 0); if (freed_list_start == freed_list_end) { freed_list_start = freed_list_end = NULL;