Merge r9103 and r9105 (add --ignore-fn to Massif) from the Darwin branch.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@9567 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/massif/ms_main.c b/massif/ms_main.c
index ee85908..7cd2603 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -233,22 +233,25 @@
// - 15,000 XPts 800,000 XPts
// - 1,800 top-XPts
-static UInt n_heap_allocs = 0;
-static UInt n_heap_reallocs = 0;
-static UInt n_heap_frees = 0;
-static UInt n_stack_allocs = 0;
-static UInt n_stack_frees = 0;
-static UInt n_xpts = 0;
-static UInt n_xpt_init_expansions = 0;
-static UInt n_xpt_later_expansions = 0;
-static UInt n_sxpt_allocs = 0;
-static UInt n_sxpt_frees = 0;
-static UInt n_skipped_snapshots = 0;
-static UInt n_real_snapshots = 0;
-static UInt n_detailed_snapshots = 0;
-static UInt n_peak_snapshots = 0;
-static UInt n_cullings = 0;
-static UInt n_XCon_redos = 0;
+static UInt n_heap_allocs = 0;
+static UInt n_heap_reallocs = 0;
+static UInt n_heap_frees = 0;
+static UInt n_ignored_heap_allocs = 0;
+static UInt n_ignored_heap_frees = 0;
+static UInt n_ignored_heap_reallocs = 0;
+static UInt n_stack_allocs = 0;
+static UInt n_stack_frees = 0;
+static UInt n_xpts = 0;
+static UInt n_xpt_init_expansions = 0;
+static UInt n_xpt_later_expansions = 0;
+static UInt n_sxpt_allocs = 0;
+static UInt n_sxpt_frees = 0;
+static UInt n_skipped_snapshots = 0;
+static UInt n_real_snapshots = 0;
+static UInt n_detailed_snapshots = 0;
+static UInt n_peak_snapshots = 0;
+static UInt n_cullings = 0;
+static UInt n_XCon_redos = 0;
//------------------------------------------------------------//
//--- Globals ---//
@@ -286,6 +289,7 @@
//------------------------------------------------------------//
static XArray* alloc_fns;
+static XArray* ignore_fns;
static void init_alloc_fns(void)
{
@@ -315,18 +319,26 @@
DO("operator new[](unsigned long, std::nothrow_t const&)");
}
-static Bool is_alloc_fn(Char* fnname)
+static void init_ignore_fns(void)
{
- Char** alloc_fn_ptr;
+ // Create the (empty) list.
+ ignore_fns = VG_(newXA)(VG_(malloc), "ms.main.iif.1",
+ VG_(free), sizeof(Char*));
+}
+
+// Determines if the named function is a member of the XArray.
+static Bool is_member_fn(XArray* fns, Char* fnname)
+{
+ Char** fn_ptr;
Int i;
// Nb: It's a linear search through the list, because we're comparing
// strings rather than pointers to strings.
// Nb: This gets called a lot. It was an OSet, but they're quite slow to
// iterate through so it wasn't a good choice.
- for (i = 0; i < VG_(sizeXA)(alloc_fns); i++) {
- alloc_fn_ptr = VG_(indexXA)(alloc_fns, i);
- if (VG_STREQ(fnname, *alloc_fn_ptr))
+ for (i = 0; i < VG_(sizeXA)(fns); i++) {
+ fn_ptr = VG_(indexXA)(fns, i);
+ if (VG_STREQ(fnname, *fn_ptr))
return True;
}
return False;
@@ -395,7 +407,9 @@
else if VG_STR_CLO(arg, "--alloc-fn", tmp_str) {
VG_(addToXA)(alloc_fns, &tmp_str);
}
-
+ else if VG_STR_CLO(arg, "--ignore-fn", tmp_str) {
+ VG_(addToXA)(ignore_fns, &tmp_str);
+ }
else if VG_STR_CLO(arg, "--massif-out-file", clo_massif_out_file) {}
else
@@ -412,7 +426,8 @@
" ignored if --heap=no [8]\n"
" --stacks=no|yes profile stack(s) [no]\n"
" --depth=<number> depth of contexts [30]\n"
-" --alloc-fn=<name> specify <fn> as an alloc function [empty]\n"
+" --alloc-fn=<name> specify <name> as an alloc function [empty]\n"
+" --ignore-fn=<name> ignore heap allocations within <name> [empty]\n"
" --threshold=<m.n> significance threshold, as a percentage [1.0]\n"
" --peak-inaccuracy=<m.n> maximum peak inaccuracy, as a percentage [1.0]\n"
" --time-unit=i|ms|B time unit: instructions executed, milliseconds\n"
@@ -780,6 +795,15 @@
// enough.
#define BUF_LEN 2048
+// Determine if the given IP belongs to a function that should be ignored.
+static Bool fn_should_be_ignored(Addr ip)
+{
+ static Char buf[BUF_LEN];
+ return
+ ( VG_(get_fnname)(ip, buf, BUF_LEN) && is_member_fn(ignore_fns, buf)
+ ? True : False );
+}
+
// Get the stack trace for an XCon, filtering out uninteresting entries:
// alloc-fns and entries above alloc-fns, and entries below main-or-below-main.
// Eg: alloc-fn1 / alloc-fn2 / a / b / main / (below main) / c
@@ -789,7 +813,7 @@
static
Int get_IPs( ThreadId tid, Bool is_custom_alloc, Addr ips[])
{
- Char buf[BUF_LEN];
+ static Char buf[BUF_LEN];
Int n_ips, i, n_alloc_fns_removed;
Int overestimate;
Bool redo;
@@ -832,7 +856,7 @@
// involves calls to VG_(malloc)/VG_(free)).
for (i = n_alloc_fns_removed; i < n_ips; i++) {
if (VG_(get_fnname)(ips[i], buf, BUF_LEN)) {
- if (is_alloc_fn(buf)) {
+ if (is_member_fn(alloc_fns, buf)) {
n_alloc_fns_removed++;
} else {
break;
@@ -859,15 +883,22 @@
}
// Gets an XCon and puts it in the tree. Returns the XCon's bottom-XPt.
+// Unless the allocation should be ignored, in which case we return NULL.
static XPt* get_XCon( ThreadId tid, Bool is_custom_alloc )
{
- Addr ips[MAX_IPS];
+ static Addr ips[MAX_IPS];
Int i;
XPt* xpt = alloc_xpt;
// After this call, the IPs we want are in ips[0]..ips[n_ips-1].
Int n_ips = get_IPs(tid, is_custom_alloc, ips);
+ // Should we ignore this allocation? (Nb: n_ips can be zero, eg. if
+ // 'main' is marked as an alloc-fn.)
+ if (n_ips > 0 && fn_should_be_ignored(ips[0])) {
+ return NULL;
+ }
+
// Now do the search/insertion of the XCon.
for (i = 0; i < n_ips; i++) {
Addr ip = ips[i];
@@ -1489,18 +1520,27 @@
if (clo_heap) {
VERB(3, "<<< new_mem_heap (%lu, %lu)", req_szB, slop_szB);
- // Update statistics.
- n_heap_allocs++;
-
- // Update heap stats.
- update_heap_stats(req_szB, clo_heap_admin + slop_szB);
-
- // Update XTree.
hc->where = get_XCon( tid, is_custom_alloc );
- update_XCon(hc->where, req_szB);
- // Maybe take a snapshot.
- maybe_take_snapshot(Normal, " alloc");
+ if (hc->where) {
+ // Update statistics.
+ n_heap_allocs++;
+
+ // Update heap stats.
+ update_heap_stats(req_szB, clo_heap_admin + slop_szB);
+
+ // Update XTree.
+ update_XCon(hc->where, req_szB);
+
+ // Maybe take a snapshot.
+ maybe_take_snapshot(Normal, " alloc");
+
+ } else {
+ // Ignored allocation.
+ n_ignored_heap_allocs++;
+
+ VERB(3, "(ignored)");
+ }
VERB(3, ">>>");
}
@@ -1522,20 +1562,27 @@
if (clo_heap) {
VERB(3, "<<< die_mem_heap");
- // Update statistics
- n_heap_frees++;
+ if (hc->where) {
+ // Update statistics.
+ n_heap_frees++;
- // Maybe take a peak snapshot, since it's a deallocation.
- maybe_take_snapshot(Peak, "de-PEAK");
+ // Maybe take a peak snapshot, since it's a deallocation.
+ maybe_take_snapshot(Peak, "de-PEAK");
- // Update heap stats.
- update_heap_stats(-hc->req_szB, -clo_heap_admin - hc->slop_szB);
+ // Update heap stats.
+ update_heap_stats(-hc->req_szB, -clo_heap_admin - hc->slop_szB);
- // Update XTree.
- update_XCon(hc->where, -hc->req_szB);
+ // Update XTree.
+ update_XCon(hc->where, -hc->req_szB);
- // Maybe take a snapshot.
- maybe_take_snapshot(Normal, "dealloc");
+ // Maybe take a snapshot.
+ maybe_take_snapshot(Normal, "dealloc");
+
+ } else {
+ n_ignored_heap_frees++;
+
+ VERB(3, "(ignored)");
+ }
VERB(3, ">>> (-%lu, -%lu)", hc->req_szB, hc->slop_szB);
}
@@ -1546,6 +1593,12 @@
VG_(cli_free)( p );
}
+// Nb: --ignore-fn is tricky for realloc. If the block's original alloc was
+// ignored, but the realloc is not requested to be ignored, and we are
+// shrinking the block, then we have to ignore the realloc -- otherwise we
+// could end up with negative heap sizes. This isn't a danger if we are
+// growing such a block, but for consistency (it also simplifies things) we
+// ignore such reallocs as well.
static __inline__
void* renew_block ( ThreadId tid, void* p_old, SizeT new_req_szB )
{
@@ -1553,6 +1606,7 @@
void* p_new;
SizeT old_req_szB, old_slop_szB, new_slop_szB, new_actual_szB;
XPt *old_where, *new_where;
+ Bool is_ignored = False;
// Remove the old block
hc = VG_(HT_remove)(malloc_list, (UWord)p_old);
@@ -1566,12 +1620,18 @@
if (clo_heap) {
VERB(3, "<<< renew_mem_heap (%lu)", new_req_szB);
- // Update statistics
- n_heap_reallocs++;
+ if (hc->where) {
+ // Update statistics.
+ n_heap_reallocs++;
- // Maybe take a peak snapshot, if it's (effectively) a deallocation.
- if (new_req_szB < old_req_szB) {
- maybe_take_snapshot(Peak, "re-PEAK");
+ // Maybe take a peak snapshot, if it's (effectively) a deallocation.
+ if (new_req_szB < old_req_szB) {
+ maybe_take_snapshot(Peak, "re-PEAK");
+ }
+ } else {
+ // The original malloc was ignored, so we have to ignore the
+ // realloc as well.
+ is_ignored = True;
}
}
@@ -1607,9 +1667,17 @@
// Update XTree.
if (clo_heap) {
new_where = get_XCon( tid, /*custom_malloc*/False);
- hc->where = new_where;
- update_XCon(old_where, -old_req_szB);
- update_XCon(new_where, new_req_szB);
+ if (!is_ignored && new_where) {
+ hc->where = new_where;
+ update_XCon(old_where, -old_req_szB);
+ update_XCon(new_where, new_req_szB);
+ } else {
+ // The realloc itself is ignored.
+ is_ignored = True;
+
+ // Update statistics.
+ n_ignored_heap_reallocs++;
+ }
}
}
@@ -1621,11 +1689,17 @@
VG_(HT_add_node)(malloc_list, hc);
if (clo_heap) {
- // Update heap stats.
- update_heap_stats(new_req_szB - old_req_szB, new_slop_szB - old_slop_szB);
+ if (!is_ignored) {
+ // Update heap stats.
+ update_heap_stats(new_req_szB - old_req_szB,
+ new_slop_szB - old_slop_szB);
- // Maybe take a snapshot.
- maybe_take_snapshot(Normal, "realloc");
+ // Maybe take a snapshot.
+ maybe_take_snapshot(Normal, "realloc");
+ } else {
+
+ VERB(3, "(ignored)");
+ }
VERB(3, ">>> (%ld, %ld)",
new_req_szB - old_req_szB, new_slop_szB - old_slop_szB);
@@ -2125,25 +2199,28 @@
// Stats
tl_assert(n_xpts > 0); // always have alloc_xpt
- VERB(1, "heap allocs: %u", n_heap_allocs);
- VERB(1, "heap reallocs: %u", n_heap_reallocs);
- VERB(1, "heap frees: %u", n_heap_frees);
- VERB(1, "stack allocs: %u", n_stack_allocs);
- VERB(1, "stack frees: %u", n_stack_frees);
- VERB(1, "XPts: %u", n_xpts);
- VERB(1, "top-XPts: %u (%d%%)",
+ VERB(1, "heap allocs: %u", n_heap_allocs);
+ VERB(1, "heap reallocs: %u", n_heap_reallocs);
+ VERB(1, "heap frees: %u", n_heap_frees);
+ VERB(1, "ignored heap allocs: %u", n_ignored_heap_allocs);
+ VERB(1, "ignored heap frees: %u", n_ignored_heap_frees);
+ VERB(1, "ignored heap reallocs: %u", n_ignored_heap_reallocs);
+ VERB(1, "stack allocs: %u", n_stack_allocs);
+ VERB(1, "stack frees: %u", n_stack_frees);
+ VERB(1, "XPts: %u", n_xpts);
+ VERB(1, "top-XPts: %u (%d%%)",
alloc_xpt->n_children,
( n_xpts ? alloc_xpt->n_children * 100 / n_xpts : 0));
- VERB(1, "XPt init expansions: %u", n_xpt_init_expansions);
- VERB(1, "XPt later expansions: %u", n_xpt_later_expansions);
- VERB(1, "SXPt allocs: %u", n_sxpt_allocs);
- VERB(1, "SXPt frees: %u", n_sxpt_frees);
- VERB(1, "skipped snapshots: %u", n_skipped_snapshots);
- VERB(1, "real snapshots: %u", n_real_snapshots);
- VERB(1, "detailed snapshots: %u", n_detailed_snapshots);
- VERB(1, "peak snapshots: %u", n_peak_snapshots);
- VERB(1, "cullings: %u", n_cullings);
- VERB(1, "XCon redos: %u", n_XCon_redos);
+ VERB(1, "XPt init expansions: %u", n_xpt_init_expansions);
+ VERB(1, "XPt later expansions: %u", n_xpt_later_expansions);
+ VERB(1, "SXPt allocs: %u", n_sxpt_allocs);
+ VERB(1, "SXPt frees: %u", n_sxpt_frees);
+ VERB(1, "skipped snapshots: %u", n_skipped_snapshots);
+ VERB(1, "real snapshots: %u", n_real_snapshots);
+ VERB(1, "detailed snapshots: %u", n_detailed_snapshots);
+ VERB(1, "peak snapshots: %u", n_peak_snapshots);
+ VERB(1, "cullings: %u", n_cullings);
+ VERB(1, "XCon redos: %u", n_XCon_redos);
}
@@ -2167,12 +2244,21 @@
clo_heap_admin = 0;
}
- // Print alloc-fns, if necessary.
+ // Print alloc-fns and ignore-fns, if necessary.
if (VG_(clo_verbosity) > 1) {
VERB(1, "alloc-fns:");
for (i = 0; i < VG_(sizeXA)(alloc_fns); i++) {
- Char** alloc_fn_ptr = VG_(indexXA)(alloc_fns, i);
- VERB(1, " %d: %s", i, *alloc_fn_ptr);
+ Char** fn_ptr = VG_(indexXA)(alloc_fns, i);
+ VERB(1, " %d: %s", i, *fn_ptr);
+ }
+
+ VERB(1, "ignore-fns:");
+ if (0 == VG_(sizeXA)(ignore_fns)) {
+ VERB(1, " <empty>");
+ }
+ for (i = 0; i < VG_(sizeXA)(ignore_fns); i++) {
+ Char** fn_ptr = VG_(indexXA)(ignore_fns, i);
+ VERB(1, " %d: %s", i, *fn_ptr);
}
}
@@ -2204,12 +2290,12 @@
"Copyright (C) 2003-2009, and GNU GPL'd, by Nicholas Nethercote");
VG_(details_bug_reports_to) (VG_BUGS_TO);
- // Basic functions
+ // Basic functions.
VG_(basic_tool_funcs) (ms_post_clo_init,
ms_instrument,
ms_fini);
- // Needs
+ // Needs.
VG_(needs_libc_freeres)();
VG_(needs_command_line_options)(ms_process_cmd_line_option,
ms_print_usage,
@@ -2229,14 +2315,15 @@
ms_malloc_usable_size,
0 );
- // HP_Chunks
+ // HP_Chunks.
malloc_list = VG_(HT_construct)( "Massif's malloc list" );
// Dummy node at top of the context structure.
alloc_xpt = new_XPt(/*ip*/0, /*parent*/NULL);
- // Initialise alloc_fns.
+ // Initialise alloc_fns and ignore_fns.
init_alloc_fns();
+ init_ignore_fns();
// Initialise args_for_massif.
args_for_massif = VG_(newXA)(VG_(malloc), "ms.main.mprci.1",