/dhat/tests/*.stdout.out
/dhat/tests/.deps
/dhat/tests/acc
+/dhat/tests/ad-hoc
/dhat/tests/basic
/dhat/tests/big
+/dhat/tests/copy
/dhat/tests/empty
/dhat/tests/sig
/dhat/tests/single
* DHAT:
+ - DHAT has been extended, with two new modes of operation. The new
+ --mode=copy flag triggers copy profiling, which records calls to memcpy,
+ strcpy, and similar functions. The new --mode=ad-hoc flag triggers ad hoc
+ profiling, which records calls to the DHAT_AD_HOC_EVENT client request in
+ the new dhat/dhat.h file. This is useful for learning more about hot code
+ paths. See the user manual for more information about the new modes.
+
+ - Because of these changes, DHAT's file format has changed. DHAT output
+ files produced with earlier versions of DHAT will not work with this
+ version of DHAT's viewer, and DHAT output files produced with this version
+ of DHAT will not work with earlier versions of DHAT's viewer.
+
* Cachegrind:
* Callgrind:
/*--- Useful functions ---*/
/*------------------------------------------------------------*/
-void* VG_(cli_malloc) ( SizeT align, SizeT nbytes )
-{
+void* VG_(cli_malloc) ( SizeT align, SizeT nbytes )
+{
// 'align' should be valid (ie. big enough and a power of two) by now.
// VG_(arena_memalign)() will abort if it's not.
if (VG_MIN_MALLOC_SZB == align)
- return VG_(arena_malloc) ( VG_AR_CLIENT, "replacemalloc.cm.1",
- nbytes );
- else
- return VG_(arena_memalign) ( VG_AR_CLIENT, "replacemalloc.cm.2",
+ return VG_(arena_malloc) ( VG_AR_CLIENT, "replacemalloc.cm.1",
+ nbytes );
+ else
+ return VG_(arena_memalign) ( VG_AR_CLIENT, "replacemalloc.cm.2",
align, nbytes );
-}
+}
-void VG_(cli_free) ( void* p )
-{
- VG_(arena_free) ( VG_AR_CLIENT, p );
+void* VG_(cli_realloc) ( void* ptr, SizeT nbytes )
+{
+ return VG_(arena_realloc) ( VG_AR_CLIENT, "replacemalloc.cr.1",
+ ptr, nbytes );
}
-// Useful for querying user blocks.
-SizeT VG_(cli_malloc_usable_size) ( void* p )
-{
+void VG_(cli_free) ( void* p )
+{
+ VG_(arena_free) ( VG_AR_CLIENT, p );
+}
+
+// Useful for querying user blocks.
+SizeT VG_(cli_malloc_usable_size) ( void* p )
+{
return VG_(arena_malloc_usable_size)(VG_AR_CLIENT, p);
-}
-
+}
+
Bool VG_(addr_is_in_block)( Addr a, Addr start, SizeT size, SizeT rz_szB )
{
return ( start - rz_szB <= a && a < start + size + rz_szB );
include $(top_srcdir)/Makefile.tool.am
-#SUBDIRS += perf
-
EXTRA_DIST = docs/dh-manual.xml dh_view.html dh_view.css dh_view.js
#----------------------------------------------------------------------------
# Headers, etc
#----------------------------------------------------------------------------
+pkginclude_HEADERS = \
+ dhat.h
+
# Ensure the viewer components get copied into the install tree.
dhatdir = $(pkglibexecdir)
dhat_DATA = dh_view.html dh_view.css dh_view.js
noinst_PROGRAMS += dhat-@VGCONF_ARCH_SEC@-@VGCONF_OS@
endif
-EXP_DHAT_SOURCES_COMMON = dh_main.c
+DHAT_SOURCES_COMMON = dh_main.c
dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_SOURCES = \
- $(EXP_DHAT_SOURCES_COMMON)
+ $(DHAT_SOURCES_COMMON)
dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CPPFLAGS = \
$(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS = $(LTO_CFLAGS) \
if VGCONF_HAVE_PLATFORM_SEC
dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_SOURCES = \
- $(EXP_DHAT_SOURCES_COMMON)
+ $(DHAT_SOURCES_COMMON)
dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CPPFLAGS = \
$(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS = $(LTO_CFLAGS) \
noinst_DSYMS = $(noinst_PROGRAMS)
endif
-vgpreload_dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_SOURCES =
+# dh_replace_strmem.c runs on the simulated CPU, and is built with
+# AM_CFLAGS_PSO_* (see $(top_srcdir)/Makefile.all.am).
+VGPRELOAD_DHAT_SOURCES_COMMON = dh_replace_strmem.c
+
+vgpreload_dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_SOURCES = \
+ $(VGPRELOAD_DHAT_SOURCES_COMMON)
vgpreload_dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CPPFLAGS = \
$(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
vgpreload_dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CFLAGS = \
- $(AM_CFLAGS_PSO_@VGCONF_PLATFORM_PRI_CAPS@)
+ $(AM_CFLAGS_PSO_@VGCONF_PLATFORM_PRI_CAPS@) -O2
vgpreload_dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_DEPENDENCIES = \
$(LIBREPLACEMALLOC_@VGCONF_PLATFORM_PRI_CAPS@)
vgpreload_dhat_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_LDFLAGS = \
$(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
if VGCONF_HAVE_PLATFORM_SEC
-vgpreload_dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_SOURCES =
+vgpreload_dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_SOURCES = \
+ $(VGPRELOAD_DHAT_SOURCES_COMMON)
vgpreload_dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CPPFLAGS = \
$(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
vgpreload_dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CFLAGS = \
- $(AM_CFLAGS_PSO_@VGCONF_PLATFORM_SEC_CAPS@)
+ $(AM_CFLAGS_PSO_@VGCONF_PLATFORM_SEC_CAPS@) -O2
vgpreload_dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_DEPENDENCIES = \
$(LIBREPLACEMALLOC_@VGCONF_PLATFORM_SEC_CAPS@)
vgpreload_dhat_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_LDFLAGS = \
/* Contributed by Julian Seward <jseward@acm.org> */
-
#include "pub_tool_basics.h"
#include "pub_tool_clientstate.h"
+#include "pub_tool_clreq.h"
#include "pub_tool_libcbase.h"
#include "pub_tool_libcassert.h"
#include "pub_tool_libcfile.h"
#include "pub_tool_tooliface.h"
#include "pub_tool_wordfm.h"
+#include "dhat.h"
+
#define HISTOGRAM_SIZE_LIMIT 1024
//------------------------------------------------------------//
static ULong g_total_blocks = 0;
static ULong g_total_bytes = 0;
-// Current values.
+// Current values. g_curr_blocks and g_curr_bytes are only used with
+// clo_mode=Heap.
static ULong g_curr_blocks = 0;
static ULong g_curr_bytes = 0;
static ULong g_curr_instrs = 0; // incremented from generated code
// Values at the global max, i.e. when g_curr_bytes peaks.
+// Only used with clo_mode=Heap.
static ULong g_max_blocks = 0;
static ULong g_max_bytes = 0;
-static ULong g_max_instrs = 0;
+
+// Time of the global max.
+static ULong g_tgmax_instrs = 0;
// Values for the entire run. Updated each time a block is retired.
+// Only used with clo_mode=Heap.
static ULong g_reads_bytes = 0;
static ULong g_writes_bytes = 0;
+//------------------------------------------------------------//
+//--- Command line args ---//
+//------------------------------------------------------------//
+
+typedef enum { Heap=55, Copy, AdHoc } ProfileKind;
+
+static ProfileKind clo_mode = Heap;
+
+static const HChar* clo_dhat_out_file = "dhat.out.%p";
+
+static Bool dh_process_cmd_line_option(const HChar* arg)
+{
+ if VG_STR_CLO(arg, "--dhat-out-file", clo_dhat_out_file) {
+
+ } else if (VG_XACT_CLO(arg, "--mode=heap", clo_mode, Heap)) {
+ } else if (VG_XACT_CLO(arg, "--mode=copy", clo_mode, Copy)) {
+ } else if (VG_XACT_CLO(arg, "--mode=ad-hoc", clo_mode, AdHoc)) {
+
+ } else {
+ return VG_(replacement_malloc_process_cmd_line_option)(arg);
+ }
+
+ return True;
+}
+
+static void dh_print_usage(void)
+{
+ VG_(printf)(
+" --dhat-out-file=<file> output file name [dhat.out.%%p]\n"
+" --mode=heap|copy|ad-hoc profiling mode\n"
+ );
+}
+
+static void dh_print_debug_usage(void)
+{
+ VG_(printf)(
+" (none)\n"
+ );
+}
+
//------------------------------------------------------------//
//--- an Interval Tree of live blocks ---//
//------------------------------------------------------------//
struct {
Addr payload;
SizeT req_szB;
- ExeContext* ap; /* allocation ec */
+ ExeContext* ec; /* allocation ec */
ULong allocd_at; /* instruction number */
ULong reads_bytes;
ULong writes_bytes;
static Block* find_Block_containing ( Addr a )
{
+ tl_assert(clo_mode == Heap);
+
if (LIKELY(fbc_cache0
&& fbc_cache0->payload <= a
&& a < fbc_cache0->payload + fbc_cache0->req_szB)) {
// known to be present.)
static void delete_Block_starting_at ( Addr a )
{
+ tl_assert(clo_mode == Heap);
+
Block fake;
fake.payload = a;
fake.req_szB = 1;
fbc_cache0 = fbc_cache1 = NULL;
}
-
//------------------------------------------------------------//
//--- a FM of allocation points (APs) ---//
//------------------------------------------------------------//
typedef
struct {
- // The allocation point that we're summarising stats for.
- ExeContext* ap;
+ // The program point that we're summarising stats for.
+ ExeContext* ec;
- // Total number of blocks and bytes allocated by this AP.
+ // Total number of blocks and bytes allocated by this PP.
ULong total_blocks;
ULong total_bytes;
- // The current number of blocks and bytes live for this AP.
+ // The current number of blocks and bytes live for this PP.
+ // Only used with clo_mode=Heap.
ULong curr_blocks;
ULong curr_bytes;
- // Values at the AP max, i.e. when this AP's curr_bytes peaks.
- ULong max_blocks; // Blocks at the AP max.
- ULong max_bytes; // The AP max, measured in bytes.
+ // Values at the PP max, i.e. when this PP's curr_bytes peaks.
+ // Only used with clo_mode=Heap.
+ ULong max_blocks; // Blocks at the PP max.
+ ULong max_bytes; // The PP max, measured in bytes.
// Values at the global max.
+ // Only used with clo_mode=Heap.
ULong at_tgmax_blocks;
ULong at_tgmax_bytes;
- // Total lifetimes of all blocks allocated by this AP. Includes blocks
+ // Total lifetimes of all blocks allocated by this PP. Includes blocks
// explicitly freed and blocks implicitly freed at termination.
+ // Only used with clo_mode=Heap.
ULong total_lifetimes_instrs;
- // Number of blocks freed by this AP. (Only used in assertions.)
+ // Number of blocks freed by this PP. (Only used in assertions.)
+ // Only used with clo_mode=Heap.
ULong freed_blocks;
// Total number of reads and writes in all blocks allocated
- // by this AP.
+ // by this PP. Only used with clo_mode=Heap.
ULong reads_bytes;
ULong writes_bytes;
/* Histogram information. We maintain a histogram aggregated for
- all retiring Blocks allocated by this AP, but only if:
- - this AP has only ever allocated objects of one size
+ all retiring Blocks allocated by this PP, but only if:
+ - this PP has only ever allocated objects of one size
- that size is <= HISTOGRAM_SIZE_LIMIT
- What we need therefore is a mechanism to see if this AP
+ What we need therefore is a mechanism to see if this PP
has only ever allocated blocks of one size.
3 states:
Unknown because no retirement yet
Exactly xsize all retiring blocks are of this size
Mixed multiple different sizes seen
+
+ Only used with clo_mode=Heap.
*/
enum { Unknown=999, Exactly, Mixed } xsize_tag;
SizeT xsize;
UInt* histo; /* [0 .. xsize-1] */
}
- APInfo;
-
-/* maps ExeContext*'s to APInfo*'s. Note that the keys must match the
- .ap field in the values. */
-static WordFM* apinfo = NULL; /* WordFM* ExeContext* APInfo* */
+ PPInfo;
+/* maps ExeContext*'s to PPInfo*'s. Note that the keys must match the
+ .ec field in the values. */
+static WordFM* ppinfo = NULL; /* WordFM* ExeContext* PPInfo* */
// Are we at peak memory? If so, update at_tgmax_blocks and at_tgmax_bytes in
-// all APInfos. Note that this is moderately expensive so we avoid calling it
+// all PPInfos. Note that this is moderately expensive so we avoid calling it
// on every allocation.
static void check_for_peak(void)
{
+ tl_assert(clo_mode == Heap);
+
if (g_curr_bytes == g_max_bytes) {
// It's a peak. (If there are multiple equal peaks we record the latest
// one.)
UWord keyW, valW;
- VG_(initIterFM)(apinfo);
- while (VG_(nextIterFM)(apinfo, &keyW, &valW)) {
- APInfo* api = (APInfo*)valW;
- tl_assert(api && api->ap == (ExeContext*)keyW);
- api->at_tgmax_blocks = api->curr_blocks;
- api->at_tgmax_bytes = api->curr_bytes;
+ VG_(initIterFM)(ppinfo);
+ while (VG_(nextIterFM)(ppinfo, &keyW, &valW)) {
+ PPInfo* ppi = (PPInfo*)valW;
+ tl_assert(ppi && ppi->ec == (ExeContext*)keyW);
+ ppi->at_tgmax_blocks = ppi->curr_blocks;
+ ppi->at_tgmax_bytes = ppi->curr_bytes;
}
- VG_(doneIterFM)(apinfo);
+ VG_(doneIterFM)(ppinfo);
}
}
/* 'bk' is being introduced (has just been allocated). Find the
- relevant APInfo entry for it, or create one, based on the block's
- allocation EC. Then, update the APInfo to the extent that we
+ relevant PPInfo entry for it, or create one, based on the block's
+ allocation EC. Then, update the PPInfo to the extent that we
actually can, to reflect the allocation. */
-static void intro_Block ( Block* bk )
+static void intro_Block(Block* bk)
{
tl_assert(bk);
- tl_assert(bk->ap);
+ tl_assert(bk->ec);
- APInfo* api = NULL;
+ PPInfo* ppi = NULL;
UWord keyW = 0;
UWord valW = 0;
- Bool found = VG_(lookupFM)( apinfo,
- &keyW, &valW, (UWord)bk->ap );
+ Bool found = VG_(lookupFM)( ppinfo,
+ &keyW, &valW, (UWord)bk->ec );
if (found) {
- api = (APInfo*)valW;
- tl_assert(keyW == (UWord)bk->ap);
+ ppi = (PPInfo*)valW;
+ tl_assert(keyW == (UWord)bk->ec);
} else {
- api = VG_(malloc)( "dh.intro_Block.1", sizeof(APInfo) );
- VG_(memset)(api, 0, sizeof(*api));
- api->ap = bk->ap;
- Bool present = VG_(addToFM)( apinfo,
- (UWord)bk->ap, (UWord)api );
+ ppi = VG_(malloc)( "dh.intro_Block.1", sizeof(PPInfo) );
+ VG_(memset)(ppi, 0, sizeof(*ppi));
+ ppi->ec = bk->ec;
+ Bool present = VG_(addToFM)( ppinfo,
+ (UWord)bk->ec, (UWord)ppi );
tl_assert(!present);
- // histo stuff
- tl_assert(api->freed_blocks == 0);
- api->xsize_tag = Unknown;
- api->xsize = 0;
- if (0) VG_(printf)("api %p --> Unknown\n", api);
+ if (clo_mode == Heap) {
+ // histo stuff
+ tl_assert(ppi->freed_blocks == 0);
+ ppi->xsize_tag = Unknown;
+ ppi->xsize = 0;
+ if (0) VG_(printf)("ppi %p --> Unknown\n", ppi);
+ }
}
- tl_assert(api->ap == bk->ap);
+ tl_assert(ppi->ec == bk->ec);
- // Update global stats first.
+ // Update global stats and PPInfo stats.
g_total_blocks++;
g_total_bytes += bk->req_szB;
- g_curr_blocks++;
- g_curr_bytes += bk->req_szB;
-
- // The use of `>=` rather than `>` means that if there are multiple equal
- // peaks we record the latest one, like `check_for_peak` does.
- if (g_curr_bytes >= g_max_bytes) {
- g_max_blocks = g_curr_blocks;
- g_max_bytes = g_curr_bytes;
- g_max_instrs = g_curr_instrs;
- }
+ ppi->total_blocks++;
+ ppi->total_bytes += bk->req_szB;
- // Now update APInfo stats.
+ if (clo_mode == Heap) {
+ g_curr_blocks++;
+ g_curr_bytes += bk->req_szB;
- api->total_blocks++;
- api->total_bytes += bk->req_szB;
+ ppi->curr_blocks++;
+ ppi->curr_bytes += bk->req_szB;
- api->curr_blocks++;
- api->curr_bytes += bk->req_szB;
+ // The use of `>=` rather than `>` means that if there are multiple equal
+ // peaks we record the latest one, like `check_for_peak` does.
+ if (g_curr_bytes >= g_max_bytes) {
+ g_max_blocks = g_curr_blocks;
+ g_max_bytes = g_curr_bytes;
+ g_tgmax_instrs = g_curr_instrs;
- // The use of `>=` rather than `>` means that if there are multiple equal
- // peaks we record the latest one, like `check_for_peak` does.
- if (api->curr_bytes >= api->max_bytes) {
- api->max_blocks = api->curr_blocks;
- api->max_bytes = api->curr_bytes;
+ ppi->max_blocks = ppi->curr_blocks;
+ ppi->max_bytes = ppi->curr_bytes;
+ }
}
}
-/* 'bk' is retiring (being freed). Find the relevant APInfo entry for
+/* 'bk' is retiring (being freed). Find the relevant PPInfo entry for
it, which must already exist. Then, fold info from 'bk' into that
entry. 'because_freed' is True if the block is retiring because
the client has freed it. If it is False then the block is retiring
because the program has finished, in which case we want to skip the
- updates of the total blocks live etc for this AP, but still fold in
+ updates of the total blocks live etc for this PP, but still fold in
the access counts and histo data that have so far accumulated for
the block. */
-static void retire_Block ( Block* bk, Bool because_freed )
+static void retire_Block(Block* bk, Bool because_freed)
{
+ tl_assert(clo_mode == Heap);
tl_assert(bk);
- tl_assert(bk->ap);
+ tl_assert(bk->ec);
- APInfo* api = NULL;
+ PPInfo* ppi = NULL;
UWord keyW = 0;
UWord valW = 0;
- Bool found = VG_(lookupFM)( apinfo,
- &keyW, &valW, (UWord)bk->ap );
-
+ Bool found = VG_(lookupFM)( ppinfo,
+ &keyW, &valW, (UWord)bk->ec );
tl_assert(found);
- api = (APInfo*)valW;
- tl_assert(api->ap == bk->ap);
+ ppi = (PPInfo*)valW;
+ tl_assert(ppi->ec == bk->ec);
// update stats following this free.
if (0)
- VG_(printf)("ec %p api->c_by_l %llu bk->rszB %llu\n",
- bk->ap, api->curr_bytes, (ULong)bk->req_szB);
+ VG_(printf)("ec %p ppi->c_by_l %llu bk->rszB %llu\n",
+ bk->ec, ppi->curr_bytes, (ULong)bk->req_szB);
if (because_freed) {
// Total bytes is coming down from a possible peak.
g_curr_blocks--;
g_curr_bytes -= bk->req_szB;
- // Then update APInfo stats.
- tl_assert(api->curr_blocks >= 1);
- tl_assert(api->curr_bytes >= bk->req_szB);
- api->curr_blocks--;
- api->curr_bytes -= bk->req_szB;
+ // Then update PPInfo stats.
+ tl_assert(ppi->curr_blocks >= 1);
+ tl_assert(ppi->curr_bytes >= bk->req_szB);
+ ppi->curr_blocks--;
+ ppi->curr_bytes -= bk->req_szB;
- api->freed_blocks++;
+ ppi->freed_blocks++;
}
tl_assert(bk->allocd_at <= g_curr_instrs);
- api->total_lifetimes_instrs += (g_curr_instrs - bk->allocd_at);
+ ppi->total_lifetimes_instrs += (g_curr_instrs - bk->allocd_at);
// access counts
- api->reads_bytes += bk->reads_bytes;
- api->writes_bytes += bk->writes_bytes;
+ ppi->reads_bytes += bk->reads_bytes;
+ ppi->writes_bytes += bk->writes_bytes;
g_reads_bytes += bk->reads_bytes;
g_writes_bytes += bk->writes_bytes;
// histo stuff. First, do state transitions for xsize/xsize_tag.
- switch (api->xsize_tag) {
+ switch (ppi->xsize_tag) {
case Unknown:
- tl_assert(api->xsize == 0);
- tl_assert(api->freed_blocks == 1 || api->freed_blocks == 0);
- tl_assert(!api->histo);
- api->xsize_tag = Exactly;
- api->xsize = bk->req_szB;
- if (0) VG_(printf)("api %p --> Exactly(%lu)\n", api, api->xsize);
+ tl_assert(ppi->xsize == 0);
+ tl_assert(ppi->freed_blocks == 1 || ppi->freed_blocks == 0);
+ tl_assert(!ppi->histo);
+ ppi->xsize_tag = Exactly;
+ ppi->xsize = bk->req_szB;
+ if (0) VG_(printf)("ppi %p --> Exactly(%lu)\n", ppi, ppi->xsize);
// and allocate the histo
if (bk->histoW) {
- api->histo = VG_(malloc)("dh.retire_Block.1",
- api->xsize * sizeof(UInt));
- VG_(memset)(api->histo, 0, api->xsize * sizeof(UInt));
+ ppi->histo = VG_(malloc)("dh.retire_Block.1",
+ ppi->xsize * sizeof(UInt));
+ VG_(memset)(ppi->histo, 0, ppi->xsize * sizeof(UInt));
}
break;
case Exactly:
- //tl_assert(api->freed_blocks > 1);
- if (bk->req_szB != api->xsize) {
- if (0) VG_(printf)("api %p --> Mixed(%lu -> %lu)\n",
- api, api->xsize, bk->req_szB);
- api->xsize_tag = Mixed;
- api->xsize = 0;
+ //tl_assert(ppi->freed_blocks > 1);
+ if (bk->req_szB != ppi->xsize) {
+ if (0) VG_(printf)("ppi %p --> Mixed(%lu -> %lu)\n",
+ ppi, ppi->xsize, bk->req_szB);
+ ppi->xsize_tag = Mixed;
+ ppi->xsize = 0;
// deallocate the histo, if any
- if (api->histo) {
- VG_(free)(api->histo);
- api->histo = NULL;
+ if (ppi->histo) {
+ VG_(free)(ppi->histo);
+ ppi->histo = NULL;
}
}
break;
case Mixed:
- //tl_assert(api->freed_blocks > 1);
+ //tl_assert(ppi->freed_blocks > 1);
break;
default:
}
// See if we can fold the histo data from this block into
- // the data for the AP
- if (api->xsize_tag == Exactly && api->histo && bk->histoW) {
- tl_assert(api->xsize == bk->req_szB);
+ // the data for the PP.
+ if (ppi->xsize_tag == Exactly && ppi->histo && bk->histoW) {
+ tl_assert(ppi->xsize == bk->req_szB);
UWord i;
- for (i = 0; i < api->xsize; i++) {
- // FIXME: do something better in case of overflow of api->histo[..]
+ for (i = 0; i < ppi->xsize; i++) {
+ // FIXME: do something better in case of overflow of ppi->histo[..]
// Right now, at least don't let it overflow/wrap around
- if (api->histo[i] <= 0xFFFE0000)
- api->histo[i] += (UInt)bk->histoW[i];
+ if (ppi->histo[i] <= 0xFFFE0000)
+ ppi->histo[i] += (UInt)bk->histoW[i];
}
- if (0) VG_(printf)("fold in, AP = %p\n", api);
+ if (0) VG_(printf)("fold in, PP = %p\n", ppi);
}
#if 0
#endif
}
-/* This handles block resizing. When a block with AP 'ec' has a
- size change of 'delta', call here to update the APInfo. */
+/* This handles block resizing. When a block with PP 'ec' has a
+ size change of 'delta', call here to update the PPInfo. */
static void resize_Block(ExeContext* ec, SizeT old_req_szB, SizeT new_req_szB)
{
+ tl_assert(clo_mode == Heap);
+
Long delta = (Long)new_req_szB - (Long)old_req_szB;
- APInfo* api = NULL;
+ PPInfo* ppi = NULL;
UWord keyW = 0;
UWord valW = 0;
- Bool found = VG_(lookupFM)( apinfo,
+ Bool found = VG_(lookupFM)( ppinfo,
&keyW, &valW, (UWord)ec );
tl_assert(found);
- api = (APInfo*)valW;
- tl_assert(api->ap == ec);
+ ppi = (PPInfo*)valW;
+ tl_assert(ppi->ec == ec);
if (delta < 0) {
- tl_assert(api->curr_bytes >= -delta);
+ tl_assert(ppi->curr_bytes >= -delta);
tl_assert(g_curr_bytes >= -delta);
- }
- // Total bytes might be coming down from a possible peak.
- if (delta < 0)
+ // Total bytes might be coming down from a possible peak.
check_for_peak();
+ }
// Note: we treat realloc() like malloc() + free() for total counts, i.e. we
// increment total_blocks by 1 and increment total_bytes by new_req_szB.
// calls to realloc wouldn't be counted towards the total_blocks count,
// which is undesirable.
- // Update global stats first.
+ // Update global stats and PPInfo stats.
g_total_blocks++;
g_total_bytes += new_req_szB;
+ ppi->total_blocks++;
+ ppi->total_bytes += new_req_szB;
+
g_curr_blocks += 0; // unchanged
g_curr_bytes += delta;
+ ppi->curr_blocks += 0; // unchanged
+ ppi->curr_bytes += delta;
+
// The use of `>=` rather than `>` means that if there are multiple equal
// peaks we record the latest one, like `check_for_peak` does.
if (g_curr_bytes >= g_max_bytes) {
g_max_blocks = g_curr_blocks;
g_max_bytes = g_curr_bytes;
- g_max_instrs = g_curr_instrs;
- }
-
- // Now update APInfo stats.
-
- api->total_blocks++;
- api->total_bytes += new_req_szB;
+ g_tgmax_instrs = g_curr_instrs;
- api->curr_blocks += 0; // unchanged
- api->curr_bytes += delta;
-
- // The use of `>=` rather than `>` means that if there are multiple equal
- // peaks we record the latest one, like `check_for_peak` does.
- if (api->curr_bytes >= api->max_bytes) {
- api->max_blocks = api->curr_blocks;
- api->max_bytes = api->curr_bytes;
+ ppi->max_blocks = ppi->curr_blocks;
+ ppi->max_bytes = ppi->curr_bytes;
}
}
-
//------------------------------------------------------------//
-//--- update both Block and APInfos after {m,re}alloc/free ---//
+//--- update both Block and PPInfos after {m,re}alloc/free ---//
//------------------------------------------------------------//
static
Bool is_zeroed )
{
tl_assert(p == NULL); // don't handle custom allocators right now
- SizeT actual_szB /*, slop_szB*/;
+ SizeT actual_szB;
if ((SSizeT)req_szB < 0) return NULL;
- if (req_szB == 0)
+ if (req_szB == 0) {
req_szB = 1; /* can't allow zero-sized blocks in the interval tree */
+ }
// Allocate and zero if necessary
if (!p) {
if (is_zeroed) VG_(memset)(p, 0, req_szB);
actual_szB = VG_(cli_malloc_usable_size)(p);
tl_assert(actual_szB >= req_szB);
- /* slop_szB = actual_szB - req_szB; */
- } else {
- /* slop_szB = 0; */
+ }
+
+ if (clo_mode != Heap) {
+ return p;
}
// Make new Block, add to interval_tree.
Block* bk = VG_(malloc)("dh.new_block.1", sizeof(Block));
bk->payload = (Addr)p;
bk->req_szB = req_szB;
- bk->ap = VG_(record_ExeContext)(tid, 0/*first word delta*/);
+ bk->ec = VG_(record_ExeContext)(tid, 0/*first word delta*/);
bk->allocd_at = g_curr_instrs;
bk->reads_bytes = 0;
bk->writes_bytes = 0;
- // set up histogram array, if the block isn't too large
+ // Set up histogram array, if the block isn't too large.
bk->histoW = NULL;
if (req_szB <= HISTOGRAM_SIZE_LIMIT) {
bk->histoW = VG_(malloc)("dh.new_block.2", req_szB * sizeof(UShort));
intro_Block(bk);
- if (0) VG_(printf)("ALLOC %lu -> %p\n", req_szB, p);
-
return p;
}
static
-void die_block ( void* p, Bool custom_free )
+void die_block ( void* p )
{
- tl_assert(!custom_free); // at least for now
+ VG_(cli_free)(p);
- Block* bk = find_Block_containing( (Addr)p );
+ if (clo_mode != Heap) {
+ return;
+ }
+ Block* bk = find_Block_containing( (Addr)p );
if (!bk) {
return; // bogus free
}
return; // bogus free
}
- if (0) VG_(printf)(" FREE %p %llu\n",
- p, g_curr_instrs - bk->allocd_at);
-
retire_Block(bk, True/*because_freed*/);
- VG_(cli_free)( (void*)bk->payload );
delete_Block_starting_at( bk->payload );
if (bk->histoW) {
VG_(free)( bk->histoW );
VG_(free)( bk );
}
-
static
void* renew_block ( ThreadId tid, void* p_old, SizeT new_req_szB )
{
- if (0) VG_(printf)("REALL %p %lu\n", p_old, new_req_szB);
void* p_new = NULL;
tl_assert(new_req_szB > 0); // map 0 to 1
+ if (clo_mode != Heap) {
+ SizeT old_actual_szB = VG_(cli_malloc_usable_size)(p_old);
+ p_new = VG_(cli_malloc)(VG_(clo_alignment), new_req_szB);
+ if (!p_new) {
+ return NULL;
+ }
+ VG_(memmove)(p_new, p_old, VG_MIN(old_actual_szB, new_req_szB));
+ VG_(cli_free)(p_old);
+ return p_new;
+ }
+
// Find the old block.
Block* bk = find_Block_containing( (Addr)p_old );
if (!bk) {
}
tl_assert(bk->req_szB > 0);
- // assert the block finder is behaving sanely
+ // Assert the block finder is behaving sanely.
tl_assert(bk->payload <= (Addr)p_old);
tl_assert( (Addr)p_old < bk->payload + bk->req_szB );
// Actually do the allocation, if necessary.
if (new_req_szB <= bk->req_szB) {
-
// New size is smaller or same; block not moved.
- resize_Block(bk->ap, bk->req_szB, new_req_szB);
+ resize_Block(bk->ec, bk->req_szB, new_req_szB);
bk->req_szB = new_req_szB;
// Update reads/writes for the implicit copy. Even though we didn't
bk->reads_bytes += new_req_szB;
bk->writes_bytes += new_req_szB;
- return p_old;
+ p_new = p_old;
} else {
-
// New size is bigger; make new block, copy shared contents, free old.
p_new = VG_(cli_malloc)(VG_(clo_alignment), new_req_szB);
if (!p_new) {
bk->writes_bytes += bk->req_szB;
// Update the metadata.
- resize_Block(bk->ap, bk->req_szB, new_req_szB);
+ resize_Block(bk->ec, bk->req_szB, new_req_szB);
bk->payload = (Addr)p_new;
bk->req_szB = new_req_szB;
= VG_(addToFM)( interval_tree, (UWord)bk, (UWord)0/*no val*/);
tl_assert(!present);
fbc_cache0 = fbc_cache1 = NULL;
-
- return p_new;
}
- /*NOTREACHED*/
- tl_assert(0);
-}
+ return p_new;
+}
//------------------------------------------------------------//
//--- malloc() et al replacement wrappers ---//
static void dh_free ( ThreadId tid __attribute__((unused)), void* p )
{
- die_block( p, /*custom_free*/False );
+ die_block(p);
}
static void dh___builtin_delete ( ThreadId tid, void* p )
{
- die_block( p, /*custom_free*/False);
+ die_block(p);
}
static void dh___builtin_vec_delete ( ThreadId tid, void* p )
{
- die_block( p, /*custom_free*/False );
+ die_block(p);
}
static void* dh_realloc ( ThreadId tid, void* p_old, SizeT new_szB )
static SizeT dh_malloc_usable_size ( ThreadId tid, void* p )
{
+ if (clo_mode != Heap) {
+ return VG_(cli_malloc_usable_size)(p);
+ }
+
Block* bk = find_Block_containing( (Addr)p );
return bk ? bk->req_szB : 0;
}
-
//------------------------------------------------------------//
//--- memory references ---//
//------------------------------------------------------------//
static VG_REGPARM(2)
void dh_handle_write ( Addr addr, UWord szB )
{
+ tl_assert(clo_mode == Heap);
+
Block* bk = find_Block_containing(addr);
if (bk) {
bk->writes_bytes += szB;
static VG_REGPARM(2)
void dh_handle_read ( Addr addr, UWord szB )
{
+ tl_assert(clo_mode == Heap);
+
Block* bk = find_Block_containing(addr);
if (bk) {
bk->reads_bytes += szB;
}
}
-
// Handle reads and writes by syscalls (read == kernel
// reads user space, write == kernel writes user space).
// Assumes no such read or write spans a heap block
void dh_handle_noninsn_read ( CorePart part, ThreadId tid, const HChar* s,
Addr base, SizeT size )
{
+ tl_assert(clo_mode == Heap);
+
switch (part) {
case Vg_CoreSysCall:
dh_handle_read(base, size);
}
}
+static
+void dh_handle_noninsn_read_asciiz(CorePart part, ThreadId tid, const HChar* s,
+ Addr str)
+{
+ tl_assert(clo_mode == Heap);
+
+ tl_assert(part == Vg_CoreSysCall);
+ dh_handle_noninsn_read(part, tid, s, str, VG_(strlen)((const HChar*)str+1));
+}
+
static
void dh_handle_noninsn_write ( CorePart part, ThreadId tid,
Addr base, SizeT size )
{
+ tl_assert(clo_mode == Heap);
+
switch (part) {
case Vg_CoreSysCall:
case Vg_CoreClientReq:
}
}
-
//------------------------------------------------------------//
//--- Instrumentation ---//
//------------------------------------------------------------//
void addMemEvent(IRSB* sbOut, Bool isWrite, Int szB, IRExpr* addr,
Int goff_sp)
{
+ if (clo_mode != Heap) {
+ return;
+ }
+
IRType tyAddr = Ity_INVALID;
const HChar* hName= NULL;
void* hAddr = NULL;
#undef mkU64
#undef assign
-
//------------------------------------------------------------//
-//--- Command line args ---//
+//--- Client requests ---//
//------------------------------------------------------------//
-static const HChar* clo_dhat_out_file = "dhat.out.%p";
-
-static Bool dh_process_cmd_line_option(const HChar* arg)
+static Bool dh_handle_client_request(ThreadId tid, UWord* arg, UWord* ret)
{
- if VG_STR_CLO(arg, "--dhat-out-file", clo_dhat_out_file) {}
+ switch (arg[0]) {
+ case VG_USERREQ__DHAT_AD_HOC_EVENT: {
+ if (clo_mode != AdHoc) {
+ return False;
+ }
- else
- return VG_(replacement_malloc_process_cmd_line_option)(arg);
+ SizeT len = (SizeT)arg[1];
- return True;
-}
+ // Only the ec and req_szB fields are used by intro_Block().
+ Block bk;
+ VG_(memset)(&bk, 0, sizeof(bk));
+ bk.req_szB = len;
+ bk.ec = VG_(record_ExeContext)(tid, 0/*first word delta*/);
-static void dh_print_usage(void)
-{
- VG_(printf)(
-" --dhat-out-file=<file> output file name [dhat.out.%%p]\n"
- );
-}
+ intro_Block(&bk);
-static void dh_print_debug_usage(void)
-{
- VG_(printf)(
-" (none)\n"
- );
-}
+ return True;
+ }
+
+ case _VG_USERREQ__DHAT_COPY: {
+ SizeT len = (SizeT)arg[1];
+
+ if (clo_mode != Copy) {
+ return False;
+ }
+
+ // Only the ec and req_szB fields are used by intro_Block().
+ Block bk;
+ VG_(memset)(&bk, 0, sizeof(bk));
+ bk.req_szB = len;
+ bk.ec = VG_(record_ExeContext)(tid, 0/*first word delta*/);
+ intro_Block(&bk);
+
+ return True;
+ }
+
+ default:
+ VG_(message)(
+ Vg_UserMsg,
+ "Warning: unknown DHAT client request code %llx\n",
+ (ULong)arg[0]
+ );
+ return False;
+ }
+}
//------------------------------------------------------------//
//--- Finalisation ---//
// using VG_(apply_ExeContext) in combination with an InlIpCursor.
//
// - We use short field names and minimal whitespace to minimize file sizes.
+//
+// Sample output:
+//
+// {
+// // Version number of the format. Incremented on each
+// // backwards-incompatible change. A mandatory integer.
+// "dhatFileVersion": 2,
+//
+// // The invocation mode. A mandatory, free-form string.
+// "mode": "heap",
+//
+// // The verb used before above stack frames, i.e. "<verb> at {". A
+// // mandatory string.
+// "verb": "Allocated",
+//
+// // Are block lifetimes recorded? Affects whether some other fields are
+// // present. A mandatory boolean.
+// "bklt": true,
+//
+// // Are block accesses recorded? Affects whether some other fields are
+// // present. A mandatory boolean.
+// "bkacc": true,
+//
+// // Byte/bytes/blocks-position units. Optional strings. "byte", "bytes",
+// // and "blocks" are the values used if these fields are omitted.
+// "bu": "byte", "bsu": "bytes", "bksu": "blocks",
+//
+// // Time units (individual and 1,000,000x). Mandatory strings.
+// "tu": "instrs", "Mtu": "Minstr"
+//
+// // The "short-lived" time threshold, measures in "tu"s.
+// // - bklt=true: a mandatory integer.
+// // - bklt=false: omitted.
+// "tuth": 500,
+//
+// // The executed command. A mandatory string.
+// "cmd": "date",
+//
+// // The process ID. A mandatory integer.
+// "pid": 61129
+//
+// // The time at the end of execution (t-end). A mandatory integer.
+// "te": 350682
+//
+// // The time of the global max (t-gmax).
+// // - bklt=true: a mandatory integer.
+// // - bklt=false: omitted.
+// "tg": 331312,
+//
+// // The program points. A mandatory array.
+// "pps": [
+// {
+// // Total bytes and blocks. Mandatory integers.
+// "tb": 5, "tbk": 1,
+//
+// // Total lifetimes of all blocks allocated at this PP.
+// // - bklt=true: a mandatory integer.
+// // - bklt=false: omitted.
+// "tl": 274,
+//
+// // The maximum bytes and blocks for this PP.
+// // - bklt=true: mandatory integers.
+// // - bklt=false: omitted.
+// "mb": 5, "mbk": 1,
+//
+// // The bytes and blocks at t-gmax for this PP.
+// // - bklt=true: mandatory integers.
+// // - bklt=false: omitted.
+// "gb": 0, "gbk": 0,
+//
+// // The bytes and blocks at t-end for this PP.
+// // - bklt=true: mandatory integers.
+// // - bklt=false: omitted.
+// "eb": 0, "ebk": 0,
+//
+// // The reads and writes of blocks for this PP.
+// // - bkacc=true: mandatory integers.
+// // - bkacc=false: omitted.
+// "rb": 41, "wb": 5,
+//
+// // The exact accesses of blocks for this PP. Only used when all
+// // allocations are the same size and sufficiently small. A negative
+// // element indicates run-length encoding of the following integer.
+// // E.g. `-3, 4` means "three 4s in a row".
+// // - bkacc=true: an optional array of integers.
+// // - bkacc=false: omitted.
+// "acc": [5, -3, 4, 2],
+//
+// // Frames. Each element is an index into the "ftbl" array below.
+// // - All modes: A mandatory array of integers.
+// "fs": [1, 2, 3]
+// }
+// ],
+//
+// // Frame table. A mandatory array of strings.
+// "ftbl": [
+// "[root]",
+// "0x4AA1D9F: _nl_normalize_codeset (l10nflist.c:332)",
+// "0x4A9B414: _nl_load_locale_from_archive (loadarchive.c:173)",
+// "0x4A9A2BE: _nl_find_locale (findlocale.c:153)"
+// ]
+// }
static VgFile* fp;
return buf;
}
-static void write_APInfo_frame(UInt n, DiEpoch ep, Addr ip, void* opaque)
+static void write_PPInfo_frame(UInt n, DiEpoch ep, Addr ip, void* opaque)
{
Bool* is_first = (Bool*)opaque;
InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
VG_(delete_IIPC)(iipc);
};
-static void write_APInfo(APInfo* api, Bool is_first)
+static void write_PPInfo(PPInfo* ppi, Bool is_first)
{
- tl_assert(api->total_blocks >= api->max_blocks);
- tl_assert(api->total_bytes >= api->max_bytes);
-
- FP(" %c{\"tb\":%llu,\"tbk\":%llu,\"tli\":%llu\n",
+ FP(" %c{\"tb\":%llu,\"tbk\":%llu\n",
is_first ? '[' : ',',
- api->total_bytes, api->total_blocks, api->total_lifetimes_instrs);
- FP(" ,\"mb\":%llu,\"mbk\":%llu\n",
- api->max_bytes, api->max_blocks);
- FP(" ,\"gb\":%llu,\"gbk\":%llu\n",
- api->at_tgmax_bytes, api->at_tgmax_blocks);
- FP(" ,\"fb\":%llu,\"fbk\":%llu\n",
- api->curr_bytes, api->curr_blocks);
- FP(" ,\"rb\":%llu,\"wb\":%llu\n",
- api->reads_bytes, api->writes_bytes);
-
- if (api->histo && api->xsize_tag == Exactly) {
- FP(" ,\"acc\":[");
-
- // Simple run-length encoding: when N entries in a row have the same
- // value M, we print "-N,M". If there is just one in a row, we just
- // print "M". This reduces file size significantly.
- UShort repval = 0;
- Int reps = 0;
- for (UWord i = 0; i < api->xsize; i++) {
- UShort h = api->histo[i];
- if (repval == h) {
- // Continue current run.
- reps++;
- } else {
- // End of run; print it.
- if (reps == 1) {
- FP("%u,", repval);
- } else if (reps > 1) {
- FP("-%d,%u,", reps, repval);
+ ppi->total_bytes, ppi->total_blocks);
+
+ if (clo_mode == Heap) {
+ tl_assert(ppi->total_blocks >= ppi->max_blocks);
+ tl_assert(ppi->total_bytes >= ppi->max_bytes);
+
+ FP(" ,\"tl\":%llu\n",
+ ppi->total_lifetimes_instrs);
+ FP(" ,\"mb\":%llu,\"mbk\":%llu\n",
+ ppi->max_bytes, ppi->max_blocks);
+ FP(" ,\"gb\":%llu,\"gbk\":%llu\n",
+ ppi->at_tgmax_bytes, ppi->at_tgmax_blocks);
+ FP(" ,\"eb\":%llu,\"ebk\":%llu\n",
+ ppi->curr_bytes, ppi->curr_blocks);
+ FP(" ,\"rb\":%llu,\"wb\":%llu\n",
+ ppi->reads_bytes, ppi->writes_bytes);
+
+ if (ppi->histo && ppi->xsize_tag == Exactly) {
+ FP(" ,\"acc\":[");
+
+ // Simple run-length encoding: when N entries in a row have the same
+ // value M, we print "-N,M". If there is just one in a row, we just
+ // print "M". This reduces file size significantly.
+ UShort repval = 0;
+ Int reps = 0;
+ for (UWord i = 0; i < ppi->xsize; i++) {
+ UShort h = ppi->histo[i];
+ if (repval == h) {
+ // Continue current run.
+ reps++;
+ } else {
+ // End of run; print it.
+ if (reps == 1) {
+ FP("%u,", repval);
+ } else if (reps > 1) {
+ FP("-%d,%u,", reps, repval);
+ }
+ reps = 1;
+ repval = h;
}
- reps = 1;
- repval = h;
}
- }
- // Print the final run.
- if (reps == 1) {
- FP("%u", repval);
- } else if (reps > 1) {
- FP("-%d,%u", reps, repval);
- }
+ // Print the final run.
+ if (reps == 1) {
+ FP("%u", repval);
+ } else if (reps > 1) {
+ FP("-%d,%u", reps, repval);
+ }
- FP("]\n");
+ FP("]\n");
+ }
+ } else {
+ tl_assert(ppi->curr_bytes == 0);
+ tl_assert(ppi->curr_blocks == 0);
+ tl_assert(ppi->max_bytes == 0);
+ tl_assert(ppi->max_blocks == 0);
+ tl_assert(ppi->at_tgmax_bytes == 0);
+ tl_assert(ppi->at_tgmax_blocks == 0);
+ tl_assert(ppi->total_lifetimes_instrs == 0);
+ tl_assert(ppi->freed_blocks == 0);
+ tl_assert(ppi->reads_bytes == 0);
+ tl_assert(ppi->writes_bytes == 0);
+ tl_assert(ppi->xsize_tag == 0);
+ tl_assert(ppi->xsize == 0);
+ tl_assert(ppi->histo == NULL);
}
FP(" ,\"fs\":");
Bool is_first_frame = True;
- VG_(apply_ExeContext)(write_APInfo_frame, &is_first_frame, api->ap);
+ VG_(apply_ExeContext)(write_PPInfo_frame, &is_first_frame, ppi->ec);
FP("]\n");
FP(" }\n");
}
-static void write_APInfos(void)
+static void write_PPInfos(void)
{
UWord keyW, valW;
- FP(",\"aps\":\n");
+ FP(",\"pps\":\n");
- VG_(initIterFM)(apinfo);
+ VG_(initIterFM)(ppinfo);
Bool is_first = True;
- while (VG_(nextIterFM)(apinfo, &keyW, &valW)) {
- APInfo* api = (APInfo*)valW;
- tl_assert(api && api->ap == (ExeContext*)keyW);
- write_APInfo(api, is_first);
+ while (VG_(nextIterFM)(ppinfo, &keyW, &valW)) {
+ PPInfo* ppi = (PPInfo*)valW;
+ tl_assert(ppi && ppi->ec == (ExeContext*)keyW);
+ write_PPInfo(ppi, is_first);
is_first = False;
}
- VG_(doneIterFM)(apinfo);
+ VG_(doneIterFM)(ppinfo);
if (is_first) {
- // We didn't print any elements. This happens if apinfo is empty.
+ // We didn't print any elements. This happens if ppinfo is empty.
FP(" [\n");
}
// This function does lots of allocations that it doesn't bother to free,
// because execution is almost over anyway.
+ UWord keyW, valW;
+
// Total bytes might be at a possible peak.
- check_for_peak();
+ if (clo_mode == Heap) {
+ check_for_peak();
- // Before printing statistics, we must harvest various stats (such as
- // lifetimes and accesses) for all the blocks that are still alive.
- UWord keyW, valW;
- VG_(initIterFM)( interval_tree );
- while (VG_(nextIterFM)( interval_tree, &keyW, &valW )) {
- Block* bk = (Block*)keyW;
- tl_assert(valW == 0);
- tl_assert(bk);
- retire_Block(bk, False/*!because_freed*/);
- }
- VG_(doneIterFM)( interval_tree );
-
- // Stats.
- if (VG_(clo_stats)) {
- VG_(dmsg)(" dhat: find_Block_containing:\n");
- VG_(dmsg)(" found: %'lu (%'lu cached + %'lu uncached)\n",
- stats__n_fBc_cached + stats__n_fBc_uncached,
- stats__n_fBc_cached,
- stats__n_fBc_uncached);
- VG_(dmsg)(" notfound: %'lu\n", stats__n_fBc_notfound);
- VG_(dmsg)("\n");
+ // Before printing statistics, we must harvest various stats (such as
+ // lifetimes and accesses) for all the blocks that are still alive.
+ VG_(initIterFM)( interval_tree );
+ while (VG_(nextIterFM)( interval_tree, &keyW, &valW )) {
+ Block* bk = (Block*)keyW;
+ tl_assert(valW == 0);
+ tl_assert(bk);
+ retire_Block(bk, False/*!because_freed*/);
+ }
+ VG_(doneIterFM)( interval_tree );
+
+ // Stats.
+ if (VG_(clo_stats)) {
+ VG_(dmsg)(" dhat: find_Block_containing:\n");
+ VG_(dmsg)(" found: %'lu (%'lu cached + %'lu uncached)\n",
+ stats__n_fBc_cached + stats__n_fBc_uncached,
+ stats__n_fBc_cached,
+ stats__n_fBc_uncached);
+ VG_(dmsg)(" notfound: %'lu\n", stats__n_fBc_notfound);
+ VG_(dmsg)("\n");
+ }
}
// Create the frame table, and insert the special "[root]" node at index 0.
}
// Write to data file.
- FP("{\"dhatFileVersion\":1\n");
+ FP("{\"dhatFileVersion\":2\n");
+
+ // The output mode, block booleans, and byte/block units.
+ if (clo_mode == Heap) {
+ FP(",\"mode\":\"heap\",\"verb\":\"Allocated\"\n");
+ FP(",\"bklt\":true,\"bkacc\":true\n");
+ } else if (clo_mode == Copy) {
+ FP(",\"mode\":\"copy\",\"verb\":\"Copied\"\n");
+ FP(",\"bklt\":false,\"bkacc\":false\n");
+ } else if (clo_mode == AdHoc) {
+ FP(",\"mode\":\"ad-hoc\",\"verb\":\"Occurred\"\n");
+ FP(",\"bklt\":false,\"bkacc\":false\n");
+ FP(",\"bu\":\"unit\",\"bsu\":\"units\",\"bksu\":\"events\"\n");
+ } else {
+ tl_assert(False);
+ }
+
+ // The time units.
+ FP(",\"tu\":\"instrs\",\"Mtu\":\"Minstr\"\n");
+ if (clo_mode == Heap) {
+ FP(",\"tuth\":500\n");
+ }
// The command.
const HChar* exe = VG_(args_the_exename);
FP(",\"pid\":%d\n", VG_(getpid)());
// Times.
- FP(",\"mi\":%llu,\"ei\":%llu\n", g_max_instrs, g_curr_instrs);
+ FP(",\"te\":%llu\n", g_curr_instrs);
+ if (clo_mode == Heap) {
+ FP(",\"tg\":%llu\n", g_tgmax_instrs);
+ } else {
+ tl_assert(g_tgmax_instrs == 0);
+ }
// APs.
- write_APInfos();
+ write_PPInfos();
// Frame table.
FP(",\"ftbl\":\n");
}
// Print brief global stats.
- VG_(umsg)("Total: %'llu bytes in %'llu blocks\n",
- g_total_bytes, g_total_blocks);
- VG_(umsg)("At t-gmax: %'llu bytes in %'llu blocks\n",
- g_max_bytes, g_max_blocks);
- VG_(umsg)("At t-end: %'llu bytes in %'llu blocks\n",
- g_curr_bytes, g_curr_blocks);
- VG_(umsg)("Reads: %'llu bytes\n", g_reads_bytes);
- VG_(umsg)("Writes: %'llu bytes\n", g_writes_bytes);
+ VG_(umsg)("Total: %'llu %s in %'llu %s\n",
+ g_total_bytes, clo_mode == AdHoc ? "units" : "bytes",
+ g_total_blocks, clo_mode == AdHoc ? "events" : "blocks");
+ if (clo_mode == Heap) {
+ VG_(umsg)("At t-gmax: %'llu bytes in %'llu blocks\n",
+ g_max_bytes, g_max_blocks);
+ VG_(umsg)("At t-end: %'llu bytes in %'llu blocks\n",
+ g_curr_bytes, g_curr_blocks);
+ VG_(umsg)("Reads: %'llu bytes\n", g_reads_bytes);
+ VG_(umsg)("Writes: %'llu bytes\n", g_writes_bytes);
+ } else {
+ tl_assert(g_max_bytes == 0);
+ tl_assert(g_max_blocks == 0);
+ tl_assert(g_curr_bytes == 0);
+ tl_assert(g_curr_blocks == 0);
+ tl_assert(g_reads_bytes == 0);
+ tl_assert(g_writes_bytes == 0);
+ }
// Print a how-to-view-the-profile hint.
VG_(umsg)("\n");
VG_(umsg)("To view the resulting profile, open\n");
VG_(umsg)(" file://%s/%s\n", DHAT_VIEW_DIR, "dh_view.html");
- VG_(umsg)("in a web browser, click on \"Load...\" "
+ VG_(umsg)("in a web browser, click on \"Load...\", "
"and then select the file\n");
VG_(umsg)(" %s\n", dhat_out_file);
- VG_(umsg)("Scroll to the end the displayed page to see a short\n");
- VG_(umsg)("explanation of some of the abbreviations used in the page.\n");
+ VG_(umsg)("The text at the bottom explains the abbreviations used in the "
+ "output.\n");
VG_(free)(dhat_out_file);
}
static void dh_post_clo_init(void)
{
+ if (clo_mode == Heap) {
+ VG_(track_pre_mem_read) ( dh_handle_noninsn_read );
+ VG_(track_pre_mem_read_asciiz) ( dh_handle_noninsn_read_asciiz );
+ VG_(track_post_mem_write) ( dh_handle_noninsn_write );
+ }
}
static void dh_pre_clo_init(void)
VG_(basic_tool_funcs) (dh_post_clo_init,
dh_instrument,
dh_fini);
-//zz
+
// Needs.
VG_(needs_libc_freeres)();
VG_(needs_cxx_freeres)();
VG_(needs_command_line_options)(dh_process_cmd_line_option,
dh_print_usage,
dh_print_debug_usage);
-//zz VG_(needs_client_requests) (dh_handle_client_request);
-//zz VG_(needs_sanity_checks) (dh_cheap_sanity_check,
-//zz dh_expensive_sanity_check);
- VG_(needs_malloc_replacement) (dh_malloc,
- dh___builtin_new,
- dh___builtin_vec_new,
- dh_memalign,
- dh_calloc,
- dh_free,
- dh___builtin_delete,
- dh___builtin_vec_delete,
- dh_realloc,
- dh_malloc_usable_size,
- 0 );
-
- VG_(track_pre_mem_read) ( dh_handle_noninsn_read );
- //VG_(track_pre_mem_read_asciiz) ( check_mem_is_defined_asciiz );
- VG_(track_post_mem_write) ( dh_handle_noninsn_write );
+ VG_(needs_client_requests) (dh_handle_client_request);
+// VG_(needs_sanity_checks) (dh_cheap_sanity_check,
+// dh_expensive_sanity_check);
+ VG_(needs_malloc_replacement)(dh_malloc,
+ dh___builtin_new,
+ dh___builtin_vec_new,
+ dh_memalign,
+ dh_calloc,
+ dh_free,
+ dh___builtin_delete,
+ dh___builtin_vec_delete,
+ dh_realloc,
+ dh_malloc_usable_size,
+ 0 );
tl_assert(!interval_tree);
tl_assert(!fbc_cache0);
VG_(free),
interval_tree_Cmp );
- apinfo = VG_(newFM)( VG_(malloc),
- "dh.apinfo.1",
+ ppinfo = VG_(newFM)( VG_(malloc),
+ "dh.ppinfo.1",
VG_(free),
NULL/*unboxedcmp*/ );
}
--- /dev/null
+/*--------------------------------------------------------------------*/
+/*--- Replacements for memcpy(), which run on the simulated CPU ---*/
+/*--- simulated CPU. ---*/
+/*--- dh_replace_strmem.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of DHAT, a Valgrind tool for profiling the
+ heap usage of programs.
+
+ Copyright (C) 2020-2020 Nicholas Nethercote
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "dhat.h"
+
+#define RECORD_COPY(_qzz_len) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__DHAT_COPY, \
+ (_qzz_len), 0, 0, 0, 0)
+
+#include "../shared/vg_replace_strmem.c"
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
name: "empty",
input:
//---------------------------------------------------------------------------
-{"dhatFileVersion":1
+{"dhatFileVersion":2
+,"mode":"heap","verb":"Allocated"
+,"bklt":true,"bkacc":true
+,"tu":"instrs","Mtu":"Minstr"
+,"tuth":500
,"cmd":"./empty"
,"pid":23431
-,"mi":0,"ei":248602
-,"aps":
+,"te":248602
+,"tg":0
+,"pps":
[
]
,"ftbl":
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./empty
PID: 23431
}
t-end: 248,602 instrs
}
-─ AP 1/1 {
+─ PP 1/1 {
Total: 0 bytes (0%, 0/Minstr) in 0 blocks (0%, 0/Minstr), avg size 0 bytes, avg lifetime 0 instrs (0% of program duration)
At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
}
}
-AP significance threshold: total >= 0 bytes (0%)
+PP significance threshold: total >= 0 bytes (0%)
`
//---------------------------------------------------------------------------
}
name: "single",
input:
//---------------------------------------------------------------------------
-{"dhatFileVersion":1
+{"dhatFileVersion":2
+,"mode":"heap","verb":"Allocated"
+,"bklt":true,"bkacc":true
+,"tu":"instrs","Mtu":"Minstr"
+,"tuth":500
,"cmd":"./single"
,"pid":30563
-,"mi":242900,"ei":249824
-,"aps":
- [{"tb":16,"tbk":1,"tli":6924
+,"te":249824
+,"tg":242900
+,"pps":
+ [{"tb":16,"tbk":1,"tl":6924
,"mb":16,"mbk":1
,"gb":16,"gbk":1
- ,"fb":16,"fbk":1
+ ,"eb":16,"ebk":1
,"rb":0,"wb":12
,"acc":[-4,3,-12,0]
,"fs":[1]
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./single
PID: 30563
}
t-end: 249,824 instrs
}
-─ AP 1/1 {
+─ PP 1/1 {
Total: 16 bytes (100%, 64.05/Minstr) in 1 blocks (100%, 4/Minstr), avg size 16 bytes, avg lifetime 6,924 instrs (2.77% of program duration)
At t-gmax: 16 bytes (100%) in 1 blocks (100%), avg size 16 bytes
At t-end: 16 bytes (100%) in 1 blocks (100%), avg size 16 bytes
}
}
-AP significance threshold: total >= 0.16 bytes (1%)
+PP significance threshold: total >= 0.16 bytes (1%)
`
//---------------------------------------------------------------------------
}
name: "subseqs",
input:
//---------------------------------------------------------------------------
-{"dhatFileVersion":1
+{"dhatFileVersion":2
+,"mode":"heap","verb":"Allocated"
+,"bklt":true,"bkacc":true
+,"tu":"instrs","Mtu":"Minstr"
+,"tuth":500
,"cmd":"subseqs"
,"pid":0
-,"mi":10000,"ei":20000
-,"aps":
- [{"tb":15,"tbk":1,"tli":1000
+,"te":20000
+,"tg":10000
+,"pps":
+ [{"tb":15,"tbk":1,"tl":1000
,"mb":15,"mbk":1
,"gb":15,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-15,0]
,"fs":[1,2,3]
}
- ,{"tb":14,"tbk":1,"tli":1000
+ ,{"tb":14,"tbk":1,"tl":1000
,"mb":14,"mbk":1
,"gb":14,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-14,0]
,"fs":[1,2,3,3]
}
- ,{"tb":13,"tbk":1,"tli":1000
+ ,{"tb":13,"tbk":1,"tl":1000
,"mb":13,"mbk":1
,"gb":13,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-13,0]
,"fs":[1,2,3,3,3]
}
- ,{"tb":12,"tbk":1,"tli":1000
+ ,{"tb":12,"tbk":1,"tl":1000
,"mb":12,"mbk":1
,"gb":12,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-12,0]
,"fs":[4,5,6,6,6]
}
- ,{"tb":11,"tbk":1,"tli":1000
+ ,{"tb":11,"tbk":1,"tl":1000
,"mb":11,"mbk":1
,"gb":11,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-11,0]
,"fs":[4,5,6,6]
}
- ,{"tb":10,"tbk":1,"tli":1000
+ ,{"tb":10,"tbk":1,"tl":1000
,"mb":10,"mbk":1
,"gb":10,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[4,5,6]
}
- ,{"tb":9,"tbk":1,"tli":1000
+ ,{"tb":9,"tbk":1,"tl":1000
,"mb":9,"mbk":1
,"gb":9,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-9,0]
,"fs":[7,8,9]
}
- ,{"tb":8,"tbk":1,"tli":1000
+ ,{"tb":8,"tbk":1,"tl":1000
,"mb":8,"mbk":1
,"gb":8,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-8,0]
,"fs":[7,8,10]
}
- ,{"tb":7,"tbk":1,"tli":1000
+ ,{"tb":7,"tbk":1,"tl":1000
,"mb":7,"mbk":1
,"gb":7,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-7,0]
,"fs":[7,8]
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: subseqs
PID: 0
}
t-end: 20,000 instrs
}
-â–¼ AP 1/1 (3 children) {
+â–¼ PP 1/1 (3 children) {
Total: 99 bytes (100%, 4,950/Minstr) in 9 blocks (100%, 450/Minstr), avg size 11 bytes, avg lifetime 1,000 instrs (5% of program duration)
At t-gmax: 99 bytes (100%) in 9 blocks (100%), avg size 11 bytes
At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
#0: [root]
}
}
- ├─▼ AP 1.1/3 (2 children) {
+ ├─▼ PP 1.1/3 (2 children) {
│ Total: 42 bytes (42.42%, 2,100/Minstr) in 3 blocks (33.33%, 150/Minstr), avg size 14 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ At t-gmax: 42 bytes (42.42%) in 3 blocks (33.33%), avg size 14 bytes
│ At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #3: c()
│ }
│ }
- │ ├─▼ AP 1.1.1/2 (2 children) {
+ │ ├─▼ PP 1.1.1/2 (2 children) {
│ │ Total: 27 bytes (27.27%, 1,350/Minstr) in 2 blocks (22.22%, 100/Minstr), avg size 13.5 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ │ At t-gmax: 27 bytes (27.27%) in 2 blocks (22.22%), avg size 13.5 bytes
│ │ At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ #4: c()
│ │ }
│ │ }
- │ │ ├── AP 1.1.1.1/2 {
+ │ │ ├── PP 1.1.1.1/2 {
│ │ │ Total: 14 bytes (14.14%, 700/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 14 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ │ │ Max: 14 bytes in 1 blocks, avg size 14 bytes
│ │ │ At t-gmax: 14 bytes (14.14%) in 1 blocks (11.11%), avg size 14 bytes
│ │ │ ^4: c()
│ │ │ }
│ │ │ }
- │ │ └── AP 1.1.1.2/2 {
+ │ │ └── PP 1.1.1.2/2 {
│ │ Total: 13 bytes (13.13%, 650/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 13 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ │ Max: 13 bytes in 1 blocks, avg size 13 bytes
│ │ At t-gmax: 13 bytes (13.13%) in 1 blocks (11.11%), avg size 13 bytes
│ │ #5: c()
│ │ }
│ │ }
- │ └── AP 1.1.2/2 {
+ │ └── PP 1.1.2/2 {
│ Total: 15 bytes (15.15%, 750/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 15 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ Max: 15 bytes in 1 blocks, avg size 15 bytes
│ At t-gmax: 15 bytes (15.15%) in 1 blocks (11.11%), avg size 15 bytes
│ ^3: c()
│ }
│ }
- ├─▼ AP 1.2/3 (2 children) {
+ ├─▼ PP 1.2/3 (2 children) {
│ Total: 33 bytes (33.33%, 1,650/Minstr) in 3 blocks (33.33%, 150/Minstr), avg size 11 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ At t-gmax: 33 bytes (33.33%) in 3 blocks (33.33%), avg size 11 bytes
│ At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #3: f()
│ }
│ }
- │ ├─▼ AP 1.2.1/2 (2 children) {
+ │ ├─▼ PP 1.2.1/2 (2 children) {
│ │ Total: 23 bytes (23.23%, 1,150/Minstr) in 2 blocks (22.22%, 100/Minstr), avg size 11.5 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ │ At t-gmax: 23 bytes (23.23%) in 2 blocks (22.22%), avg size 11.5 bytes
│ │ At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ #4: f()
│ │ }
│ │ }
- │ │ ├── AP 1.2.1.1/2 {
+ │ │ ├── PP 1.2.1.1/2 {
│ │ │ Total: 12 bytes (12.12%, 600/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 12 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ │ │ Max: 12 bytes in 1 blocks, avg size 12 bytes
│ │ │ At t-gmax: 12 bytes (12.12%) in 1 blocks (11.11%), avg size 12 bytes
│ │ │ #5: f()
│ │ │ }
│ │ │ }
- │ │ └── AP 1.2.1.2/2 {
+ │ │ └── PP 1.2.1.2/2 {
│ │ Total: 11 bytes (11.11%, 550/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 11 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ │ Max: 11 bytes in 1 blocks, avg size 11 bytes
│ │ At t-gmax: 11 bytes (11.11%) in 1 blocks (11.11%), avg size 11 bytes
│ │ ^4: f()
│ │ }
│ │ }
- │ └── AP 1.2.2/2 {
+ │ └── PP 1.2.2/2 {
│ Total: 10 bytes (10.1%, 500/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 10 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ Max: 10 bytes in 1 blocks, avg size 10 bytes
│ At t-gmax: 10 bytes (10.1%) in 1 blocks (11.11%), avg size 10 bytes
│ ^3: f()
│ }
│ }
- └─▼ AP 1.3/3 (3 children) {
+ └─▼ PP 1.3/3 (3 children) {
Total: 24 bytes (24.24%, 1,200/Minstr) in 3 blocks (33.33%, 150/Minstr), avg size 8 bytes, avg lifetime 1,000 instrs (5% of program duration)
At t-gmax: 24 bytes (24.24%) in 3 blocks (33.33%), avg size 8 bytes
At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
#2: h()
}
}
- ├── AP 1.3.1/3 {
+ ├── PP 1.3.1/3 {
│ Total: 9 bytes (9.09%, 450/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 9 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ Max: 9 bytes in 1 blocks, avg size 9 bytes
│ At t-gmax: 9 bytes (9.09%) in 1 blocks (11.11%), avg size 9 bytes
│ #3: i()
│ }
│ }
- ├── AP 1.3.2/3 {
+ ├── PP 1.3.2/3 {
│ Total: 8 bytes (8.08%, 400/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 8 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ Max: 8 bytes in 1 blocks, avg size 8 bytes
│ At t-gmax: 8 bytes (8.08%) in 1 blocks (11.11%), avg size 8 bytes
│ #3: j()
│ }
│ }
- └── AP 1.3.3/3 {
+ └── PP 1.3.3/3 {
Total: 7 bytes (7.07%, 350/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 7 bytes, avg lifetime 1,000 instrs (5% of program duration)
Max: 7 bytes in 1 blocks, avg size 7 bytes
At t-gmax: 7 bytes (7.07%) in 1 blocks (11.11%), avg size 7 bytes
}
}
-AP significance threshold: total >= 0.99 bytes (1%)
+PP significance threshold: total >= 0.99 bytes (1%)
`
//---------------------------------------------------------------------------
}
name: "acc",
input:
//---------------------------------------------------------------------------
-{"dhatFileVersion":1
+{"dhatFileVersion":2
+,"mode":"heap","verb":"Allocated"
+,"bklt":true,"bkacc":true
+,"tu":"instrs","Mtu":"Minstr"
+,"tuth":500
,"cmd":"./acc"
,"pid":23513
-,"mi":265120,"ei":1337753
-,"aps":
- [{"tb":32,"tbk":1,"tli":4751
+,"te":1337753
+,"tg":265120
+,"pps":
+ [{"tb":32,"tbk":1,"tl":4751
,"mb":32,"mbk":1
,"gb":0,"gbk":0
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":496
,"acc":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]
,"fs":[1]
}
- ,{"tb":20,"tbk":1,"tli":106
+ ,{"tb":20,"tbk":1,"tl":106
,"mb":20,"mbk":1
,"gb":0,"gbk":0
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":4,"wb":48
,"acc":[-4,2,-4,0,-4,1,-4,0,-4,10]
,"fs":[2]
}
- ,{"tb":33,"tbk":1,"tli":39
+ ,{"tb":33,"tbk":1,"tl":39
,"mb":33,"mbk":1
,"gb":0,"gbk":0
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":1
,"acc":[-32,0,1]
,"fs":[3]
}
- ,{"tb":1024,"tbk":1,"tli":15179
+ ,{"tb":1024,"tbk":1,"tl":15179
,"mb":1024,"mbk":1
,"gb":0,"gbk":0
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":1024,"wb":1124
,"acc":[-500,2,-100,3,-424,2]
,"fs":[4]
}
- ,{"tb":1025,"tbk":1,"tli":15415
+ ,{"tb":1025,"tbk":1,"tl":15415
,"mb":1025,"mbk":1
,"gb":1025,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":1025,"wb":1025
,"fs":[5]
}
- ,{"tb":100,"tbk":1,"tli":350084
+ ,{"tb":100,"tbk":1,"tl":350084
,"mb":100,"mbk":1
,"gb":0,"gbk":0
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":200000
,"acc":[-4,50000,-96,0]
,"fs":[6,7]
}
- ,{"tb":100,"tbk":1,"tli":350072
+ ,{"tb":100,"tbk":1,"tl":350072
,"mb":100,"mbk":1
,"gb":0,"gbk":0
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":200000
,"acc":[-4,50000,-96,0]
,"fs":[6,8]
}
- ,{"tb":100,"tbk":1,"tli":700084
+ ,{"tb":100,"tbk":1,"tl":700084
,"mb":100,"mbk":1
,"gb":0,"gbk":0
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":400000
,"acc":[-4,65535,-96,0]
,"fs":[9,10]
}
- ,{"tb":100,"tbk":1,"tli":700072
+ ,{"tb":100,"tbk":1,"tl":700072
,"mb":100,"mbk":1
,"gb":0,"gbk":0
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":400000
,"acc":[-4,65535,-96,0]
,"fs":[9,11]
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./acc
PID: 23513
}
t-end: 1,337,753 instrs
}
-â–¼ AP 1/1 (7 children) {
+â–¼ PP 1/1 (7 children) {
Total: 2,534 bytes (100%, 1,894.22/Minstr) in 9 blocks (100%, 6.73/Minstr), avg size 281.56 bytes, avg lifetime 237,311.33 instrs (17.74% of program duration)
At t-gmax: 1,025 bytes (100%) in 1 blocks (100%), avg size 1,025 bytes
At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
#0: [root]
}
}
- ├── AP 1.1/7 {
+ ├── PP 1.1/7 {
│ Total: 1,025 bytes (40.45%, 766.21/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 1,025 bytes, avg lifetime 15,415 instrs (1.15% of program duration)
│ Max: 1,025 bytes in 1 blocks, avg size 1,025 bytes
│ At t-gmax: 1,025 bytes (100%) in 1 blocks (100%), avg size 1,025 bytes
│ #1: 0x10886F: main (acc.c:47)
│ }
│ }
- ├── AP 1.2/7 {
+ ├── PP 1.2/7 {
│ Total: 1,024 bytes (40.41%, 765.46/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 1,024 bytes, avg lifetime 15,179 instrs (1.13% of program duration)
│ Max: 1,024 bytes in 1 blocks, avg size 1,024 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #1: 0x1087F0: main (acc.c:37)
│ }
│ }
- ├─▼ AP 1.3/7 (2 children) {
+ ├─▼ PP 1.3/7 (2 children) {
│ Total: 200 bytes (7.89%, 149.5/Minstr) in 2 blocks (22.22%, 1.5/Minstr), avg size 100 bytes, avg lifetime 350,078 instrs (26.17% of program duration)
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #1: 0x1086F1: m1 (acc.c:7)
│ }
│ }
- │ ├── AP 1.3.1/2 {
+ │ ├── PP 1.3.1/2 {
│ │ Total: 100 bytes (3.95%, 74.75/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 100 bytes, avg lifetime 350,084 instrs (26.17% of program duration)
│ │ Max: 100 bytes in 1 blocks, avg size 100 bytes
│ │ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ #2: 0x1088C3: main (acc.c:54)
│ │ }
│ │ }
- │ └── AP 1.3.2/2 {
+ │ └── PP 1.3.2/2 {
│ Total: 100 bytes (3.95%, 74.75/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 100 bytes, avg lifetime 350,072 instrs (26.17% of program duration)
│ Max: 100 bytes in 1 blocks, avg size 100 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #2: 0x1088D1: main (acc.c:55)
│ }
│ }
- ├─▼ AP 1.4/7 (2 children) {
+ ├─▼ PP 1.4/7 (2 children) {
│ Total: 200 bytes (7.89%, 149.5/Minstr) in 2 blocks (22.22%, 1.5/Minstr), avg size 100 bytes, avg lifetime 700,078 instrs (52.33% of program duration)
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #1: 0x10870B: m2 (acc.c:9)
│ }
│ }
- │ ├── AP 1.4.1/2 {
+ │ ├── PP 1.4.1/2 {
│ │ Total: 100 bytes (3.95%, 74.75/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 100 bytes, avg lifetime 700,084 instrs (52.33% of program duration)
│ │ Max: 100 bytes in 1 blocks, avg size 100 bytes
│ │ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ #2: 0x108921: main (acc.c:64)
│ │ }
│ │ }
- │ └── AP 1.4.2/2 {
+ │ └── PP 1.4.2/2 {
│ Total: 100 bytes (3.95%, 74.75/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 100 bytes, avg lifetime 700,072 instrs (52.33% of program duration)
│ Max: 100 bytes in 1 blocks, avg size 100 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #2: 0x10892F: main (acc.c:65)
│ }
│ }
- ├── AP 1.5/7 {
+ ├── PP 1.5/7 {
│ Total: 33 bytes (1.3%, 24.67/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 33 bytes, avg lifetime 39 instrs (0% of program duration)
│ Max: 33 bytes in 1 blocks, avg size 33 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #1: 0x1087CB: main (acc.c:32)
│ }
│ }
- ├── AP 1.6/7 {
+ ├── PP 1.6/7 {
│ Total: 32 bytes (1.26%, 23.92/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 32 bytes, avg lifetime 4,751 instrs (0.36% of program duration)
│ Max: 32 bytes in 1 blocks, avg size 32 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #1: 0x10871F: main (acc.c:14)
│ }
│ }
- └── AP 1.7/7 {
+ └── PP 1.7/7 {
Total: 20 bytes (0.79%, 14.95/Minstr) in 1 blocks (11.11%, 0.75/Minstr), avg size 20 bytes, avg lifetime 106 instrs (0.01% of program duration)
Max: 20 bytes in 1 blocks, avg size 20 bytes
At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
}
}
-AP significance threshold: at-t-end >= 0 bytes (0%)
+PP significance threshold: at-t-end >= 0 bytes (0%)
`
//---------------------------------------------------------------------------
}
name: "big",
input:
//---------------------------------------------------------------------------
-{"dhatFileVersion":1
+{"dhatFileVersion":2
+,"mode":"heap","verb":"Allocated"
+,"bklt":true,"bkacc":true
+,"tu":"instrs","Mtu":"Minstr"
+,"tuth":500
,"cmd":"./big"
,"pid":3902
-,"mi":245281,"ei":253354
-,"aps":
- [{"tb":706,"tbk":1,"tli":543
+,"te":253354
+,"tg":245281
+,"pps":
+ [{"tb":706,"tbk":1,"tl":543
,"mb":706,"mbk":1
,"gb":706,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-706,0]
,"fs":[1,2,3,4,5]
}
- ,{"tb":5,"tbk":1,"tli":7972
+ ,{"tb":5,"tbk":1,"tl":7972
,"mb":5,"mbk":1
,"gb":0,"gbk":0
- ,"fb":5,"fbk":1
+ ,"eb":5,"ebk":1
,"rb":0,"wb":0
,"acc":[-5,0]
,"fs":[1,2,3,6,7]
}
- ,{"tb":30,"tbk":1,"tli":7910
+ ,{"tb":30,"tbk":1,"tl":7910
,"mb":30,"mbk":1
,"gb":0,"gbk":0
- ,"fb":30,"fbk":1
+ ,"eb":30,"ebk":1
,"rb":0,"wb":0
,"acc":[-30,0]
,"fs":[1,2,8,9]
}
- ,{"tb":20,"tbk":1,"tli":7857
+ ,{"tb":20,"tbk":1,"tl":7857
,"mb":20,"mbk":1
,"gb":0,"gbk":0
- ,"fb":20,"fbk":1
+ ,"eb":20,"ebk":1
,"rb":0,"wb":0
,"acc":[-20,0]
,"fs":[1,10,11]
}
- ,{"tb":10,"tbk":1,"tli":7792
+ ,{"tb":10,"tbk":1,"tl":7792
,"mb":10,"mbk":1
,"gb":0,"gbk":0
- ,"fb":10,"fbk":1
+ ,"eb":10,"ebk":1
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[1,12,13,14,15]
}
- ,{"tb":60,"tbk":1,"tli":7709
+ ,{"tb":60,"tbk":1,"tl":7709
,"mb":60,"mbk":1
,"gb":0,"gbk":0
- ,"fb":60,"fbk":1
+ ,"eb":60,"ebk":1
,"rb":0,"wb":0
,"acc":[-60,0]
,"fs":[16,17,18,19,20,21,22]
}
- ,{"tb":30,"tbk":1,"tli":7622
+ ,{"tb":30,"tbk":1,"tl":7622
,"mb":30,"mbk":1
,"gb":0,"gbk":0
- ,"fb":30,"fbk":1
+ ,"eb":30,"ebk":1
,"rb":0,"wb":0
,"acc":[-30,0]
,"fs":[16,17,18,23,24,25,26]
}
- ,{"tb":20,"tbk":1,"tli":7528
+ ,{"tb":20,"tbk":1,"tl":7528
,"mb":20,"mbk":1
,"gb":0,"gbk":0
- ,"fb":20,"fbk":1
+ ,"eb":20,"ebk":1
,"rb":0,"wb":0
,"acc":[-20,0]
,"fs":[16,17,18,23,24,27,28,29]
}
- ,{"tb":7,"tbk":1,"tli":7446
+ ,{"tb":7,"tbk":1,"tl":7446
,"mb":7,"mbk":1
,"gb":0,"gbk":0
- ,"fb":7,"fbk":1
+ ,"eb":7,"ebk":1
,"rb":0,"wb":0
,"acc":[-7,0]
,"fs":[16,17,18,30,31,32]
}
- ,{"tb":3,"tbk":1,"tli":7375
+ ,{"tb":3,"tbk":1,"tl":7375
,"mb":3,"mbk":1
,"gb":0,"gbk":0
- ,"fb":3,"fbk":1
+ ,"eb":3,"ebk":1
,"rb":0,"wb":0
,"acc":[-3,0]
,"fs":[16,17,18,33,34]
}
- ,{"tb":30,"tbk":1,"tli":7299
+ ,{"tb":30,"tbk":1,"tl":7299
,"mb":30,"mbk":1
,"gb":0,"gbk":0
- ,"fb":30,"fbk":1
+ ,"eb":30,"ebk":1
,"rb":0,"wb":0
,"acc":[-30,0]
,"fs":[35,36,37,38,39,40]
}
- ,{"tb":20,"tbk":1,"tli":7249
+ ,{"tb":20,"tbk":1,"tl":7249
,"mb":20,"mbk":1
,"gb":0,"gbk":0
- ,"fb":20,"fbk":1
+ ,"eb":20,"ebk":1
,"rb":0,"wb":0
,"acc":[-20,0]
,"fs":[41,42]
}
- ,{"tb":19,"tbk":1,"tli":7207
+ ,{"tb":19,"tbk":1,"tl":7207
,"mb":19,"mbk":1
,"gb":0,"gbk":0
- ,"fb":19,"fbk":1
+ ,"eb":19,"ebk":1
,"rb":0,"wb":0
,"acc":[-19,0]
,"fs":[43,44]
}
- ,{"tb":9,"tbk":1,"tli":7158
+ ,{"tb":9,"tbk":1,"tl":7158
,"mb":9,"mbk":1
,"gb":0,"gbk":0
- ,"fb":9,"fbk":1
+ ,"eb":9,"ebk":1
,"rb":0,"wb":0
,"acc":[-9,0]
,"fs":[45,46,47]
}
- ,{"tb":8,"tbk":1,"tli":7107
+ ,{"tb":8,"tbk":1,"tl":7107
,"mb":8,"mbk":1
,"gb":0,"gbk":0
- ,"fb":8,"fbk":1
+ ,"eb":8,"ebk":1
,"rb":0,"wb":0
,"acc":[-8,0]
,"fs":[45,48,49]
}
- ,{"tb":7,"tbk":1,"tli":7056
+ ,{"tb":7,"tbk":1,"tl":7056
,"mb":7,"mbk":1
,"gb":0,"gbk":0
- ,"fb":7,"fbk":1
+ ,"eb":7,"ebk":1
,"rb":0,"wb":0
,"acc":[-7,0]
,"fs":[45,50,51]
}
- ,{"tb":5,"tbk":1,"tli":7005
+ ,{"tb":5,"tbk":1,"tl":7005
,"mb":5,"mbk":1
,"gb":0,"gbk":0
- ,"fb":5,"fbk":1
+ ,"eb":5,"ebk":1
,"rb":0,"wb":0
,"acc":[-5,0]
,"fs":[45,52,53]
}
- ,{"tb":1,"tbk":1,"tli":6954
+ ,{"tb":1,"tbk":1,"tl":6954
,"mb":1,"mbk":1
,"gb":0,"gbk":0
- ,"fb":1,"fbk":1
+ ,"eb":1,"ebk":1
,"rb":0,"wb":0
,"acc":[0]
,"fs":[45,52,54]
}
- ,{"tb":10,"tbk":1,"tli":6917
+ ,{"tb":10,"tbk":1,"tl":6917
,"mb":10,"mbk":1
,"gb":0,"gbk":0
- ,"fb":10,"fbk":1
+ ,"eb":10,"ebk":1
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[55]
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./big
PID: 3902
}
t-end: 253,354 instrs
}
-â–¼ AP 1/1 (7 children) {
+â–¼ PP 1/1 (7 children) {
Total: 1,000 bytes (100%, 3,947.05/Minstr) in 19 blocks (100%, 74.99/Minstr), avg size 52.63 bytes, avg lifetime 7,037.16 instrs (2.78% of program duration)
At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
At t-end: 294 bytes (100%) in 18 blocks (100%), avg size 16.33 bytes
#0: [root]
}
}
- ├─▼ AP 1.1/7 (3 children) {
+ ├─▼ PP 1.1/7 (3 children) {
│ Total: 771 bytes (77.1%, 3,043.17/Minstr) in 5 blocks (26.32%, 19.74/Minstr), avg size 154.2 bytes, avg lifetime 6,414.8 instrs (2.53% of program duration)
│ At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
│ At t-end: 65 bytes (22.11%) in 4 blocks (22.22%), avg size 16.25 bytes
│ #1: 0x1086A1: a (big.c:10)
│ }
│ }
- │ ├─▼ AP 1.1.1/3 (2 children) {
+ │ ├─▼ PP 1.1.1/3 (2 children) {
│ │ Total: 741 bytes (74.1%, 2,924.76/Minstr) in 3 blocks (15.79%, 11.84/Minstr), avg size 247 bytes, avg lifetime 5,475 instrs (2.16% of program duration)
│ │ At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
│ │ At t-end: 35 bytes (11.9%) in 2 blocks (11.11%), avg size 17.5 bytes
│ │ #2: 0x1086BB: b1 (big.c:11)
│ │ }
│ │ }
- │ │ ├─▼ AP 1.1.1.1/2 (2 children) {
+ │ │ ├─▼ PP 1.1.1.1/2 (2 children) {
│ │ │ Total: 711 bytes (71.1%, 2,806.35/Minstr) in 2 blocks (10.53%, 7.89/Minstr), avg size 355.5 bytes, avg lifetime 4,257.5 instrs (1.68% of program duration)
│ │ │ At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
│ │ │ At t-end: 5 bytes (1.7%) in 1 blocks (5.56%), avg size 5 bytes
│ │ │ #3: 0x1086D5: c1 (big.c:12)
│ │ │ }
│ │ │ }
- │ │ │ ├── AP 1.1.1.1.1/2 {
+ │ │ │ ├── PP 1.1.1.1.1/2 {
│ │ │ │ Total: 706 bytes (70.6%, 2,786.61/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 706 bytes, avg lifetime 543 instrs (0.21% of program duration)
│ │ │ │ Max: 706 bytes in 1 blocks, avg size 706 bytes
│ │ │ │ At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
│ │ │ │ #5: 0x108A43: main (big.c:38)
│ │ │ │ }
│ │ │ │ }
- │ │ │ └── AP 1.1.1.1.2/2 {
+ │ │ │ └── PP 1.1.1.1.2/2 {
│ │ │ Total: 5 bytes (0.5%, 19.74/Minstr)
│ │ │ Allocated at {
│ │ │ [1 insignificant]
│ │ │ }
│ │ │ }
- │ │ └── AP 1.1.1.2/2 {
+ │ │ └── PP 1.1.1.2/2 {
│ │ Total: 30 bytes (3%, 118.41/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 30 bytes, avg lifetime 7,910 instrs (3.12% of program duration)
│ │ Max: 30 bytes in 1 blocks, avg size 30 bytes
│ │ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ #4: 0x108A67: main (big.c:42)
│ │ }
│ │ }
- │ ├── AP 1.1.2/3 {
+ │ ├── PP 1.1.2/3 {
│ │ Total: 20 bytes (2%, 78.94/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 20 bytes, avg lifetime 7,857 instrs (3.1% of program duration)
│ │ Max: 20 bytes in 1 blocks, avg size 20 bytes
│ │ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ #3: 0x108A71: main (big.c:43)
│ │ }
│ │ }
- │ └── AP 1.1.3/3 {
+ │ └── PP 1.1.3/3 {
│ Total: 10 bytes (1%, 39.47/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 10 bytes, avg lifetime 7,792 instrs (3.08% of program duration)
│ Max: 10 bytes in 1 blocks, avg size 10 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #5: 0x108A7B: main (big.c:44)
│ }
│ }
- ├─▼ AP 1.2/7 (3 children) {
+ ├─▼ PP 1.2/7 (3 children) {
│ Total: 120 bytes (12%, 473.65/Minstr) in 5 blocks (26.32%, 19.74/Minstr), avg size 24 bytes, avg lifetime 7,536 instrs (2.97% of program duration)
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ At t-end: 120 bytes (40.82%) in 5 blocks (27.78%), avg size 24 bytes
│ #3: 0x1087D9: i (big.c:18)
│ }
│ }
- │ ├── AP 1.2.1/3 {
+ │ ├── PP 1.2.1/3 {
│ │ Total: 60 bytes (6%, 236.82/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 60 bytes, avg lifetime 7,709 instrs (3.04% of program duration)
│ │ Max: 60 bytes in 1 blocks, avg size 60 bytes
│ │ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ #7: 0x108A85: main (big.c:45)
│ │ }
│ │ }
- │ ├─▼ AP 1.2.2/3 (2 children) {
+ │ ├─▼ PP 1.2.2/3 (2 children) {
│ │ Total: 50 bytes (5%, 197.35/Minstr) in 2 blocks (10.53%, 7.89/Minstr), avg size 25 bytes, avg lifetime 7,575 instrs (2.99% of program duration)
│ │ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ At t-end: 50 bytes (17.01%) in 2 blocks (11.11%), avg size 25 bytes
│ │ #5: 0x10885B: m (big.c:20)
│ │ }
│ │ }
- │ │ ├── AP 1.2.2.1/2 {
+ │ │ ├── PP 1.2.2.1/2 {
│ │ │ Total: 30 bytes (3%, 118.41/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 30 bytes, avg lifetime 7,622 instrs (3.01% of program duration)
│ │ │ Max: 30 bytes in 1 blocks, avg size 30 bytes
│ │ │ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ │ #7: 0x108A8F: main (big.c:46)
│ │ │ }
│ │ │ }
- │ │ └── AP 1.2.2.2/2 {
+ │ │ └── PP 1.2.2.2/2 {
│ │ Total: 20 bytes (2%, 78.94/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 20 bytes, avg lifetime 7,528 instrs (2.97% of program duration)
│ │ Max: 20 bytes in 1 blocks, avg size 20 bytes
│ │ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ │ #8: 0x108A99: main (big.c:47)
│ │ }
│ │ }
- │ └── AP 1.2.3/3 {
+ │ └── PP 1.2.3/3 {
│ Total: 10 bytes (1%, 39.47/Minstr)
│ Allocated at {
│ [2 insignificant]
│ }
│ }
- ├── AP 1.3/7 {
+ ├── PP 1.3/7 {
│ Total: 30 bytes (3%, 118.41/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 30 bytes, avg lifetime 7,299 instrs (2.88% of program duration)
│ Max: 30 bytes in 1 blocks, avg size 30 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #6: 0x108AB7: main (big.c:50)
│ }
│ }
- ├─▼ AP 1.4/7 (1 children) {
+ ├─▼ PP 1.4/7 (1 children) {
│ Total: 30 bytes (3%, 118.41/Minstr) in 5 blocks (26.32%, 19.74/Minstr), avg size 6 bytes, avg lifetime 7,056 instrs (2.79% of program duration)
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ At t-end: 30 bytes (10.2%) in 5 blocks (27.78%), avg size 6 bytes
│ #1: 0x1089C7: v (big.c:28)
│ }
│ }
- │ └── AP 1.4.1/1 {
+ │ └── PP 1.4.1/1 {
│ Total: 30 bytes (3%, 118.41/Minstr)
│ Allocated at {
│ [4 insignificant]
│ }
│ }
- ├── AP 1.5/7 {
+ ├── PP 1.5/7 {
│ Total: 20 bytes (2%, 78.94/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 20 bytes, avg lifetime 7,249 instrs (2.86% of program duration)
│ Max: 20 bytes in 1 blocks, avg size 20 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #2: 0x108AC1: main (big.c:51)
│ }
│ }
- ├── AP 1.6/7 {
+ ├── PP 1.6/7 {
│ Total: 19 bytes (1.9%, 74.99/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 19 bytes, avg lifetime 7,207 instrs (2.84% of program duration)
│ Max: 19 bytes in 1 blocks, avg size 19 bytes
│ At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
│ #2: 0x108ACB: main (big.c:52)
│ }
│ }
- └── AP 1.7/7 {
+ └── PP 1.7/7 {
Total: 10 bytes (1%, 39.47/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 10 bytes, avg lifetime 6,917 instrs (2.73% of program duration)
Max: 10 bytes in 1 blocks, avg size 10 bytes
At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
}
}
-AP significance threshold: total >= 10 bytes (1%)
+PP significance threshold: total >= 10 bytes (1%)
`
//---------------------------------------------------------------------------
},
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./big
PID: 3902
}
t-end: 253,354 instrs
}
-â–¼ AP 1/1 (1 children) {
+â–¼ PP 1/1 (1 children) {
Total: 19 blocks (100%, 74.99/Minstr), avg lifetime 7,037.16 instrs (2.78% of program duration)
Allocated at {
#0: [root]
}
}
- └── AP 1.1/1 {
+ └── PP 1.1/1 {
Total: 19 blocks (100%, 74.99/Minstr), avg lifetime 7,037.16 instrs (2.78% of program duration)
Allocated at {
[7 insignificant]
}
}
-AP significance threshold: (total >= 0.1 blocks (0.5%)) && (total avg lifetime <= 500 instrs)
+PP significance threshold: (total >= 0.1 blocks (0.5%)) && (avg lifetime <= 500 instrs)
`
//---------------------------------------------------------------------------
},
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./big
PID: 3902
}
t-end: 253,354 instrs
}
-â–¼ AP 1/1 (2 children) {
+â–¼ PP 1/1 (2 children) {
Total: 1,000 bytes (100%, 3,947.05/Minstr) in 19 blocks (100%, 74.99/Minstr), avg size 52.63 bytes, avg lifetime 7,037.16 instrs (2.78% of program duration)
At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
At t-end: 294 bytes (100%) in 18 blocks (100%), avg size 16.33 bytes
#0: [root]
}
}
- ├─▼ AP 1.1/2 (2 children) {
+ ├─▼ PP 1.1/2 (2 children) {
│ Total: 771 bytes (77.1%, 3,043.17/Minstr) in 5 blocks (26.32%, 19.74/Minstr), avg size 154.2 bytes, avg lifetime 6,414.8 instrs (2.53% of program duration)
│ At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
│ At t-end: 65 bytes (22.11%) in 4 blocks (22.22%), avg size 16.25 bytes
│ #1: 0x1086A1: a (big.c:10)
│ }
│ }
- │ ├─▼ AP 1.1.1/2 (2 children) {
+ │ ├─▼ PP 1.1.1/2 (2 children) {
│ │ Total: 741 bytes (74.1%, 2,924.76/Minstr) in 3 blocks (15.79%, 11.84/Minstr), avg size 247 bytes, avg lifetime 5,475 instrs (2.16% of program duration)
│ │ At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
│ │ At t-end: 35 bytes (11.9%) in 2 blocks (11.11%), avg size 17.5 bytes
│ │ #2: 0x1086BB: b1 (big.c:11)
│ │ }
│ │ }
- │ │ ├─▼ AP 1.1.1.1/2 (2 children) {
+ │ │ ├─▼ PP 1.1.1.1/2 (2 children) {
│ │ │ Total: 711 bytes (71.1%, 2,806.35/Minstr) in 2 blocks (10.53%, 7.89/Minstr), avg size 355.5 bytes, avg lifetime 4,257.5 instrs (1.68% of program duration)
│ │ │ At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
│ │ │ At t-end: 5 bytes (1.7%) in 1 blocks (5.56%), avg size 5 bytes
│ │ │ #3: 0x1086D5: c1 (big.c:12)
│ │ │ }
│ │ │ }
- │ │ │ ├── AP 1.1.1.1.1/2 {
+ │ │ │ ├── PP 1.1.1.1.1/2 {
│ │ │ │ Total: 706 bytes (70.6%, 2,786.61/Minstr) in 1 blocks (5.26%, 3.95/Minstr), avg size 706 bytes, avg lifetime 543 instrs (0.21% of program duration)
│ │ │ │ Max: 706 bytes in 1 blocks, avg size 706 bytes
│ │ │ │ At t-gmax: 706 bytes (100%) in 1 blocks (100%), avg size 706 bytes
│ │ │ │ #5: 0x108A43: main (big.c:38)
│ │ │ │ }
│ │ │ │ }
- │ │ │ └── AP 1.1.1.1.2/2 {
+ │ │ │ └── PP 1.1.1.1.2/2 {
│ │ │ At t-gmax: 0 bytes (0%)
│ │ │ Allocated at {
│ │ │ [1 insignificant]
│ │ │ }
│ │ │ }
- │ │ └── AP 1.1.1.2/2 {
+ │ │ └── PP 1.1.1.2/2 {
│ │ At t-gmax: 0 bytes (0%)
│ │ Allocated at {
│ │ [1 insignificant]
│ │ }
│ │ }
- │ └── AP 1.1.2/2 {
+ │ └── PP 1.1.2/2 {
│ At t-gmax: 0 bytes (0%)
│ Allocated at {
│ [2 insignificant]
│ }
│ }
- └── AP 1.2/2 {
+ └── PP 1.2/2 {
At t-gmax: 0 bytes (0%)
Allocated at {
[6 insignificant]
}
}
-AP significance threshold: at-t-gmax >= 7.06 bytes (1%)
+PP significance threshold: at-t-gmax >= 7.06 bytes (1%)
`
//---------------------------------------------------------------------------
}
name: "sig",
input:
//---------------------------------------------------------------------------
-{"dhatFileVersion":1
+{"dhatFileVersion":2
+,"mode":"heap","verb":"Allocated"
+,"bklt":true,"bkacc":true
+,"tu":"instrs","Mtu":"Minstr"
+,"tuth":500
,"cmd":"./sig"
,"pid":21476
-,"mi":1311861,"ei":1318783
-,"aps":
- [{"tb":11,"tbk":1,"tli":1075941
+,"te":1318783
+,"tg":1311861
+,"pps":
+ [{"tb":11,"tbk":1,"tl":1075941
,"mb":11,"mbk":1
,"gb":11,"gbk":1
- ,"fb":11,"fbk":1
+ ,"eb":11,"ebk":1
,"rb":11,"wb":16489
,"acc":[-11,1500]
,"fs":[1,2]
}
- ,{"tb":10,"tbk":1,"tli":880845
+ ,{"tb":10,"tbk":1,"tl":880845
,"mb":10,"mbk":1
,"gb":10,"gbk":1
- ,"fb":10,"fbk":1
+ ,"eb":10,"ebk":1
,"rb":10,"wb":14990
,"acc":[-10,1500]
,"fs":[1,3,4]
}
- ,{"tb":5,"tbk":1,"tli":702250
+ ,{"tb":5,"tbk":1,"tl":702250
,"mb":5,"mbk":1
,"gb":5,"gbk":1
- ,"fb":5,"fbk":1
+ ,"eb":5,"ebk":1
,"rb":5,"wb":7495
,"acc":[-5,1500]
,"fs":[1,5,6]
}
- ,{"tb":4,"tbk":1,"tli":606170
+ ,{"tb":4,"tbk":1,"tl":606170
,"mb":4,"mbk":1
,"gb":4,"gbk":1
- ,"fb":4,"fbk":1
+ ,"eb":4,"ebk":1
,"rb":4,"wb":5996
,"acc":[-4,1500]
,"fs":[1,5,7]
}
- ,{"tb":10,"tbk":1,"tli":510097
+ ,{"tb":10,"tbk":1,"tl":510097
,"mb":10,"mbk":1
,"gb":10,"gbk":1
- ,"fb":10,"fbk":1
+ ,"eb":10,"ebk":1
,"rb":10,"wb":14990
,"acc":[-10,1500]
,"fs":[8,9]
}
- ,{"tb":9,"tbk":1,"tli":331504
+ ,{"tb":9,"tbk":1,"tl":331504
,"mb":9,"mbk":1
,"gb":9,"gbk":1
- ,"fb":9,"fbk":1
+ ,"eb":9,"ebk":1
,"rb":9,"wb":13491
,"acc":[-9,1500]
,"fs":[8,10,11]
}
- ,{"tb":5,"tbk":1,"tli":169412
+ ,{"tb":5,"tbk":1,"tl":169412
,"mb":5,"mbk":1
,"gb":5,"gbk":1
- ,"fb":5,"fbk":1
+ ,"eb":5,"ebk":1
,"rb":0,"wb":0
,"acc":[-5,0]
,"fs":[8,12,13]
}
- ,{"tb":3,"tbk":1,"tli":169360
+ ,{"tb":3,"tbk":1,"tl":169360
,"mb":3,"mbk":1
,"gb":3,"gbk":1
- ,"fb":3,"fbk":1
+ ,"eb":3,"ebk":1
,"rb":0,"wb":0
,"acc":[-3,0]
,"fs":[8,12,14]
}
- ,{"tb":9,"tbk":1,"tli":169315
+ ,{"tb":9,"tbk":1,"tl":169315
,"mb":9,"mbk":1
,"gb":9,"gbk":1
- ,"fb":9,"fbk":1
+ ,"eb":9,"ebk":1
,"rb":9,"wb":13491
,"acc":[-9,1500]
,"fs":[15,16]
}
- ,{"tb":8,"tbk":1,"tli":7225
+ ,{"tb":8,"tbk":1,"tl":7225
,"mb":8,"mbk":1
,"gb":8,"gbk":1
- ,"fb":8,"fbk":1
+ ,"eb":8,"ebk":1
,"rb":0,"wb":0
,"acc":[-8,0]
,"fs":[15,17,18]
}
- ,{"tb":4,"tbk":1,"tli":7173
+ ,{"tb":4,"tbk":1,"tl":7173
,"mb":4,"mbk":1
,"gb":4,"gbk":1
- ,"fb":4,"fbk":1
+ ,"eb":4,"ebk":1
,"rb":0,"wb":0
,"acc":[-4,0]
,"fs":[15,19,20]
}
- ,{"tb":3,"tbk":1,"tli":7121
+ ,{"tb":3,"tbk":1,"tl":7121
,"mb":3,"mbk":1
,"gb":3,"gbk":1
- ,"fb":3,"fbk":1
+ ,"eb":3,"ebk":1
,"rb":0,"wb":0
,"acc":[-3,0]
,"fs":[15,19,21]
}
- ,{"tb":8,"tbk":1,"tli":7076
+ ,{"tb":8,"tbk":1,"tl":7076
,"mb":8,"mbk":1
,"gb":8,"gbk":1
- ,"fb":8,"fbk":1
+ ,"eb":8,"ebk":1
,"rb":0,"wb":0
,"acc":[-8,0]
,"fs":[22,23]
}
- ,{"tb":7,"tbk":1,"tli":7026
+ ,{"tb":7,"tbk":1,"tl":7026
,"mb":7,"mbk":1
,"gb":7,"gbk":1
- ,"fb":7,"fbk":1
+ ,"eb":7,"ebk":1
,"rb":0,"wb":0
,"acc":[-7,0]
,"fs":[22,24,25]
}
- ,{"tb":4,"tbk":1,"tli":6974
+ ,{"tb":4,"tbk":1,"tl":6974
,"mb":4,"mbk":1
,"gb":4,"gbk":1
- ,"fb":4,"fbk":1
+ ,"eb":4,"ebk":1
,"rb":0,"wb":0
,"acc":[-4,0]
,"fs":[22,26,27]
}
- ,{"tb":2,"tbk":1,"tli":6922
+ ,{"tb":2,"tbk":1,"tl":6922
,"mb":2,"mbk":1
,"gb":2,"gbk":1
- ,"fb":2,"fbk":1
+ ,"eb":2,"ebk":1
,"rb":0,"wb":0
,"acc":[-2,0]
,"fs":[22,26,28]
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./sig
PID: 21476
}
t-end: 1,318,783 instrs
}
-â–¼ AP 1/1 (4 children) {
+â–¼ PP 1/1 (4 children) {
Total: 102 bytes (100%, 77.34/Minstr)
Reads: 58 bytes (100%, 43.98/Minstr)
Writes: 86,942 bytes (100%, 65,925.93/Minstr)
#0: [root]
}
}
- ├── AP 1.1/4 {
+ ├── PP 1.1/4 {
│ Total: 30 bytes (29.41%, 22.75/Minstr)
│ Reads: 30 bytes (51.72%, 22.75/Minstr)
│ Writes: 44,970 bytes (51.72%, 34,099.62/Minstr)
│ [1 insignificant]
│ }
│ }
- ├─▼ AP 1.2/4 (2 children) {
+ ├─▼ PP 1.2/4 (2 children) {
│ Total: 27 bytes (26.47%, 20.47/Minstr)
│ Reads: 19 bytes (32.76%, 14.41/Minstr)
│ Writes: 28,481 bytes (32.76%, 21,596.43/Minstr)
│ #1: 0x1086CF: bm (sig.c:15)
│ }
│ }
- │ ├── AP 1.2.1/2 {
+ │ ├── PP 1.2.1/2 {
│ │ Total: 19 bytes (18.63%, 14.41/Minstr)
│ │ Reads: 19 bytes (32.76%, 14.41/Minstr)
│ │ Writes: 28,481 bytes (32.76%, 21,596.43/Minstr)
│ │ [2 insignificant]
│ │ }
│ │ }
- │ └─▼ AP 1.2.2/2 (2 children) {
+ │ └─▼ PP 1.2.2/2 (2 children) {
│ Total: 8 bytes (7.84%, 6.07/Minstr) in 2 blocks (12.5%, 1.52/Minstr), avg size 4 bytes, avg lifetime 169,386 instrs (12.84% of program duration)
│ At t-gmax: 8 bytes (7.84%) in 2 blocks (12.5%), avg size 4 bytes
│ At t-end: 8 bytes (7.84%) in 2 blocks (12.5%), avg size 4 bytes
│ #2: 0x108703: b3 (sig.c:18)
│ }
│ }
- │ ├── AP 1.2.2.1/2 {
+ │ ├── PP 1.2.2.1/2 {
│ │ Total: 5 bytes (4.9%, 3.79/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 5 bytes, avg lifetime 169,412 instrs (12.85% of program duration)
│ │ Max: 5 bytes in 1 blocks, avg size 5 bytes
│ │ At t-gmax: 5 bytes (4.9%) in 1 blocks (6.25%), avg size 5 bytes
│ │ #3: 0x1088F6: main (sig.c:64)
│ │ }
│ │ }
- │ └── AP 1.2.2.2/2 {
+ │ └── PP 1.2.2.2/2 {
│ Total: 3 bytes (2.94%, 2.27/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 3 bytes, avg lifetime 169,360 instrs (12.84% of program duration)
│ Max: 3 bytes in 1 blocks, avg size 3 bytes
│ At t-gmax: 3 bytes (2.94%) in 1 blocks (6.25%), avg size 3 bytes
│ #3: 0x108904: main (sig.c:65)
│ }
│ }
- ├─▼ AP 1.3/4 (3 children) {
+ ├─▼ PP 1.3/4 (3 children) {
│ Total: 24 bytes (23.53%, 18.2/Minstr)
│ Reads: 9 bytes (15.52%, 6.82/Minstr)
│ Writes: 13,491 bytes (15.52%, 10,229.89/Minstr)
│ #1: 0x10871D: cm (sig.c:21)
│ }
│ }
- │ ├── AP 1.3.1/3 {
+ │ ├── PP 1.3.1/3 {
│ │ Total: 9 bytes (8.82%, 6.82/Minstr)
│ │ Reads: 9 bytes (15.52%, 6.82/Minstr)
│ │ Writes: 13,491 bytes (15.52%, 10,229.89/Minstr)
│ │ [1 insignificant]
│ │ }
│ │ }
- │ ├── AP 1.3.2/3 {
+ │ ├── PP 1.3.2/3 {
│ │ Total: 8 bytes (7.84%, 6.07/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 8 bytes, avg lifetime 7,225 instrs (0.55% of program duration)
│ │ Max: 8 bytes in 1 blocks, avg size 8 bytes
│ │ At t-gmax: 8 bytes (7.84%) in 1 blocks (6.25%), avg size 8 bytes
│ │ #3: 0x108931: main (sig.c:68)
│ │ }
│ │ }
- │ └─▼ AP 1.3.3/3 (2 children) {
+ │ └─▼ PP 1.3.3/3 (2 children) {
│ Total: 7 bytes (6.86%, 5.31/Minstr) in 2 blocks (12.5%, 1.52/Minstr), avg size 3.5 bytes, avg lifetime 7,147 instrs (0.54% of program duration)
│ At t-gmax: 7 bytes (6.86%) in 2 blocks (12.5%), avg size 3.5 bytes
│ At t-end: 7 bytes (6.86%) in 2 blocks (12.5%), avg size 3.5 bytes
│ #2: 0x108751: c3 (sig.c:24)
│ }
│ }
- │ ├── AP 1.3.3.1/2 {
+ │ ├── PP 1.3.3.1/2 {
│ │ Total: 4 bytes (3.92%, 3.03/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 4 bytes, avg lifetime 7,173 instrs (0.54% of program duration)
│ │ Max: 4 bytes in 1 blocks, avg size 4 bytes
│ │ At t-gmax: 4 bytes (3.92%) in 1 blocks (6.25%), avg size 4 bytes
│ │ #3: 0x10893F: main (sig.c:69)
│ │ }
│ │ }
- │ └── AP 1.3.3.2/2 {
+ │ └── PP 1.3.3.2/2 {
│ Total: 3 bytes (2.94%, 2.27/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 3 bytes, avg lifetime 7,121 instrs (0.54% of program duration)
│ Max: 3 bytes in 1 blocks, avg size 3 bytes
│ At t-gmax: 3 bytes (2.94%) in 1 blocks (6.25%), avg size 3 bytes
│ #3: 0x10894D: main (sig.c:70)
│ }
│ }
- └─▼ AP 1.4/4 (3 children) {
+ └─▼ PP 1.4/4 (3 children) {
Total: 21 bytes (20.59%, 15.92/Minstr) in 4 blocks (25%, 3.03/Minstr), avg size 5.25 bytes, avg lifetime 6,999.5 instrs (0.53% of program duration)
At t-gmax: 21 bytes (20.59%) in 4 blocks (25%), avg size 5.25 bytes
At t-end: 21 bytes (20.59%) in 4 blocks (25%), avg size 5.25 bytes
#1: 0x10876B: dm (sig.c:27)
}
}
- ├── AP 1.4.1/3 {
+ ├── PP 1.4.1/3 {
│ Total: 8 bytes (7.84%, 6.07/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 8 bytes, avg lifetime 7,076 instrs (0.54% of program duration)
│ Max: 8 bytes in 1 blocks, avg size 8 bytes
│ At t-gmax: 8 bytes (7.84%) in 1 blocks (6.25%), avg size 8 bytes
│ #2: 0x10895B: main (sig.c:72)
│ }
│ }
- ├── AP 1.4.2/3 {
+ ├── PP 1.4.2/3 {
│ Total: 7 bytes (6.86%, 5.31/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 7 bytes, avg lifetime 7,026 instrs (0.53% of program duration)
│ Max: 7 bytes in 1 blocks, avg size 7 bytes
│ At t-gmax: 7 bytes (6.86%) in 1 blocks (6.25%), avg size 7 bytes
│ #3: 0x108969: main (sig.c:73)
│ }
│ }
- └─▼ AP 1.4.3/3 (2 children) {
+ └─▼ PP 1.4.3/3 (2 children) {
Total: 6 bytes (5.88%, 4.55/Minstr) in 2 blocks (12.5%, 1.52/Minstr), avg size 3 bytes, avg lifetime 6,948 instrs (0.53% of program duration)
At t-gmax: 6 bytes (5.88%) in 2 blocks (12.5%), avg size 3 bytes
At t-end: 6 bytes (5.88%) in 2 blocks (12.5%), avg size 3 bytes
#2: 0x10879F: d3 (sig.c:30)
}
}
- ├── AP 1.4.3.1/2 {
+ ├── PP 1.4.3.1/2 {
│ Total: 4 bytes (3.92%, 3.03/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 4 bytes, avg lifetime 6,974 instrs (0.53% of program duration)
│ Max: 4 bytes in 1 blocks, avg size 4 bytes
│ At t-gmax: 4 bytes (3.92%) in 1 blocks (6.25%), avg size 4 bytes
│ #3: 0x108977: main (sig.c:74)
│ }
│ }
- └── AP 1.4.3.2/2 {
+ └── PP 1.4.3.2/2 {
Total: 2 bytes (1.96%, 1.52/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 2 bytes, avg lifetime 6,922 instrs (0.52% of program duration)
Max: 2 bytes in 1 blocks, avg size 2 bytes
At t-gmax: 2 bytes (1.96%) in 1 blocks (6.25%), avg size 2 bytes
}
}
-AP significance threshold: (total >= 0.51 bytes (0.5%)) && ((reads == 0 bytes) || (writes == 0 bytes))
+PP significance threshold: (total >= 0.51 bytes (0.5%)) && ((reads == 0 bytes) || (writes == 0 bytes))
`
//---------------------------------------------------------------------------
},
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./sig
PID: 21476
}
t-end: 1,318,783 instrs
}
-â–¼ AP 1/1 (2 children) {
+â–¼ PP 1/1 (2 children) {
Total: 16 blocks (100%, 12.13/Minstr)
Reads: 0.57/byte
Writes: 852.37/byte
#0: [root]
}
}
- ├── AP 1.1/2 {
+ ├── PP 1.1/2 {
│ Total: 12 blocks (75%, 9.1/Minstr)
│ Reads: 0.63/byte
│ Writes: 941.68/byte
│ [3 insignificant]
│ }
│ }
- └─▼ AP 1.2/2 (1 children) {
+ └─▼ PP 1.2/2 (1 children) {
Total: 24 bytes (23.53%, 18.2/Minstr) in 4 blocks (25%, 3.03/Minstr), avg size 6 bytes, avg lifetime 47,708.5 instrs (3.62% of program duration)
At t-gmax: 24 bytes (23.53%) in 4 blocks (25%), avg size 6 bytes
At t-end: 24 bytes (23.53%) in 4 blocks (25%), avg size 6 bytes
#1: 0x10871D: cm (sig.c:21)
}
}
- └── AP 1.2.1/1 {
+ └── PP 1.2.1/1 {
Total: 4 blocks (25%, 3.03/Minstr)
Reads: 0.38/byte
Writes: 562.13/byte
}
}
-AP significance threshold: (total >= 0.08 blocks (0.5%)) && (reads != 0 bytes) && (writes != 0 bytes) && ((reads <= 0.4/byte) || (writes <= 0.4/byte))
+PP significance threshold: (total >= 0.08 blocks (0.5%)) && (reads != 0 bytes) && (writes != 0 bytes) && ((reads <= 0.4/byte) || (writes <= 0.4/byte))
`
//---------------------------------------------------------------------------
},
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: ./sig
PID: 21476
}
t-end: 1,318,783 instrs
}
-â–¼ AP 1/1 (4 children) {
+â–¼ PP 1/1 (4 children) {
Writes: 86,942 bytes (100%, 65,925.93/Minstr), 852.37/byte
Allocated at {
#0: [root]
}
}
- ├─▼ AP 1.1/4 (3 children) {
+ ├─▼ PP 1.1/4 (3 children) {
│ Total: 30 bytes (29.41%, 22.75/Minstr) in 4 blocks (25%, 3.03/Minstr), avg size 7.5 bytes, avg lifetime 816,301.5 instrs (61.9% of program duration)
│ At t-gmax: 30 bytes (29.41%) in 4 blocks (25%), avg size 7.5 bytes
│ At t-end: 30 bytes (29.41%) in 4 blocks (25%), avg size 7.5 bytes
│ #1: 0x108681: am (sig.c:9)
│ }
│ }
- │ ├── AP 1.1.1/3 {
+ │ ├── PP 1.1.1/3 {
│ │ Total: 11 bytes (10.78%, 8.34/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 11 bytes, avg lifetime 1,075,941 instrs (81.59% of program duration)
│ │ Max: 11 bytes in 1 blocks, avg size 11 bytes
│ │ At t-gmax: 11 bytes (10.78%) in 1 blocks (6.25%), avg size 11 bytes
│ │ #2: 0x10883C: main (sig.c:57)
│ │ }
│ │ }
- │ ├── AP 1.1.2/3 {
+ │ ├── PP 1.1.2/3 {
│ │ Total: 10 bytes (9.8%, 7.58/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 10 bytes, avg lifetime 880,845 instrs (66.79% of program duration)
│ │ Max: 10 bytes in 1 blocks, avg size 10 bytes
│ │ At t-gmax: 10 bytes (9.8%) in 1 blocks (6.25%), avg size 10 bytes
│ │ #3: 0x10885B: main (sig.c:58)
│ │ }
│ │ }
- │ └─▼ AP 1.1.3/3 (2 children) {
+ │ └─▼ PP 1.1.3/3 (2 children) {
│ Total: 9 bytes (8.82%, 6.82/Minstr) in 2 blocks (12.5%, 1.52/Minstr), avg size 4.5 bytes, avg lifetime 654,210 instrs (49.61% of program duration)
│ At t-gmax: 9 bytes (8.82%) in 2 blocks (12.5%), avg size 4.5 bytes
│ At t-end: 9 bytes (8.82%) in 2 blocks (12.5%), avg size 4.5 bytes
│ #2: 0x1086B5: a3 (sig.c:12)
│ }
│ }
- │ ├── AP 1.1.3.1/2 {
+ │ ├── PP 1.1.3.1/2 {
│ │ Total: 5 bytes (4.9%, 3.79/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 5 bytes, avg lifetime 702,250 instrs (53.25% of program duration)
│ │ Max: 5 bytes in 1 blocks, avg size 5 bytes
│ │ At t-gmax: 5 bytes (4.9%) in 1 blocks (6.25%), avg size 5 bytes
│ │ #3: 0x10887A: main (sig.c:59)
│ │ }
│ │ }
- │ └── AP 1.1.3.2/2 {
+ │ └── PP 1.1.3.2/2 {
│ Total: 4 bytes (3.92%, 3.03/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 4 bytes, avg lifetime 606,170 instrs (45.96% of program duration)
│ Max: 4 bytes in 1 blocks, avg size 4 bytes
│ At t-gmax: 4 bytes (3.92%) in 1 blocks (6.25%), avg size 4 bytes
│ #3: 0x108899: main (sig.c:60)
│ }
│ }
- ├─▼ AP 1.2/4 (3 children) {
+ ├─▼ PP 1.2/4 (3 children) {
│ Total: 27 bytes (26.47%, 20.47/Minstr) in 4 blocks (25%, 3.03/Minstr), avg size 6.75 bytes, avg lifetime 295,093.25 instrs (22.38% of program duration)
│ At t-gmax: 27 bytes (26.47%) in 4 blocks (25%), avg size 6.75 bytes
│ At t-end: 27 bytes (26.47%) in 4 blocks (25%), avg size 6.75 bytes
│ #1: 0x1086CF: bm (sig.c:15)
│ }
│ }
- │ ├── AP 1.2.1/3 {
+ │ ├── PP 1.2.1/3 {
│ │ Total: 10 bytes (9.8%, 7.58/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 10 bytes, avg lifetime 510,097 instrs (38.68% of program duration)
│ │ Max: 10 bytes in 1 blocks, avg size 10 bytes
│ │ At t-gmax: 10 bytes (9.8%) in 1 blocks (6.25%), avg size 10 bytes
│ │ #2: 0x1088B8: main (sig.c:62)
│ │ }
│ │ }
- │ ├── AP 1.2.2/3 {
+ │ ├── PP 1.2.2/3 {
│ │ Total: 9 bytes (8.82%, 6.82/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 9 bytes, avg lifetime 331,504 instrs (25.14% of program duration)
│ │ Max: 9 bytes in 1 blocks, avg size 9 bytes
│ │ At t-gmax: 9 bytes (8.82%) in 1 blocks (6.25%), avg size 9 bytes
│ │ #3: 0x1088D7: main (sig.c:63)
│ │ }
│ │ }
- │ └── AP 1.2.3/3 {
+ │ └── PP 1.2.3/3 {
│ Writes: 0 bytes (0%, 0/Minstr), 0/byte
│ Allocated at {
│ [1 insignificant]
│ }
│ }
- ├─▼ AP 1.3/4 (2 children) {
+ ├─▼ PP 1.3/4 (2 children) {
│ Writes: 13,491 bytes (15.52%, 10,229.89/Minstr), 562.13/byte
│ Allocated at {
│ #1: 0x10871D: cm (sig.c:21)
│ }
│ }
- │ ├── AP 1.3.1/2 {
+ │ ├── PP 1.3.1/2 {
│ │ Total: 9 bytes (8.82%, 6.82/Minstr) in 1 blocks (6.25%, 0.76/Minstr), avg size 9 bytes, avg lifetime 169,315 instrs (12.84% of program duration)
│ │ Max: 9 bytes in 1 blocks, avg size 9 bytes
│ │ At t-gmax: 9 bytes (8.82%) in 1 blocks (6.25%), avg size 9 bytes
│ │ #2: 0x108912: main (sig.c:67)
│ │ }
│ │ }
- │ └── AP 1.3.2/2 {
+ │ └── PP 1.3.2/2 {
│ Writes: 0 bytes (0%, 0/Minstr), 0/byte
│ Allocated at {
│ [2 insignificant]
│ }
│ }
- └── AP 1.4/4 {
+ └── PP 1.4/4 {
Writes: 0 bytes (0%, 0/Minstr), 0/byte
Allocated at {
[1 insignificant]
}
}
-AP significance threshold: (writes >= 434.71 bytes (0.5%)) && ((reads >= 1,000/byte) || (writes >= 1,000/byte))
+PP significance threshold: (writes >= 434.71 bytes (0.5%)) && ((reads >= 1,000/byte) || (writes >= 1,000/byte))
`
//---------------------------------------------------------------------------
}
name: "sig2",
input:
//---------------------------------------------------------------------------
-{"dhatFileVersion":1
+{"dhatFileVersion":2
+,"mode":"heap","verb":"Allocated"
+,"bklt":true,"bkacc":true
+,"tu":"instrs","Mtu":"Minstr"
+,"tuth":500
,"cmd":"subseqs"
,"pid":0
-,"mi":10000,"ei":20000
-,"aps":
- [{"tb":100,"tbk":1,"tli":1000
+,"te":20000
+,"tg":10000
+,"pps":
+ [{"tb":100,"tbk":1,"tl":1000
,"mb":100,"mbk":1
,"gb":100,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[1]
}
- ,{"tb":101,"tbk":1,"tli":1000
+ ,{"tb":101,"tbk":1,"tl":1000
,"mb":101,"mbk":1
,"gb":101,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[2]
}
- ,{"tb":102,"tbk":1,"tli":1000
+ ,{"tb":102,"tbk":1,"tl":1000
,"mb":102,"mbk":1
,"gb":102,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[3,4]
}
- ,{"tb":103,"tbk":1,"tli":1000
+ ,{"tb":103,"tbk":1,"tl":1000
,"mb":103,"mbk":1
,"gb":103,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[3,5]
}
- ,{"tb":104,"tbk":1,"tli":1000
+ ,{"tb":104,"tbk":1,"tl":1000
,"mb":104,"mbk":1
,"gb":104,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[3,6,7]
}
- ,{"tb":105,"tbk":1,"tli":1000
+ ,{"tb":105,"tbk":1,"tl":1000
,"mb":105,"mbk":1
,"gb":105,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[3,6,8]
}
- ,{"tb":10,"tbk":1,"tli":1000
+ ,{"tb":10,"tbk":1,"tl":1000
,"mb":10,"mbk":1
,"gb":10,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[3,6,9,10]
}
- ,{"tb":106,"tbk":1,"tli":1000
+ ,{"tb":106,"tbk":1,"tl":1000
,"mb":106,"mbk":1
,"gb":106,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[3,6,9,11]
}
- ,{"tb":107,"tbk":1,"tli":1000
+ ,{"tb":107,"tbk":1,"tl":1000
,"mb":107,"mbk":1
,"gb":107,"gbk":1
- ,"fb":0,"fbk":0
+ ,"eb":0,"ebk":0
,"rb":0,"wb":0
,"acc":[-10,0]
,"fs":[3,6,9,12]
//---------------------------------------------------------------------------
`\
Invocation {
+ Mode: heap
Command: subseqs
PID: 0
}
t-end: 20,000 instrs
}
-â–¼ AP 1/1 (2 children) {
+â–¼ PP 1/1 (2 children) {
Total: 9 blocks (100%, 450/Minstr), avg size 93.11 bytes
Allocated at {
#0: [root]
}
}
- ├─▼ AP 1.1/2 (2 children) {
+ ├─▼ PP 1.1/2 (2 children) {
│ Total: 7 blocks (77.78%, 350/Minstr), avg size 91 bytes
│ Allocated at {
│ #1: a3()
│ }
│ }
- │ ├─▼ AP 1.1.1/2 (2 children) {
+ │ ├─▼ PP 1.1.1/2 (2 children) {
│ │ Total: 5 blocks (55.56%, 250/Minstr), avg size 86.4 bytes
│ │ Allocated at {
│ │ #2: b3()
│ │ }
│ │ }
- │ │ ├─▼ AP 1.1.1.1/2 (2 children) {
+ │ │ ├─▼ PP 1.1.1.1/2 (2 children) {
│ │ │ Total: 3 blocks (33.33%, 150/Minstr), avg size 74.33 bytes
│ │ │ Allocated at {
│ │ │ #3: c3()
│ │ │ }
│ │ │ }
- │ │ │ ├── AP 1.1.1.1.1/2 {
+ │ │ │ ├── PP 1.1.1.1.1/2 {
│ │ │ │ Total: 2 blocks (22.22%, 100/Minstr), avg size 106.5 bytes
│ │ │ │ Allocated at {
│ │ │ │ [2 insignificant]
│ │ │ │ }
│ │ │ │ }
- │ │ │ └── AP 1.1.1.1.2/2 {
+ │ │ │ └── PP 1.1.1.1.2/2 {
│ │ │ Total: 10 bytes (1.19%, 500/Minstr) in 1 blocks (11.11%, 50/Minstr), avg size 10 bytes, avg lifetime 1,000 instrs (5% of program duration)
│ │ │ Max: 10 bytes in 1 blocks, avg size 10 bytes
│ │ │ At t-gmax: 10 bytes (1.19%) in 1 blocks (11.11%), avg size 10 bytes
│ │ │ #4: d1()
│ │ │ }
│ │ │ }
- │ │ └── AP 1.1.1.2/2 {
+ │ │ └── PP 1.1.1.2/2 {
│ │ Total: 2 blocks (22.22%, 100/Minstr), avg size 104.5 bytes
│ │ Allocated at {
│ │ [2 insignificant]
│ │ }
│ │ }
- │ └── AP 1.1.2/2 {
+ │ └── PP 1.1.2/2 {
│ Total: 2 blocks (22.22%, 100/Minstr), avg size 102.5 bytes
│ Allocated at {
│ [2 insignificant]
│ }
│ }
- └── AP 1.2/2 {
+ └── PP 1.2/2 {
Total: 2 blocks (22.22%, 100/Minstr), avg size 100.5 bytes
Allocated at {
[2 insignificant]
}
}
-AP significance threshold: (total >= 0.05 blocks (0.5%)) && (total avg size <= 16 bytes)
+PP significance threshold: (total >= 0.05 blocks (0.5%)) && (avg size <= 16 bytes)
`
//---------------------------------------------------------------------------
}
};
tests.push(sig2);
+//---------------------------------------------------------------------------
+// copy (corresponds to dhat/tests/copy.c, with `pps` elements for copies
+// from system libs removed, but with no removal to `fbtl` elements)
+//---------------------------------------------------------------------------
+
+let copy = {
+ name: "copy",
+ input:
+//---------------------------------------------------------------------------
+{"dhatFileVersion":2
+,"mode":"copy","verb":"Copied"
+,"bklt":false,"bkacc":false
+,"tu":"instrs","Mtu":"Minstr"
+,"cmd":"./copy"
+,"pid":8568
+,"te":4033604
+,"pps":
+ [{"tb":100000,"tbk":100
+ ,"fs":[19,20,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[19,22,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[19,23,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[24,25,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[19,26,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[27,28,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[29,30,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[27,31,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[32,33,21]
+ }
+ ,{"tb":100000,"tbk":100
+ ,"fs":[34,35,21]
+ }
+ ]
+,"ftbl":
+ ["[root]"
+ ,"0x4843690: mempcpy (vg_replace_strmem.c:1566)"
+ ,"0x4008B4F: open_path (dl-load.c:1810)"
+ ,"0x400A7A2: _dl_map_object (dl-load.c:2067)"
+ ,"0x400F504: openaux (dl-deps.c:64)"
+ ,"0x401DC19: _dl_catch_exception (dl-error-skeleton.c:208)"
+ ,"0x400F952: _dl_map_object_deps (dl-deps.c:248)"
+ ,"0x4004063: dl_main (rtld.c:1805)"
+ ,"0x401CBAA: _dl_sysdep_start (dl-sysdep.c:252)"
+ ,"0x400204B: _dl_start_final (rtld.c:449)"
+ ,"0x400204B: _dl_start (rtld.c:539)"
+ ,"0x4001107: ??? (in /lib/x86_64-linux-gnu/ld-2.31.so)"
+ ,"0x4008BCC: open_path (dl-load.c:1818)"
+ ,"0x4008BE2: open_path (dl-load.c:1818)"
+ ,"0x400D4B4: _dl_new_object (dl-object.c:242)"
+ ,"0x4006E96: _dl_map_object_from_fd (dl-load.c:997)"
+ ,"0x400A61A: _dl_map_object (dl-load.c:2236)"
+ ,"0x401486E: _dl_allocate_tls_init (dl-tls.c:507)"
+ ,"0x400469D: dl_main (rtld.c:2292)"
+ ,"0x4842524: memmove (vg_replace_strmem.c:1289)"
+ ,"0x10930E: f (copy.c:40)"
+ ,"0x1092C9: main (copy.c:31)"
+ ,"0x109326: f (copy.c:41)"
+ ,"0x10933E: f (copy.c:42)"
+ ,"0x4843390: mempcpy (vg_replace_strmem.c:1562)"
+ ,"0x109356: f (copy.c:43)"
+ ,"0x10936E: f (copy.c:44)"
+ ,"0x483EBB0: strcpy (vg_replace_strmem.c:523)"
+ ,"0x109381: f (copy.c:45)"
+ ,"0x483ECD7: strncpy (vg_replace_strmem.c:564)"
+ ,"0x109399: f (copy.c:46)"
+ ,"0x1093AC: f (copy.c:47)"
+ ,"0x4842368: stpncpy (vg_replace_strmem.c:1219)"
+ ,"0x1093C4: f (copy.c:48)"
+ ,"0x4843DD2: wcscpy (vg_replace_strmem.c:2018)"
+ ,"0x1093D7: f (copy.c:49)"
+ ]
+}
+//---------------------------------------------------------------------------
+ ,
+ outputs: [
+ {
+ label: "Total (blocks)",
+ expected:
+//---------------------------------------------------------------------------
+`\
+Invocation {
+ Mode: copy
+ Command: ./copy
+ PID: 8568
+}
+
+Times {
+ t-end: 4,033,604 instrs
+}
+
+â–¼ PP 1/1 (6 children) {
+ Total: 1,000,000 bytes (100%, 247,917.25/Minstr) in 1,000 blocks (100%, 247.92/Minstr), avg size 1,000 bytes
+ Copied at {
+ #0: [root]
+ }
+ }
+ ├─▼ PP 1.1/6 (4 children) {
+ │ Total: 400,000 bytes (40%, 99,166.9/Minstr) in 400 blocks (40%, 99.17/Minstr), avg size 1,000 bytes
+ │ Copied at {
+ │ #1: 0x4842524: memmove (vg_replace_strmem.c:1289)
+ │ }
+ │ }
+ │ ├── PP 1.1.1/4 {
+ │ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ │ Copied at {
+ │ │ ^1: 0x4842524: memmove (vg_replace_strmem.c:1289)
+ │ │ #2: 0x10930E: f (copy.c:40)
+ │ │ #3: 0x1092C9: main (copy.c:31)
+ │ │ }
+ │ │ }
+ │ ├── PP 1.1.2/4 {
+ │ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ │ Copied at {
+ │ │ ^1: 0x4842524: memmove (vg_replace_strmem.c:1289)
+ │ │ #2: 0x109326: f (copy.c:41)
+ │ │ #3: 0x1092C9: main (copy.c:31)
+ │ │ }
+ │ │ }
+ │ ├── PP 1.1.3/4 {
+ │ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ │ Copied at {
+ │ │ ^1: 0x4842524: memmove (vg_replace_strmem.c:1289)
+ │ │ #2: 0x10933E: f (copy.c:42)
+ │ │ #3: 0x1092C9: main (copy.c:31)
+ │ │ }
+ │ │ }
+ │ └── PP 1.1.4/4 {
+ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ Copied at {
+ │ ^1: 0x4842524: memmove (vg_replace_strmem.c:1289)
+ │ #2: 0x10936E: f (copy.c:44)
+ │ #3: 0x1092C9: main (copy.c:31)
+ │ }
+ │ }
+ ├─▼ PP 1.2/6 (2 children) {
+ │ Total: 200,000 bytes (20%, 49,583.45/Minstr) in 200 blocks (20%, 49.58/Minstr), avg size 1,000 bytes
+ │ Copied at {
+ │ #1: 0x483EBB0: strcpy (vg_replace_strmem.c:523)
+ │ }
+ │ }
+ │ ├── PP 1.2.1/2 {
+ │ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ │ Copied at {
+ │ │ ^1: 0x483EBB0: strcpy (vg_replace_strmem.c:523)
+ │ │ #2: 0x109381: f (copy.c:45)
+ │ │ #3: 0x1092C9: main (copy.c:31)
+ │ │ }
+ │ │ }
+ │ └── PP 1.2.2/2 {
+ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ Copied at {
+ │ ^1: 0x483EBB0: strcpy (vg_replace_strmem.c:523)
+ │ #2: 0x1093AC: f (copy.c:47)
+ │ #3: 0x1092C9: main (copy.c:31)
+ │ }
+ │ }
+ ├── PP 1.3/6 {
+ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ Copied at {
+ │ #1: 0x4843390: mempcpy (vg_replace_strmem.c:1562)
+ │ #2: 0x109356: f (copy.c:43)
+ │ #3: 0x1092C9: main (copy.c:31)
+ │ }
+ │ }
+ ├── PP 1.4/6 {
+ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ Copied at {
+ │ #1: 0x483ECD7: strncpy (vg_replace_strmem.c:564)
+ │ #2: 0x109399: f (copy.c:46)
+ │ #3: 0x1092C9: main (copy.c:31)
+ │ }
+ │ }
+ ├── PP 1.5/6 {
+ │ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ │ Copied at {
+ │ #1: 0x4842368: stpncpy (vg_replace_strmem.c:1219)
+ │ #2: 0x1093C4: f (copy.c:48)
+ │ #3: 0x1092C9: main (copy.c:31)
+ │ }
+ │ }
+ └── PP 1.6/6 {
+ Total: 100,000 bytes (10%, 24,791.72/Minstr) in 100 blocks (10%, 24.79/Minstr), avg size 1,000 bytes
+ Copied at {
+ #1: 0x4843DD2: wcscpy (vg_replace_strmem.c:2018)
+ #2: 0x1093D7: f (copy.c:49)
+ #3: 0x1092C9: main (copy.c:31)
+ }
+ }
+
+PP significance threshold: total >= 10 blocks (1%)
+`
+//---------------------------------------------------------------------------
+ }
+ ]
+};
+tests.push(copy);
+
+//---------------------------------------------------------------------------
+// ad-hoc (corresponds to dhat/tests/ad-hoc.c)
+//---------------------------------------------------------------------------
+
+let ad_hoc = {
+ name: "ad_hoc",
+ input:
+//---------------------------------------------------------------------------
+{"dhatFileVersion":2
+,"mode":"ad-hoc","verb":"Occurred"
+,"bklt":false,"bkacc":false
+,"bu":"unit","bsu":"units","bksu":"events"
+,"tu":"instrs","Mtu":"Minstr"
+,"cmd":"./ad-hoc"
+,"pid":26995
+,"te":150455
+,"pps":
+ [{"tb":30,"tbk":1
+ ,"fs":[1,2,3]
+ }
+ ,{"tb":20,"tbk":1
+ ,"fs":[4,3]
+ }
+ ,{"tb":30,"tbk":1
+ ,"fs":[1,5,3]
+ }
+ ,{"tb":10,"tbk":1
+ ,"fs":[6]
+ }
+ ,{"tb":30,"tbk":1
+ ,"fs":[1,2,7]
+ }
+ ,{"tb":20,"tbk":1
+ ,"fs":[4,7]
+ }
+ ,{"tb":30,"tbk":1
+ ,"fs":[1,5,7]
+ }
+ ]
+,"ftbl":
+ ["[root]"
+ ,"0x1093A7: g (ad-hoc.c:4)"
+ ,"0x1093C5: f (ad-hoc.c:8)"
+ ,"0x109437: main (ad-hoc.c:14)"
+ ,"0x109414: f (ad-hoc.c:9)"
+ ,"0x109423: f (ad-hoc.c:10)"
+ ,"0x109486: main (ad-hoc.c:15)"
+ ,"0x109495: main (ad-hoc.c:16)"
+ ]
+}
+//---------------------------------------------------------------------------
+ ,
+ outputs: [
+ {
+ label: "Total (events)",
+ expected:
+//---------------------------------------------------------------------------
+`\
+Invocation {
+ Mode: ad-hoc
+ Command: ./ad-hoc
+ PID: 26995
+}
+
+Times {
+ t-end: 150,455 instrs
+}
+
+â–¼ PP 1/1 (3 children) {
+ Total: 170 units (100%, 1,129.91/Minstr) in 7 events (100%, 46.53/Minstr), avg size 24.29 units
+ Occurred at {
+ #0: [root]
+ }
+ }
+ ├─▼ PP 1.1/3 (2 children) {
+ │ Total: 120 units (70.59%, 797.58/Minstr) in 4 events (57.14%, 26.59/Minstr), avg size 30 units
+ │ Occurred at {
+ │ #1: 0x1093A7: g (ad-hoc.c:4)
+ │ }
+ │ }
+ │ ├─▼ PP 1.1.1/2 (2 children) {
+ │ │ Total: 60 units (35.29%, 398.79/Minstr) in 2 events (28.57%, 13.29/Minstr), avg size 30 units
+ │ │ Occurred at {
+ │ │ ^1: 0x1093A7: g (ad-hoc.c:4)
+ │ │ #2: 0x1093C5: f (ad-hoc.c:8)
+ │ │ }
+ │ │ }
+ │ │ ├── PP 1.1.1.1/2 {
+ │ │ │ Total: 30 units (17.65%, 199.4/Minstr) in 1 events (14.29%, 6.65/Minstr), avg size 30 units
+ │ │ │ Occurred at {
+ │ │ │ ^1: 0x1093A7: g (ad-hoc.c:4)
+ │ │ │ ^2: 0x1093C5: f (ad-hoc.c:8)
+ │ │ │ #3: 0x109437: main (ad-hoc.c:14)
+ │ │ │ }
+ │ │ │ }
+ │ │ └── PP 1.1.1.2/2 {
+ │ │ Total: 30 units (17.65%, 199.4/Minstr) in 1 events (14.29%, 6.65/Minstr), avg size 30 units
+ │ │ Occurred at {
+ │ │ ^1: 0x1093A7: g (ad-hoc.c:4)
+ │ │ ^2: 0x1093C5: f (ad-hoc.c:8)
+ │ │ #3: 0x109495: main (ad-hoc.c:16)
+ │ │ }
+ │ │ }
+ │ └─▼ PP 1.1.2/2 (2 children) {
+ │ Total: 60 units (35.29%, 398.79/Minstr) in 2 events (28.57%, 13.29/Minstr), avg size 30 units
+ │ Occurred at {
+ │ ^1: 0x1093A7: g (ad-hoc.c:4)
+ │ #2: 0x109423: f (ad-hoc.c:10)
+ │ }
+ │ }
+ │ ├── PP 1.1.2.1/2 {
+ │ │ Total: 30 units (17.65%, 199.4/Minstr) in 1 events (14.29%, 6.65/Minstr), avg size 30 units
+ │ │ Occurred at {
+ │ │ ^1: 0x1093A7: g (ad-hoc.c:4)
+ │ │ ^2: 0x109423: f (ad-hoc.c:10)
+ │ │ #3: 0x109437: main (ad-hoc.c:14)
+ │ │ }
+ │ │ }
+ │ └── PP 1.1.2.2/2 {
+ │ Total: 30 units (17.65%, 199.4/Minstr) in 1 events (14.29%, 6.65/Minstr), avg size 30 units
+ │ Occurred at {
+ │ ^1: 0x1093A7: g (ad-hoc.c:4)
+ │ ^2: 0x109423: f (ad-hoc.c:10)
+ │ #3: 0x109495: main (ad-hoc.c:16)
+ │ }
+ │ }
+ ├─▼ PP 1.2/3 (2 children) {
+ │ Total: 40 units (23.53%, 265.86/Minstr) in 2 events (28.57%, 13.29/Minstr), avg size 20 units
+ │ Occurred at {
+ │ #1: 0x109414: f (ad-hoc.c:9)
+ │ }
+ │ }
+ │ ├── PP 1.2.1/2 {
+ │ │ Total: 20 units (11.76%, 132.93/Minstr) in 1 events (14.29%, 6.65/Minstr), avg size 20 units
+ │ │ Occurred at {
+ │ │ ^1: 0x109414: f (ad-hoc.c:9)
+ │ │ #2: 0x109437: main (ad-hoc.c:14)
+ │ │ }
+ │ │ }
+ │ └── PP 1.2.2/2 {
+ │ Total: 20 units (11.76%, 132.93/Minstr) in 1 events (14.29%, 6.65/Minstr), avg size 20 units
+ │ Occurred at {
+ │ ^1: 0x109414: f (ad-hoc.c:9)
+ │ #2: 0x109495: main (ad-hoc.c:16)
+ │ }
+ │ }
+ └── PP 1.3/3 {
+ Total: 10 units (5.88%, 66.47/Minstr) in 1 events (14.29%, 6.65/Minstr), avg size 10 units
+ Occurred at {
+ #1: 0x109486: main (ad-hoc.c:15)
+ }
+ }
+
+PP significance threshold: total >= 0.07 events (1%)
+`
+//---------------------------------------------------------------------------
+ }
+ ]
+};
+tests.push(ad_hoc);
+
+//---------------------------------------------------------------------------
+// rust-heap. Input came from this Rust program:
+//
+// use dhat::{Dhat, DhatAlloc};
+// #[global_allocator]
+// static ALLOC: DhatAlloc = DhatAlloc;
+// fn main() {
+// let _dhat = Dhat::start_heap_profiling();
+// let _v: Vec<u8> = Vec::with_capacity(1000);
+// }
+//---------------------------------------------------------------------------
+
+let rust_heap = {
+ name: "rust_heap",
+ input:
+//---------------------------------------------------------------------------
+{
+ "dhatFileVersion": 2,
+ "mode": "rust-heap",
+ "verb": "Allocated",
+ "bklt": true,
+ "bkacc": false,
+ "tu": "µs",
+ "Mtu": "s",
+ "tuth": 10,
+ "cmd": "target/debug/dhatter",
+ "pid": 85218,
+ "tg": 174,
+ "te": 201,
+ "pps": [
+ {
+ "tb": 1000,
+ "tbk": 1,
+ "tl": 16,
+ "mb": 1000,
+ "mbk": 1,
+ "gb": 1000,
+ "gbk": 1,
+ "eb": 0,
+ "ebk": 0,
+ "fs": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+ }
+ ],
+ "ftbl": [
+ "[root]",
+ "0x10e13fb2b: <alloc::alloc::Global as core::alloc::AllocRef>::alloc (alloc.rs:203:9)",
+ "0x10e13cae4: alloc::raw_vec::RawVec<T,A>::allocate_in (raw_vec.rs:186:45)",
+ "0x10e13d09d: alloc::raw_vec::RawVec<T,A>::with_capacity_in (raw_vec.rs:161:9)",
+ "0x10e13c921: alloc::raw_vec::RawVec<T>::with_capacity (raw_vec.rs:92:9)",
+ "0x10e13f40f: alloc::vec::Vec<T>::with_capacity (vec.rs:355:20)",
+ "0x10e067a08: dhatter::main (main.rs:8:23)",
+ "0x10e06794e: core::ops::function::FnOnce::call_once (function.rs:227:5)",
+ "0x10e067801: std::sys_common::backtrace::__rust_begin_short_backtrace (backtrace.rs:137:18)",
+ "0x10e0677d4: std::rt::lang_start::{{closure}} (rt.rs:66:18)",
+ "0x10e17b220: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once (function.rs:259:13)",
+ "0x10e17b220: std::panicking::try::do_call (panicking.rs:373:40)",
+ "0x10e17b220: std::panicking::try (panicking.rs:337:19)",
+ "0x10e17b220: std::panic::catch_unwind (panic.rs:379:14)",
+ "0x10e17b220: std::rt::lang_start_internal (rt.rs:51:25)",
+ "0x10e0677b1: std::rt::lang_start (rt.rs:65:5)",
+ "0x10e067bb2: _main (???:0:0)"
+ ]
+}
+//---------------------------------------------------------------------------
+ ,
+ outputs: [
+ {
+ label: "Total (blocks)",
+ expected:
+//---------------------------------------------------------------------------
+`\
+Invocation {
+ Mode: rust-heap
+ Command: target/debug/dhatter
+ PID: 85218
+}
+
+Times {
+ t-gmax: 174 µs (86.57% of program duration)
+ t-end: 201 µs
+}
+
+─ PP 1/1 {
+ Total: 1,000 bytes (100%, 4,975,124.38/s) in 1 blocks (100%, 4,975.12/s), avg size 1,000 bytes, avg lifetime 16 µs (7.96% of program duration)
+ At t-gmax: 1,000 bytes (100%) in 1 blocks (100%), avg size 1,000 bytes
+ At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
+ Allocated at {
+ #0: [root]
+ #1: 0x10e13fb2b: <alloc::alloc::Global as core::alloc::AllocRef>::alloc (alloc.rs:203:9)
+ #2: 0x10e13cae4: alloc::raw_vec::RawVec<T,A>::allocate_in (raw_vec.rs:186:45)
+ #3: 0x10e13d09d: alloc::raw_vec::RawVec<T,A>::with_capacity_in (raw_vec.rs:161:9)
+ #4: 0x10e13c921: alloc::raw_vec::RawVec<T>::with_capacity (raw_vec.rs:92:9)
+ #5: 0x10e13f40f: alloc::vec::Vec<T>::with_capacity (vec.rs:355:20)
+ #6: 0x10e067a08: dhatter::main (main.rs:8:23)
+ #7: 0x10e06794e: core::ops::function::FnOnce::call_once (function.rs:227:5)
+ #8: 0x10e067801: std::sys_common::backtrace::__rust_begin_short_backtrace (backtrace.rs:137:18)
+ #9: 0x10e0677d4: std::rt::lang_start::{{closure}} (rt.rs:66:18)
+ #10: 0x10e17b220: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once (function.rs:259:13)
+ #11: 0x10e17b220: std::panicking::try::do_call (panicking.rs:373:40)
+ #12: 0x10e17b220: std::panicking::try (panicking.rs:337:19)
+ #13: 0x10e17b220: std::panic::catch_unwind (panic.rs:379:14)
+ #14: 0x10e17b220: std::rt::lang_start_internal (rt.rs:51:25)
+ #15: 0x10e0677b1: std::rt::lang_start (rt.rs:65:5)
+ #16: 0x10e067bb2: _main (???:0:0)
+ }
+ }
+
+PP significance threshold: total >= 0.01 blocks (1%)
+`
+//---------------------------------------------------------------------------
+ }
+ ]
+};
+tests.push(rust_heap);
+
//---------------------------------------------------------------------------
// Code
//---------------------------------------------------------------------------
let j = 0;
let labelFound = false;
for (let opt of gSelect.options) {
- if (gSelectData[opt.value].label == label) {
+ if (gSelectData[opt.value].label() == label) {
gSelect.selectedIndex = j;
labelFound = true;
break;
}
j++;
}
- assert(labelFound, "test label not found in gSelectData");
+ assert(labelFound, `test label not found in gSelectData: ${label}`);
// Build and display the tree.
tryFunc(() => {
let gFilename;
// The object extracted from the JSON input.
-let gData;
+let gData = {};
// The root of the radix tree build from gData. A radix tree is a
// space-optimized prefix tree in which each node that is the only child is
// - label: Used in the drop-down menu.
// - bolds: Which fields to highlight in the output.
// - cmpField: Field used to sort the radix tree.
+// - enable: Function saying whether this option is enabled.
// - sig: Significance function used to determine aggregate nodes.
// - sigLabel: Significance threshold description function.
//
const gSelectData = [
{
- label: "Total (bytes)",
+ label: () => `Total (${bytesUnit()})`,
bolds: { "totalTitle": 1, "totalBytes": 1 },
cmpField: "_totalBytes",
+ enable: (aBkLt, aBkAcc) => true,
sig: (aT) => aT._totalBytes >= 0.01 * gRoot._totalBytes,
sigLabel: () => `\
total >= ${bytesAndPerc(0.01 * gRoot._totalBytes, gRoot._totalBytes)}`
},
{
isDefault: true,
- label: "Total (blocks)",
+ label: () => `Total (${blocksUnit()})`,
bolds: { "totalTitle": 1, "totalBlocks": 1 },
cmpField: "_totalBlocks",
+ enable: (aBkLt, aBkAcc) => true,
sig: (aT) => aT._totalBlocks >= 0.01 * gRoot._totalBlocks,
sigLabel: () => `\
total >= ${blocksAndPerc(0.01 * gRoot._totalBlocks, gRoot._totalBlocks)}`
},
- // No "Total (bytes), tiny" because it's extremely unlikely that an AP with a
+ // No "Total (bytes), tiny" because it's extremely unlikely that a PP with a
// tiny average size will take up a significant number of bytes.
{
- label: "Total (blocks), tiny",
+ label: () => `Total (${blocksUnit()}), tiny`,
bolds: { "totalTitle": 1, "totalBlocks": 1, "totalAvgSizeBytes": 1 },
cmpField: "_totalBlocks",
+ enable: (aBkLt, aBkAcc) => true,
sig: (aT) => aT._totalBlocks >= 0.005 * gRoot._totalBlocks &&
aT._totalAvgSizeBytes() <= 16,
sigLabel: () => `\
(total >= ${blocksAndPerc(0.005 * gRoot._totalBlocks, gRoot._totalBlocks)}) && \
-(total avg size <= ${bytes(16)})`
+(avg size <= ${bytes(16)})`
},
- // No "Total (bytes), short-lived", because an AP with few large, short-lived
+ // No "Total (bytes), short-lived", because a PP with few large, short-lived
// blocks is unlikely. (In contrast, "Total (blocks), short-lived" is useful,
- // because an AP with many small, short-lived blocks *is* likely.) And if
- // such an AP existed, it'll probably show up in "Total (bytes), zero reads
+ // because a PP with many small, short-lived blocks *is* likely.) And if
+ // such a PP existed, it'll probably show up in "Total (bytes), zero reads
// or zero writes" or "Total (bytes), low-access" anyway, because there's
- // little time for accesses in 500 instructions.
+ // little time for accesses in a small number of instructions.
{
- label: "Total (blocks), short-lived",
- bolds: { "totalTitle": 1, "totalBlocks": 1, "totalAvgLifetimeInstrs": 1 },
+ label: () => "Total (blocks), short-lived",
+ bolds: { "totalTitle": 1, "totalBlocks": 1, "totalAvgLifetime": 1 },
cmpField: "_totalBlocks",
+ enable: (aBkLt, aBkAcc) => aBkLt,
sig: (aT) => aT._totalBlocks >= 0.005 * gRoot._totalBlocks &&
- aT._totalAvgLifetimeInstrs() <= 500,
+ aT._totalAvgLifetimes() <= gData.tuth,
sigLabel: () => `\
(total >= ${blocksAndPerc(0.005 * gRoot._totalBlocks, gRoot._totalBlocks)}) && \
-(total avg lifetime <= ${instrs(500)})`
+(avg lifetime <= ${time(gData.tuth)})`
},
{
- label: "Total (bytes), zero reads or zero writes",
+ label: () => "Total (bytes), zero reads or zero writes",
bolds: { "totalTitle": 1, "totalBytes": 1,
"readsTitle": 1, "readsBytes": 1,
"writesTitle": 1, "writesBytes": 1,
},
cmpField: "_totalBytes",
+ enable: (aBkLt, aBkAcc) => aBkAcc,
sig: (aT) => aT._totalBytes >= 0.005 * gRoot._totalBytes &&
(aT._readsBytes === 0 || aT._writesBytes === 0),
sigLabel: () => `\
((reads == ${bytes(0)}) || (writes == ${bytes(0)}))`
},
{
- label: "Total (blocks), zero reads or zero writes",
+ label: () => "Total (blocks), zero reads or zero writes",
bolds: { "totalTitle": 1, "totalBlocks": 1,
"readsTitle": 1, "readsBytes": 1,
"writesTitle": 1, "writesBytes": 1,
},
cmpField: "_totalBlocks",
+ enable: (aBkLt, aBkAcc) => aBkAcc,
sig: (aT) => aT._totalBlocks >= 0.005 * gRoot._totalBlocks &&
(aT._readsBytes === 0 || aT._writesBytes === 0),
sigLabel: () => `\
((reads == ${bytes(0)}) || (writes == ${bytes(0)}))`
},
{
- label: "Total (bytes), low-access",
+ label: () => "Total (bytes), low-access",
bolds: { "totalTitle": 1, "totalBytes": 1,
"readsTitle": 1, "readsAvgPerByte": 1,
"writesTitle": 1, "writesAvgPerByte": 1,
},
cmpField: "_totalBytes",
+ enable: (aBkLt, aBkAcc) => aBkAcc,
sig: (aT) => aT._totalBytes >= 0.005 * gRoot._totalBytes &&
aT._readsBytes !== 0 &&
aT._writesBytes !== 0 &&
((reads <= ${perByte(0.4)}) || (writes <= ${perByte(0.4)}))`
},
{
- label: "Total (blocks), low-access",
+ label: () => "Total (blocks), low-access",
bolds: { "totalTitle": 1, "totalBlocks": 1,
"readsTitle": 1, "readsAvgPerByte": 1,
"writesTitle": 1, "writesAvgPerByte": 1,
},
cmpField: "_totalBlocks",
+ enable: (aBkLt, aBkAcc) => aBkAcc,
sig: (aT) => aT._totalBlocks >= 0.005 * gRoot._totalBlocks &&
aT._readsBytes !== 0 &&
aT._writesBytes !== 0 &&
((reads <= ${perByte(0.4)}) || (writes <= ${perByte(0.4)}))`
},
// No "Total (avg size bytes)": not interesting.
- // No "Total (avg lifetime instrs)": covered by "Total (blocks), short-lived".
+ // No "Total (avg lifetime)": covered by "Total (blocks), short-lived".
// No "Max (bytes)": not interesting, and unclear how to sort.
// No "Max (blocks)": not interesting, and unclear how to sort.
// No "Max (avg size bytes)": not interesting, and unclear how to sort.
{
- label: "At t-gmax (bytes)",
+ label: () => "At t-gmax (bytes)",
bolds: { "atTGmaxTitle": 1, "atTGmaxBytes": 1 },
cmpField: "_atTGmaxBytes",
+ enable: (aBkLt, aBkAcc) => aBkLt,
sig: (aT) => aT._atTGmaxBytes >= 0.01 * gRoot._atTGmaxBytes,
sigLabel: () => `\
at-t-gmax >= ${bytesAndPerc(0.01 * gRoot._atTGmaxBytes, gRoot._atTGmaxBytes)}`
// No "At t-gmax (blocks)": not interesting.
// No "At t-gmax (avg size bytes)": not interesting.
{
- label: "At t-end (bytes)",
+ label: () => "At t-end (bytes)",
bolds: { "atTEndTitle": 1, "atTEndBytes": 1 },
cmpField: "_atTEndBytes",
+ enable: (aBkLt, aBkAcc) => aBkLt,
sig: (aT) => aT._atTEndBytes >= 0.01 * gRoot._atTEndBytes,
sigLabel: () => `\
at-t-end >= ${bytesAndPerc(0.01 * gRoot._atTEndBytes, gRoot._atTEndBytes)}`
// No "At t-end (blocks)": not interesting.
// No "At t-end (avg size bytes)": not interesting.
{
- label: "Reads (bytes)",
+ label: () => "Reads (bytes)",
bolds: { "readsTitle": 1, "readsBytes": 1 },
cmpField: "_readsBytes",
+ enable: (aBkLt, aBkAcc) => aBkAcc,
sig: (aT) => aT._readsBytes >= 0.01 * gRoot._readsBytes,
sigLabel: () => `\
reads >= ${bytesAndPerc(0.01 * gRoot._readsBytes, gRoot._readsBytes)}`
},
{
- label: "Reads (bytes), high-access",
+ label: () => "Reads (bytes), high-access",
bolds: { "readsTitle": 1, "readsBytes": 1, "readsAvgPerByte": 1 },
cmpField: "_readsBytes",
+ enable: (aBkLt, aBkAcc) => aBkAcc,
sig: (aT) => aT._readsBytes >= 0.005 * gRoot._readsBytes &&
(aT._readsAvgPerByte() >= 1000 ||
aT._writesAvgPerByte() >= 1000),
},
// No "Reads (avg per byte)": covered by other access-related ones.
{
- label: "Writes (bytes)",
+ label: () => "Writes (bytes)",
bolds: { "writesTitle": 1, "writesBytes": 1 },
cmpField: "_writesBytes",
+ enable: (aBkLt, aBkAcc) => aBkAcc,
sig: (aT) => aT._writesBytes >= 0.01 * gRoot._writesBytes,
sigLabel: () => `\
writes >= ${bytesAndPerc(0.01 * gRoot._writesBytes, gRoot._writesBytes)}`
},
{
- label: "Writes (bytes), high-access",
+ label: () => "Writes (bytes), high-access",
bolds: { "writesTitle": 1, "writesBytes": 1, "writesAvgPerByte": 1 },
cmpField: "_writesBytes",
+ enable: (aBkLt, aBkAcc) => aBkAcc,
sig: (aT) => aT._writesBytes >= 0.005 * gRoot._writesBytes &&
(aT._readsAvgPerByte() >= 1000 ||
aT._writesAvgPerByte() >= 1000),
this._totalBytes = 0;
this._totalBlocks = 0;
- this._totalLifetimesInstrs = 0;
+ this._totalLifetimes = 0;
// These numbers only make sense for leaf nodes. Unlike total stats, which
- // can be summed, _maxBytes/_maxBlocks for two APs can't be easily combined
+ // can be summed, _maxBytes/_maxBlocks for two PPs can't be easily combined
// because the maxes may have occurred at different times.
if (this._kind === kLeaf) {
this._maxBytes = 0;
}
TreeNode.prototype = {
- _add(aTotalBytes, aTotalBlocks, aTotalLifetimesInstrs, aMaxBytes,
+ _add(aTotalBytes, aTotalBlocks, aTotalLifetimes, aMaxBytes,
aMaxBlocks, aAtTGmaxBytes, aAtTGmaxBlocks, aAtTEndBytes,
aAtTEndBlocks, aReadsBytes, aWritesBytes, aAccesses) {
// We ignore this._kind, this._frames, and this._kids.
+ // Note: if !gData.bklt and/or !gData.bkacc, some of these fields these
+ // values come from will be missing in the input file, so the values will
+ // be `undefined`, and the fields will end up as `NaN`. But this is ok
+ // because we don't show them.
+
this._totalBytes += aTotalBytes;
this._totalBlocks += aTotalBlocks;
- this._totalLifetimesInstrs += aTotalLifetimesInstrs;
+ this._totalLifetimes += aTotalLifetimes;
if (this._kind === kLeaf) {
// Leaf nodes should only be added to once, because DHAT currently
}
},
- _addAP(aAP) {
- this._add(aAP.tb, aAP.tbk, aAP.tli, aAP.mb, aAP.mbk, aAP.gb, aAP.gbk,
- aAP.fb, aAP.fbk, aAP.rb, aAP.wb, aAP.acc);
+ _addPP(aPP) {
+ this._add(aPP.tb, aPP.tbk, aPP.tl, aPP.mb, aPP.mbk, aPP.gb, aPP.gbk,
+ aPP.eb, aPP.ebk, aPP.rb, aPP.wb, aPP.acc);
},
// This is called in two cases.
// cloning a node).
// - Aggregating multiple nodes.
_addNode(aT) {
- this._add(aT._totalBytes, aT._totalBlocks, aT._totalLifetimesInstrs,
+ this._add(aT._totalBytes, aT._totalBlocks, aT._totalLifetimes,
aT._maxBytes, aT._maxBlocks, aT._atTGmaxBytes, aT._atTGmaxBlocks,
aT._atTEndBytes, aT._atTEndBlocks,
aT._readsBytes, aT._writesBytes, aT._accesses);
// Split the node after the aTi'th internal frame. The inheriting kid will
// get the post-aTi frames; the new kid will get aNewFrames.
- _split(aTi, aAP, aNewFrames) {
+ _split(aTi, aPP, aNewFrames) {
// kid1 inherits t's kind and values.
let inheritedFrames = this._frames.splice(aTi + 1);
let kid1 = new TreeNode(this._kind, inheritedFrames);
// Put all remaining frames into kid2.
let kid2 = new TreeNode(kLeaf, aNewFrames);
- kid2._addAP(aAP);
+ kid2._addPP(aPP);
// Update this.
if (this._kind === kLeaf) {
delete this._maxBlocks;
}
this._kids = [kid1, kid2];
- this._addAP(aAP);
+ this._addPP(aPP);
},
_totalAvgSizeBytes() {
return div(this._totalBytes, this._totalBlocks);
},
- _totalAvgLifetimeInstrs() {
- return div(this._totalLifetimesInstrs, this._totalBlocks);
+ _totalAvgLifetimes() {
+ return div(this._totalLifetimes, this._totalBlocks);
},
_maxAvgSizeBytes() {
}
}
-// Do basic checking of an AP read from file.
-function checkAP(aAP) {
- let fields = ["tb", "tbk", "tli",
- "mb", "mbk",
- "gb", "gbk",
- "fb", "fbk",
- "rb", "wb",
- "fs"];
- checkFields(aAP, fields);
+// Do basic checking of a PP read from file.
+function checkPP(aPP) {
+ checkFields(aPP, ["tb", "tbk", "fs"]);
+ if (gData.bklt) {
+ checkFields(aPP, ["mb", "mbk", "gb", "gbk", "eb", "ebk"]);
+ }
+ if (gData.bkacc) {
+ checkFields(aPP, ["rb", "wb"]);
+ }
}
// Access counts latch as 0xffff. Treating 0xffff as Infinity gives us exactly
assert(false, "too-large access value");
}
-const kExpectedFileVersion = 1;
+const kExpectedFileVersion = 2;
// Build gRoot from gData.
function buildTree() {
// Check global values.
- let fields = ["dhatFileVersion",
+ let fields = ["dhatFileVersion", "mode", "verb",
+ "bklt", "bkacc",
+ "tu", "Mtu",
"cmd", "pid",
- "mi", "ei",
- "aps", "ftbl"];
+ "te", "pps", "ftbl"];
checkFields(gData, fields);
if (gData.dhatFileVersion != kExpectedFileVersion) {
- throw Error(`data file has version number ${gData.dhatFileVersion}, ` +
- `expected version number ${kExpectedFileVersion}`);
+ throw new Error(
+ `data file has version number ${gData.dhatFileVersion}, ` +
+ `expected version number ${kExpectedFileVersion}`);
+ }
+
+ if (gData.bklt) {
+ checkFields(gData, ["tg", "tuth"]);
+ }
+
+ // Update sort metric labels, and disable sort metrics that aren't allowed
+ // for this data.
+ for (let [i, option] of gSelect.childNodes.entries()) {
+ let data = gSelectData[i];
+ option.label = data.label();
+ option.disabled = !data.enable(gData.bklt, gData.bkacc);
+ }
+
+ // If the selected sort metric was just disabled, switch the sort metric
+ // back to the default (which is never disabled).
+ let option = gSelect.childNodes[gSelect.selectedIndex];
+ if (option.disabled) {
+ for (let [i, data] of gSelectData.entries()) {
+ let option = gSelect.childNodes[i];
+ if (data.isDefault) {
+ option.selected = true;
+ break;
+ }
+ }
}
// Build the radix tree. Nodes are in no particular order to start with. The
// algorithm is tricky because we need to use internal frames when possible.
gRoot = new TreeNode(kLeaf, [0]); // Frame 0 is always "[root]".
- for (let [i, ap] of gData.aps.entries()) {
- checkAP(ap);
+ for (let [i, pp] of gData.pps.entries()) {
+ checkPP(pp);
// Decompress the run-length encoding in `acc`, if present.
- if (ap.acc) {
+ if (pp.acc) {
let acc = [];
- for (let i = 0; i < ap.acc.length; i++) {
- if (ap.acc[i] < 0) {
+ for (let i = 0; i < pp.acc.length; i++) {
+ if (pp.acc[i] < 0) {
// A negative number encodes a repeat count. The following entry has
// the value to be repeated.
- let reps = -ap.acc[i++];
- let val = ap.acc[i];
+ let reps = -pp.acc[i++];
+ let val = pp.acc[i];
for (let j = 0; j < reps; j++) {
acc.push(normalizeAccess(val));
}
} else {
- acc.push(normalizeAccess(ap.acc[i]));
+ acc.push(normalizeAccess(pp.acc[i]));
}
}
- ap.acc = acc;
+ pp.acc = acc;
}
- // The first AP is a special case, because we have to build gRoot.
+ // The first PP is a special case, because we have to build gRoot.
if (i === 0) {
- gRoot._frames.push(...ap.fs);
- gRoot._addAP(ap);
+ gRoot._frames.push(...pp.fs);
+ gRoot._addPP(pp);
continue;
}
// `abcd` is a frame sequence (and `-` is an empty sequence), `N` is a node
// value, and `Xs` are the node's children.
- for (let [j, kidFrame] of ap.fs.entries()) {
-
+ for (let [j, kidFrame] of pp.fs.entries()) {
// Search for kidFrame among internal frames.
if (ti + 1 < t._frames.length) {
// t has an internal frame at the right index.
// The internal frame doesn't match. Split the node.
//
// E.g. abcd:20-[] + abef:10 => ab:30-[cd:20-[], ef:10-[]]
- t._split(ti, ap, ap.fs.slice(j));
+ t._split(ti, pp, pp.fs.slice(j));
done = true;
break;
}
// get the leftover frames.
//
// E.g. ab:20-[] + abcd:10 => ab:30-[-:20-[], cd:10-[]]
- t._split(ti, ap, ap.fs.slice(j));
+ t._split(ti, pp, pp.fs.slice(j));
done = true;
break;
}
- t._addAP(ap);
+ t._addPP(pp);
// Search for the frame among the kids.
let kid;
//
// E.g. ab:20-[c:10-Xs, d:10-Ys] + abef:10 =>
// ab:30-[c:10-Xs, d:10-Ys, ef:10-[]]
- kid = new TreeNode(kLeaf, ap.fs.slice(j));
- kid._addAP(ap);
+ kid = new TreeNode(kLeaf, pp.fs.slice(j));
+ kid._addPP(pp);
t._kids.push(kid);
done = true;
break;
if (!done) {
// If we reach here, either:
- // - ap's frames match an existing frame sequence, in which case we
- // just need to _addAP(); or
- // - ap's frames are a subsequence of an existing sequence, in which
+ // - pp's frames match an existing frame sequence, in which case we
+ // just need to _addPP(); or
+ // - pp's frames are a subsequence of an existing sequence, in which
// case we must split.
if (ti + 1 < t._frames.length) {
// frames. Split, creating an empty node.
//
// E.g. abcd:20-Xs + ab:10 => ab:30-[cd:20-Xs, -:10-[]]
- t._split(ti, ap, []);
+ t._split(ti, pp, []);
} else if (!t._kids) {
// This is impossible because DHAT currently produces records with
// unique locations. If we remove addresses from frames in the future
// then duplicate locations will occur, and the following code is how
// it must be handled.
- throw Error(`data file contains a repeated location`);
+ throw new Error(`data file contains a repeated location (1)`);
// Matches an existing sequence that doesn't end in node with empty
- // frames. Add the AP.
+ // frames. Add the PP.
//
// E.g. ab:20-[] + ab:10 => ab:30-[]
- t._addAP(ap);
+ t._addPP(pp);
} else {
// Look for a kid with empty frames.
// unique locations. If we remove addresses from frames in the future
// then duplicate locations will occur, and the following code is how
// it must be handled.
- throw Error(`data file contains a repeated location`);
+ throw new Error(`data file contains a repeated location (2)`);
// Matches an existing sequence that ends in a node with empty
- // frames. Add the AP.
+ // frames. Add the PP.
//
// E.g. ab:20-[c:10-Xs, -:10-[]] + ab:10 => ab:30-[c:10-Xs, -:20-[]]
- t._addAP(ap);
- emptyKid._addAP(ap);
+ t._addPP(pp);
+ emptyKid._addPP(pp);
} else {
// A subsequence of an existing sequence that ends at the end of t's
// E.g. ab:20-[c:10-Xs, d:10-Ys] + ab:10 =>
// ab:30-[c:10-Xs, d:10-Ys, -:10-[]]
let newKid = new TreeNode(kLeaf, []);
- newKid._addAP(ap);
+ newKid._addPP(pp);
t._kids.push(newKid);
- t._addAP(ap);
+ t._addPP(pp);
}
}
}
-
}
}
}
function perMinstr(aN) {
- return `${kDFormat.format(div(1000000 * aN, gData.ei))}/Minstr`;
+ return `${kDFormat.format(div(1000000 * aN, gData.te))}/${gData.Mtu}`;
+}
+
+function byteUnit() {
+ return gData.hasOwnProperty("bu") ? gData.bsu : "byte";
+}
+
+function bytesUnit() {
+ return gData.hasOwnProperty("bsu") ? gData.bsu : "bytes";
+}
+
+function blocksUnit() {
+ return gData.hasOwnProperty("bksu") ? gData.bksu : "blocks";
}
function bytes(aN) {
- return `${kDFormat.format(aN)} bytes`;
+ return `${kDFormat.format(aN)} ${bytesUnit()}`;
}
function bytesAndPerc(aN, aTotalN) {
}
function blocks(aN) {
- return `${kDFormat.format(aN)} blocks`;
+ return `${kDFormat.format(aN)} ${blocksUnit()}`;
}
function blocksAndPerc(aN, aTotalN) {
}
function perByte(aN) {
- return `${kDFormat.format(aN)}/byte`;
+ return `${kDFormat.format(aN)}/${byteUnit()}`;
}
-function instrs(aN) {
- return `${kDFormat.format(aN)} instrs`;
+function time(aN) {
+ return `${kDFormat.format(aN)} ${gData.tu}`;
}
-function avgLifetimeInstrs(aN) {
- return `avg lifetime ${instrs(aN)}`;
+function avgLifetime(aN) {
+ return `avg lifetime ${time(aN)}`;
}
function accesses(aAccesses) {
let v, v1, v2;
v = "Invocation {\n";
+ v += ` Mode: ${gData.mode}\n`;
v += ` Command: ${gData.cmd}\n`;
v += ` PID: ${gData.pid}\n`;
v += "}\n\n";
v = "Times {\n";
- v1 = perc(gData.mi, gData.ei);
- v += ` t-gmax: ${instrs(gData.mi)} (${v1} of program duration)\n`;
- v += ` t-end: ${instrs(gData.ei)}\n`;
+ v1 = perc(gData.tg, gData.te);
+ if (gData.bklt) {
+ v += ` t-gmax: ${time(gData.tg)} (${v1} of program duration)\n`;
+ }
+ v += ` t-end: ${time(gData.te)}\n`;
v += "}\n\n";
let v1, v2, v3, v4, v5;
- // "AP" + node ID + kid count.
+ // "PP" + node ID + kid count.
v1 = aNodeIdNums.join('.');
v2 = aNumSibs + 1;
v3 = kids ? `(${kids.length} children) ` : "";
- fr(`AP ${v1}/${v2} ${v3}{`, true, false);
+ fr(`PP ${v1}/${v2} ${v3}{`, true, false);
nl(true);
// "Total".
v1 = bytesAndPercAndRate(aT._totalBytes, gRoot._totalBytes);
v2 = blocksAndPercAndRate(aT._totalBlocks, gRoot._totalBlocks);
v3 = avgSizeBytes(aT._totalAvgSizeBytes());
- v4 = avgLifetimeInstrs(aT._totalAvgLifetimeInstrs());
- v5 = perc(aT._totalAvgLifetimeInstrs(), gData.ei);
+ v4 = avgLifetime(aT._totalAvgLifetimes());
+ v5 = perc(aT._totalAvgLifetimes(), gData.te);
fr(" Total: ", aBolds.totalTitle);
fr(v1, aBolds.totalBytes);
fr(" in ");
fr(v2, aBolds.totalBlocks);
fr(", ", aBolds.totalAvgSizeBytes, false);
fr(v3, aBolds.totalAvgSizeBytes);
- fr(", ", aBolds.totalAvgLifetimeInstrs, false);
- fr(`${v4} (${v5} of program duration)`, aBolds.totalAvgLifetimeInstrs);
+ if (gData.bklt) {
+ fr(", ", aBolds.totalAvgLifetime, false);
+ fr(`${v4} (${v5} of program duration)`, aBolds.totalAvgLifetime);
+ }
nl(aBolds.totalTitle);
- // "Max".
- if (aT !== gRoot && aT._kind === kLeaf) {
- assert(!kids, "leaf node has children");
- // These percentages are relative to the local totals, not the root
- // totals.
- v1 = bytes(aT._maxBytes);
- v2 = blocks(aT._maxBlocks);
- v3 = avgSizeBytes(aT._maxAvgSizeBytes());
- fr(` Max: ${v1} in ${v2}, ${v3}`);
- nl();
+ if (gData.bklt) {
+ // "Max".
+ if (aT !== gRoot && aT._kind === kLeaf) {
+ assert(!kids, "leaf node has children");
+ // These percentages are relative to the local totals, not the root
+ // totals.
+ v1 = bytes(aT._maxBytes);
+ v2 = blocks(aT._maxBlocks);
+ v3 = avgSizeBytes(aT._maxAvgSizeBytes());
+ fr(` Max: ${v1} in ${v2}, ${v3}`);
+ nl();
+ }
+
+ // "At t-gmax".
+ v1 = bytesAndPerc(aT._atTGmaxBytes, gRoot._atTGmaxBytes);
+ v2 = blocksAndPerc(aT._atTGmaxBlocks, gRoot._atTGmaxBlocks);
+ v3 = avgSizeBytes(aT._atTGmaxAvgSizeBytes());
+ fr(" At t-gmax: ", aBolds.atTGmaxTitle);
+ fr(v1, aBolds.atTGmaxBytes);
+ fr(` in ${v2}, ${v3}`);
+ nl(aBolds.atTGmaxTitle);
+
+ // "At t-end".
+ v1 = bytesAndPerc(aT._atTEndBytes, gRoot._atTEndBytes);
+ v2 = blocksAndPerc(aT._atTEndBlocks, gRoot._atTEndBlocks);
+ v3 = avgSizeBytes(aT._atTEndAvgSizeBytes());
+ fr(" At t-end: ", aBolds.atTEndTitle);
+ fr(v1, aBolds.atTEndBytes);
+ fr(` in ${v2}, ${v3}`);
+ nl(aBolds.atTEndTitle);
}
- // "At t-gmax".
- v1 = bytesAndPerc(aT._atTGmaxBytes, gRoot._atTGmaxBytes);
- v2 = blocksAndPerc(aT._atTGmaxBlocks, gRoot._atTGmaxBlocks);
- v3 = avgSizeBytes(aT._atTGmaxAvgSizeBytes());
- fr(" At t-gmax: ", aBolds.atTGmaxTitle);
- fr(v1, aBolds.atTGmaxBytes);
- fr(` in ${v2}, ${v3}`);
- nl(aBolds.atTGmaxTitle);
-
- // "At t-end".
- v1 = bytesAndPerc(aT._atTEndBytes, gRoot._atTEndBytes);
- v2 = blocksAndPerc(aT._atTEndBlocks, gRoot._atTEndBlocks);
- v3 = avgSizeBytes(aT._atTEndAvgSizeBytes());
- fr(" At t-end: ", aBolds.atTEndTitle);
- fr(v1, aBolds.atTEndBytes);
- fr(` in ${v2}, ${v3}`);
- nl(aBolds.atTEndTitle);
-
- // "Reads".
- v1 = bytesAndPercAndRate(aT._readsBytes, gRoot._readsBytes);
- v2 = perByte(aT._readsAvgPerByte());
- fr(" Reads: ", aBolds.readsTitle);
- fr(v1, aBolds.readsBytes);
- fr(", ", aBolds.readsBytes && aBolds.readsAvgPerByte, false);
- fr(v2, aBolds.readsAvgPerByte);
- nl(aBolds.readsTitle);
-
- // "Writes".
- v1 = bytesAndPercAndRate(aT._writesBytes, gRoot._writesBytes);
- v2 = perByte(aT._writesAvgPerByte());
- fr(" Writes: ", aBolds.writesTitle);
- fr(v1, aBolds.writesBytes);
- fr(", ", aBolds.writesBytes && aBolds.writesAvgPerByte, false);
- fr(v2, aBolds.writesAvgPerByte);
- nl(aBolds.writesTitle);
-
- // "Accesses". We show 32 per line (but not on aggregate nodes).
- if (aT._accesses && aT._accesses.length > 0) {
- let v = " Accesses: {";
- let prevN;
- for (let [i, n] of aT._accesses.entries()) {
- if ((i % 32) === 0) {
- fr(v);
- nl();
- v1 = i.toString().padStart(3, ' ');
- v = ` [${v1}] `;
- v += `${accesses(n)} `;
- } else {
- // Use a ditto mark for repeats.
- v += (n === prevN && n !== 0) ? "〃 " : `${accesses(n)} `;
+ if (gData.bkacc) {
+ // "Reads".
+ v1 = bytesAndPercAndRate(aT._readsBytes, gRoot._readsBytes);
+ v2 = perByte(aT._readsAvgPerByte());
+ fr(" Reads: ", aBolds.readsTitle);
+ fr(v1, aBolds.readsBytes);
+ fr(", ", aBolds.readsBytes && aBolds.readsAvgPerByte, false);
+ fr(v2, aBolds.readsAvgPerByte);
+ nl(aBolds.readsTitle);
+
+ // "Writes".
+ v1 = bytesAndPercAndRate(aT._writesBytes, gRoot._writesBytes);
+ v2 = perByte(aT._writesAvgPerByte());
+ fr(" Writes: ", aBolds.writesTitle);
+ fr(v1, aBolds.writesBytes);
+ fr(", ", aBolds.writesBytes && aBolds.writesAvgPerByte, false);
+ fr(v2, aBolds.writesAvgPerByte);
+ nl(aBolds.writesTitle);
+
+ // "Accesses". We show 32 per line (but not on aggregate nodes).
+ if (aT._accesses && aT._accesses.length > 0) {
+ let v = " Accesses: {";
+ let prevN;
+ for (let [i, n] of aT._accesses.entries()) {
+ if ((i % 32) === 0) {
+ fr(v);
+ nl();
+ v1 = i.toString().padStart(3, ' ');
+ v = ` [${v1}] `;
+ v += `${accesses(n)} `;
+ } else {
+ // Use a ditto mark for repeats.
+ v += (n === prevN && n !== 0) ? "〃 " : `${accesses(n)} `;
+ }
+ prevN = n;
}
- prevN = n;
- }
- fr(v);
- nl();
+ fr(v);
+ nl();
- fr(" }");
- nl();
+ fr(" }");
+ nl();
+ }
}
// "Allocated at".
- fr(" Allocated at {", true, false);
+ fr(` ${gData.verb} at {`, true, false);
nl(true);
if (aT._kind === kAgg) {
// Don't print ancestor frames; just print the "insignificant" frame.
}
function appendSignificanceThreshold(aP, aSigLabel) {
- let v = `\nAP significance threshold: ${aSigLabel()}\n`;
+ let v = `\nPP significance threshold: ${aSigLabel()}\n`;
appendElementWithText(aP, "span", v, "threshold");
}
// Get details relating to the chosen sort metrics.
let data = gSelectData[gSelect.selectedIndex];
let bolds = data.bolds;
- let label = data.label;
+ let label = data.label();
let cmpField = data.cmpField;
let sig = data.sig;
let sigLabel = data.sigLabel;
gSelect = appendElement(selectDiv, "select");
gSelect.onchange = changeSortMetric;
for (let [i, data] of gSelectData.entries()) {
- let option = appendElementWithText(gSelect, "option", data.label);
+ let option = appendElementWithText(gSelect, "option", data.label());
option.value = i;
if (data.isDefault) {
option.selected = true;
appendElementWithText(ul, "li", "'t-gmax': time of global heap maximum " +
"(as measured in bytes)");
appendElementWithText(ul, "li", "'t-end': time of program end");
+ // The file may use different units (via the `tu` and `Mtu` fields), but
+ // these are the standard units so mention them here.
appendElementWithText(ul, "li", "'instrs': instructions");
appendElementWithText(ul, "li", "'Minstr': mega-instruction, i.e. one " +
"million instructions");
- appendElementWithText(ul, "li", "'AP': allocation point");
+ appendElementWithText(ul, "li", "'PP': program point");
appendElementWithText(ul, "li", "'avg': average");
appendElementWithText(ul, "li", "'-' (in accesses): zero");
- appendElementWithText(ul, "li", "'∞' (in accesses): leaf AP counts max out " +
+ appendElementWithText(ul, "li", "'∞' (in accesses): leaf PP counts max out " +
"at 65534; larger counts are treated as " +
"infinity");
appendElementWithText(ul, "li", "'〃' (in accesses): same as previous entry");
--- /dev/null
+
+/*
+ ----------------------------------------------------------------
+
+ Notice that the following BSD-style license applies to this one
+ file (dhat.h) only. The rest of Valgrind is licensed under the
+ terms of the GNU General Public License, version 2, unless
+ otherwise indicated. See the COPYING file in the source
+ distribution for details.
+
+ ----------------------------------------------------------------
+
+ This file is part of DHAT, a Valgrind tool for profiling the
+ heap usage of programs.
+
+ Copyright (C) 2020 Nicholas Nethercote. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ----------------------------------------------------------------
+
+ Notice that the above BSD-style license applies to this one file
+ (memcheck.h) only. The entire rest of Valgrind is licensed under
+ the terms of the GNU General Public License, version 2. See the
+ COPYING file in the source distribution for details.
+
+ ----------------------------------------------------------------
+*/
+
+#include "valgrind.h"
+
+typedef
+ enum {
+ VG_USERREQ__DHAT_AD_HOC_EVENT = VG_USERREQ_TOOL_BASE('D', 'H'),
+
+ // This is just for DHAT's internal use. Don't use it.
+ _VG_USERREQ__DHAT_COPY = VG_USERREQ_TOOL_BASE('D','H') + 256
+ } Vg_DHATClientRequest;
+
+// Record an ad hoc event. The meaning of the weight argument will depend on
+// what the event represents, which is up to the user. If no meaningful weight
+// argument exists, just use 1.
+#define DHAT_AD_HOC_EVENT(_qzz_weight) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DHAT_AD_HOC_EVENT, \
+ (_qzz_weight), 0, 0, 0, 0)
+
<sect1 id="dh-manual.overview" xreflabel="Overview">
<title>Overview</title>
-<para>DHAT is a tool for examining how programs use their heap
+<para>DHAT is primarily a tool for examining how programs use their heap
allocations.</para>
<para>It tracks the allocated blocks, and inspects every memory access
-to find which block, if any, it is to. It presents, on an allocation point
+to find which block, if any, it is to. It presents, on a program point
basis, information about these blocks such as sizes, lifetimes, numbers of
reads and writes, and read and write patterns.</para>
-<para>Using this information it is possible to identify allocation points with
+<para>Using this information it is possible to identify program points with
the following characteristics:</para>
<itemizedlist>
makes runs repeatable in a way which is not possible if CPU time is
used.</para>
+<para>DHAT also has support for copy profiling and ad hoc profiling. These are
+described below.</para>
+
</sect1>
<sect2 id="dh-output-header"><title>The Output Header</title>
-<para>The first part of the output shows the program command and process ID.
-For example:</para>
+<para>The first part of the output shows the mode, program command and process
+ID. For example:</para>
<programlisting><![CDATA[
Invocation {
+ Mode: heap
Command: /home/njn/moz/rust0/build/x86_64-unknown-linux-gnu/stage2/bin/rustc --crate-name tuple_stress src/main.rs
PID: 18816
}
</sect2>
-<sect2 id="dh-ap-tree"><title>The AP Tree</title>
+<sect2 id="dh-ap-tree"><title>The PP Tree</title>
<para>The third part of the output is the largest and most interesting part,
-showing the allocation point (AP) tree.</para>
+showing the program point (PP) tree.</para>
<sect3 id="dh-structure"><title>Structure</title>
-<para>The following image shows a screenshot of part of an AP
+<para>The following image shows a screenshot of part of a PP
tree. The font is very small because this screenshot is intended to
demonstrate the high-level structure of the tree rather than the
-details within the text.</para>
+details within the text. (It is also slightly out-of-date, and doesn't quite
+match the current output produced by DHAT's viewer.)</para>
<graphic fileref="images/dh-tree.png" scalefit="1"/>
<para>The root node looks like this:</para>
<programlisting><![CDATA[
-AP 1/1 (25 children) {
+PP 1/1 (25 children) {
Total: 1,355,253,987 bytes (100%, 67,454.81/Minstr) in 5,943,417 blocks (100%, 295.82/Minstr), avg size 228.03 bytes, avg lifetime 3,134,692,250.67 instrs (15.6% of program duration)
At t-gmax: 423,930,307 bytes (100%) in 1,575,682 blocks (100%), avg size 269.05 bytes
At t-end: 258,002 bytes (100%) in 2,129 blocks (100%), avg size 121.18 bytes
<sect3 id="dh-interior-nodes"><title>Interior Nodes</title>
-<para>AP nodes further down the tree show information about a subset of
+<para>PP nodes further down the tree show information about a subset of
allocations. For example:</para>
<programlisting><![CDATA[
-AP 1.1/25 (2 children) {
+PP 1.1/25 (2 children) {
Total: 54,533,440 bytes (4.02%, 2,714.28/Minstr) in 458,839 blocks (7.72%, 22.84/Minstr), avg size 118.85 bytes, avg lifetime 1,127,259,403.64 instrs (5.61% of program duration)
At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
At t-end: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
<para>The <computeroutput>Total</computeroutput> line shows that this node
accounts for 4.02% of all bytes allocated during execution, and 7.72% of all
blocks. These percentages are useful for comparing the significance of
-different nodes within a single profile; an AP that accounts for 10% of bytes
+different nodes within a single profile; a PP that accounts for 10% of bytes
allocated is likely to be more interesting than one that accounts for
2%.</para>
average size and lifetimes of these blocks.</para>
<para>The <computeroutput>At t-gmax</computeroutput> line says shows that no
-blocks from this AP were alive when the global heap peak occurred. In other
+blocks from this PP were alive when the global heap peak occurred. In other
words, these blocks do not contribute at all to the global heap peak.</para>
<para>The <computeroutput>At t-end</computeroutput> line shows that no blocks
-were from this AP were alive at shutdown. In other words, all those blocks were
+were from this PP were alive at shutdown. In other words, all those blocks were
explicitly freed before termination.</para>
<para>The <computeroutput>Reads</computeroutput> and
<computeroutput>Writes</computeroutput> lines show how many bytes were read
-within this AP's blocks, the fraction this represents of all heap reads, and
+within this PP's blocks, the fraction this represents of all heap reads, and
the read rate. Finally, it shows the read ratio, which is the number of reads
per byte. In this case the number is 0.29, which is quite low -- if no byte was
read twice, then only 29% of the allocated bytes, which means that at least 71%
<para>This is a leaf node:</para>
<programlisting><![CDATA[
-AP 1.1.1.1/2 {
+PP 1.1.1.1/2 {
Total: 31,460,928 bytes (2.32%, 1,565.9/Minstr) in 262,171 blocks (4.41%, 13.05/Minstr), avg size 120 bytes, avg lifetime 986,406,885.05 instrs (4.91% of program duration)
Max: 16,779,136 bytes in 65,543 blocks, avg size 256 bytes
At t-gmax: 0 bytes (0%) in 0 blocks (0%), avg size 0 bytes
previous example; and has no children.</para>
<para>Leaf nodes contain an additional <computeroutput>Max</computeroutput>
-line, indicating the peak memory use for the blocks covered by this AP. (This
+line, indicating the peak memory use for the blocks covered by this PP. (This
peak may have occurred at a time other than
<computeroutput>t-gmax</computeroutput>.) In this case, 31,460,298 bytes were
-allocated from this AP, but the maximum size alive at once was 16,779,136
+allocated from this PP, but the maximum size alive at once was 16,779,136
bytes.</para>
<para>Stack frames that begin with a <computeroutput>^</computeroutput> rather
<sect3 id="dh-access-counts"><title>Access Counts</title>
-<para>If all blocks covered by an AP node have the same size, an additional
+<para>If all blocks covered by a PP node have the same size, an additional
<computeroutput>Accesses</computeroutput> field will be present. It indicates
how the reads and writes within these blocks were distributed. For
example:</para>
}
]]></programlisting>
-<para>Every block covered by this AP was 32 bytes. Within all of those blocks,
+<para>Every block covered by this PP was 32 bytes. Within all of those blocks,
byte 0 was accessed (read or written) 65,547 times, byte 1 was accessed 7
times, byte 2 was accessed 8 times, and so on.</para>
<sect3 id="aggregate-nodes"><title>Aggregate Nodes</title>
-<para>The AP tree is very large and many nodes represent tiny numbers of blocks
+<para>The PP tree is very large and many nodes represent tiny numbers of blocks
and bytes. Therefore, DHAT's viewer aggregates insignificant nodes like
this:</para>
<programlisting><![CDATA[
-AP 1.14.2/2 {
+PP 1.14.2/2 {
Total: 5,175 blocks (0.09%, 0.26/Minstr)
Allocated at {
[5 insignificant]
<sect2 id="dh-output-footer"><title>The Output Footer</title>
-<para>Below the AP tree is a line like this:</para>
+<para>Below the PP tree is a line like this:</para>
<programlisting><![CDATA[
-AP significance threshold: total >= 59,434.17 blocks (1%)
+PP significance threshold: total >= 59,434.17 blocks (1%)
]]></programlisting>
-<para>It shows the function used to determine if an AP node is significant. All
+<para>It shows the function used to determine if a PP node is significant. All
nodes that don't satisfy this function are aggregated. It is occasionally
-useful if you don't understand why an AP node has been aggregated. The exact
+useful if you don't understand why a PP node has been aggregated. The exact
threshold depends on the sort metric (see below).</para>
<para>Finally, the bottom of the page shows a legend that explains some of the
<para>The values within a node that represent the chosen sort metric are shown
in bold, so they stand out.</para>
-<para>Here is part of an AP node found with "Total (blocks), tiny", showing
+<para>Here is part of a PP node found with "Total (blocks), tiny", showing
blocks with an average size of only 8.67 bytes:</para>
<programlisting><![CDATA[
Total: 3,407,848 bytes (0.25%, 169.62/Minstr) in 393,214 blocks (6.62%, 19.57/Minstr), avg size 8.67 bytes, avg lifetime 1,167,795,629.1 instrs (5.81% of program duration)
]]></programlisting>
-<para>Here is part of an AP node found with "Total (blocks), short-lived",
+<para>Here is part of a PP node found with "Total (blocks), short-lived",
showing blocks with an average lifetime of only 181.75 instructions:</para>
<programlisting><![CDATA[
Total: 23,068,584 bytes (1.7%, 1,148.19/Minstr) in 262,143 blocks (4.41%, 13.05/Minstr), avg size 88 bytes, avg lifetime 181.75 instrs (0% of program duration)
]]></programlisting>
-<para>Here is an example of an AP identified with "Total (blocks), zero reads
+<para>Here is an example of a PP identified with "Total (blocks), zero reads
or zero writes", showing blocks that are allocated but never touched:</para>
<programlisting><![CDATA[
Writes: 0 bytes (0%, 0/Minstr), 0/byte
]]></programlisting>
-<para>All the blocks identified by these APs are good candidates for
+<para>All the blocks identified by these PPs are good candidates for
optimization.</para>
</sect2>
bytes.) As a result, it can only increase the global heap peak (if indeed,
this results in a new peak) by 100 bytes.</para>
-<para>Finally, the allocation point assigned to the block allocated by the
+<para>Finally, the program point assigned to the block allocated by the
<computeroutput>malloc(100)</computeroutput> call is retained once the block
is reallocated. Which means that all 300 bytes are attributed to that
-allocation point, and no separate allocation point is created for the
+program point, and no separate program point is created for the
<computeroutput>realloc(200)</computeroutput> call. This may be surprising,
but it has one large benefit.</para>
adds data to that buffer from numerous different points in the code,
reallocating the buffer each time it gets full. (E.g. code generation in a
compiler might work this way.) With the described approach, the first heap
-block and all subsequent heap blocks are attributed to the same allocation
-point. While this is something of a lie -- the first allocation point isn't
-actually responsible for the other allocations -- it is arguably better than
-having the allocation points spread around, in a distribution
-that unpredictably depends on whenever the reallocation points were
-triggered.</para>
+block and all subsequent heap blocks are attributed to the same program point.
+While this is something of a lie -- the first program point isn't actually
+responsible for the other allocations -- it is arguably better than having the
+program points spread around in a distribution that unpredictably depends on
+whenever the reallocations were triggered.</para>
+
+</sect1>
+
+
+<sect1 id="dh-manual.copy-profiling" xreflabel="Copy profiling">
+<title>Copy profiling</title>
+
+<para>If DHAT is invoked with <option>--mode=copy</option>, instead of
+profiling heap operations (allocations and deallocations), it profiles copy
+operations, such as <computeroutput>memcpy</computeroutput>,
+<computeroutput>memmove</computeroutput>,
+<computeroutput>strcpy</computeroutput>, and
+<computeroutput>bcopy</computeroutput>. This is sometimes useful.</para>
+
+<para>Here is an example PP node from this mode:</para>
+
+<programlisting><![CDATA[
+PP 1.1.2/5 (4 children) {
+ Total: 1,210,925 bytes (10.03%, 4,358.66/Minstr) in 112,717 blocks (35.2%, 405.72/Minstr), avg size 10.74 bytes
+ Copied at {
+ ^1: 0x4842524: memmove (vg_replace_strmem.c:1289)
+ #2: 0x1F0A0D: copy_nonoverlapping<u8> (intrinsics.rs:1858)
+ #3: 0x1F0A0D: copy_from_slice<u8> (mod.rs:2524)
+ #4: 0x1F0A0D: spec_extend<u8> (vec.rs:2227)
+ #5: 0x1F0A0D: extend_from_slice<u8> (vec.rs:1619)
+ #6: 0x1F0A0D: push_str (string.rs:821)
+ #7: 0x1F0A0D: write_str (string.rs:2418)
+ #8: 0x1F0A0D: <&mut W as core::fmt::Write>::write_str (mod.rs:195)
+ }
+}
+]]></programlisting>
+
+<para>It is very similar to the PP nodes for heap profiling, but with less
+information, because copy profiling doesn't involve any tracking of memory
+regions with lifetimes.</para>
+
+</sect1>
+
+
+<sect1 id="dh-manual.ad-hoc-profiling" xreflabel="Ad hoc profiling">
+<title>Ad hoc profiling</title>
+
+<para>If DHAT is invoked with <option>--mode=ad-hoc</option>, instead of
+profiling heap operations (allocations and deallocations), it profiles calls to
+the <computeroutput>DHAT_AD_HOC_EVENT</computeroutput> client request, which is
+declared in <filename>dhat/dhat.h</filename>.</para>
+
+<para>Here is an example PP node from this mode:</para>
+
+<programlisting><![CDATA[
+PP 1.1.1.1/2 {
+ Total: 30 units (17.65%, 115.97/Minstr) in 1 events (14.29%, 3.87/Minstr), avg size 30 units
+ Occurred at {
+ ^1: 0x109407: g (ad-hoc.c:4)
+ ^2: 0x109425: f (ad-hoc.c:8)
+ #3: 0x109497: main (ad-hoc.c:14)
+ }
+}
+]]></programlisting>
+
+<para>This kind of profiling is useful when you know a code path is hot but you
+want to know more about it.</para>
+
+<para>For example, you might want to know which callsites of a hot function
+account for most of the calls. You could put a
+<computeroutput>DHAT_AD_HOC_EVENT(1);</computeroutput> call at the start of
+that function.</para>
+
+<para>Alternatively, you might want to know the typical length of a vector in a
+hot location. You could put a
+<computeroutput>DHAT_AD_HOC_EVENT(len);</computeroutput> call at the
+appropriate location, when <computeroutput>len</computeroutput> is the length
+of the vector.</para>
</sect1>
</listitem>
</varlistentry>
+ <varlistentry id="opt.mode" xreflabel="--mode">
+ <term>
+ <option><![CDATA[--mode=<heap|copy|ad-hoc> [default: heap] ]]></option>
+ </term>
+ <listitem>
+ <para>The profiling mode: heap profiling, copy profiling, or ad hoc
+ profiling.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
<para>Note that stacks by default have 12 frames. This may be more than
EXTRA_DIST = \
acc.stderr.exp acc.vgtest \
+ ad-hoc.stderr.exp ad-hoc.vgtest \
basic.stderr.exp basic.vgtest \
big.stderr.exp big.vgtest \
+ copy.stderr.exp copy.vgtest \
empty.stderr.exp empty.vgtest \
sig.stderr.exp sig.vgtest \
single.stderr.exp single.vgtest
check_PROGRAMS = \
acc \
+ ad-hoc \
basic \
big \
+ copy \
empty \
sig \
single
--- /dev/null
+#include "dhat/dhat.h"
+#include <stdlib.h>
+void g(void) {
+ DHAT_AD_HOC_EVENT(30);
+}
+
+void f(void) {
+ g();
+ DHAT_AD_HOC_EVENT(20);
+ g();
+}
+
+int main(void) {
+ f();
+ DHAT_AD_HOC_EVENT(10);
+ f();
+
+ // At one point malloc was broken with --mode=ad-hoc(!), and Valgrind was
+ // printing messages like "VG_USERREQ__CLIENT_CALL1: func=0x0" when malloc
+ // was called. So check that it's basically working...
+ char* p = malloc(100);
+ p = realloc(p, 200);
+ free(p);
+
+ return 0;
+}
+
--- /dev/null
+Total: 170 units in 7 events
--- /dev/null
+prog: ad-hoc
+vgopts: --mode=ad-hoc --dhat-out-file=dhat.out
+cleanup: rm dhat.out
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include "dhat/dhat.h"
int main(void)
{
free(c);
// totals: 3008 read, 3516 write
+
+ // Should be ignored because we're not in ad hoc mode.
+ DHAT_AD_HOC_EVENT(100);
+
return 0;
}
--- /dev/null
+// This tests --mode=copy with various copying functions.
+
+#define _GNU_SOURCE // For mempcpy.
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+void f(char* a, char* b, wchar_t* wa, wchar_t* wb);
+void test_malloc();
+
+int main(void) {
+ char a[1000];
+ char b[1000];
+ for (int i = 0; i < 1000; i++) {
+ a[i] = 'a';
+ b[i] = 'b';
+ }
+ a[999] = '\0';
+ b[999] = '\0';
+
+ wchar_t wa[250];
+ wchar_t wb[250];
+ for (int i = 0; i < 250; i++) {
+ wa[i] = 'A';
+ wb[i] = 'B';
+ }
+ wa[249] = '\0';
+ wb[249] = '\0';
+
+ for (int i = 0; i < 100; i++) {
+ f(a, b, wa, wb);
+ }
+
+ test_malloc();
+ return 0;
+}
+
+void f(char* a, char* b, wchar_t* wa, wchar_t* wb) {
+ // The memcpy is duplicated so we have 10 calls, which makes for nice round
+ // numbers in the totals.
+ memcpy (a, b, 1000); // Redirects to memmove
+ memcpy (a, b, 1000); // Redirects to memmove
+ memmove(a, b, 1000);
+ mempcpy(a, b, 1000);
+ bcopy (a, b, 1000); // Redirects to memmove
+ strcpy (a, b);
+ strncpy(a, b, 1000);
+ stpcpy (a, b); // Redirects to strcpy
+ stpncpy(a, b, 1000);
+ wcscpy (wa, wb);
+}
+
+void test_malloc() {
+ // At one point malloc was broken with --mode=copy(!), and Valgrind was
+ // printing messages like "VG_USERREQ__CLIENT_CALL1: func=0x0" when malloc
+ // was called. So check that it's basically working...
+ char* p = malloc(100);
+ p = realloc(p, 200);
+ free(p);
+}
--- /dev/null
+Total: 1,000,... bytes in 1,0.. blocks
--- /dev/null
+prog: copy
+vgopts: --mode=copy --dhat-out-file=dhat.out
+stderr_filter: filter_copy
+cleanup: rm dhat.out
--- /dev/null
+#! /bin/sh
+
+# It's impossible to get exact matches for copy counts because even trivial C
+# programs do a few memcpy/strcpy calls. So we allow some fuzzy matching.
+# So we allow 1,000,000..1,009,999 bytes and 1,000..1,099 blocks.
+
+./filter_stderr "$@" |
+sed -e "s/1,00.,... bytes in 1,0.. blocks/1,000,... bytes in 1,0.. blocks/"
+
sed "/^in a web browser/ d" |
sed "/^ \// d" | # This is pretty feeble, but I don't see
# how to do better
-sed "/^Scroll to the end/ d" |
-sed "/^explanation of some/ d" |
+sed "/^The text at the bottom/ d" |
# and remove any blank lines in the output
sed "/^[[:space:]]*$/d"
/* Can be called from VG_(tdict).malloc_malloc et al to do the actual
* alloc/freeing. */
extern void* VG_(cli_malloc) ( SizeT align, SizeT nbytes );
+extern void* VG_(cli_realloc)( void* ptr, SizeT nbytes );
extern void VG_(cli_free) ( void* p );
// Returns the usable size of a heap-block. It's the asked-for size plus
// possibly some more due to rounding up.
const VexArchInfo* archinfo_host,
IRType gWordTy, IRType hWordTy )
{
- return bb;
+ return bb;
}
static void nl_fini(Int exitcode)
#include "pub_tool_clreq.h"
/* ---------------------------------------------------------------------
- We have our own versions of these functions for two reasons:
+ We have our own versions of these functions for multiple reasons:
(a) it allows us to do overlap checking
- (b) some of the normal versions are hyper-optimised, which fools
+ (b) it allows us to do copy tracking
+ (c) some of the normal versions are hyper-optimised, which fools
Memcheck and cause spurious value warnings. Our versions are
simpler.
- (c) the glibc SSE-variants can read past the end of the input data
+ (d) the glibc SSE-variants can read past the end of the input data
ranges. This can cause false-positive Memcheck / Helgrind / DRD
reports.
#ifndef RECORD_OVERLAP_ERROR
#define RECORD_OVERLAP_ERROR(s, src, dst, len) do { } while (0)
#endif
+
+// Used for tools that record bulk copies: memcpy, strcpy, etc.
+#ifndef RECORD_COPY
+#define RECORD_COPY(len) do { } while (0)
+#define FOR_COPY(x)
+#else
+#define FOR_COPY(x) x
+#endif
+
#ifndef VALGRIND_CHECK_VALUE_IS_DEFINED
#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) 1
#endif
while (*src) *dst++ = *src++; \
*dst = 0; \
\
- /* This checks for overlap after copying, unavoidable without */ \
+ /* This happens after copying, unavoidable without */ \
/* pre-counting length... should be ok */ \
+ SizeT srclen = (Addr)src-(Addr)src_orig+1; \
+ RECORD_COPY(srclen); \
if (is_overlap(dst_orig, \
src_orig, \
(Addr)dst-(Addr)dst_orig+1, \
- (Addr)src-(Addr)src_orig+1)) \
+ srclen)) \
RECORD_OVERLAP_ERROR("strcpy", dst_orig, src_orig, 0); \
\
return dst_orig; \
while (m < n && *src) { m++; *dst++ = *src++; } \
/* Check for overlap after copying; all n bytes of dst are relevant, */ \
/* but only m+1 bytes of src if terminator was found */ \
- if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
+ SizeT srclen = (m < n) ? m+1 : n; \
+ RECORD_COPY(srclen); \
+ if (is_overlap(dst_orig, src_orig, n, srclen)) \
RECORD_OVERLAP_ERROR("strncpy", dst, src, n); \
while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
\
/* m non-nul bytes have now been copied, and m <= n-1. */ \
/* Check for overlap after copying; all n bytes of dst are relevant, */ \
/* but only m+1 bytes of src if terminator was found */ \
- if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
+ SizeT srclen = (m < n) ? m+1 : n; \
+ RECORD_COPY(srclen); \
+ if (is_overlap(dst_orig, src_orig, n, srclen)) \
RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
/* Nul-terminate dst. */ \
if (n > 0) *dst = 0; \
void* VG_REPLACE_FUNCTION_EZZ(becTag,soname,fnname) \
( void *dst, const void *src, SizeT len ) \
{ \
+ RECORD_COPY(len); \
if (do_ol_check && is_overlap(dst, src, len, len)) \
RECORD_OVERLAP_ERROR("memcpy", dst, src, len); \
\
MEMCPY(VG_Z_LIBC_SONAME, memcpy) /* fallback case */
MEMCPY(VG_Z_LIBC_SONAME, __GI_memcpy)
MEMCPY(VG_Z_LIBC_SONAME, __memcpy_sse2)
+ MEMCPY(VG_Z_LIBC_SONAME, __memcpy_avx_unaligned_erms)
MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
/* icc9 blats these around all over the place. Not only in the main
\
/* This checks for overlap after copying, unavoidable without */ \
/* pre-counting length... should be ok */ \
+ SizeT srclen = (Addr)src-(Addr)src_orig+1; \
+ RECORD_COPY(srclen); \
if (is_overlap(dst_orig, \
src_orig, \
(Addr)dst-(Addr)dst_orig+1, \
- (Addr)src-(Addr)src_orig+1)) \
+ srclen)) \
RECORD_OVERLAP_ERROR("stpcpy", dst_orig, src_orig, 0); \
\
return dst; \
while (m < n && *src) { m++; *dst++ = *src++; } \
/* Check for overlap after copying; all n bytes of dst are relevant, */ \
/* but only m+1 bytes of src if terminator was found */ \
- if (is_overlap(dst_str, src_orig, n, (m < n) ? m+1 : n)) \
+ SizeT srclen = (m < n) ? m+1 : n; \
+ RECORD_COPY(srclen); \
+ if (is_overlap(dst_str, src_orig, n, srclen)) \
RECORD_OVERLAP_ERROR("stpncpy", dst, src, n); \
dst_str = dst; \
while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
/*---------------------- memset ----------------------*/
-/* Why are we bothering to intercept this? It seems entirely
- pointless. */
-
#define MEMSET(soname, fnname) \
void* VG_REPLACE_FUNCTION_EZZ(20210,soname,fnname) \
(void *s, Int c, SizeT n); \
void VG_REPLACE_FUNCTION_EZU(20230,soname,fnname) \
(const void *srcV, void *dstV, SizeT n) \
{ \
+ RECORD_COPY(n); \
SizeT i; \
HChar* dst = dstV; \
const HChar* src = srcV; \
void* VG_REPLACE_FUNCTION_EZU(20240,soname,fnname) \
(void *dstV, const void *srcV, SizeT n, SizeT destlen) \
{ \
+ RECORD_COPY(n); \
SizeT i; \
HChar* dst = dstV; \
const HChar* src = srcV; \
char* VG_REPLACE_FUNCTION_EZU(20270,soname,fnname) \
(char* dst, const char* src, SizeT len) \
{ \
+ FOR_COPY(const HChar* src_orig = src); \
HChar* ret = dst; \
if (! len) \
goto badness; \
while ((*dst++ = *src++) != '\0') \
if (--len == 0) \
goto badness; \
+ RECORD_COPY((Addr)src-(Addr)src_orig); \
return ret; \
badness: \
VALGRIND_PRINTF_BACKTRACE( \
char* VG_REPLACE_FUNCTION_EZU(20280,soname,fnname) \
(char* dst, const char* src, SizeT len) \
{ \
+ FOR_COPY(const HChar* src_orig = src); \
if (! len) \
goto badness; \
while ((*dst++ = *src++) != '\0') \
if (--len == 0) \
goto badness; \
+ RECORD_COPY((Addr)src-(Addr)src_orig); \
return dst - 1; \
badness: \
VALGRIND_PRINTF_BACKTRACE( \
void* VG_REPLACE_FUNCTION_EZU(20290,soname,fnname) \
( void *dst, const void *src, SizeT len ) \
{ \
+ RECORD_COPY(len); \
SizeT len_saved = len; \
\
if (len == 0) \
{ \
register HChar *d; \
register const HChar *s; \
- \
- if (dstlen < len) goto badness; \
- \
+ if (dstlen < len) \
+ goto badness; \
+ RECORD_COPY(len); \
if (len == 0) \
return dst; \
- \
if (is_overlap(dst, src, len, len)) \
RECORD_OVERLAP_ERROR("memcpy_chk", dst, src, len); \
- \
if ( dst > src ) { \
d = (HChar *)dst + len - 1; \
s = (const HChar *)src + len - 1; \
\
/* This checks for overlap after copying, unavoidable without */ \
/* pre-counting length... should be ok */ \
+ /* +4 because sizeof(wchar_t) == 4 */ \
+ SizeT srclen = (Addr)src-(Addr)src_orig+4; \
+ RECORD_COPY(srclen); \
if (is_overlap(dst_orig, \
src_orig, \
/* +4 because sizeof(wchar_t) == 4 */ \
(Addr)dst-(Addr)dst_orig+4, \
- (Addr)src-(Addr)src_orig+4)) \
+ srclen)) \
RECORD_OVERLAP_ERROR("wcscpy", dst_orig, src_orig, 0); \
\
return dst_orig; \