Merged the MASSIF2 branch to the trunk. Main changes:
- ms_main.c: completely overhauled.
- massif/tests/*: lots of them now.
- massif/perf/: added.
- massif/hp2ps: removed. No longer used.
- vg_regtest: renamed the previously unused "posttest" notion to "post".
Using it for checking ms_print's output.
Although the code has changed dramatically, as has the form of the tool's
output, the information presented in the output is basically the same,
although it's now (hopefully) much more useful. So the tool name is
unchanged.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7069 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/configure.in b/configure.in
index f82dfb5..2f54fd7 100644
--- a/configure.in
+++ b/configure.in
@@ -982,6 +982,7 @@
massif/Makefile
massif/hp2ps/Makefile
massif/tests/Makefile
+ massif/perf/Makefile
massif/docs/Makefile
lackey/Makefile
lackey/tests/Makefile
diff --git a/massif/Makefile.am b/massif/Makefile.am
index b237178..f1940ff 100644
--- a/massif/Makefile.am
+++ b/massif/Makefile.am
@@ -1,6 +1,6 @@
include $(top_srcdir)/Makefile.tool.am
-SUBDIRS += hp2ps
+SUBDIRS += perf
noinst_PROGRAMS =
if VGP_X86_LINUX
diff --git a/massif/docs/ms-manual.xml b/massif/docs/ms-manual.xml
index 4bbae50..49dbda6 100644
--- a/massif/docs/ms-manual.xml
+++ b/massif/docs/ms-manual.xml
@@ -6,6 +6,25 @@
<chapter id="ms-manual" xreflabel="Massif: a heap profiler">
<title>Massif: a heap profiler</title>
+</pre>
+ Docs:
+ - Mention that complex functions names are best protected with single
+ quotes, eg:
+ --alloc-fn='operator new(unsigned, std::nothrow_t const&)'
+ [XXX: that doesn't work if the option is in a .valgrindrc file or in
+ $VALGRIND_OPTS. In m_commandline.c:add_args_from_string() need to
+ respect single quotes...]
+ - Explain the --threshold=0 case -- entries with zero bytes must have
+ allocated some memory and then freed it all again.
+ - Explain that no peak will be taken if no deallocations are done.
+ - Explain how the stack is computed -- size is assumed to be zero when
+ code starts executing, which isn't true, but reflects what you have
+ control over in a normal program.
+ - file format -- not specified, because it may change in the future to
+ become more generic
+</pre>
+
+
<para>To use this tool, you must specify
<computeroutput>--tool=massif</computeroutput> on the Valgrind
command line.</para>
diff --git a/massif/hp2ps/AreaBelow.c b/massif/hp2ps/AreaBelow.c
deleted file mode 100644
index e14ed5e..0000000
--- a/massif/hp2ps/AreaBelow.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Error.h"
-#include "HpFile.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "AreaBelow.h"
-
-/*
- * Return the area enclosed by all of the curves. The algorithm
- * used is the same as the trapizoidal rule for integration.
- */
-
-floatish
-AreaBelow()
-{
- intish i;
- intish j;
- intish bucket;
- floatish value;
- struct chunk *ch;
- floatish area;
- floatish trap;
- floatish base;
- floatish *maxima;
-
- maxima = (floatish *) xmalloc(nsamples * sizeof(floatish));
- for (i = 0; i < nsamples; i++) {
- maxima[i] = 0.0;
- }
-
- for (i = 0; i < nidents; i++) {
- for (ch = identtable[i]->chk; ch; ch = ch->next) {
- for (j = 0; j < ch->nd; j++) {
- bucket = ch->d[j].bucket;
- value = ch->d[j].value;
- if (bucket >= nsamples)
- Disaster("bucket out of range");
- maxima[ bucket ] += value;
- }
- }
- }
-
- area = 0.0;
-
- for (i = 1; i < nsamples; i++) {
- base = samplemap[i] - samplemap[i-1];
- if (maxima[i] > maxima[i-1]) {
- trap = base * maxima[i-1] + ((base * (maxima[i] - maxima[i-1]))/ 2.0);
- } else {
- trap = base * maxima[i] + ((base * (maxima[i-1] - maxima[i]))/ 2.0);
- }
-
- area += trap;
- }
-
- free(maxima);
- return area;
-}
diff --git a/massif/hp2ps/AreaBelow.h b/massif/hp2ps/AreaBelow.h
deleted file mode 100644
index a4c20d9..0000000
--- a/massif/hp2ps/AreaBelow.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef AREA_BELOW_H
-#define AREA_BELOW_H
-
-floatish AreaBelow PROTO((void));
-
-#endif /* AREA_BELOW_H */
diff --git a/massif/hp2ps/AuxFile.c b/massif/hp2ps/AuxFile.c
deleted file mode 100644
index dfc26cd..0000000
--- a/massif/hp2ps/AuxFile.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Shade.h"
-#include "Error.h"
-#include "HpFile.h"
-#include "Reorder.h"
-
-/* own stuff */
-#include "AuxFile.h"
-
-static void GetAuxLine PROTO((FILE *)); /* forward */
-static void GetAuxTok PROTO((FILE *)); /* forward */
-
-void
-GetAuxFile(auxfp)
- FILE* auxfp;
-{
- g_ch = ' ';
- endfile = 0;
- linenum = 1;
-
- GetAuxTok(auxfp);
-
- while (endfile == 0) {
- GetAuxLine(auxfp);
- }
-
- fclose(auxfp);
-}
-
-
-
-/*
- * Read the next line from the aux file, check the syntax, and
- * perform the appropriate action.
- */
-
-static void
-GetAuxLine(auxfp)
- FILE* auxfp;
-{
- switch (thetok) {
- case X_RANGE_TOK:
- GetAuxTok(auxfp);
- if (thetok != FLOAT_TOK) {
- Error("%s, line %d, floating point number must follow X_RANGE",
- auxfile, linenum);
- }
- auxxrange = thefloatish;
- GetAuxTok(auxfp);
- break;
- case Y_RANGE_TOK:
- GetAuxTok(auxfp);
- if (thetok != FLOAT_TOK) {
- Error("%s, line %d, floating point number must follow Y_RANGE",
- auxfile, linenum);
- }
- auxyrange = thefloatish;
- GetAuxTok(auxfp);
- break;
- case ORDER_TOK:
- GetAuxTok(auxfp);
- if (thetok != IDENTIFIER_TOK) {
- Error("%s, line %d: identifier must follow ORDER",
- auxfile, linenum);
- }
- GetAuxTok(auxfp);
- if (thetok != INTEGER_TOK) {
- Error("%s, line %d: identifier and integer must follow ORDER",
- auxfile, linenum);
- }
- OrderFor(theident, theinteger);
- GetAuxTok(auxfp);
- break;
- case SHADE_TOK:
- GetAuxTok(auxfp);
- if (thetok != IDENTIFIER_TOK) {
- Error("%s, line %d: identifier must follow SHADE",
- auxfile, linenum);
- }
- GetAuxTok(auxfp);
- if (thetok != FLOAT_TOK) {
- Error("%s, line %d: identifier and floating point number must follow SHADE",
- auxfile, linenum);
- }
- ShadeFor(theident, thefloatish);
- GetAuxTok(auxfp);
- break;
- case EOF_TOK:
- endfile = 1;
- break;
- default:
- Error("%s, line %d: %s unexpected", auxfile, linenum,
- TokenToString(thetok));
- break;
- }
-}
-
-
-
-/*
- * Read the next token from the input and assign its value
- * to the global variable "thetok". In the case of numbers,
- * the corresponding value is also assigned to "thefloatish";
- * in the case of identifiers it is assigned to "theident".
- */
-
-static void GetAuxTok(auxfp)
-FILE* auxfp;
-{
-
- while (isspace(g_ch)) { /* skip whitespace */
- if (g_ch == '\n') linenum++;
- g_ch = getc(auxfp);
- }
-
- if (g_ch == EOF) {
- thetok = EOF_TOK;
- return;
- }
-
- if (isdigit(g_ch)) {
- thetok = GetNumber(auxfp);
- return;
- } else if (IsIdChar(g_ch)) { /* g_ch can't be a digit here */
- GetIdent(auxfp);
- if (!isupper(theident[0])) {
- thetok = IDENTIFIER_TOK;
- } else if (strcmp(theident, "X_RANGE") == 0) {
- thetok = X_RANGE_TOK;
- } else if (strcmp(theident, "Y_RANGE") == 0) {
- thetok = Y_RANGE_TOK;
- } else if (strcmp(theident, "ORDER") == 0) {
- thetok = ORDER_TOK;
- } else if (strcmp(theident, "SHADE") == 0) {
- thetok = SHADE_TOK;
- } else {
- thetok = IDENTIFIER_TOK;
- }
- return;
- } else {
- Error("%s, line %d: strange character (%c)", auxfile, linenum, g_ch);
- }
-}
-
-void
-PutAuxFile(auxfp)
- FILE* auxfp;
-{
- int i;
-
- fprintf(auxfp, "X_RANGE %.2f\n", xrange);
- fprintf(auxfp, "Y_RANGE %.2f\n", yrange);
-
- for (i = 0; i < nidents; i++) {
- fprintf(auxfp, "ORDER %s %d\n", identtable[i]->name, i+1);
- }
-
- for (i = 0; i < nidents; i++) {
- fprintf(auxfp, "SHADE %s %.2f\n", identtable[i]->name,
- ShadeOf(identtable[i]->name));
- }
-
- fclose(auxfp);
-}
diff --git a/massif/hp2ps/AuxFile.h b/massif/hp2ps/AuxFile.h
deleted file mode 100644
index be3fe11..0000000
--- a/massif/hp2ps/AuxFile.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef AUX_FILE_H
-#define AUX_FILE_H
-
-void PutAuxFile PROTO((FILE *));
-void GetAuxFile PROTO((FILE *));
-
-#endif /* AUX_FILE_H */
diff --git a/massif/hp2ps/Axes.c b/massif/hp2ps/Axes.c
deleted file mode 100644
index b803610..0000000
--- a/massif/hp2ps/Axes.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <string.h>
-#include "Main.h"
-#include "Curves.h"
-#include "Defines.h"
-#include "Dimensions.h"
-#include "HpFile.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "Axes.h"
-
-typedef enum {MEGABYTE, KILOBYTE, BYTE} mkb;
-
-static void XAxis PROTO((void)); /* forward */
-static void YAxis PROTO((void)); /* forward */
-
-static void XAxisMark PROTO((floatish, floatish)); /* forward */
-static void YAxisMark PROTO((floatish, floatish, mkb)); /* forward */
-
-static floatish Round PROTO((floatish)); /* forward */
-
-void
-Axes()
-{
- XAxis();
- YAxis();
-}
-
-static void
-XAxisMark(x, num)
- floatish x; floatish num;
-{
- /* calibration mark */
- fprintf(psfp, "%f %f moveto\n", xpage(x), ypage(0.0));
- fprintf(psfp, "0 -4 rlineto\n");
- fprintf(psfp, "stroke\n");
-
- /* number */
- fprintf(psfp, "HE%d setfont\n", NORMAL_FONT);
- fprintf(psfp, "(%.1f)\n", num);
- fprintf(psfp, "dup stringwidth pop\n");
- fprintf(psfp, "2 div\n");
- fprintf(psfp, "%f exch sub\n", xpage(x));
- fprintf(psfp, "%f moveto\n", borderspace);
- fprintf(psfp, "show\n");
-}
-
-
-#define N_X_MARKS 7
-#define XFUDGE 15
-
-extern floatish xrange;
-extern char *sampleunitstring;
-
-static void
-XAxis()
-{
- floatish increment, i;
- floatish t, x;
- floatish legendlen;
-
- /* draw the x axis line */
- fprintf(psfp, "%f %f moveto\n", xpage(0.0), ypage(0.0));
- fprintf(psfp, "%f 0 rlineto\n", graphwidth);
- fprintf(psfp, "%f setlinewidth\n", borderthick);
- fprintf(psfp, "stroke\n");
-
- /* draw x axis legend */
- fprintf(psfp, "HE%d setfont\n", NORMAL_FONT);
- fprintf(psfp, "(%s)\n", sampleunitstring);
- fprintf(psfp, "dup stringwidth pop\n");
- fprintf(psfp, "%f\n", xpage(0.0) + graphwidth);
- fprintf(psfp, "exch sub\n");
- fprintf(psfp, "%f moveto\n", borderspace);
- fprintf(psfp, "show\n");
-
-
- /* draw x axis scaling */
-
- increment = Round(xrange / (floatish) N_X_MARKS);
-
- t = graphwidth / xrange;
- legendlen = StringSize(sampleunitstring) + (floatish) XFUDGE;
-
- for (i = samplemap[0]; i < samplemap[nsamples - 1]; i += increment) {
- x = (i - samplemap[0]) * t;
-
- if (x < (graphwidth - legendlen)) {
- XAxisMark(x,i);
- }
- }
-}
-
-static void
-YAxisMark(y, num, unit)
- floatish y; floatish num; mkb unit;
-{
- /* calibration mark */
- fprintf(psfp, "%f %f moveto\n", xpage(0.0), ypage(y));
- fprintf(psfp, "-4 0 rlineto\n");
- fprintf(psfp, "stroke\n");
-
- /* number */
- fprintf(psfp, "HE%d setfont\n", NORMAL_FONT);
-
- switch (unit) {
- case MEGABYTE :
- fprintf(psfp, "(");
- CommaPrint(psfp, (intish) (num / 1e6 + 0.5));
- fprintf(psfp, "M)\n");
- break;
- case KILOBYTE :
- fprintf(psfp, "(");
- CommaPrint(psfp, (intish) (num / 1e3 + 0.5));
- fprintf(psfp, "k)\n");
- break;
- case BYTE:
- fprintf(psfp, "(");
- CommaPrint(psfp, (intish) (num + 0.5));
- fprintf(psfp, ")\n");
- break;
- }
-
- fprintf(psfp, "dup stringwidth\n");
- fprintf(psfp, "2 div\n");
- fprintf(psfp, "%f exch sub\n", ypage(y));
-
- fprintf(psfp, "exch\n");
- fprintf(psfp, "%f exch sub\n", graphx0 - borderspace);
-
- fprintf(psfp, "exch\n");
- fprintf(psfp, "moveto\n");
- fprintf(psfp, "show\n");
-}
-
-#define N_Y_MARKS 7
-#define YFUDGE 15
-
-extern floatish yrange;
-extern char *valueunitstring;
-
-static void
-YAxis()
-{
- floatish increment, i;
- floatish t, y;
- floatish legendlen;
- mkb unit;
-
- /* draw the y axis line */
- fprintf(psfp, "%f %f moveto\n", xpage(0.0), ypage(0.0));
- fprintf(psfp, "0 %f rlineto\n", graphheight);
- fprintf(psfp, "%f setlinewidth\n", borderthick);
- fprintf(psfp, "stroke\n");
-
- /* draw y axis legend */
- fprintf(psfp, "gsave\n");
- fprintf(psfp, "HE%d setfont\n", NORMAL_FONT);
- fprintf(psfp, "(%s)\n", valueunitstring);
- fprintf(psfp, "dup stringwidth pop\n");
- fprintf(psfp, "%f\n", ypage(0.0) + graphheight);
- fprintf(psfp, "exch sub\n");
- fprintf(psfp, "%f exch\n", xpage(0.0) - borderspace);
- fprintf(psfp, "translate\n");
- fprintf(psfp, "90 rotate\n");
- fprintf(psfp, "0 0 moveto\n");
- fprintf(psfp, "show\n");
- fprintf(psfp, "grestore\n");
-
- /* draw y axis scaling */
- increment = max( yrange / (floatish) N_Y_MARKS, 1.0);
- increment = Round(increment);
-
- if (increment >= 1e6) {
- unit = MEGABYTE;
- } else if (increment >= 1e3) {
- unit = KILOBYTE;
- } else {
- unit = BYTE;
- }
-
- t = graphheight / yrange;
- legendlen = StringSize(valueunitstring) + (floatish) YFUDGE;
-
- for (i = 0.0; i <= yrange; i += increment) {
- y = i * t;
-
- if (y < (graphheight - legendlen)) {
- YAxisMark(y, i, unit);
- }
- }
-}
-
-
-/*
- * Find a "nice round" value to use on the axis.
- */
-
-static floatish OneTwoFive PROTO((floatish)); /* forward */
-
-static floatish
-Round(y)
- floatish y;
-{
- int i;
-
- if (y > 10.0) {
- for (i = 0; y > 10.0; y /= 10.0, i++) ;
- y = OneTwoFive(y);
- for ( ; i > 0; y = y * 10.0, i--) ;
-
- } else if (y < 1.0) {
- for (i = 0; y < 1.0; y *= 10.0, i++) ;
- y = OneTwoFive(y);
- for ( ; i > 0; y = y / 10.0, i--) ;
-
- } else {
- y = OneTwoFive(y);
- }
-
- return (y);
-}
-
-
-/*
- * OneTwoFive() -- Runciman's 1,2,5 scaling rule. Argument 1.0 <= y <= 10.0.
- */
-
-static floatish
-OneTwoFive(y)
- floatish y;
-{
- if (y > 4.0) {
- return (5.0);
- } else if (y > 1.0) {
- return (2.0);
- } else {
- return (1.0);
- }
-}
diff --git a/massif/hp2ps/Axes.h b/massif/hp2ps/Axes.h
deleted file mode 100644
index f9f252f..0000000
--- a/massif/hp2ps/Axes.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef AXES_H
-#define AXES_H
-
-void Axes PROTO((void));
-
-#endif /* AXES_H */
diff --git a/massif/hp2ps/CHANGES b/massif/hp2ps/CHANGES
deleted file mode 100644
index 60933d6..0000000
--- a/massif/hp2ps/CHANGES
+++ /dev/null
@@ -1,39 +0,0 @@
-1.
-
-When generating PostScript to show strings, '(' and ')' may need to be escaped.
-These characters are now escaped when the JOB string is shown.
-
-2.
-
-Manually deleting samples from a .hp file now does what you would expect.
-
-3.
-
-The -t flag for setting the threshold percentage has been scrapped. No one
-ever used it.
-
-4.
-
-Long JOB strings cause hp2ps to use a big title box. Big and small boxes
-can be forced with -b and -s flag.
-
-5.
-
-MARKS now print as small triangles which remain below the x axis.
-
-6.
-
-There is an updated manual page.
-
-7.
-
--m flag for setting maximum no of bands (default 20, cant be more than 20).
--t flag for setting threshold (between 0% and 5%, default 1%).
-
-8.
-
-Axes scaling rounding errors removed.
-
-9.
-
-Fixed bug whereby x-axis was assumed to start at zero when placing MARKs.
diff --git a/massif/hp2ps/Curves.c b/massif/hp2ps/Curves.c
deleted file mode 100644
index 5176ecf..0000000
--- a/massif/hp2ps/Curves.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <math.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Dimensions.h"
-#include "HpFile.h"
-#include "Shade.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "Curves.h"
-
-static floatish *g_x; /* x and y values */
-static floatish *g_y;
-
-static floatish *g_py; /* previous y values */
-
-static void Curve PROTO((struct entry *)); /* forward */
-static void ShadeCurve
- PROTO((floatish *x, floatish *y, floatish *py, floatish shade));
-
-void
-Curves()
-{
- intish i;
-
- for (i = 0; i < nidents; i++) {
- Curve(identtable[i]);
- }
-}
-
-/*
- * Draw a curve, and fill the area that is below it and above
- * the previous curve.
- */
-
-static void
-Curve(e)
- struct entry* e;
-{
- struct chunk* ch;
- int j;
-
- for (ch = e->chk; ch; ch = ch->next) {
- for (j = 0; j < ch->nd; j++) {
- g_y[ ch->d[j].bucket ] += ch->d[j].value;
- }
- }
-
- ShadeCurve(g_x, g_y, g_py, ShadeOf(e->name));
-}
-
-
-static void PlotCurveLeftToRight PROTO((floatish *, floatish *)); /* forward */
-static void PlotCurveRightToLeft PROTO((floatish *, floatish *)); /* forward */
-
-static void SaveCurve PROTO((floatish *, floatish *)); /* forward */
-
-/*
- * Map virtual x coord to physical x coord
- */
-
-floatish
-xpage(x)
- floatish x;
-{
- return (x + graphx0);
-}
-
-
-
-/*
- * Map virtual y coord to physical y coord
- */
-
-floatish
-ypage(y)
- floatish y;
-{
- return (y + graphy0);
-}
-
-
-/*
- * Fill the region bounded by two splines, using the given
- * shade.
- */
-
-static void
-ShadeCurve(x, y, py, shade)
- floatish *x; floatish *y; floatish *py; floatish shade;
-{
- fprintf(psfp, "%f %f moveto\n", xpage(x[0]), ypage(py[0]));
- PlotCurveLeftToRight(x, py);
-
- fprintf(psfp, "%f %f lineto\n", xpage(x[nsamples - 1]),
- ypage(y[nsamples - 1]));
- PlotCurveRightToLeft(x, y);
-
- fprintf(psfp, "closepath\n");
-
- fprintf(psfp, "gsave\n");
-
- SetPSColour(shade);
- fprintf(psfp, "fill\n");
-
- fprintf(psfp, "grestore\n");
- fprintf(psfp, "stroke\n");
-
- SaveCurve(y, py);
-}
-
-static void
-PlotCurveLeftToRight(x,y)
- floatish *x; floatish *y;
-{
- intish i;
-
- for (i = 0; i < nsamples; i++) {
- fprintf(psfp, "%f %f lineto\n", xpage(x[i]), ypage(y[i]));
- }
-}
-
-static void
-PlotCurveRightToLeft(x,y)
- floatish *x; floatish *y;
-{
- intish i;
-
- for (i = nsamples - 1; i >= 0; i-- ) {
- fprintf(psfp, "%f %f lineto\n", xpage(x[i]), ypage(y[i]));
- }
-}
-
-/*
- * Save the curve coordinates stored in y[] in py[].
- */
-
-static void
-SaveCurve(y, py)
- floatish *y; floatish* py;
-{
- intish i;
-
- for (i = 0; i < nsamples; i++) {
- py[i] = y[i];
- }
-}
-
-extern floatish xrange;
-
-void
-CurvesInit()
-{
- intish i;
-
- g_x = (floatish*) xmalloc(nsamples * sizeof(floatish));
- g_y = (floatish*) xmalloc(nsamples * sizeof(floatish));
- g_py = (floatish*) xmalloc(nsamples * sizeof(floatish));
-
- for (i = 0; i < nsamples; i++) {
- g_x[i] = ((samplemap[i] - samplemap[0])/ xrange) * graphwidth;
- g_y[i] = g_py[i] = 0.0;
- }
-}
diff --git a/massif/hp2ps/Curves.h b/massif/hp2ps/Curves.h
deleted file mode 100644
index 7ca720e..0000000
--- a/massif/hp2ps/Curves.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef CURVES_H
-#define CURVES_H
-
-void Curves PROTO((void));
-void CurvesInit PROTO((void));
-
-floatish xpage PROTO((floatish));
-floatish ypage PROTO((floatish));
-
-#endif /* CURVES_H */
diff --git a/massif/hp2ps/Defines.h b/massif/hp2ps/Defines.h
deleted file mode 100644
index 4973555..0000000
--- a/massif/hp2ps/Defines.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef DEFINES_H
-#define DEFINES_H
-
-/*
- * Things that can be altered.
- */
-
-#define THRESHOLD_PERCENT _thresh_ /* all values below 1% insignificant */
-#define DEFAULT_THRESHOLD 1.0
-extern floatish _thresh_;
-
-#define TWENTY _twenty_ /* show top 20 bands, grouping excess */
-#define DEFAULT_TWENTY 20 /* this is default and absolute maximum */
-extern int _twenty_;
-
-#define LARGE_FONT 12 /* Helvetica 12pt */
-#define NORMAL_FONT 10 /* Helvetica 10pt */
-
-#define BORDER_HEIGHT 432.0 /* page border box 432pt (6 inches high) */
-#define BORDER_WIDTH 648.0 /* page border box 648pt (9 inches wide) */
-#define BORDER_SPACE 5.0 /* page border space */
-#define BORDER_THICK 0.5 /* page border line thickness 0.5pt */
-
-
-#define TITLE_HEIGHT 20.0 /* title box is 20pt high */
-#define TITLE_TEXT_FONT LARGE_FONT /* title in large font */
-#define TITLE_TEXT_SPACE 6.0 /* space between title text and box */
-
-
-#define AXIS_THICK 0.5 /* axis thickness 0.5pt */
-#define AXIS_TEXT_SPACE 6 /* space between axis legends and axis */
-#define AXIS_TEXT_FONT NORMAL_FONT /* axis legends in normal font */
-#define AXIS_Y_TEXT_SPACE 35 /* space for y axis text */
-
-#define KEY_BOX_WIDTH 14 /* key boxes are 14pt high */
-
-#define SMALL_JOB_STRING_WIDTH 35 /* small title for 35 characters or less */
-#define BIG_JOB_STRING_WIDTH 80 /* big title for everything else */
-
-#define GRAPH_X0 (AXIS_Y_TEXT_SPACE + (2 * BORDER_SPACE))
-#define GRAPH_Y0 (AXIS_TEXT_FONT + (2 * BORDER_SPACE))
-
-
-/*
- * Things that should be left well alone.
- */
-
-
-
-#define START_X 72 /* start 72pt (1 inch) from left (portrait) */
-#define START_Y 108 /* start 108pt (1.5 inch) from bottom (portrait) */
-
-#define NUMBER_LENGTH 32
-
-#define N_CHUNK 24
-
-#define VERSION "0.25" /* as of 95/03/21 */
-
-#define max(x,y) ((x) > (y) ? (x) : (y)) /* not everyone has this */
-
-#endif /* DEFINES_H */
diff --git a/massif/hp2ps/Deviation.c b/massif/hp2ps/Deviation.c
deleted file mode 100644
index 22a0e9e..0000000
--- a/massif/hp2ps/Deviation.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Error.h"
-#include "HpFile.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "Deviation.h"
-
-/*
- * Reorder the identifiers in the identifier table so that the
- * ones whose data points exhibit the mininal standard deviation
- * come first.
- */
-
-void
-Deviation()
-{
- intish i;
- intish j;
- floatish dev;
- struct chunk* ch;
- int min;
- floatish t;
- struct entry* e;
- floatish *averages;
- floatish *deviations;
-
- averages = (floatish*) xmalloc(nidents * sizeof(floatish));
- deviations = (floatish*) xmalloc(nidents * sizeof(floatish));
-
- /* find averages */
-
- for (i = 0; i < nidents; i++) {
- averages[i] = 0.0;
- }
-
- for (i = 0; i < nidents; i++) {
- for (ch = identtable[i]->chk; ch; ch = ch->next) {
- for (j = 0; j < ch->nd; j++) {
- averages[i] += ch->d[j].value;
- }
- }
- }
-
- for (i = 0; i < nidents; i++) {
- averages[i] /= (floatish) nsamples;
- }
-
- /* calculate standard deviation */
-
- for (i = 0; i < nidents; i++) {
- deviations[i] = 0.0;
- }
-
- for (i = 0; i < nidents; i++) {
- for (ch = identtable[i]->chk; ch; ch = ch->next) {
- for (j = 0; j < ch->nd; j++) {
- dev = ch->d[j].value - averages[i];
- deviations[i] += dev * dev;
- }
- }
- }
-
- for (i = 0; i < nidents; i++) {
- deviations[i] = (floatish) sqrt ((doublish) (deviations[i] /
- (floatish) (nsamples - 1)));
- }
-
-
- /* sort on basis of standard deviation */
-
- for (i = 0; i < nidents-1; i++) {
- min = i;
- for (j = i+1; j < nidents; j++) {
- if (deviations[ j ] < deviations[min]) {
- min = j;
- }
- }
-
- t = deviations[min];
- deviations[min] = deviations[i];
- deviations[i] = t;
-
- e = identtable[min];
- identtable[min] = identtable[i];
- identtable[i] = e;
- }
-
- free(averages);
- free(deviations);
-}
-
-void
-Identorder(iflag)
- int iflag; /* a funny three-way flag ? WDP 95/03 */
-{
- int i;
- int j;
- int min;
- struct entry* e;
-
- /* sort on basis of ident string */
- if (iflag > 0) {
- /* greatest at top i.e. smallest at start */
-
- for (i = 0; i < nidents-1; i++) {
- min = i;
- for (j = i+1; j < nidents; j++) {
- if (strcmp(identtable[j]->name, identtable[min]->name) < 0) {
- min = j;
- }
- }
-
- e = identtable[min];
- identtable[min] = identtable[i];
- identtable[i] = e;
- }
- } else {
- /* smallest at top i.e. greatest at start */
-
- for (i = 0; i < nidents-1; i++) {
- min = i;
- for (j = i+1; j < nidents; j++) {
- if (strcmp(identtable[j]->name, identtable[min]->name) > 0) {
- min = j;
- }
- }
-
- e = identtable[min];
- identtable[min] = identtable[i];
- identtable[i] = e;
- }
- }
-}
diff --git a/massif/hp2ps/Deviation.h b/massif/hp2ps/Deviation.h
deleted file mode 100644
index 1fe50ad..0000000
--- a/massif/hp2ps/Deviation.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef DEVIATION_H
-#define DEVIATION_H
-
-void Deviation PROTO((void));
-void Identorder PROTO((int));
-
-#endif /* DEVIATION_H */
diff --git a/massif/hp2ps/Dimensions.c b/massif/hp2ps/Dimensions.c
deleted file mode 100644
index e3ebe00..0000000
--- a/massif/hp2ps/Dimensions.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <ctype.h>
-#include <string.h>
-#include <stdio.h>
-#include "Main.h"
-#include "Defines.h"
-#include "HpFile.h"
-#include "Scale.h"
-
-/* own stuff */
-#include "Dimensions.h"
-
-/*
- * Get page and other dimensions before printing.
- */
-
-floatish borderheight = BORDER_HEIGHT;
-floatish borderwidth = BORDER_WIDTH;
-floatish borderspace = BORDER_SPACE;
-floatish borderthick = BORDER_THICK;
-
-floatish titlewidth = (BORDER_WIDTH - (2 * BORDER_SPACE));
-floatish titletextspace = TITLE_TEXT_SPACE;
-floatish titleheight;
-
-floatish graphx0 = GRAPH_X0;
-floatish graphy0 = GRAPH_Y0;
-
-floatish graphheight;
-floatish graphwidth;
-
-static floatish KeyWidth PROTO((void)); /* forward */
-
-void
-Dimensions()
-{
- xrange = samplemap[nsamples - 1] - samplemap[0];
- xrange = max(xrange, auxxrange);
- if (xrange == 0.0) xrange = 1.0; /* avoid division by 0.0 */
-
- yrange = MaxCombinedHeight();
- yrange = max(yrange, auxyrange);
- if (yrange == 0.0) yrange = 1.0; /* avoid division by 0.0 */
-
- if (!bflag && !sflag) {
- bflag = strlen(jobstring) > SMALL_JOB_STRING_WIDTH;
- }
-
- if (bflag) {
- titleheight = 2 * TITLE_HEIGHT;
- } else {
- titleheight = TITLE_HEIGHT;
- }
-
- graphwidth = titlewidth - graphx0 - (TWENTY ? KeyWidth() : 0);
- graphheight = borderheight - titleheight - (2 * borderspace) - graphy0;
-}
-
-/*
- * Calculate the width of the key.
- */
-
-static floatish
-KeyWidth()
-{
- intish i;
- floatish c;
-
- c = 0.0;
-
- for (i = 0; i < nidents; i++) {
- c = max(c, StringSize(identtable[i]->name));
- }
-
- c += 3.0 * borderspace;
-
- c += (floatish) KEY_BOX_WIDTH;
-
- return c;
-}
-
-
-/*
- * A desperately grim solution.
- */
-
-
-floatish fonttab[] = {
- /* 20 (' ') = */ 3.0,
- /* 21 ('!') = */ 1.0,
- /* 22 ('"') = */ 1.0,
- /* 23 ('#') = */ 3.0,
- /* 24 ('$') = */ 3.0,
- /* 25 ('%') = */ 3.0,
- /* 26 ('&') = */ 3.0,
- /* 27 (''') = */ 1.0,
- /* 28 ('(') = */ 3.0,
- /* 29 (')') = */ 3.0,
- /* 2a ('*') = */ 2.0,
- /* 2b ('+') = */ 3.0,
- /* 2c (',') = */ 1.0,
- /* 2d ('-') = */ 3.0,
- /* 2e ('.') = */ 1.0,
- /* 2f ('/') = */ 3.0,
- /* 30 ('0') = */ 4.0,
- /* 31 ('1') = */ 4.0,
- /* 32 ('2') = */ 4.0,
- /* 33 ('3') = */ 4.0,
- /* 34 ('4') = */ 4.0,
- /* 35 ('5') = */ 4.0,
- /* 36 ('6') = */ 4.0,
- /* 37 ('7') = */ 4.0,
- /* 38 ('8') = */ 4.0,
- /* 39 ('9') = */ 4.0,
- /* 3a (':') = */ 1.0,
- /* 3b (';') = */ 1.0,
- /* 3c ('<') = */ 3.0,
- /* 3d ('=') = */ 3.0,
- /* 3e ('>') = */ 3.0,
- /* 3f ('?') = */ 2.0,
- /* 40 ('@') = */ 3.0,
- /* 41 ('A') = */ 5.0,
- /* 42 ('B') = */ 5.0,
- /* 43 ('C') = */ 5.0,
- /* 44 ('D') = */ 5.0,
- /* 45 ('E') = */ 5.0,
- /* 46 ('F') = */ 5.0,
- /* 47 ('G') = */ 5.0,
- /* 48 ('H') = */ 5.0,
- /* 49 ('I') = */ 1.0,
- /* 4a ('J') = */ 5.0,
- /* 4b ('K') = */ 5.0,
- /* 4c ('L') = */ 5.0,
- /* 4d ('M') = */ 5.0,
- /* 4e ('N') = */ 5.0,
- /* 4f ('O') = */ 5.0,
- /* 50 ('P') = */ 5.0,
- /* 51 ('Q') = */ 5.0,
- /* 52 ('R') = */ 5.0,
- /* 53 ('S') = */ 5.0,
- /* 54 ('T') = */ 5.0,
- /* 55 ('U') = */ 5.0,
- /* 56 ('V') = */ 5.0,
- /* 57 ('W') = */ 5.0,
- /* 58 ('X') = */ 5.0,
- /* 59 ('Y') = */ 5.0,
- /* 5a ('Z') = */ 5.0,
- /* 5b ('[') = */ 2.0,
- /* 5c ('\') = */ 3.0,
- /* 5d (']') = */ 2.0,
- /* 5e ('^') = */ 1.0,
- /* 5f ('_') = */ 3.0,
- /* 60 ('`') = */ 1.0,
- /* 61 ('a') = */ 3.0,
- /* 62 ('b') = */ 3.0,
- /* 63 ('c') = */ 3.0,
- /* 64 ('d') = */ 3.0,
- /* 65 ('e') = */ 3.0,
- /* 66 ('f') = */ 3.0,
- /* 67 ('g') = */ 3.0,
- /* 68 ('h') = */ 3.0,
- /* 69 ('i') = */ 1.0,
- /* 6a ('j') = */ 2.0,
- /* 6b ('k') = */ 3.0,
- /* 6c ('l') = */ 1.0,
- /* 6d ('m') = */ 5.0,
- /* 6e ('n') = */ 3.0,
- /* 6f ('o') = */ 3.0,
- /* 70 ('p') = */ 3.0,
- /* 71 ('q') = */ 3.0,
- /* 72 ('r') = */ 2.0,
- /* 73 ('s') = */ 3.0,
- /* 74 ('t') = */ 2.0,
- /* 75 ('u') = */ 3.0,
- /* 76 ('v') = */ 3.0,
- /* 77 ('w') = */ 3.0,
- /* 78 ('x') = */ 3.0,
- /* 79 ('y') = */ 3.0,
- /* 7a ('z') = */ 3.0,
- /* 7b ('{') = */ 2.0,
- /* 7c ('|') = */ 1.0,
- /* 7d ('}') = */ 2.0,
- /* 7e ('~') = */ 2.0
-};
-
-
-/*
- * What size is a string (in points)?
- */
-
-#define FUDGE (2.834646 * 0.6)
-
-floatish
-StringSize(s)
- char* s;
-{
- floatish r;
-
- for (r = 0.0; *s; s++) {
- r += fonttab[(*s) - 0x20];
- }
-
- return r * FUDGE;
-}
diff --git a/massif/hp2ps/Dimensions.h b/massif/hp2ps/Dimensions.h
deleted file mode 100644
index 3ce5ab5..0000000
--- a/massif/hp2ps/Dimensions.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef DIMENSIONS_H
-#define DIMENSIONS_H
-
-extern floatish borderheight;
-extern floatish borderwidth;
-extern floatish borderspace;
-extern floatish borderthick;
-
-extern floatish titleheight;
-extern floatish titlewidth;
-extern floatish titletextspace;
-
-extern floatish graphx0;
-extern floatish graphy0;
-
-extern floatish graphheight;
-extern floatish graphwidth;
-
-void Dimensions PROTO((void));
-floatish StringSize PROTO((char *));
-
-#endif /* DIMENSIONS_H */
diff --git a/massif/hp2ps/Error.c b/massif/hp2ps/Error.c
deleted file mode 100644
index 2ecba3d..0000000
--- a/massif/hp2ps/Error.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "Main.h"
-#include "Defines.h"
-
-/* own stuff */
-#include "Error.h"
-
-/*VARARGS0*/
-void
-Error(const char *fmt, ...)
-{
- va_list ap;
- fflush(stdout);
- fprintf(stderr, "%s: ", programname);
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, "\n");
- exit(1);
-}
-
-/*VARARGS0*/
-void
-Disaster(const char *fmt, ...)
-{
- va_list ap;
- fflush(stdout);
- fprintf(stderr, "%s: ", programname);
- fprintf(stderr, " Disaster! (");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, ")\n");
- exit(1);
-}
-
-void
-Usage(str)
- const char *str;
-{
- if (str) printf("error: %s\n", str);
- printf("usage: %s -b -d -ef -g -i -p -mn -p -s -tf -y [file[.hp]]\n", programname);
- printf("where -b use large title box\n");
- printf(" -d sort by standard deviation\n");
- printf(" -ef[in|mm|pt] produce Encapsulated PostScript f units wide (f > 2 inches)\n");
- printf(" -g produce output suitable for GHOSTSCRIPT previever\n");
- printf(" -i[+|-] sort by identifier string (-i+ gives greatest on top) \n");
- printf(" -mn print maximum of n bands (default & max 20)\n");
- printf(" -m0 removes the band limit altogether\n");
- printf(" -p use previous scaling, shading and ordering\n");
- printf(" -s use small title box\n");
- printf(" -tf ignore trace bands which sum below f%% (default 1%%, max 5%%)\n");
- printf(" -y traditional\n");
- printf(" -c colour ouput\n");
- exit(0);
-}
-
diff --git a/massif/hp2ps/Error.h b/massif/hp2ps/Error.h
deleted file mode 100644
index d38518d..0000000
--- a/massif/hp2ps/Error.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef ERROR_H
-#define ERROR_H
-
-extern void Error PROTO((const char *, ...));
-extern void Disaster PROTO((const char *, ...));
-extern void Usage PROTO((const char *));
-
-#endif /* ERROR_H */
diff --git a/massif/hp2ps/HpFile.c b/massif/hp2ps/HpFile.c
deleted file mode 100644
index c19b6aa..0000000
--- a/massif/hp2ps/HpFile.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Error.h"
-#include "HpFile.h"
-#include "Utilities.h"
-
-#ifndef atof
-double atof PROTO((const char *));
-#endif
-
-/* own stuff already included */
-
-#define N_MARKS 50 /* start size of the mark table */
-#define N_SAMPLES 500 /* start size of the sample table */
-
-char *theident;
-char *thestring;
-int theinteger;
-floatish thefloatish;
-int g_ch; /* last character read */
-token thetok; /* last token */
-int linenum; /* current line number */
-int endfile; /* true at end of file */
-
-static boolish gotjob = 0; /* "JOB" read */
-static boolish gotdate = 0; /* "DATE" read */
-static boolish gotvalueunit = 0; /* "VALUE_UNIT" read */
-static boolish gotsampleunit = 0; /* "SAMPLE_UNIT" read */
-static boolish insample = 0; /* true when in sample */
-
-static floatish lastsample; /* the last sample time */
-
-static void GetHpLine PROTO((FILE *)); /* forward */
-static void GetHpTok PROTO((FILE *)); /* forward */
-
-static struct entry *GetEntry PROTO((char *)); /* forward */
-
-static void MakeIdentTable PROTO((void)); /* forward */
-
-char *jobstring;
-char *datestring;
-
-char *sampleunitstring;
-char *valueunitstring;
-
-floatish *samplemap; /* sample intervals */
-floatish *markmap; /* sample marks */
-
-/*
- * An extremely simple parser. The input is organised into lines of
- * the form
- *
- * JOB s -- job identifier string
- * DATE s -- date string
- * SAMPLE_UNIT s -- sample unit eg "seconds"
- * VALUE_UNIT s -- value unit eg "bytes"
- * MARK i -- sample mark
- * BEGIN_SAMPLE i -- start of ith sample
- * identifier i -- there are i identifiers in this sample
- * END_SAMPLE i -- end of ith sample
- *
- */
-
-void
-GetHpFile(infp)
- FILE *infp;
-{
- nsamples = 0;
- nmarks = 0;
- nidents = 0;
-
- g_ch = ' ';
- endfile = 0;
- linenum = 1;
- lastsample = 0.0;
-
- GetHpTok(infp);
-
- while (endfile == 0) {
- GetHpLine(infp);
- }
-
- if (!gotjob) {
- Error("%s: JOB missing", hpfile);
- }
-
- if (!gotdate) {
- Error("%s: DATE missing", hpfile);
- }
-
- if (!gotvalueunit) {
- Error("%s: VALUE_UNIT missing", hpfile);
- }
-
- if (!gotsampleunit) {
- Error("%s: SAMPLE_UNIT missing", hpfile);
- }
-
- if (nsamples == 0) {
- Error("%s: contains no samples", hpfile);
- }
-
-
- MakeIdentTable();
-
- fclose(hpfp);
-}
-
-
-/*
- * Read the next line from the input, check the syntax, and perform
- * the appropriate action.
- */
-
-static void
-GetHpLine(infp)
- FILE* infp;
-{
- static intish nmarkmax = 0, nsamplemax = 0;
-
- switch (thetok) {
- case JOB_TOK:
- GetHpTok(infp);
- if (thetok != STRING_TOK) {
- Error("%s, line %d: string must follow JOB", hpfile, linenum);
- }
- jobstring = thestring;
- gotjob = 1;
- GetHpTok(infp);
- break;
-
- case DATE_TOK:
- GetHpTok(infp);
- if (thetok != STRING_TOK) {
- Error("%s, line %d: string must follow DATE", hpfile, linenum);
- }
- datestring = thestring;
- gotdate = 1;
- GetHpTok(infp);
- break;
-
- case SAMPLE_UNIT_TOK:
- GetHpTok(infp);
- if (thetok != STRING_TOK) {
- Error("%s, line %d: string must follow SAMPLE_UNIT", hpfile,
- linenum);
- }
- sampleunitstring = thestring;
- gotsampleunit = 1;
- GetHpTok(infp);
- break;
-
- case VALUE_UNIT_TOK:
- GetHpTok(infp);
- if (thetok != STRING_TOK) {
- Error("%s, line %d: string must follow VALUE_UNIT", hpfile,
- linenum);
- }
- valueunitstring = thestring;
- gotvalueunit = 1;
- GetHpTok(infp);
- break;
-
- case MARK_TOK:
- GetHpTok(infp);
- if (thetok != FLOAT_TOK) {
- Error("%s, line %d, floating point number must follow MARK",
- hpfile, linenum);
- }
- if (insample) {
- Error("%s, line %d, MARK occurs within sample", hpfile, linenum);
- }
- if (nmarks >= nmarkmax) {
- if (!markmap) {
- nmarkmax = N_MARKS;
- markmap = (floatish*) xmalloc(nmarkmax * sizeof(floatish));
- } else {
- nmarkmax *= 2;
- markmap = (floatish*) xrealloc(markmap, nmarkmax * sizeof(floatish));
- }
- }
- markmap[ nmarks++ ] = thefloatish;
- GetHpTok(infp);
- break;
-
- case BEGIN_SAMPLE_TOK:
- insample = 1;
- GetHpTok(infp);
- if (thetok != FLOAT_TOK) {
- Error("%s, line %d, floating point number must follow BEGIN_SAMPLE", hpfile, linenum);
- }
- if (thefloatish < lastsample) {
- Error("%s, line %d, samples out of sequence", hpfile, linenum);
- } else {
- lastsample = thefloatish;
- }
- if (nsamples >= nsamplemax) {
- if (!samplemap) {
- nsamplemax = N_SAMPLES;
- samplemap = (floatish*) xmalloc(nsamplemax * sizeof(floatish));
- } else {
- nsamplemax *= 2;
- samplemap = (floatish*) xrealloc(samplemap,
- nsamplemax * sizeof(floatish));
- }
- }
- samplemap[ nsamples ] = thefloatish;
- GetHpTok(infp);
- break;
-
- case END_SAMPLE_TOK:
- insample = 0;
- GetHpTok(infp);
- if (thetok != FLOAT_TOK) {
- Error("%s, line %d: floating point number must follow END_SAMPLE",
- hpfile, linenum);
- }
- nsamples++;
- GetHpTok(infp);
- break;
-
- case IDENTIFIER_TOK:
- GetHpTok(infp);
- if (thetok != INTEGER_TOK) {
- Error("%s, line %d: integer must follow identifier", hpfile,
- linenum);
- }
- StoreSample(GetEntry(theident), nsamples, (floatish) theinteger);
- GetHpTok(infp);
- break;
-
- case EOF_TOK:
- endfile = 1;
- break;
-
- default:
- Error("%s, line %d: %s unexpected", hpfile, linenum,
- TokenToString(thetok));
- break;
- }
-}
-
-
-char *
-TokenToString(t)
- token t;
-{
- switch (t) {
- case EOF_TOK: return "EOF";
- case INTEGER_TOK: return "integer";
- case FLOAT_TOK: return "floating point number";
- case IDENTIFIER_TOK: return "identifier";
- case STRING_TOK: return "string";
- case BEGIN_SAMPLE_TOK: return "BEGIN_SAMPLE";
- case END_SAMPLE_TOK: return "END_SAMPLE";
- case JOB_TOK: return "JOB";
- case DATE_TOK: return "DATE";
- case SAMPLE_UNIT_TOK: return "SAMPLE_UNIT";
- case VALUE_UNIT_TOK: return "VALUE_UNIT";
- case MARK_TOK: return "MARK";
-
- case X_RANGE_TOK: return "X_RANGE";
- case Y_RANGE_TOK: return "Y_RANGE";
- case ORDER_TOK: return "ORDER";
- case SHADE_TOK: return "SHADE";
- default: return "(strange token)";
- }
-}
-
-/*
- * Read the next token from the input and assign its value
- * to the global variable "thetok". In the case of numbers,
- * the corresponding value is also assigned to "theinteger"
- * or "thefloatish" as appropriate; in the case of identifiers
- * it is assigned to "theident".
- */
-
-static void
-GetHpTok(infp)
- FILE* infp;
-{
-
- while (isspace(g_ch)) { /* skip whitespace */
- if (g_ch == '\n') linenum++;
- g_ch = getc(infp);
- }
-
- if (g_ch == EOF) {
- thetok = EOF_TOK;
- return;
- }
-
- if (isdigit(g_ch)) {
- thetok = GetNumber(infp);
- return;
- } else if (g_ch == '\"') {
- GetString(infp);
- thetok = STRING_TOK;
- return;
- } else if (IsIdChar(g_ch)) {
- ASSERT(! (isdigit(g_ch))); /* g_ch can't be a digit here */
- GetIdent(infp);
- if (!isupper(theident[0])) {
- thetok = IDENTIFIER_TOK;
- } else if (strcmp(theident, "BEGIN_SAMPLE") == 0) {
- thetok = BEGIN_SAMPLE_TOK;
- } else if (strcmp(theident, "END_SAMPLE") == 0) {
- thetok = END_SAMPLE_TOK;
- } else if (strcmp(theident, "JOB") == 0) {
- thetok = JOB_TOK;
- } else if (strcmp(theident, "DATE") == 0) {
- thetok = DATE_TOK;
- } else if (strcmp(theident, "SAMPLE_UNIT") == 0) {
- thetok = SAMPLE_UNIT_TOK;
- } else if (strcmp(theident, "VALUE_UNIT") == 0) {
- thetok = VALUE_UNIT_TOK;
- } else if (strcmp(theident, "MARK") == 0) {
- thetok = MARK_TOK;
- } else {
- thetok = IDENTIFIER_TOK;
- }
- return;
- } else {
- Error("%s, line %d: strange character (%c)", hpfile, linenum, g_ch);
- }
-}
-
-
-/*
- * Read a sequence of digits and convert the result to an integer
- * or floating point value (assigned to the "theinteger" or
- * "thefloatish").
- */
-
-static char numberstring[ NUMBER_LENGTH ];
-
-token
-GetNumber(infp)
- FILE* infp;
-{
- int i;
- int containsdot;
-
- ASSERT(isdigit(ch)); /* we must have a digit to start with */
-
- containsdot = 0;
-
- for (i = 0; i < NUMBER_LENGTH && (isdigit(g_ch) || g_ch == '.'); i++) {
- numberstring[ i ] = g_ch;
- containsdot |= (g_ch == '.');
- g_ch = getc(infp);
- }
-
- ASSERT(i < NUMBER_LENGTH); /* did not overflow */
-
- numberstring[ i ] = '\0';
-
- if (containsdot) {
- thefloatish = (floatish) atof(numberstring);
- return FLOAT_TOK;
- } else {
- theinteger = atoi(numberstring);
- return INTEGER_TOK;
- }
-}
-
-/*
- * Read a sequence of identifier characters and assign the result
- * to the string "theident".
- */
-
-void
-GetIdent(infp)
- FILE *infp;
-{
- unsigned int i;
- char idbuffer[5000];
-
- for (i = 0; i < (sizeof idbuffer)-1 && IsIdChar(g_ch); i++) {
- idbuffer[ i ] = g_ch;
- g_ch = getc(infp);
- }
-
- idbuffer[ i ] = '\0';
-
- if (theident)
- free(theident);
-
- theident = copystring(idbuffer);
-}
-
-
-/*
- * Read a sequence of characters that make up a string and
- * assign the result to "thestring".
- */
-
-void
-GetString(infp)
- FILE *infp;
-{
- unsigned int i;
- char stringbuffer[5000];
-
- ASSERT(ch == '\"');
-
- g_ch = getc(infp); /* skip the '\"' that begins the string */
-
- for (i = 0; i < (sizeof stringbuffer)-1 && g_ch != '\"'; i++) {
- stringbuffer[ i ] = g_ch;
- g_ch = getc(infp);
- }
-
- stringbuffer[i] = '\0';
- thestring = copystring(stringbuffer);
-
- ASSERT(g_ch == '\"');
-
- g_ch = getc(infp); /* skip the '\"' that terminates the string */
-}
-
-boolish
-IsIdChar(ch)
- int ch;
-{
- return (!isspace(ch));
-}
-
-
-/*
- * The information associated with each identifier is stored
- * in a linked list of chunks. The table below allows the list
- * of chunks to be retrieved given an identifier name.
- */
-
-#define N_HASH 513
-
-static struct entry* hashtable[ N_HASH ];
-
-static intish
-Hash(char* s)
-{
- int r;
-
- for (r = 0; *s; s++) {
- r = r + r + r + *s;
- }
-
- if (r < 0) r = -r;
-
- return r % N_HASH;
-}
-
-/*
- * Get space for a new chunk. Initialise it, and return a pointer
- * to the new chunk.
- */
-
-static struct chunk*
-MakeChunk(void)
-{
- struct chunk* ch;
- struct datapoint* d;
-
- ch = (struct chunk*) xmalloc( sizeof(struct chunk) );
-
- d = (struct datapoint*) xmalloc (sizeof(struct datapoint) * N_CHUNK);
-
- ch->nd = 0;
- ch->d = d;
- ch->next = 0;
- return ch;
-}
-
-
-/*
- * Get space for a new entry. Initialise it, and return a pointer
- * to the new entry.
- */
-
-struct entry *
-MakeEntry(name)
- char *name;
-{
- struct entry* e;
-
- e = (struct entry *) xmalloc(sizeof(struct entry));
- e->chk = MakeChunk();
- e->name = copystring(name);
- return e;
-}
-
-/*
- * Get the entry associated with "name", creating a new entry if
- * necessary.
- */
-
-static struct entry *
-GetEntry(name)
- char* name;
-{
- intish h;
- struct entry* e;
-
- h = Hash(name);
-
- for (e = hashtable[ h ]; e; e = e->next) {
- if (strcmp(e->name, name) == 0) {
- break;
- }
- }
-
- if (e) {
- return (e);
- } else {
- nidents++;
- e = MakeEntry(name);
- e->next = hashtable[ h ];
- hashtable[ h ] = e;
- return (e);
- }
-}
-
-
-/*
- * Store information from a sample.
- */
-
-void
-StoreSample(en, bucket, value)
- struct entry* en; intish bucket; floatish value;
-{
- struct chunk* chk;
-
- for (chk = en->chk; chk->next != 0; chk = chk->next)
- ;
-
- if (chk->nd < N_CHUNK) {
- chk->d[ chk->nd ].bucket = bucket;
- chk->d[ chk->nd ].value = value;
- chk->nd += 1;
- } else {
- struct chunk* t;
- t = chk->next = MakeChunk();
- t->d[ 0 ].bucket = bucket;
- t->d[ 0 ].value = value;
- t->nd += 1;
- }
-}
-
-
-struct entry** identtable;
-
-/*
- * The hash table is useful while reading the input, but it
- * becomes a liability thereafter. The code below converts
- * it to a more easily processed table.
- */
-
-static void
-MakeIdentTable()
-{
- intish i;
- intish j;
- struct entry* e;
-
- nidents = 0;
- for (i = 0; i < N_HASH; i++) {
- for (e = hashtable[ i ]; e; e = e->next) {
- nidents++;
- }
- }
-
- identtable = (struct entry**) xmalloc(nidents * sizeof(struct entry*));
- j = 0;
-
- for (i = 0; i < N_HASH; i++) {
- for (e = hashtable[ i ]; e; e = e->next, j++) {
- identtable[ j ] = e;
- }
- }
-}
diff --git a/massif/hp2ps/HpFile.h b/massif/hp2ps/HpFile.h
deleted file mode 100644
index 7a23dfe..0000000
--- a/massif/hp2ps/HpFile.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef HP_FILE_H
-#define HP_FILE_H
-
-typedef enum {
- /* These tokens are found in ".hp" files */
-
- EOF_TOK,
- INTEGER_TOK,
- FLOAT_TOK,
- IDENTIFIER_TOK,
- STRING_TOK,
- BEGIN_SAMPLE_TOK,
- END_SAMPLE_TOK,
- JOB_TOK,
- DATE_TOK,
- SAMPLE_UNIT_TOK,
- VALUE_UNIT_TOK,
- MARK_TOK,
-
- /* These extra ones are found only in ".aux" files */
-
- X_RANGE_TOK,
- Y_RANGE_TOK,
- ORDER_TOK,
- SHADE_TOK
-} token;
-
-struct datapoint {
- int bucket;
- floatish value;
-};
-
-struct chunk {
- struct chunk *next;
- short nd; /* 0 .. N_CHUNK - 1 */
- struct datapoint *d;
-};
-
-
-struct entry {
- struct entry *next;
- struct chunk *chk;
- char *name;
-};
-
-extern char *theident;
-extern char *thestring;
-extern int theinteger;
-extern floatish thefloatish;
-extern int g_ch;
-extern token thetok;
-extern int linenum;
-extern int endfile;
-
-char *TokenToString PROTO((token));
-
-extern struct entry** identtable;
-
-extern floatish *samplemap;
-extern floatish *markmap;
-
-void GetHpFile PROTO((FILE *));
-void StoreSample PROTO((struct entry *, intish, floatish));
-struct entry *MakeEntry PROTO((char *));
-
-token GetNumber PROTO((FILE *));
-void GetIdent PROTO((FILE *));
-void GetString PROTO((FILE *));
-boolish IsIdChar PROTO((int)); /* int is a "char" from getc */
-
-extern char *jobstring;
-extern char *datestring;
-
-extern char *sampleunitstring;
-extern char *valueunitstring;
-
-#endif /* HP_FILE_H */
diff --git a/massif/hp2ps/INSTALL b/massif/hp2ps/INSTALL
deleted file mode 100644
index 92fe7b7..0000000
--- a/massif/hp2ps/INSTALL
+++ /dev/null
@@ -1,17 +0,0 @@
-NOTE: these are instructions for installing hp2ps separately. If you only want
-to use it with the Valgrind tool, Massif, it should be installed automatically.
-
-The original Makefile, for which the below instructions apply, is kept as
-Makefile.old.
-
------------------------------------------------------------------------------
-For binary distribution:
-
- - just copy "hp2ps" into an appropriate directory.
-
-For source distribution:
-
- - edit "Makefile" and set the $DSTBIN to the directory you wish to install
- hp2ps in
-
- - do "make install"
diff --git a/massif/hp2ps/Key.c b/massif/hp2ps/Key.c
deleted file mode 100644
index d611552..0000000
--- a/massif/hp2ps/Key.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <math.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Dimensions.h"
-#include "HpFile.h"
-#include "Shade.h"
-
-/* own stuff */
-#include "Key.h"
-
-static void KeyEntry PROTO((floatish, char *, floatish));
-
-void Key()
-{
- intish i;
- floatish c;
- floatish dc;
-
- for (i = 0; i < nidents; i++) /* count identifiers */
- ;
-
- c = graphy0;
- dc = graphheight / (floatish) (i + 1);
-
- for (i = 0; i < nidents; i++) {
- c += dc;
- KeyEntry(c, identtable[i]->name, ShadeOf(identtable[i]->name));
- }
-}
-
-
-
-static void
-KeyEntry(centreline, name, colour)
- floatish centreline; char* name; floatish colour;
-{
- floatish namebase;
- floatish keyboxbase;
- floatish kstart;
-
- namebase = centreline - (floatish) (NORMAL_FONT / 2);
- keyboxbase = centreline - ((floatish) KEY_BOX_WIDTH / 2.0);
-
- kstart = graphx0 + graphwidth;
-
- fprintf(psfp, "%f %f moveto\n", kstart + borderspace, keyboxbase);
- fprintf(psfp, "0 %d rlineto\n", KEY_BOX_WIDTH);
- fprintf(psfp, "%d 0 rlineto\n", KEY_BOX_WIDTH);
- fprintf(psfp, "0 %d rlineto\n", -KEY_BOX_WIDTH);
- fprintf(psfp, "closepath\n");
-
- fprintf(psfp, "gsave\n");
- SetPSColour(colour);
- fprintf(psfp, "fill\n");
- fprintf(psfp, "grestore\n");
- fprintf(psfp, "stroke\n");
-
- fprintf(psfp, "HE%d setfont\n", NORMAL_FONT);
- fprintf(psfp, "%f %f moveto\n", kstart + (floatish) KEY_BOX_WIDTH + 2 * borderspace, namebase);
-
- fprintf(psfp, "(%s) show\n", name);
-}
diff --git a/massif/hp2ps/Key.h b/massif/hp2ps/Key.h
deleted file mode 100644
index b573ea0..0000000
--- a/massif/hp2ps/Key.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef KEY_H
-#define KEY_H
-
-void Key PROTO((void));
-
-#endif /* KEY_H */
diff --git a/massif/hp2ps/LICENSE b/massif/hp2ps/LICENSE
deleted file mode 100644
index b5059b7..0000000
--- a/massif/hp2ps/LICENSE
+++ /dev/null
@@ -1,31 +0,0 @@
-The Glasgow Haskell Compiler License
-
-Copyright 2002, The University Court of the University of Glasgow.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-- Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.
-
-- Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-
-- Neither name of the University nor the names of its contributors may be
-used to endorse or promote products derived from this software without
-specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
-GLASGOW AND THE CONTRIBUTORS "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
-UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS 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.
diff --git a/massif/hp2ps/Main.c b/massif/hp2ps/Main.c
deleted file mode 100644
index 661e161..0000000
--- a/massif/hp2ps/Main.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "Main.h"
-#include "Defines.h"
-#include "AuxFile.h"
-#include "AreaBelow.h"
-#include "Dimensions.h"
-#include "HpFile.h"
-#include "PsFile.h"
-#include "Reorder.h"
-#include "Scale.h"
-#include "TopTwenty.h"
-#include "TraceElement.h"
-#include "Deviation.h"
-#include "Error.h"
-#include "Utilities.h"
-
-boolish pflag = 0; /* read auxiliary file */
-boolish eflag = 0; /* scaled EPSF */
-boolish dflag = 0; /* sort by standard deviation */
-int iflag = 0; /* sort by identifier (3-way flag) */
-boolish gflag = 0; /* output suitable for previewer */
-boolish yflag = 0; /* ignore marks */
-boolish bflag = 0; /* use a big title box */
-boolish sflag = 0; /* use a small title box */
-int mflag = 0; /* max no. of bands displayed (default 20) */
-boolish tflag = 0; /* ignored threshold specified */
-boolish cflag = 0; /* colour output */
-
-boolish filter; /* true when running as a filter */
-
-static floatish WidthInPoints PROTO((char *)); /* forward */
-static FILE *Fp PROTO((char *, char **, char *, char *)); /* forward */
-
-char *hpfile;
-char *psfile;
-char *auxfile;
-
-char *programname;
-
-static char *pathName;
-static char *baseName; /* "basename" is a std C library name (sigh) */
-
-FILE* hpfp;
-FILE* psfp;
-FILE* auxfp;
-
-floatish xrange = 0.0;
-floatish yrange = 0.0;
-
-floatish auxxrange = 0.0;
-floatish auxyrange = 0.0;
-
-floatish epsfwidth;
-floatish areabelow;
-
-intish nsamples;
-intish nmarks;
-intish nidents;
-
-floatish THRESHOLD_PERCENT = DEFAULT_THRESHOLD;
-int TWENTY = DEFAULT_TWENTY;
-
-int main(int argc, char* argv[])
-{
-
- programname = copystring(Basename(argv[0]));
-
- argc--, argv++;
- while (argc && argv[0][0] == '-') {
- while (*++*argv)
- switch(**argv) {
- case 'p':
- pflag++;
- break;
- case 'e':
- eflag++;
- epsfwidth = WidthInPoints(*argv + 1);
- goto nextarg;
- case 'd':
- dflag++;
- goto nextarg;
- case 'i':
- switch( *(*argv + 1) ) {
- case '-':
- iflag = -1;
- break;
- case '+':
- default:
- iflag = 1;
- }
- goto nextarg;
- case 'g':
- gflag++;
- goto nextarg;
- case 'y':
- yflag++;
- goto nextarg;
- case 'b':
- bflag++;
- goto nextarg;
- case 's':
- sflag++;
- goto nextarg;
- case 'm':
- mflag++;
- TWENTY = atoi(*argv + 1);
- if (TWENTY > DEFAULT_TWENTY)
- Usage(*argv-1);
- goto nextarg;
- case 't':
- tflag++;
- THRESHOLD_PERCENT = (floatish) atof(*argv + 1);
- if (THRESHOLD_PERCENT < 0 || THRESHOLD_PERCENT > 5)
- Usage(*argv-1);
- goto nextarg;
- case 'c':
- cflag++;
- goto nextarg;
- case '?':
- default:
- Usage(*argv-1);
- }
-nextarg: ;
- argc--, argv++;
- }
-
- hpfile = "stdin";
- psfile = "stdout";
-
- hpfp = stdin;
- psfp = stdout;
-
- filter = argc < 1;
-
-
-
- if (!filter) {
- pathName = copystring(argv[0]);
- DropSuffix(pathName, ".hp");
- baseName = copystring(Basename(pathName));
-
- hpfp = Fp(pathName, &hpfile, ".hp", "r");
-
- // I changed these two lines to use 'pathName' instead of
- // 'baseName'. This means that the .ps and .aux files get put in
- // the same directory as the .hp file. This solved Valgrind bugt
- // #117686. --njn
-// psfp = Fp(baseName, &psfile, ".ps", "w");
- psfp = Fp(pathName, &psfile, ".ps", "w");
-
-// if (pflag) auxfp = Fp(baseName, &auxfile, ".aux", "r");
- if (pflag) auxfp = Fp(pathName, &auxfile, ".aux", "r");
- }
-
- GetHpFile(hpfp);
-
- if (!filter && pflag) GetAuxFile(auxfp);
-
-
- TraceElement(); /* Orders on total, Removes trace elements (tflag) */
-
- if (dflag) Deviation(); /* ReOrders on deviation */
-
- if (iflag) Identorder(iflag); /* ReOrders on identifier */
-
- if (pflag) Reorder(); /* ReOrders on aux file */
-
- if (TWENTY) TopTwenty(); /* Selects top twenty (mflag) */
-
- Dimensions();
-
- areabelow = AreaBelow();
-
- Scale();
-
- PutPsFile();
-
- if (!filter) {
- auxfp = Fp(baseName, &auxfile, ".aux", "w");
- PutAuxFile(auxfp);
- }
-
- return(0);
-}
-
-
-
-typedef enum {POINTS, INCHES, MILLIMETRES} pim;
-
-static pim Units PROTO((char *)); /* forward */
-
-static floatish
-WidthInPoints(wstr)
- char *wstr;
-{
- floatish result;
-
- result = (floatish) atof(wstr);
-
- switch (Units(wstr)) {
- case INCHES:
- result *= 72.0;
- break;
- case MILLIMETRES:
- result *= 2.834646;
- break;
- case POINTS:
- default: ;
- }
-
- if (result <= 144) /* Minimum of 2in wide ! */
- Usage(wstr);
-
- return result;
-}
-
-
-static pim
-Units(wstr)
- char* wstr;
-{
-int i;
-
- i = strlen(wstr) - 2;
-
- if (wstr[i] == 'p' && wstr[i+1] == 't') {
- return POINTS;
- } else if (wstr[i] == 'i' && wstr[i+1] == 'n') {
- return INCHES;
- } else if (wstr[i] == 'm' && wstr[i+1] == 'm') {
- return MILLIMETRES;
- } else {
- return POINTS;
- }
-}
-
-static FILE *
-Fp(rootname, filename, suffix, mode)
- char* rootname; char** filename; char* suffix; char* mode;
-{
- *filename = copystring2(rootname, suffix);
-
- return(OpenFile(*filename, mode));
-}
-
-#ifdef DEBUG
-void
-_stgAssert (filename, linenum)
- char *filename;
- unsigned int linenum;
-{
- fflush(stdout);
- fprintf(stderr, "ASSERTION FAILED: file %s, line %u\n", filename, linenum);
- fflush(stderr);
- abort();
-}
-#endif
diff --git a/massif/hp2ps/Main.h b/massif/hp2ps/Main.h
deleted file mode 100644
index c743f78..0000000
--- a/massif/hp2ps/Main.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef MAIN_H
-#define MAIN_H
-
-//#include "config.h"
-
-//#ifdef __STDC__
-#define PROTO(x) x
-//#else
-//#define PROTO(x) ()
-//#endif
-
-/* our own ASSERT macro (for C) */
-#ifndef DEBUG
-#define ASSERT(predicate) /*nothing*/
-
-#else
-void _ghcAssert PROTO((char *, unsigned int));
-
-#define ASSERT(predicate) \
- if (predicate) \
- /*null*/; \
- else \
- _ghcAssert(__FILE__, __LINE__)
-#endif
-
-/* partain: some ubiquitous types: floatish & intish.
- Dubious to use float/int, but that is what it used to be...
- (WDP 95/03)
-*/
-typedef double floatish;
-typedef double doublish; /* higher precision, if anything; little used */
-typedef int boolish;
-
-/* Use "long long" if we have it: the numbers in profiles can easily
- * overflow 32 bits after a few seconds execution.
- */
-#define HAVE_LONG_LONG 1 // --added by njn, because config.h removed
-
-#ifdef HAVE_LONG_LONG
-typedef long long int intish;
-#else
-typedef long int intish;
-#endif
-
-extern intish nsamples;
-extern intish nmarks;
-extern intish nidents;
-
-extern floatish maxcombinedheight;
-extern floatish areabelow;
-extern floatish epsfwidth;
-
-extern floatish xrange;
-extern floatish yrange;
-
-extern floatish auxxrange;
-extern floatish auxyrange;
-
-extern boolish eflag;
-extern boolish gflag;
-extern boolish yflag;
-extern boolish bflag;
-extern boolish sflag;
-extern int mflag;
-extern boolish tflag;
-extern boolish cflag;
-
-extern char *programname;
-
-extern char *hpfile;
-extern char *psfile;
-extern char *auxfile;
-
-extern FILE *hpfp;
-extern FILE *psfp;
-extern FILE *g_auxfp;
-
-#endif /* MAIN_H */
diff --git a/massif/hp2ps/Makefile.am b/massif/hp2ps/Makefile.am
deleted file mode 100644
index 6c223d7..0000000
--- a/massif/hp2ps/Makefile.am
+++ /dev/null
@@ -1,68 +0,0 @@
-
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.flags.am
-
-AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -g
-
-val_PROGRAMS = hp2ps
-
-EXTRA_DIST = \
- CHANGES \
- INSTALL \
- LICENSE \
- README \
- Makefile.old \
- hp2ps.1
-
-hp2ps_SOURCES = \
- AuxFile.c \
- Axes.c \
- AreaBelow.c \
- Curves.c \
- Deviation.c \
- Dimensions.c \
- Error.c \
- HpFile.c \
- Key.c \
- Main.c \
- Marks.c \
- TopTwenty.c \
- TraceElement.c \
- PsFile.c \
- Reorder.c \
- Scale.c \
- Shade.c \
- Utilities.c
-
-# Build hp2ps for the primary target only.
-hp2ps_LDADD = -lm
-hp2ps_CPPFLAGS = $(AM_CPPFLAGS_PRI)
-hp2ps_CFLAGS = $(AM_CFLAGS_PRI)
-hp2ps_CCASFLAGS = $(AM_CCASFLAGS_PRI)
-hp2ps_LDFLAGS = $(AM_CFLAGS_PRI)
-
-noinst_HEADERS = \
- AreaBelow.h \
- AuxFile.h \
- Axes.h \
- Curves.h \
- Defines.h \
- Deviation.h \
- Dimensions.h \
- Error.h \
- HpFile.h \
- Key.h \
- Main.h \
- Marks.h \
- PsFile.h \
- Reorder.h \
- Scale.h \
- Shade.h \
- TopTwenty.h \
- TraceElement.h \
- Utilities.h
-
-all-local:
- mkdir -p $(inplacedir)
- -rm -f $(addprefix $(inplacedir)/,$(val_PROGRAMS))
- ln -f -s $(addprefix ../$(subdir)/,$(val_PROGRAMS)) $(inplacedir)
diff --git a/massif/hp2ps/Makefile.old b/massif/hp2ps/Makefile.old
deleted file mode 100644
index a625149..0000000
--- a/massif/hp2ps/Makefile.old
+++ /dev/null
@@ -1,42 +0,0 @@
-OBJS= \
- AuxFile.o \
- Axes.o \
- AreaBelow.o \
- Curves.o \
- Deviation.o \
- Dimensions.o \
- Error.o \
- HpFile.o \
- Key.o \
- Main.o \
- Marks.o \
- TopTwenty.o \
- TraceElement.o \
- PsFile.o \
- Reorder.o \
- Scale.o \
- Shade.o \
- Utilities.o
-
-# Please set MATHLIB and BIN appropriately. I don't need MATHLIB on my machine,
-# but you may.
-
-MATHLIB = -lm
-
-DSTBIN = /n/Numbers/usr/lml/lml-0.997.4hp/sun3/bin
-
-CC= cc # gcc -Wall
-CFLAGS= -g
-LDFLAGS= ${STATICFLAG}
-
-TARGET=hp2ps
-
-${TARGET}: ${OBJS}
- ${CC} -o ${TARGET} ${CCFLAGS} ${LDFLAGS} ${OBJS} ${MATHLIB}
-
-install: ${TARGET}
- mv ${TARGET} ${DSTBIN}/${TARGET}
- chmod 555 ${DSTBIN}/${TARGET}
-
-clean:
- rm -f core *.o ${TARGET}
diff --git a/massif/hp2ps/Marks.c b/massif/hp2ps/Marks.c
deleted file mode 100644
index 80947df..0000000
--- a/massif/hp2ps/Marks.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include "Main.h"
-#include "Curves.h"
-#include "Dimensions.h"
-#include "HpFile.h"
-
-/* own stuff */
-#include "Marks.h"
-
-static void Caret PROTO((floatish, floatish, floatish));
-
-void
-Marks()
-{
- intish i;
- floatish m;
-
- for (i = 0; i < nmarks; i++) {
- m = ((markmap[i] - samplemap[0]) / xrange) * graphwidth;
- Caret(xpage(m), ypage(0.0), 4.0);
- }
-}
-
-
-/*
- * Draw a small white caret at (x,y) with width 2 * d
- */
-
-static void
-Caret(x,y,d)
- floatish x; floatish y; floatish d;
-{
- fprintf(psfp, "%f %f moveto\n", x - d, y);
- fprintf(psfp, "%f %f rlineto\n", d, -d);
- fprintf(psfp, "%f %f rlineto\n", d, d);
- fprintf(psfp, "closepath\n");
-
- fprintf(psfp, "gsave\n");
- fprintf(psfp, "1.0 setgray\n");
- fprintf(psfp, "fill\n");
- fprintf(psfp, "grestore\n");
- fprintf(psfp, "stroke\n");
-}
diff --git a/massif/hp2ps/Marks.h b/massif/hp2ps/Marks.h
deleted file mode 100644
index e71f1cd..0000000
--- a/massif/hp2ps/Marks.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef MARKS_H
-#define MARKS_H
-
-void Marks PROTO((void));
-
-#endif /* MARKS_H */
diff --git a/massif/hp2ps/PsFile.c b/massif/hp2ps/PsFile.c
deleted file mode 100644
index 2b203e4..0000000
--- a/massif/hp2ps/PsFile.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <string.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Dimensions.h"
-#include "Curves.h"
-#include "HpFile.h"
-#include "Axes.h"
-#include "Key.h"
-#include "Marks.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "PsFile.h"
-
-static void Prologue PROTO((void)); /* forward */
-static void Variables PROTO((void)); /* forward */
-static void BorderOutlineBox PROTO((void)); /* forward */
-static void BigTitleOutlineBox PROTO((void)); /* forward */
-static void TitleOutlineBox PROTO((void)); /* forward */
-static void BigTitleText PROTO((void)); /* forward */
-static void TitleText PROTO((void)); /* forward */
-
-void
-PutPsFile()
-{
- Prologue();
- Variables();
- BorderOutlineBox();
-
- if (bflag) {
- BigTitleOutlineBox();
- BigTitleText();
- } else {
- TitleOutlineBox();
- TitleText();
- }
-
- CurvesInit();
-
- Axes();
-
- if (TWENTY) Key();
-
- Curves();
-
- if (!yflag) Marks();
-
- fprintf(psfp, "showpage\n");
-}
-
-
-static void StandardSpecialComments PROTO((void)); /* forward */
-static void EPSFSpecialComments PROTO((floatish)); /* forward */
-static void Landscape PROTO((void)); /* forward */
-static void Portrait PROTO((void)); /* forward */
-static void Scaling PROTO((floatish)); /* forward */
-
-static void
-Prologue()
-{
- if (eflag) {
- floatish epsfscale = epsfwidth / (floatish) borderwidth;
- EPSFSpecialComments(epsfscale);
- Scaling(epsfscale);
- } else {
- StandardSpecialComments();
- if (gflag) Portrait(); else Landscape();
- }
-}
-
-extern char *jobstring;
-extern char *datestring;
-
-static void
-StandardSpecialComments()
-{
- fprintf(psfp, "%%!PS-Adobe-2.0\n");
- fprintf(psfp, "%%%%Title: %s\n", jobstring);
- fprintf(psfp, "%%%%Creator: %s (version %s)\n", programname, VERSION);
- fprintf(psfp, "%%%%CreationDate: %s\n", datestring);
- fprintf(psfp, "%%%%EndComments\n");
-}
-
-static void
-EPSFSpecialComments(epsfscale)
- floatish epsfscale;
-{
- fprintf(psfp, "%%!PS-Adobe-2.0\n");
- fprintf(psfp, "%%%%Title: %s\n", jobstring);
- fprintf(psfp, "%%%%Creator: %s (version %s)\n", programname, VERSION);
- fprintf(psfp, "%%%%CreationDate: %s\n", datestring);
- fprintf(psfp, "%%%%BoundingBox: 0 0 %d %d\n",
- (int) (borderwidth * epsfscale + 0.5),
- (int) (borderheight * epsfscale + 0.5) );
- fprintf(psfp, "%%%%EndComments\n");
-}
-
-
-
-static void
-Landscape()
-{
- fprintf(psfp, "-90 rotate\n");
- fprintf(psfp, "%f %f translate\n", -(borderwidth + (floatish) START_Y),
- (floatish) START_X);
-}
-
-static void
-Portrait()
-{
- fprintf(psfp, "%f %f translate\n", (floatish) START_X, (floatish) START_Y);
-}
-
-static void
-Scaling(epsfscale)
- floatish epsfscale;
-{
- fprintf(psfp, "%f %f scale\n", epsfscale, epsfscale);
-}
-
-
-static void
-Variables()
-{
- fprintf(psfp, "/HE%d /Helvetica findfont %d scalefont def\n",
- NORMAL_FONT, NORMAL_FONT);
-
- fprintf(psfp, "/HE%d /Helvetica findfont %d scalefont def\n",
- LARGE_FONT, LARGE_FONT);
-}
-
-
-static void
-BorderOutlineBox()
-{
- fprintf(psfp, "newpath\n");
- fprintf(psfp, "0 0 moveto\n");
- fprintf(psfp, "0 %f rlineto\n", borderheight);
- fprintf(psfp, "%f 0 rlineto\n", borderwidth);
- fprintf(psfp, "0 %f rlineto\n", -borderheight);
- fprintf(psfp, "closepath\n");
- fprintf(psfp, "%f setlinewidth\n", borderthick);
- fprintf(psfp, "stroke\n");
-}
-
-static void
-BigTitleOutlineBox()
-{
- fprintf(psfp, "newpath\n");
- fprintf(psfp, "%f %f moveto\n", borderspace,
- borderheight - titleheight - borderspace);
- fprintf(psfp, "0 %f rlineto\n", titleheight);
- fprintf(psfp, "%f 0 rlineto\n", titlewidth);
- fprintf(psfp, "0 %f rlineto\n", -titleheight);
- fprintf(psfp, "closepath\n");
- fprintf(psfp, "%f setlinewidth\n", borderthick);
- fprintf(psfp, "stroke\n");
-
- fprintf(psfp, "%f %f moveto\n", borderspace,
- borderheight - titleheight / 2 - borderspace);
- fprintf(psfp, "%f 0 rlineto\n", titlewidth);
- fprintf(psfp, "stroke\n");
-}
-
-
-static void
-TitleOutlineBox()
-{
- fprintf(psfp, "newpath\n");
- fprintf(psfp, "%f %f moveto\n", borderspace,
- borderheight - titleheight - borderspace);
- fprintf(psfp, "0 %f rlineto\n", titleheight);
- fprintf(psfp, "%f 0 rlineto\n", titlewidth);
- fprintf(psfp, "0 %f rlineto\n", -titleheight);
- fprintf(psfp, "closepath\n");
- fprintf(psfp, "%f setlinewidth\n", borderthick);
- fprintf(psfp, "stroke\n");
-}
-
-static void EscapePrint PROTO((char *, int)); /* forward */
-
-static void
-BigTitleText()
-{
- floatish x, y;
-
- x = borderspace + titletextspace;
- y = borderheight - titleheight / 2 - borderspace + titletextspace;
-
- /* job identifier goes on top at the far left */
-
- fprintf(psfp, "HE%d setfont\n", TITLE_TEXT_FONT);
- fprintf(psfp, "%f %f moveto\n", x, y);
- fputc('(', psfp);
- EscapePrint(jobstring, BIG_JOB_STRING_WIDTH);
- fprintf(psfp, ") show\n");
-
- y = borderheight - titleheight - borderspace + titletextspace;
-
- /* area below curve gows at the botton, far left */
-
- fprintf(psfp, "HE%d setfont\n", TITLE_TEXT_FONT);
- fprintf(psfp, "%f %f moveto\n", x, y);
- fputc('(', psfp);
- CommaPrint(psfp, (intish)areabelow);
- fprintf(psfp, " %s x %s)\n", valueunitstring, sampleunitstring);
- fprintf(psfp, "show\n");
-
- /* date goes at far right */
-
- fprintf(psfp, "HE%d setfont\n", TITLE_TEXT_FONT);
- fprintf(psfp, "(%s)\n", datestring);
- fprintf(psfp, "dup stringwidth pop\n");
- fprintf(psfp, "%f\n", (titlewidth + borderspace) - titletextspace);
- fprintf(psfp, "exch sub\n");
- fprintf(psfp, "%f moveto\n", y);
- fprintf(psfp, "show\n");
-}
-
-
-static void
-TitleText()
-{
- floatish x, y;
-
- x = borderspace + titletextspace;
- y = borderheight - titleheight - borderspace + titletextspace;
-
- /* job identifier goes at far left */
-
- fprintf(psfp, "HE%d setfont\n", TITLE_TEXT_FONT);
- fprintf(psfp, "%f %f moveto\n", x, y);
- fputc('(', psfp);
- EscapePrint(jobstring, SMALL_JOB_STRING_WIDTH);
- fprintf(psfp, ") show\n");
-
- /* area below curve is centered */
-
- fprintf(psfp, "HE%d setfont\n", TITLE_TEXT_FONT);
- fputc('(', psfp);
- CommaPrint(psfp, (intish) areabelow);
- fprintf(psfp, " %s x %s)\n", valueunitstring, sampleunitstring);
-
- fprintf(psfp, "dup stringwidth pop\n");
- fprintf(psfp, "2 div\n");
- fprintf(psfp, "%f\n", titlewidth / 2);
- fprintf(psfp, "exch sub\n");
- fprintf(psfp, "%f moveto\n", y);
- fprintf(psfp, "show\n");
-
- /* date goes at far right */
-
- fprintf(psfp, "HE%d setfont\n", TITLE_TEXT_FONT);
- fprintf(psfp, "(%s)\n", datestring);
- fprintf(psfp, "dup stringwidth pop\n");
- fprintf(psfp, "%f\n", (titlewidth + borderspace) - titletextspace);
- fprintf(psfp, "exch sub\n");
- fprintf(psfp, "%f moveto\n", y);
- fprintf(psfp, "show\n");
-}
-
-/*
- * Print a string s in width w, escaping characters where necessary.
- */
-
-static void
-EscapePrint(s,w)
- char* s; int w;
-{
- for ( ; *s && w > 0; s++, w--) {
- if (*s == '(') { /* escape required */
- fputc('\\', psfp);
- } else if (*s == ')') {
- fputc('\\', psfp);
- }
-
- fputc(*s, psfp);
- }
-}
diff --git a/massif/hp2ps/PsFile.h b/massif/hp2ps/PsFile.h
deleted file mode 100644
index 01f8cc1..0000000
--- a/massif/hp2ps/PsFile.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef PS_FILE_H
-#define PS_FILE_H
-
-void PutPsFile PROTO((void));
-
-#endif /* PS_FILE_H */
diff --git a/massif/hp2ps/README b/massif/hp2ps/README
deleted file mode 100644
index f0f09ce..0000000
--- a/massif/hp2ps/README
+++ /dev/null
@@ -1 +0,0 @@
-This "hp2ps" program was written by Dave Wakeling at York.
diff --git a/massif/hp2ps/Reorder.c b/massif/hp2ps/Reorder.c
deleted file mode 100644
index fc6db6a..0000000
--- a/massif/hp2ps/Reorder.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Error.h"
-#include "HpFile.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "Reorder.h"
-
-static struct order {
- char* ident;
- int order;
-} *ordermap = 0;
-
-static int ordermapmax = 0;
-static int ordermapindex = 0;
-
-
-void
-OrderFor(ident, order)
- char* ident;
- int order;
-{
- if (! ordermap) {
- ordermapmax = (nidents > TWENTY ? nidents : TWENTY) * 2;
- /* Assume nidents read is indication of the No of
- idents in the .aux file (*2 for good luck !) */
- ordermap = xmalloc(ordermapmax * sizeof(struct order));
- }
-
- if (ordermapindex < ordermapmax) {
- ordermap[ ordermapindex ].ident = copystring(ident);
- ordermap[ ordermapindex ].order = order;
- ordermapindex++;
- } else {
- Disaster("order map overflow");
- }
-}
-
-/*
- * Get the order of to be used for "ident" if there is one.
- * Otherwise, return 0 which is the minimum ordering value.
- */
-
-int
-OrderOf(ident)
- char* ident;
-{
- int i;
-
- for (i = 0; i < ordermapindex; i++) {
- if (strcmp(ordermap[i].ident, ident) == 0) { /* got it */
- return(ordermap[i].order);
- }
- }
-
- return 0;
-}
-
-/*
- * Reorder on the basis of information from ".aux" file.
- */
-
-void
-Reorder()
-{
- intish i;
- intish j;
- int min;
- struct entry* e;
- int o1, o2;
-
- for (i = 0; i < nidents-1; i++) {
- min = i;
- for (j = i+1; j < nidents; j++) {
- o1 = OrderOf(identtable[ j ]->name);
- o2 = OrderOf(identtable[ min ]->name);
-
- if (o1 < o2 ) min = j;
- }
-
- e = identtable[ min ];
- identtable[ min ] = identtable[ i ];
- identtable[ i ] = e;
- }
-}
diff --git a/massif/hp2ps/Reorder.h b/massif/hp2ps/Reorder.h
deleted file mode 100644
index 81c4ba3..0000000
--- a/massif/hp2ps/Reorder.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef REORDER_H
-#define REORDER_H
-
-void Reorder PROTO((void));
-int OrderOf PROTO((char *));
-void OrderFor PROTO((char *, int));
-
-#endif /* REORDER_H */
diff --git a/massif/hp2ps/Scale.c b/massif/hp2ps/Scale.c
deleted file mode 100644
index b6b5e3a..0000000
--- a/massif/hp2ps/Scale.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Dimensions.h"
-#include "Error.h"
-#include "HpFile.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "Scale.h"
-
-/*
- * Return the maximum combined height that all the sample
- * curves will reach. This (absolute) figure can then be
- * used to scale the samples automatically so that they
- * fit on the page.
- */
-
-floatish
-MaxCombinedHeight()
-{
- intish i;
- intish j;
- floatish mx;
- int bucket;
- floatish value;
- struct chunk* ch;
- floatish *maxima;
-
- maxima = (floatish*) xmalloc(nsamples * sizeof(floatish));
- for (i = 0; i < nsamples; i++) {
- maxima[ i ] = 0.0;
- }
-
- for (i = 0; i < nidents; i++) {
- for (ch = identtable[i]->chk; ch; ch = ch->next) {
- for (j = 0; j < ch->nd; j++) {
- bucket = ch->d[j].bucket;
- value = ch->d[j].value;
- if (bucket >= nsamples)
- Disaster("bucket out of range");
- maxima[ bucket ] += value;
- }
- }
- }
-
- for (mx = maxima[ 0 ], i = 0; i < nsamples; i++) {
- if (maxima[ i ] > mx) mx = maxima[ i ];
- }
-
- free(maxima);
- return mx;
-}
-
-
-
-/*
- * Scale the values from the samples so that they will fit on
- * the page.
- */
-
-extern floatish xrange;
-extern floatish yrange;
-
-void
-Scale()
-{
- intish i;
- intish j;
- floatish sf;
- struct chunk* ch;
-
- if (yrange == 0.0) /* no samples */
- return;
-
- sf = graphheight / yrange;
-
- for (i = 0; i < nidents; i++) {
- for (ch = identtable[i]->chk; ch; ch = ch->next) {
- for (j = 0; j < ch->nd; j++) {
- ch->d[j].value = ch->d[j].value * sf;
- }
- }
- }
-}
diff --git a/massif/hp2ps/Scale.h b/massif/hp2ps/Scale.h
deleted file mode 100644
index 2a3487e..0000000
--- a/massif/hp2ps/Scale.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef SCALE_H
-#define SCALE_H
-
-floatish MaxCombinedHeight PROTO((void));
-void Scale PROTO((void));
-
-#endif /* SCALE_H */
diff --git a/massif/hp2ps/Shade.c b/massif/hp2ps/Shade.c
deleted file mode 100644
index e828eba..0000000
--- a/massif/hp2ps/Shade.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Error.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "Shade.h"
-
-static struct shade {
- char* ident;
- floatish shade;
-} *shademap;
-
-static int shademapmax = 0;
-static int shademapindex = 0;
-
-/*
- * Set the shade to be used for "ident" to "shade".
- */
-
-void
-ShadeFor(ident, shade)
- char* ident;
- floatish shade;
-{
- if (! shademap) {
- shademapmax = (nidents > TWENTY ? nidents : TWENTY) * 2;
- /* Assume nidents read is indication of the No of
- idents in the .aux file (*2 for good luck) */
- /* NB *2 is needed as .aux and .hp elements may differ */
- shademap = xmalloc(shademapmax * sizeof(struct shade));
- }
-
- if (shademapindex < shademapmax) {
- shademap[ shademapindex ].ident = copystring(ident);
- shademap[ shademapindex ].shade = shade;
- shademapindex++;
- } else {
- Disaster("shade map overflow");
- }
-}
-
-/*
- * Get the shade to be used for "ident" if there is one.
- * Otherwise, think of a new one.
- */
-
-static floatish ThinkOfAShade PROTO((void)); /* forward */
-
-floatish
-ShadeOf(ident)
- char* ident;
-{
- int i;
- floatish shade;
-
- for (i = 0; i < shademapindex; i++) {
- if (strcmp(shademap[i].ident, ident) == 0) { /* got it */
- return(shademap[i].shade);
- }
- }
-
- shade = ThinkOfAShade();
-
- ShadeFor(ident, shade);
-
- return shade;
-}
-
-
-
-#define N_MONO_SHADES 10
-
-static floatish m_shades[ N_MONO_SHADES ] = {
- 0.00000, 0.20000, 0.60000, 0.30000, 0.90000,
- 0.40000, 1.00000, 0.70000, 0.50000, 0.80000
-};
-
-#define N_COLOUR_SHADES 27
-
-/* HACK: 0.100505 means 100% red, 50% green, 50% blue */
-
-static floatish c_shades[ N_COLOUR_SHADES ] = {
- 0.000000, 0.000010, 0.001000, 0.001010, 0.100000,
- 0.100010, 0.101000, 0.101010, 0.000005, 0.000500,
- 0.000510, 0.001005, 0.050000, 0.050010, 0.051000,
- 0.051010, 0.100005, 0.100500, 0.100510, 0.101005,
- 0.000505, 0.050005, 0.050500, 0.050510, 0.051005,
- 0.100505, 0.050505
-};
-
-static floatish
-ThinkOfAShade()
-{
- static int thisshade = -1;
-
- thisshade++;
- return cflag ?
- c_shades[ thisshade % N_COLOUR_SHADES ] :
- m_shades[ thisshade % N_MONO_SHADES ] ;
-}
-
-static floatish
-extract_colour(floatish shade, intish factor)
-{
- intish i,j;
-
- i = (int)(shade * factor);
- j = i / 100;
- return (i - j * 100) / 10.0;
-}
-
-void
-SetPSColour(shade)
- floatish shade;
-{
- if (cflag) {
- fprintf(psfp, "%f %f %f setrgbcolor\n",
- extract_colour(shade, (intish)100),
- extract_colour(shade, (intish)10000),
- extract_colour(shade, (intish)1000000));
- } else {
- fprintf(psfp, "%f setgray\n", shade);
- }
-}
diff --git a/massif/hp2ps/Shade.h b/massif/hp2ps/Shade.h
deleted file mode 100644
index 66a803e..0000000
--- a/massif/hp2ps/Shade.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef SHADE_H
-#define SHADE_H
-
-floatish ShadeOf PROTO((char *));
-void ShadeFor PROTO((char *, floatish));
-void SetPSColour PROTO((floatish));
-
-#endif /* SHADE_H */
diff --git a/massif/hp2ps/TopTwenty.c b/massif/hp2ps/TopTwenty.c
deleted file mode 100644
index 3c6ccbd..0000000
--- a/massif/hp2ps/TopTwenty.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "Main.h"
-#include "Defines.h"
-#include "Error.h"
-#include "HpFile.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "TopTwenty.h"
-
-/*
- * We only have room in the key for a maximum of 20 identifiers.
- * We therefore choose to keep the top 20 bands --- these will
- * be the most important ones, since this pass is performed after
- * the threshold and standard deviation passes. If there are more
- * than 20 bands, the excess are gathered together as an "OTHER" ]
- * band which appears as band 20.
- */
-
-void
-TopTwenty()
-{
- intish i;
- intish j;
- intish compact;
- intish bucket;
- floatish value;
- struct entry* en;
- struct chunk* ch;
- floatish *other;
-
- i = nidents;
- if (i <= TWENTY) return; /* nothing to do! */
-
- other = (floatish*) xmalloc(nsamples * sizeof(floatish));
- /* build a list of samples for "OTHER" */
-
- compact = (i - TWENTY) + 1;
-
- for (i = 0; i < nsamples; i++) {
- other[ i ] = 0.0;
- }
-
- for (i = 0; i < compact && i < nidents; i++) {
- for (ch = identtable[i]->chk; ch; ch = ch->next) {
- for (j = 0; j < ch->nd; j++) {
- bucket = ch->d[j].bucket;
- value = ch->d[j].value;
- if (bucket >= nsamples)
- Disaster("bucket out of range");
- other[ bucket ] += value;
- }
- }
- }
-
- en = MakeEntry("OTHER");
- en->next = 0;
-
- for (i = 0; i < nsamples; i++) {
- StoreSample(en, i, other[i]);
- }
-
- /* slide samples down */
- for (i = compact; i < nidents; i++) {
- identtable[i-compact+1] = identtable[i];
- }
-
- nidents = TWENTY;
- identtable[0] = en;
- free(other);
-}
diff --git a/massif/hp2ps/TopTwenty.h b/massif/hp2ps/TopTwenty.h
deleted file mode 100644
index f724a4d..0000000
--- a/massif/hp2ps/TopTwenty.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef TOP_TWENTY_H
-#define TOP_TWENTY_H
-
-void TopTwenty PROTO((void));
-
-#endif /* TOP_TWENTY_H */
diff --git a/massif/hp2ps/TraceElement.c b/massif/hp2ps/TraceElement.c
deleted file mode 100644
index 158eb93..0000000
--- a/massif/hp2ps/TraceElement.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "Main.h"
-#include "Defines.h"
-#include "HpFile.h"
-#include "Error.h"
-#include "Utilities.h"
-
-/* own stuff */
-#include "TraceElement.h"
-
-/*
- * Compute the total volume for each identifier, and the grand
- * total of these totals. The identifiers whose totals when
- * added together amount to less that a threshold percentage
- * (default 1%) of the grand total are considered to be ``trace
- * elements'' and they are thrown away.
- */
-
-extern floatish thresholdpercent;
-
-void TraceElement()
-{
- intish i;
- intish j;
- struct chunk* ch;
- floatish grandtotal;
- intish min;
- floatish t;
- floatish p;
- struct entry* e;
- intish *totals;
-
- totals = (intish *) xmalloc(nidents * sizeof(intish));
-
- /* find totals */
-
- for (i = 0; i < nidents; i++) {
- totals[ i ] = 0;
- }
-
- for (i = 0; i < nidents; i++) {
- for (ch = identtable[i]->chk; ch; ch = ch->next) {
- for (j = 0; j < ch->nd; j++) {
- totals[ i ] += ch->d[j].value;
- }
- }
- }
-
- /* sort on the basis of total */
-
- for (i = 0; i < nidents-1; i++) {
- min = i;
- for (j = i+1; j < nidents; j++) {
- if (totals[ j ] < totals[ min ]) {
- min = j;
- }
- }
-
- t = totals[ min ];
- totals[ min ] = totals[ i ];
- totals[ i ] = t;
-
- e = identtable[ min ];
- identtable[ min ] = identtable[ i ];
- identtable[ i ] = e;
- }
-
-
- /* find the grand total (NB: can get *BIG*!) */
-
- grandtotal = 0.0;
-
- for (i = 0; i < nidents; i++) {
- grandtotal += (floatish) totals[ i ];
- }
-
- t = 0.0; /* cumulative percentage */
-
- for (i = 0; i < nidents; i++) {
- p = (100.0 * (floatish) totals[i]) / grandtotal;
- t = t + p;
- if (t >= THRESHOLD_PERCENT) {
- break;
- }
- }
-
- /* identifiers from 0 to i-1 should be removed */
- for (j = 0; i < nidents; i++, j++) {
- identtable[j] = identtable[i];
- }
-
- nidents = j;
-
- free(totals);
-}
diff --git a/massif/hp2ps/TraceElement.h b/massif/hp2ps/TraceElement.h
deleted file mode 100644
index b5ee8b5..0000000
--- a/massif/hp2ps/TraceElement.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef TRACE_ELEMENT_H
-#define TRACE_ELEMENT_H
-
-void TraceElement PROTO((void));
-
-#endif /* TRACE_ELEMENT_H */
diff --git a/massif/hp2ps/Utilities.c b/massif/hp2ps/Utilities.c
deleted file mode 100644
index f9915bb..0000000
--- a/massif/hp2ps/Utilities.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "Main.h"
-#include "Error.h"
-#include "Utilities.h"
-
-
-char*
-Basename(char* name)
-{
- char* t;
-
- t = name;
-
- while (*name) {
- if (*name == '/') {
- t = name+1;
- }
- name++;
- }
-
- return t;
-}
-
-void
-DropSuffix(name, suffix)
- char* name; char* suffix;
-{
- char* t;
-
- t = (char*) 0;
-
- while (*name) {
- if (*name == '.') {
- t = name;
- }
- name++;
- }
-
- if (t != (char*) 0 && strcmp(t, suffix) == 0) {
- *t = '\0';
- }
-}
-
-FILE*
-OpenFile(s, mode)
- char* s; char* mode;
-{
- FILE* r;
-
- if ((r = fopen(s, mode)) == NULL) {
- /*NOTREACHED*/
- Error("cannot open %s", s);
- }
-
- return r;
-}
-
-
-#define ONETHOUSAND 1000
-
-/*
- * Print a positive integer with commas
- */
-
-void
-CommaPrint(fp,n)
- FILE* fp;
- intish n;
-{
- if (n < ONETHOUSAND) {
- fprintf(fp, "%d", (int)n);
- } else {
- CommaPrint(fp, n / ONETHOUSAND);
- fprintf(fp, ",%03d", (int)(n % ONETHOUSAND));
- }
-}
-
-void *
-xmalloc(n)
- size_t n;
-{
- void *r;
-
- r = (void*) malloc(n);
- if (!r) {
- /*NOTREACHED*/
- Disaster("%s, sorry, out of memory", hpfile);
- }
- return r;
-}
-
-void *
-xrealloc(p, n)
- void *p;
- size_t n;
-{
- void *r;
-
- r = realloc(p, n);
- if (!r) {
- /*NOTREACHED*/
- Disaster("%s, sorry, out of memory", hpfile);
- }
- return r;
-}
-
-char *
-copystring(s)
- char *s;
-{
- char *r;
-
- r = (char*) xmalloc(strlen(s)+1);
- strcpy(r, s);
- return r;
-}
-
-char *
-copystring2(s, t)
- char *s, *t;
-{
- char *r;
-
- r = (char*) xmalloc(strlen(s)+strlen(t)+1);
- strcpy(r, s);
- strcat(r, t);
- return r;
-}
-
diff --git a/massif/hp2ps/Utilities.h b/massif/hp2ps/Utilities.h
deleted file mode 100644
index 674843a..0000000
--- a/massif/hp2ps/Utilities.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* This file is part of hp2ps, a graph drawer for memory profiles.
- Copyright (C) 2002 The University Court of the University of Glasgow.
- This program is governed by the license contained in the file LICENSE. */
-
-#ifndef UTILITIES_H
-#define UTILITIES_H
-
-char* Basename PROTO((char *));
-void DropSuffix PROTO((char *, char *));
-FILE* OpenFile PROTO((char *, char *));
-void CommaPrint PROTO((FILE *, intish));
-char *copystring PROTO((char *));
-char *copystring2 PROTO((char *, char *));
-void *xmalloc PROTO((size_t));
-void *xrealloc PROTO((void *, size_t));
-
-#endif /* UTILITIES_H */
diff --git a/massif/hp2ps/hp2ps.1 b/massif/hp2ps/hp2ps.1
deleted file mode 100644
index fd0bca0..0000000
--- a/massif/hp2ps/hp2ps.1
+++ /dev/null
@@ -1,145 +0,0 @@
-.\" man page for hp2ps
-.ds PS P\s-2OST\s+2S\s-2CRIPT\s+2
-.\" typeset examples in fixed size font as indented paragraph
-.de Ex
-.sp
-.RS
-.nf
-.ft C
-..
-.de Xe
-.RE
-.sp
-.fi
-..
-.TH HP2PS 1 "18 April 1992"
-.SH NAME
-hp2ps \- convert a heap profile to a \*(PS graph
-.SH SYNOPSIS
-.B hp2ps
-[flags] [file][.hp]
-.SH DESCRIPTION
-The program
-.B hp2ps
-converts a heap profile stored in
-.IR file
-into a \*(PS graph, sending the result to
-.IR file.ps.
-By convention, files to be processed by
-.B hp2ps
-have a
-.I .hp
-extension. However, for compatibility with older versions of
-.B hp2ps,
-this extension can be omitted. If
-.IR file
-is omitted entirely, then the program behaves as a filter.
-.SH OPTIONS
-The flags are:
-.IP "\fB\-d\fP"
-In order to make graphs more readable,
-.B hp2ps
-sorts the shaded bands for each identifier. The default sort ordering is for
-the bands with the largest area to be stacked on top of the smaller ones.
-The
-.B \-d
-option causes rougher bands (those reprsenting series of values with the
-largest standard deviations) to be stacked on top of smoother ones.
-.IP "\fB\-b\fP"
-Normally,
-.B hp2ps
-puts the title of the graph in a small box at the top of the page. However,
-if the JOB string is too long to fit in a small box (more than 35 characters),
-then
-.B hp2ps
-will choose to use a big box instead. The
-.B \-b
-option forces
-.B hp2ps
-to use a big box.
-.IP "\fB\-e\fP \fIfloat\fP[in|mm|pt]"
-Generate encapsulated \*(PS suitable for inclusion in LaTeX documents.
-Usually, the \*(PS graph is drawn in landscape mode in an area
-9 inches wide by 6 inches high, and
-.B hp2ps
-arranges for this area to be approximately centered on a sheet of a4
-paper. This format is convenient of studying the graph in detail, but
-it is unsuitable for inclusion in LaTeX documents. The
-.B \-e
-option causes the graph to be drawn in portrait mode, with
-.I float
-specifying the width in inches, millimetres or points (the default).
-The resulting \*(PS file conforms to the
-.I "Encapsulated Post Script"
-(EPS) convention, and it can be included in a LaTeX document using Rokicki's
-dvi-to-\*(PS converter
-.B dvips.
-.B hp2ps
-requires the width to exceed 2 inches.
-.IP "\fB\-g\fP"
-Create output suitable for the
-.B gs
-\*(PS previewer (or similar). In this case the graph is printed in portrait
-mode without scaling. The output is unsuitable for a laser printer.
-.IP "\fB\-p\fP"
-Use previous parameters. By default, the \*(PS graph is automatically
-scaled both horizontally and vertically so that it fills the page.
-However, when preparing a seires of graphs for use in a presentation,
-it is often useful to draw a new graph using the same scale, shading and
-ordering as a previous one. The
-.B \-p
-flag causes the graph to be drawn using the parameters determined by
-a previous run of
-.B hp2ps
-on
-.IR file.
-.IP "\fB\-s\fP"
-Use a small box for the title.
-.IP "\fB\-y\fP"
-Draw the graph in the traditional York style, ignoring marks.
-.IP "\fB\-?\fP"
-Print out usage information.
-.SH "INPUT FORMAT"
-The format of a heap profile is best described by example:
-.Ex
-JOB "a.out -p"
-DATE "Fri Apr 17 11:43:45 1992"
-SAMPLE_UNIT "seconds"
-VALUE_UNIT "bytes"
-BEGIN_SAMPLE 0.00
- SYSTEM 24
-END_SAMPLE 0.00
-BEGIN_SAMPLE 1.00
- elim 180
- insert 24
- intersect 12
- disin 60
- main 12
- reduce 20
- SYSTEM 12
-END_SAMPLE 1.00
-MARK 1.50
-MARK 1.75
-MARK 1.80
-BEGIN_SAMPLE 2.00
- elim 192
- insert 24
- intersect 12
- disin 84
- main 12
- SYSTEM 24
-END_SAMPLE 2.00
-BEGIN_SAMPLE 2.82
-END_SAMPLE 2.82
-
-.Xe
-.SH "SEE ALSO"
-dvips(1), latex(1), hbchp (1), lmlchp(1)
-.br
-C. Runciman and D. Wakeling,
-.I
-Heap Profiling for Lazy Functional Languages, YCS-172, University of York, 1992
-.SH NOTES
-\*(PS is a registered trademark of Adobe Systems Incorporated.
-.SH AUTHOR
-David Wakeling of the University of York.
diff --git a/massif/ms_main.c b/massif/ms_main.c
index a5a3cc1..97bf2ee 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -1,7 +1,6 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Massif: a heap profiling tool. ms_main.c ---*/
-/*--------------------------------------------------------------------*/
+//--------------------------------------------------------------------*/
+//--- Massif: a heap profiling tool. ms_main.c ---*/
+//--------------------------------------------------------------------*/
/*
This file is part of Massif, a Valgrind tool for profiling memory
@@ -28,11 +27,182 @@
The GNU General Public License is contained in the file COPYING.
*/
-// Memory profiler. Produces a graph, gives lots of information about
-// allocation contexts, in terms of space.time values (ie. area under the
-// graph). Allocation context information is hierarchical, and can thus
-// be inspected step-wise to an appropriate depth. See comments on data
-// structures below for more info on how things work.
+//---------------------------------------------------------------------------
+// XXX:
+//---------------------------------------------------------------------------
+// Todo -- critical for release:
+// - do a graph-drawing test
+// - write a good basic test that shows how the tool works, suitable for
+// documentation
+// - write documentation
+// - make --threshold and --peak-inaccuracy fractional
+// - do filename properly, clean up Valgrind-wide log file naming mess
+// - currently recording asked-for sizes of heap blocks, not actual sizes.
+// Should add the difference to heap-admin, and change heap-admin name to
+// something else (heap-extra?).
+//
+// Todo -- nice, but less critical:
+// - make file format more generic. Obstacles:
+// - unit prefixes are not generic
+// - preset column widths for stats are not generic
+// - preset column headers are not generic
+// - "Massif arguments:" line is not generic
+// - do snapshots on client requests
+// - (Michael Meeks): have an interactive way to request a dump
+// (callgrind_control-style)
+// - "profile now"
+// - "show me the extra allocations since the last snapshot"
+// - "start/stop logging" (eg. quickly skip boring bits)
+// - Add ability to draw multiple graphs, eg. heap-only, stack-only, total.
+// Give each graph a title. (try to do it generically!)
+// - allow truncation of long fnnames if the exact line number is
+// identified? [hmm, could make getting the name of alloc-fns more
+// difficult] [could dump full names to file, truncate in ms_print]
+// - make --show-below-main=no work
+//
+// Performance:
+// - To run the benchmarks:
+//
+// perl perf/vg_perf --tools=massif --reps=3 perf/{heap,tinycc} massif
+// time valgrind --tool=massif --depth=100 konqueror
+//
+// The other benchmarks don't do much allocation, and so give similar speeds
+// to Nulgrind.
+//
+// Timing results on 'nevermore' (njn's machine) as of r7013:
+//
+// heap 0.53s ma:12.4s (23.5x, -----)
+// tinycc 0.46s ma: 4.9s (10.7x, -----)
+// many-xpts 0.08s ma: 2.0s (25.0x, -----)
+// konqueror 29.6s real 0:21.0s user
+//
+// - get_XCon accounts for about 9% of konqueror startup time. Try
+// keeping XPt children sorted by 'ip' and use binary search in get_XCon.
+// Requires factoring out binary search code from various places into a
+// VG_(bsearch) function.
+//
+// Todo -- low priority:
+// - Consider 'instructions executed' as a time unit -- more regular than
+// ms, less artificial than B (bug #121629).
+// - In each XPt, record both bytes and the number of allocations, and
+// possibly the global number of allocations.
+// - (Artur Wisz) add a feature to Massif to ignore any heap blocks larger
+// than a certain size! Because: "linux's malloc allows to set a
+// MMAP_THRESHOLD value, so we set it to 4096 - all blocks above that will
+// be handled directly by the kernel, and are guaranteed to be returned to
+// the system when freed. So we needed to profile only blocks below this
+// limit."
+//
+// Examine and fix bugs on bugzilla:
+// IGNORE:
+// 112163 nor MASSIF crashed with signal 7 (SIGBUS) after running 2 days
+// - weird, crashes in VEX, ignore
+// 82871 nor Massif output function names too short
+// - on .ps graph, now irrelevant, ignore
+// 129576 nor Massif loses track of memory, incorrect graphs
+// - dunno, hard to reproduce, ignore
+// 132132 nor massif --format=html output does not do html entity escaping
+// - only for HTML output, irrelevant, ignore
+// 132950 Heap alloc/usage summary
+// - doesn't seem that interesting or general
+//
+// FIXED/NOW IRRELEVANT:
+// 89061 cra Massif: ms_main.c:485 (get_XCon): Assertion `xpt->max_chi...
+// - relevant code now gone
+// 143062 cra massif crashes on app exit with signal 8 SIGFPE
+// - fixed
+// 95483 nor massif feature request: include peak allocation in report
+// - implemented in Massif2
+// 92615 nor Write output from Massif at crash
+// - this happens unless Massif2 itself crashes
+// 121629 add instruction-counting mode for timing
+// - time-unit=B is similar, plus I'm considering this above anyway
+// 142197 nor massif tool ignores --massif:alloc-fn parameters in .valg...
+// - fixed in trunk
+// 142491 nor Maximise use of alloc_fns array
+// - addressed, it's now an XArray and thus unlimited in size
+// 144453 (get_XCon): Assertion 'xpt->max_children != 0' failed.
+// - relevant code now gone
+//
+// POSSIBLY FIXED BY BETTER SANITY CHECKING, BUT HARD TO TELL:
+// 141631 Massif: percentages don't add up correctly
+// - better sanity-checking should help this greatly
+// 142706 massif numbers don't seem to add up
+// - better sanity-checking should help this greatly
+// 149504 Assertion hit on alloc_xpt->curr_space >= -space_delta
+// - better sanity-checking should help this greatly
+// 146456 (update_XCon): Assertion 'xpt->curr_space >= -space_delta' failed.
+// - better sanity-checking should help this greatly
+//
+// File format working notes:
+
+#if 0
+desc: --heap-admin=foo
+cmd: date
+time_unit: ms
+#-----------
+snapshot=0
+#-----------
+time=0
+mem_heap_B=0
+mem_heap_admin_B=0
+mem_stacks_B=0
+heap_tree=empty
+#-----------
+snapshot=1
+#-----------
+time=353
+mem_heap_B=5
+mem_heap_admin_B=0
+mem_stacks_B=0
+heap_tree=detailed
+n1: 5 (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+ n1: 5 0x27F6E0: _nl_normalize_codeset (in /lib/libc-2.3.5.so)
+ n1: 5 0x279DE6: _nl_load_locale_from_archive (in /lib/libc-2.3.5.so)
+ n1: 5 0x278E97: _nl_find_locale (in /lib/libc-2.3.5.so)
+ n1: 5 0x278871: setlocale (in /lib/libc-2.3.5.so)
+ n1: 5 0x8049821: (within /bin/date)
+ n0: 5 0x26ED5E: (below main) (in /lib/libc-2.3.5.so)
+
+
+n_events: n time(ms) total(B) useful-heap(B) admin-heap(B) stacks(B)
+t_events: B
+n 0 0 0 0 0
+n 0 0 0 0 0
+t1: 5 <string...>
+ t1: 6 <string...>
+
+Ideas:
+- each snapshot specifies an x-axis value and one or more y-axis values.
+- can display the y-axis values separately if you like
+- can completely separate connection between snapshots and trees.
+
+Challenges:
+- how to specify and scale/abbreviate units on axes?
+- how to combine multiple values into the y-axis?
+
+--------------------------------------------------------------------------------Command: date
+Massif arguments: --heap-admin=foo
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+ KB
+6.472^ :#
+ | :# :: . .
+ ...
+ | ::@ :@ :@ :@:::# :: : ::::
+ 0 +-----------------------------------@---@---@-----@--@---#-------------->ms 0 713
+
+Number of snapshots: 50
+ Detailed snapshots: [2, 11, 13, 19, 25, 32 (peak)]
+-------------------------------------------------------------------------------- n time(ms) total(B) useful-heap(B) admin-heap(B) stacks(B)
+-------------------------------------------------------------------------------- 0 0 0 0 0 0
+ 1 345 5 5 0 0
+ 2 353 5 5 0 0
+100.00% (5B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (5B) 0x27F6E0: _nl_normalize_codeset (in /lib/libc-2.3.5.so)
+#endif
+
+//---------------------------------------------------------------------------
#include "pub_tool_basics.h"
#include "pub_tool_vki.h"
@@ -55,153 +225,49 @@
#include "valgrind.h" // For {MALLOC,FREE}LIKE_BLOCK
-/*------------------------------------------------------------*/
-/*--- Overview of operation ---*/
-/*------------------------------------------------------------*/
+//------------------------------------------------------------*/
+//--- Overview of operation ---*/
+//------------------------------------------------------------*/
-// Heap blocks are tracked, and the amount of space allocated by various
-// contexts (ie. lines of code, more or less) is also tracked.
-// Periodically, a census is taken, and the amount of space used, at that
-// point, by the most significant (highly allocating) contexts is recorded.
-// Census start off frequently, but are scaled back as the program goes on,
-// so that there are always a good number of them. At the end, overall
-// spacetimes for different contexts (of differing levels of precision) is
-// calculated, the graph is printed, and the text giving spacetimes for the
-// increasingly precise contexts is given.
+// The size of the stacks and heap is tracked. The heap is tracked in a lot
+// of detail, enough to tell how many bytes each line of code is responsible
+// for, more or less. The main data structure is a tree representing the
+// call tree beneath all the allocation functions like malloc().
//
-// Measures the following:
-// - heap blocks
-// - heap admin bytes
-// - stack(s)
-// - code (code segments loaded at startup, and loaded with mmap)
-// - data (data segments loaded at startup, and loaded/created with mmap,
-// and brk()d segments)
-
-/*------------------------------------------------------------*/
-/*--- Main types ---*/
-/*------------------------------------------------------------*/
-
-// An XPt represents an "execution point", ie. a code address. Each XPt is
-// part of a tree of XPts (an "execution tree", or "XTree"). Each
-// top-to-bottom path through an XTree gives an execution context ("XCon"),
-// and is equivalent to a traditional Valgrind ExeContext.
+// "Snapshots" are recordings of the memory usage. There are two basic
+// kinds:
+// - Normal: these record the current time, total memory size, total heap
+// size, heap admin size and stack size.
+// - Detailed: these record those things in a normal snapshot, plus a very
+// detailed XTree (see below) indicating how the heap is structured.
//
-// The XPt at the top of an XTree (but below "alloc_xpt") is called a
-// "top-XPt". The XPts are the bottom of an XTree (leaf nodes) are
-// "bottom-XPTs". The number of XCons in an XTree is equal to the number of
-// bottom-XPTs in that XTree.
-//
-// All XCons have the same top-XPt, "alloc_xpt", which represents all
-// allocation functions like malloc(). It's a bit of a fake XPt, though,
-// and is only used because it makes some of the code simpler.
-//
-// XTrees are bi-directional.
-//
-// > parent < Example: if child1() calls parent() and child2()
-// / | \ also calls parent(), and parent() calls malloc(),
-// | / \ | the XTree will look like this.
-// | v v |
-// child1 child2
+// Snapshots are taken every so often. There are two storage classes of
+// snapshots:
+// - Temporary: Massif does a temporary snapshot every so often. The idea
+// is to always have a certain number of temporary snapshots around. So
+// we take them frequently to begin with, but decreasingly often as the
+// program continues to run. Also, we remove some old ones after a while.
+// Overall it's a kind of exponential decay thing. Most of these are
+// normal snapshots, a small fraction are detailed snapshots.
+// - Permanent: Massif takes a permanent (detailed) snapshot in some
+// circumstances. They are:
+// - Peak snapshot: When the memory usage peak is reached, it takes a
+// snapshot. It keeps this, unless the peak is subsequently exceeded,
+// in which case it will overwrite the peak snapshot.
+// - User-requested snapshots: These are done in response to client
+// requests. They are always kept.
-typedef struct _XPt XPt;
-
-struct _XPt {
- Addr ip; // code address
-
- // Bottom-XPts: space for the precise context.
- // Other XPts: space of all the descendent bottom-XPts.
- // Nb: this value goes up and down as the program executes.
- UInt curr_space;
-
- // An approximate space.time calculation used along the way for selecting
- // which contexts to include at each census point.
- // !!! top-XPTs only !!!
- ULong approx_ST;
-
- // exact_ST_dbld is an exact space.time calculation done at the end, and
- // used in the results.
- // Note that it is *doubled*, to avoid rounding errors.
- // !!! not used for 'alloc_xpt' !!!
- ULong exact_ST_dbld;
-
- // n_children and max_children are integers; a very big program might
- // have more than 65536 allocation points (Konqueror startup has 1800).
- XPt* parent; // pointer to parent XPt
- UInt n_children; // number of children
- UInt max_children; // capacity of children array
- XPt** children; // pointers to children XPts
-};
-
-// Each census snapshots the most significant XTrees, each XTree having a
-// top-XPt as its root. The 'curr_space' element for each XPt is recorded
-// in the snapshot. The snapshot contains all the XTree's XPts, not in a
-// tree structure, but flattened into an array. This flat snapshot is used
-// at the end for computing exact_ST_dbld for each XPt.
-//
-// Graph resolution, x-axis: no point having more than about 200 census
-// x-points; you can't see them on the graph. Therefore:
-//
-// - do a census every 1 ms for first 200 --> 200, all (200 ms)
-// - halve (drop half of them) --> 100, every 2nd (200 ms)
-// - do a census every 2 ms for next 200 --> 200, every 2nd (400 ms)
-// - halve --> 100, every 4th (400 ms)
-// - do a census every 4 ms for next 400 --> 200, every 4th (800 ms)
-// - etc.
-//
-// This isn't exactly right, because we actually drop (N/2)-1 when halving,
-// but it shows the basic idea.
-
-#define MAX_N_CENSI 200 // Keep it even, for simplicity
-
-// Graph resolution, y-axis: hp2ps only draws the 19 biggest (in space-time)
-// bands, rest get lumped into OTHERS. I only print the top N
-// (cumulative-so-far space-time) at each point. N should be a bit bigger
-// than 19 in case the cumulative space-time doesn't fit with the eventual
-// space-time computed by hp2ps (but it should be close if the samples are
-// evenly spread, since hp2ps does an approximate per-band space-time
-// calculation that just sums the totals; ie. it assumes all samples are
-// the same distance apart).
-
-#define MAX_SNAPSHOTS 32
-
-typedef
- struct {
- XPt* xpt;
- UInt space;
+// Used for printing things when clo_verbosity > 1.
+#define VERB(verb, format, args...) \
+ if (VG_(clo_verbosity) > verb) { \
+ VG_(message)(Vg_DebugMsg, "Massif: " format, ##args); \
}
- XPtSnapshot;
-// An XTree snapshot is stored as an array of of XPt snapshots.
-typedef XPtSnapshot* XTreeSnapshot;
-typedef
- struct {
- Int ms_time; // Int: must allow -1
- XTreeSnapshot xtree_snapshots[MAX_SNAPSHOTS+1]; // +1 for zero-termination
- UInt others_space;
- UInt heap_admin_space;
- UInt stacks_space;
- }
- Census;
-// Metadata for heap blocks. Each one contains a pointer to a bottom-XPt,
-// which is a foothold into the XCon at which it was allocated. From
-// HP_Chunks, XPt 'space' fields are incremented (at allocation) and
-// decremented (at deallocation).
-//
-// Nb: first two fields must match core's VgHashNode.
-typedef
- struct _HP_Chunk {
- struct _HP_Chunk* next;
- Addr data; // Ptr to actual block
- SizeT size; // Size requested
- XPt* where; // Where allocated; bottom-XPt
- }
- HP_Chunk;
-
-/*------------------------------------------------------------*/
-/*--- Statistics ---*/
-/*------------------------------------------------------------*/
+//------------------------------------------------------------//
+//--- Statistics ---//
+//------------------------------------------------------------//
// Konqueror startup, to give an idea of the numbers involved with a biggish
// program, with default depth:
@@ -212,102 +278,163 @@
// - 15,000 XPts 800,000 XPts
// - 1,800 top-XPts
-static UInt n_xpts = 0;
-static UInt n_bot_xpts = 0;
-static UInt n_allocs = 0;
-static UInt n_zero_allocs = 0;
-static UInt n_frees = 0;
-static UInt n_children_reallocs = 0;
-static UInt n_snapshot_frees = 0;
+static UInt n_heap_allocs = 0;
+static UInt n_heap_reallocs = 0;
+static UInt n_heap_frees = 0;
+static UInt n_stack_allocs = 0;
+static UInt n_stack_frees = 0;
+static UInt n_xpts = 0;
+static UInt n_xpt_init_expansions = 0;
+static UInt n_xpt_later_expansions = 0;
+static UInt n_sxpt_allocs = 0;
+static UInt n_sxpt_frees = 0;
+static UInt n_skipped_snapshots = 0;
+static UInt n_real_snapshots = 0;
+static UInt n_detailed_snapshots = 0;
+static UInt n_peak_snapshots = 0;
+static UInt n_cullings = 0;
+static UInt n_XCon_redos = 0;
-static UInt n_halvings = 0;
-static UInt n_real_censi = 0;
-static UInt n_fake_censi = 0;
-static UInt n_attempted_censi = 0;
+//------------------------------------------------------------//
+//--- Globals ---//
+//------------------------------------------------------------//
-/*------------------------------------------------------------*/
-/*--- Globals ---*/
-/*------------------------------------------------------------*/
+static SizeT heap_szB = 0; // Live heap size
+static SizeT stacks_szB = 0; // Live stacks size
-#define FILENAME_LEN 256
+// This is the total size from the current peak snapshot, or 0 if no peak
+// snapshot has been taken yet.
+static SizeT peak_snapshot_total_szB = 0;
-#define SPRINTF(zz_buf, fmt, args...) \
- do { Int len = VG_(sprintf)(zz_buf, fmt, ## args); \
- VG_(write)(fd, (void*)zz_buf, len); \
- } while (0)
-
-#define BUF_LEN 1024 // general purpose
-static Char buf [BUF_LEN];
-static Char buf2[BUF_LEN];
-static Char buf3[BUF_LEN];
-
-static SizeT sigstacks_space = 0; // Current signal stacks space sum
-
-static VgHashTable malloc_list = NULL; // HP_Chunks
+// Incremented every time memory is allocated/deallocated, by the
+// allocated/deallocated amount; includes heap, heap-admin and stack
+// memory. An alternative to milliseconds as a unit of program "time".
+static ULong total_allocs_deallocs_szB = 0;
static UInt n_heap_blocks = 0;
// Current directory at startup.
-static Char base_dir[VKI_PATH_MAX];
+static Char base_dir[VKI_PATH_MAX]; // XXX: currently unused
-#define MAX_ALLOC_FNS 128 // includes the builtin ones
+// We don't start taking snapshots until the first basic block is executed,
+// rather than doing it in ms_post_clo_init (which is the obvious spot), for
+// two reasons.
+// - It lets us ignore stack events prior to that, because they're not
+// really proper ones and just would screw things up.
+// - Because there's still some core initialisation to do, and so there
+// would be an artificial time gap between the first and second snapshots.
+//
+static Bool have_started_executing_code = False;
-// First few filled in, rest should be zeroed. Zero-terminated vector.
-static UInt n_alloc_fns = 10;
-static Char* alloc_fns[MAX_ALLOC_FNS] = {
- "malloc",
- "operator new(unsigned)",
- "operator new[](unsigned)",
- "operator new(unsigned, std::nothrow_t const&)",
- "operator new[](unsigned, std::nothrow_t const&)",
- "__builtin_new",
- "__builtin_vec_new",
- "calloc",
- "realloc",
- "memalign",
-};
+//------------------------------------------------------------//
+//--- Alloc fns ---//
+//------------------------------------------------------------//
+static XArray* alloc_fns;
-/*------------------------------------------------------------*/
-/*--- Command line args ---*/
-/*------------------------------------------------------------*/
+static void init_alloc_fns(void)
+{
+ // Create the list, and add the default elements.
+ alloc_fns = VG_(newXA)(VG_(malloc), VG_(free), sizeof(Char*));
+ #define DO(x) { Char* s = x; VG_(addToXA)(alloc_fns, &s); }
-#define MAX_DEPTH 50
+ // Ordered according to (presumed) frequency.
+ // Nb: The C++ "operator new*" ones are overloadable. We include them
+ // always anyway, because even if they're overloaded, it would be a
+ // prodigiously stupid overloading that caused them to not allocate
+ // memory.
+ DO("malloc" );
+ DO("__builtin_new" );
+ DO("operator new(unsigned)" );
+ DO("operator new(unsigned long)" );
+ DO("__builtin_vec_new" );
+ DO("operator new[](unsigned)" );
+ DO("operator new[](unsigned long)" );
+ DO("calloc" );
+ DO("realloc" );
+ DO("memalign" );
+ DO("operator new(unsigned, std::nothrow_t const&)" );
+ DO("operator new[](unsigned, std::nothrow_t const&)" );
+ DO("operator new(unsigned long, std::nothrow_t const&)" );
+ DO("operator new[](unsigned long, std::nothrow_t const&)");
+}
-typedef
- enum {
- XText, XHTML,
+static Bool is_alloc_fn(Char* fnname)
+{
+ Char** alloc_fn_ptr;
+ Int i;
+
+ // Nb: It's a linear search through the list, because we're comparing
+ // strings rather than pointers to strings.
+ // Nb: This gets called a lot. It was an OSet, but they're quite slow to
+ // iterate through so it wasn't a good choice.
+ for (i = 0; i < VG_(sizeXA)(alloc_fns); i++) {
+ alloc_fn_ptr = VG_(indexXA)(alloc_fns, i);
+ if (VG_STREQ(fnname, *alloc_fn_ptr))
+ return True;
}
- XFormat;
+ return False;
+}
-static Bool clo_heap = True;
-static UInt clo_heap_admin = 8;
-static Bool clo_stacks = True;
-static Bool clo_depth = 3;
-static XFormat clo_format = XText;
+
+//------------------------------------------------------------//
+//--- Command line args ---//
+//------------------------------------------------------------//
+
+#define MAX_DEPTH 200
+
+typedef enum { TimeMS, TimeB } TimeUnit;
+
+static Char* TimeUnit_to_string(TimeUnit time_unit)
+{
+ switch (time_unit) {
+ case TimeMS: return "ms";
+ case TimeB: return "B";
+ default: tl_assert2(0, "TimeUnit_to_string: unrecognised TimeUnit");
+ }
+}
+
+static Bool clo_heap = True;
+static UInt clo_heap_admin = 8;
+static Bool clo_stacks = False;
+static UInt clo_depth = 30;
+static UInt clo_threshold = 100; // 100 == 1%
+static UInt clo_peak_inaccuracy = 100; // 100 == 1%
+static UInt clo_time_unit = TimeMS;
+static UInt clo_detailed_freq = 10;
+static UInt clo_max_snapshots = 100;
+
+static XArray* args_for_massif;
static Bool ms_process_cmd_line_option(Char* arg)
{
- VG_BOOL_CLO(arg, "--heap", clo_heap)
- else VG_BOOL_CLO(arg, "--stacks", clo_stacks)
+ // Remember the arg for later use.
+ VG_(addToXA)(args_for_massif, &arg);
- else VG_NUM_CLO (arg, "--heap-admin", clo_heap_admin)
- else VG_BNUM_CLO(arg, "--depth", clo_depth, 1, MAX_DEPTH)
+ VG_BOOL_CLO(arg, "--heap", clo_heap)
+ else VG_BOOL_CLO(arg, "--stacks", clo_stacks)
+
+ // XXX: "--heap-admin= " is accepted!
+ else VG_NUM_CLO(arg, "--heap-admin", clo_heap_admin)
+ else VG_NUM_CLO(arg, "--depth", clo_depth)
+
+ // XXX: use a fractional number, so no division by 100
+ else VG_NUM_CLO(arg, "--threshold", clo_threshold)
+
+ // XXX: use a fractional number, so no division by 100
+ else VG_NUM_CLO(arg, "--peak-inaccuracy", clo_peak_inaccuracy)
+
+ else VG_NUM_CLO(arg, "--detailed-freq", clo_detailed_freq)
+ else VG_NUM_CLO(arg, "--max-snapshots", clo_max_snapshots)
+
+ else if (VG_CLO_STREQ(arg, "--time-unit=ms")) clo_time_unit = TimeMS;
+ else if (VG_CLO_STREQ(arg, "--time-unit=B")) clo_time_unit = TimeB;
else if (VG_CLO_STREQN(11, arg, "--alloc-fn=")) {
- alloc_fns[n_alloc_fns] = & arg[11];
- n_alloc_fns++;
- if (n_alloc_fns >= MAX_ALLOC_FNS) {
- VG_(printf)("Too many alloc functions specified, sorry");
- VG_(err_bad_option)(arg);
- }
+ Char* alloc_fn = &arg[11];
+ VG_(addToXA)(alloc_fns, &alloc_fn);
}
- else if (VG_CLO_STREQ(arg, "--format=text"))
- clo_format = XText;
- else if (VG_CLO_STREQ(arg, "--format=html"))
- clo_format = XHTML;
-
else
return VG_(replacement_malloc_process_cmd_line_option)(arg);
@@ -316,13 +443,22 @@
static void ms_print_usage(void)
{
- VG_(printf)(
+ VG_(printf)(
" --heap=no|yes profile heap blocks [yes]\n"
-" --heap-admin=<number> average admin bytes per heap block [8]\n"
-" --stacks=no|yes profile stack(s) [yes]\n"
-" --depth=<number> depth of contexts [3]\n"
+" --heap-admin=<number> average admin bytes per heap block;"
+" ignored if --heap=no [8]\n"
+" --stacks=no|yes profile stack(s) [no]\n"
+" --depth=<number> depth of contexts [30]\n"
" --alloc-fn=<name> specify <fn> as an alloc function [empty]\n"
-" --format=text|html format of textual output [text]\n"
+" --threshold=<n> significance threshold, in 100ths of a percent\n"
+" (eg. <n>=100 shows nodes covering >= 1%% of\n"
+" total size, <n>=0 shows all nodes) [100]\n"
+" --peak-inaccuracy=<n> closeness of recorded peak to true peak,\n"
+" in 100ths of a percent\n"
+" --time-unit=ms|B time unit, milliseconds or bytes\n"
+" alloc'd/dealloc'd on the heap [ms]\n"
+" --detailed-freq=<N> every Nth snapshot should be detailed [10]\n"
+" --max-snapshots=<N> maximum number of snapshots recorded [100]\n"
);
VG_(replacement_malloc_print_usage)();
}
@@ -332,9 +468,98 @@
VG_(replacement_malloc_print_debug_usage)();
}
-/*------------------------------------------------------------*/
-/*--- Execution contexts ---*/
-/*------------------------------------------------------------*/
+
+//------------------------------------------------------------//
+//--- XPts, XTrees and XCons ---//
+//------------------------------------------------------------//
+
+// An XPt represents an "execution point", ie. a code address. Each XPt is
+// part of a tree of XPts (an "execution tree", or "XTree"). The details of
+// the heap are represented by a single XTree.
+//
+// The root of the tree is 'alloc_xpt', which represents all allocation
+// functions, eg:
+// - malloc/calloc/realloc/memalign/new/new[];
+// - user-specified allocation functions (using --alloc-fn);
+// - custom allocation (MALLOCLIKE) points
+// It's a bit of a fake XPt (ie. its 'ip' is zero), and is only used because
+// it makes the code simpler.
+//
+// Any child of 'alloc_xpt' is called a "top-XPt". The XPts at the bottom
+// of an XTree (leaf nodes) are "bottom-XPTs".
+//
+// Each path from a top-XPt to a bottom-XPt through an XTree gives an
+// execution context ("XCon"), ie. a stack trace. (And sub-paths represent
+// stack sub-traces.) The number of XCons in an XTree is equal to the
+// number of bottom-XPTs in that XTree.
+//
+// alloc_xpt XTrees are bi-directional.
+// | ^
+// v |
+// > parent < Example: if child1() calls parent() and child2()
+// / | \ also calls parent(), and parent() calls malloc(),
+// | / \ | the XTree will look like this.
+// | v v |
+// child1 child2
+//
+// XTrees and XPts are mirrored by SXTrees and SXPts, where the 'S' is short
+// for "saved". When the XTree is duplicated for a snapshot, we duplicate
+// it as an SXTree, which is similar but omits some things it does not need,
+// and aggregates up insignificant nodes. This is important as an SXTree is
+// typically much smaller than an XTree.
+
+// XXX: make XPt and SXPt extensible arrays, to avoid having to do two
+// allocations per Pt.
+
+typedef struct _XPt XPt;
+struct _XPt {
+ Addr ip; // code address
+
+ // Bottom-XPts: space for the precise context.
+ // Other XPts: space of all the descendent bottom-XPts.
+ // Nb: this value goes up and down as the program executes.
+ SizeT szB;
+
+ XPt* parent; // pointer to parent XPt
+
+ // Children.
+ // n_children and max_children are 32-bit integers. 16-bit integers
+ // are too small -- a very big program might have more than 65536
+ // allocation points (ie. top-XPts) -- Konqueror starting up has 1800.
+ UInt n_children; // number of children
+ UInt max_children; // capacity of children array
+ XPt** children; // pointers to children XPts
+};
+
+typedef
+ enum {
+ SigSXPt,
+ InsigSXPt
+ }
+ SXPtTag;
+
+typedef struct _SXPt SXPt;
+struct _SXPt {
+ SXPtTag tag;
+ SizeT szB; // memory size for the node, be it Sig or Insig
+ union {
+ // An SXPt representing a single significant code location. Much like
+ // an XPt, minus the fields that aren't necessary.
+ struct {
+ Addr ip;
+ UInt n_children;
+ SXPt** children;
+ }
+ Sig;
+
+ // An SXPt representing one or more code locations, all below the
+ // significance threshold.
+ struct {
+ Int n_xpts; // number of aggregated XPts
+ }
+ Insig;
+ };
+};
// Fake XPt representing all allocation functions like malloc(). Acts as
// parent node to all top-XPts.
@@ -352,7 +577,7 @@
if (hp + n_bytes > hp_lim) {
hp = (Addr)VG_(am_shadow_alloc)(SUPERBLOCK_SIZE);
if (hp == 0)
- VG_(out_of_memory_NORETURN)( "massif:perm_malloc",
+ VG_(out_of_memory_NORETURN)( "massif:perm_malloc",
SUPERBLOCK_SIZE);
hp_lim = hp + SUPERBLOCK_SIZE - 1;
}
@@ -362,35 +587,22 @@
return (void*)(hp - n_bytes);
}
-
-
-static XPt* new_XPt(Addr ip, XPt* parent, Bool is_bottom)
+static XPt* new_XPt(Addr ip, XPt* parent)
{
- XPt* xpt = perm_malloc(sizeof(XPt));
- xpt->ip = ip;
+ // XPts are never freed, so we can use perm_malloc to allocate them.
+ // Note that we cannot use perm_malloc for the 'children' array, because
+ // that needs to be resizable.
+ XPt* xpt = perm_malloc(sizeof(XPt));
+ xpt->ip = ip;
+ xpt->szB = 0;
+ xpt->parent = parent;
- xpt->curr_space = 0;
- xpt->approx_ST = 0;
- xpt->exact_ST_dbld = 0;
-
- xpt->parent = parent;
-
- // Check parent is not a bottom-XPt
- tl_assert(parent == NULL || 0 != parent->max_children);
-
+ // We don't initially allocate any space for children. We let that
+ // happen on demand. Many XPts (ie. all the bottom-XPts) don't have any
+ // children anyway.
xpt->n_children = 0;
-
- // If a bottom-XPt, don't allocate space for children. This can be 50%
- // or more, although it tends to drop as --depth increases (eg. 10% for
- // konqueror with --depth=20).
- if ( is_bottom ) {
- xpt->max_children = 0;
- xpt->children = NULL;
- n_bot_xpts++;
- } else {
- xpt->max_children = 4;
- xpt->children = VG_(malloc)( xpt->max_children * sizeof(XPt*) );
- }
+ xpt->max_children = 0;
+ xpt->children = NULL;
// Update statistics
n_xpts++;
@@ -398,277 +610,887 @@
return xpt;
}
-static Bool is_alloc_fn(Addr ip)
+static void add_child_xpt(XPt* parent, XPt* child)
+{
+ // Expand 'children' if necessary.
+ tl_assert(parent->n_children <= parent->max_children);
+ if (parent->n_children == parent->max_children) {
+ if (parent->max_children == 0) {
+ parent->max_children = 4;
+ parent->children = VG_(malloc)( parent->max_children * sizeof(XPt*) );
+ n_xpt_init_expansions++;
+ } else {
+ parent->max_children *= 2; // Double size
+ parent->children = VG_(realloc)( parent->children,
+ parent->max_children * sizeof(XPt*) );
+ n_xpt_later_expansions++;
+ }
+ }
+
+ // Insert new child XPt in parent's children list.
+ parent->children[ parent->n_children++ ] = child;
+}
+
+// Reverse comparison for a reverse sort -- biggest to smallest.
+static Int SXPt_revcmp_szB(void* n1, void* n2)
+{
+ SXPt* sxpt1 = *(SXPt**)n1;
+ SXPt* sxpt2 = *(SXPt**)n2;
+ return ( sxpt1->szB < sxpt2->szB ? 1
+ : sxpt1->szB > sxpt2->szB ? -1
+ : 0);
+}
+
+//------------------------------------------------------------//
+//--- XTree Operations ---//
+//------------------------------------------------------------//
+
+// Duplicates an XTree as an SXTree.
+static SXPt* dup_XTree(XPt* xpt, SizeT total_szB)
+{
+ Int i, n_sig_children, n_insig_children, n_child_sxpts;
+ SizeT insig_children_szB, sig_child_threshold_szB;
+ SXPt* sxpt;
+
+ // Number of XPt children Action for SXPT
+ // ------------------ ---------------
+ // 0 sig, 0 insig alloc 0 children
+ // N sig, 0 insig alloc N children, dup all
+ // N sig, M insig alloc N+1, dup first N, aggregate remaining M
+ // 0 sig, M insig alloc 1, aggregate M
+
+ // Work out how big a child must be to be significant. If the current
+ // total_szB is zero, then we set it to 1, which means everything will be
+ // judged insignificant -- this is sensible, as there's no point showing
+ // any detail for this case. Unless they used --threshold=0, in which
+ // case we show them everything because that's what they asked for.
+ //
+ // Nb: We do this once now, rather than once per child, because if we do
+ // that the cost of all the divisions adds up to something significant.
+ if (total_szB == 0 && clo_threshold != 0) {
+ sig_child_threshold_szB = 1;
+ } else {
+ sig_child_threshold_szB = (((ULong)total_szB) * clo_threshold) / 10000ULL;
+ }
+
+ // How many children are significant? And do we need an aggregate SXPt?
+ n_sig_children = 0;
+ for (i = 0; i < xpt->n_children; i++) {
+ if (xpt->children[i]->szB >= sig_child_threshold_szB) {
+ n_sig_children++;
+ }
+ }
+ n_insig_children = xpt->n_children - n_sig_children;
+ n_child_sxpts = n_sig_children + ( n_insig_children > 0 ? 1 : 0 );
+
+ // Duplicate the XPt.
+ sxpt = VG_(malloc)(sizeof(SXPt));
+ n_sxpt_allocs++;
+ sxpt->tag = SigSXPt;
+ sxpt->szB = xpt->szB;
+ sxpt->Sig.ip = xpt->ip;
+ sxpt->Sig.n_children = n_child_sxpts;
+
+ // Create the SXPt's children.
+ if (n_child_sxpts > 0) {
+ Int j;
+ SizeT sig_children_szB = 0;
+ sxpt->Sig.children = VG_(malloc)(n_child_sxpts * sizeof(SXPt*));
+
+ // Duplicate the significant children.
+ j = 0;
+ for (i = 0; i < xpt->n_children; i++) {
+ if (xpt->children[i]->szB >= sig_child_threshold_szB) {
+ sxpt->Sig.children[j++] = dup_XTree(xpt->children[i], total_szB);
+ sig_children_szB += xpt->children[i]->szB;
+ }
+ }
+
+ // Create the SXPt for the insignificant children, if any, and put it
+ // in the last child entry.
+ insig_children_szB = sxpt->szB - sig_children_szB;
+ if (n_insig_children > 0) {
+ // Nb: We 'n_sxpt_allocs' here because creating an Insig SXPt
+ // doesn't involve a call to dup_XTree().
+ SXPt* insig_sxpt = VG_(malloc)(sizeof(SXPt));
+ n_sxpt_allocs++;
+ insig_sxpt->tag = InsigSXPt;
+ insig_sxpt->szB = insig_children_szB;
+ insig_sxpt->Insig.n_xpts = n_insig_children;
+ sxpt->Sig.children[n_sig_children] = insig_sxpt;
+ }
+ } else {
+ sxpt->Sig.children = NULL;
+ }
+
+ return sxpt;
+}
+
+static void free_SXTree(SXPt* sxpt)
+{
+ Int i;
+ tl_assert(sxpt != NULL);
+
+ switch (sxpt->tag) {
+ case SigSXPt:
+ // Free all children SXPts, then the children array.
+ for (i = 0; i < sxpt->Sig.n_children; i++) {
+ free_SXTree(sxpt->Sig.children[i]);
+ sxpt->Sig.children[i] = NULL;
+ }
+ VG_(free)(sxpt->Sig.children); sxpt->Sig.children = NULL;
+ break;
+
+ case InsigSXPt:
+ break;
+
+ default: tl_assert2(0, "free_SXTree: unknown SXPt tag");
+ }
+
+ // Free the SXPt itself.
+ VG_(free)(sxpt); sxpt = NULL;
+ n_sxpt_frees++;
+}
+
+// Sanity checking: we periodically check the heap XTree with
+// ms_expensive_sanity_check.
+static void sanity_check_XTree(XPt* xpt, XPt* parent)
{
Int i;
- if ( VG_(get_fnname)(ip, buf, BUF_LEN) ) {
- for (i = 0; i < n_alloc_fns; i++) {
- if (VG_STREQ(buf, alloc_fns[i]))
- return True;
+ tl_assert(xpt != NULL);
+
+ // Check back-pointer.
+ tl_assert2(xpt->parent == parent,
+ "xpt->parent = %p, parent = %p\n", xpt->parent, parent);
+
+ // Check children counts look sane.
+ tl_assert(xpt->n_children <= xpt->max_children);
+
+ // Check the sum of any children szBs equals the XPt's szB. Check the
+ // children at the same time.
+ if (xpt->n_children > 0) {
+ SizeT children_sum_szB = 0;
+ for (i = 0; i < xpt->n_children; i++) {
+ sanity_check_XTree(xpt->children[i], xpt);
+ children_sum_szB += xpt->children[i]->szB;
}
+ tl_assert(children_sum_szB == xpt->szB);
}
- return False;
}
-// Returns an XCon, from the bottom-XPt. Nb: the XPt returned must be a
-// bottom-XPt now and must always remain a bottom-XPt. We go to some effort
-// to ensure this in certain cases. See comments below.
-static XPt* get_XCon( ThreadId tid, Bool custom_malloc )
+// Sanity checking: we check SXTrees (which are in snapshots) after
+// snapshots are created, before they are deleted, and before they are
+// printed.
+static void sanity_check_SXTree(SXPt* sxpt)
{
- // Static to minimise stack size. +1 for added ~0 IP
- static Addr ips[MAX_DEPTH + MAX_ALLOC_FNS + 1];
+ Int i;
- XPt* xpt = alloc_xpt;
- UInt n_ips, L, A, B, nC;
- UInt overestimate;
- Bool reached_bottom;
+ tl_assert(sxpt != NULL);
- // Want at least clo_depth non-alloc-fn entries in the snapshot.
- // However, because we have 1 or more (an unknown number, at this point)
- // alloc-fns ignored, we overestimate the size needed for the stack
- // snapshot. Then, if necessary, we repeatedly increase the size until
- // it is enough.
- overestimate = 2;
- while (True) {
+ // Check the sum of any children szBs equals the SXPt's szB. Check the
+ // children at the same time.
+ switch (sxpt->tag) {
+ case SigSXPt: {
+ if (sxpt->Sig.n_children > 0) {
+ SizeT children_sum_szB = 0;
+ for (i = 0; i < sxpt->Sig.n_children; i++) {
+ sanity_check_SXTree(sxpt->Sig.children[i]);
+ children_sum_szB += sxpt->Sig.children[i]->szB;
+ }
+ tl_assert(children_sum_szB == sxpt->szB);
+ }
+ break;
+ }
+ case InsigSXPt:
+ break; // do nothing
+
+ default: tl_assert2(0, "sanity_check_SXTree: unknown SXPt tag");
+ }
+}
+
+
+//------------------------------------------------------------//
+//--- XCon Operations ---//
+//------------------------------------------------------------//
+
+// This is the limit on the number of removed alloc-fns that can be in a
+// single XCon.
+#define MAX_OVERESTIMATE 50
+#define MAX_IPS (MAX_DEPTH + MAX_OVERESTIMATE)
+
+// Get the stack trace for an XCon, filtering out uninteresting entries:
+// alloc-fns and entries above alloc-fns, and entries below main-or-below-main.
+// Eg: alloc-fn1 / alloc-fn2 / a / b / main / (below main) / c
+// becomes: a / b / main
+// Nb: it's possible to end up with an empty trace, eg. if 'main' is marked
+// as an alloc-fn. This is ok.
+static
+Int get_IPs( ThreadId tid, Bool is_custom_alloc, Addr ips[])
+{
+ #define BUF_LEN 1024
+ Char buf[BUF_LEN];
+ Int n_ips, i, n_alloc_fns_removed;
+ Int overestimate;
+ Bool redo;
+
+ // We ask for a few more IPs than clo_depth suggests we need. Then we
+ // remove every entry that is an alloc-fn. Depending on the
+ // circumstances, we may need to redo it all, asking for more IPs.
+ // Details:
+ // - If the original stack trace is smaller than asked-for, redo=False
+ // - Else if after filtering we have >= clo_depth IPs, redo=False
+ // - Else redo=True
+ // In other words, to redo, we'd have to get a stack trace as big as we
+ // asked for and remove more than 'overestimate' alloc-fns.
+
+ // Main loop.
+ redo = True; // Assume this to begin with.
+ for (overestimate = 3; redo; overestimate += 6) {
+ // This should never happen -- would require MAX_OVERESTIMATE
+ // alloc-fns to be removed from the stack trace.
+ if (overestimate > MAX_OVERESTIMATE)
+ VG_(tool_panic)("get_IPs: ips[] too small, inc. MAX_OVERESTIMATE?");
+
+ // Ask for more IPs than clo_depth suggests we need.
n_ips = VG_(get_StackTrace)( tid, ips, clo_depth + overestimate );
+ tl_assert(n_ips > 0);
- // Now we add a dummy "unknown" IP at the end. This is only used if we
- // run out of IPs before hitting clo_depth. It's done to ensure the
- // XPt we return is (now and forever) a bottom-XPt. If the returned XPt
- // wasn't a bottom-XPt (now or later) it would cause problems later (eg.
- // the parent's approx_ST wouldn't be equal [or almost equal] to the
- // total of the childrens' approx_STs).
- ips[ n_ips++ ] = ~((Addr)0);
+ // If the original stack trace is smaller than asked-for, redo=False.
+ if (n_ips < clo_depth + overestimate) { redo = False; }
- // Skip over alloc functions in ips[].
- for (L = 0; is_alloc_fn(ips[L]) && L < n_ips; L++) { }
+ // If it's a non-custom block, we will always remove the first stack
+ // trace entry (which will be one of malloc, __builtin_new, etc).
+ n_alloc_fns_removed = ( is_custom_alloc ? 0 : 1 );
- // Must be at least one alloc function, unless client used
- // MALLOCLIKE_BLOCK
- if (!custom_malloc) tl_assert(L > 0);
+ // Filter out alloc fns. If it's a non-custom block, we remove the
+ // first entry (which will be one of malloc, __builtin_new, etc)
+ // without looking at it, because VG_(get_fnname) is expensive (it
+ // involves calls to VG_(malloc)/VG_(free)).
+ for (i = n_alloc_fns_removed; i < n_ips; i++) {
+ if (VG_(get_fnname)(ips[i], buf, BUF_LEN)) {
+ if (is_alloc_fn(buf)) {
+ n_alloc_fns_removed++;
+ } else {
+ break;
+ }
+ }
+ }
+ // Remove the alloc fns by shuffling the rest down over them.
+ n_ips -= n_alloc_fns_removed;
+ for (i = 0; i < n_ips; i++) {
+ ips[i] = ips[i + n_alloc_fns_removed];
+ }
- // Should be at least one non-alloc function. If not, try again.
- if (L == n_ips) {
- overestimate += 2;
- if (overestimate > MAX_ALLOC_FNS)
- VG_(tool_panic)("No stk snapshot big enough to find non-alloc fns");
- } else {
- break;
+ // If after filtering we have >= clo_depth IPs, redo=False
+ if (n_ips >= clo_depth) {
+ redo = False;
+ n_ips = clo_depth; // Ignore any IPs below --depth.
+ }
+
+ if (redo) {
+ n_XCon_redos++;
}
}
- A = L;
- B = n_ips - 1;
- reached_bottom = False;
+ return n_ips;
+}
- // By this point, the IPs we care about are in ips[A]..ips[B]
+// Gets an XCon and puts it in the tree. Returns the XCon's bottom-XPt.
+static XPt* get_XCon( ThreadId tid, Bool is_custom_alloc )
+{
+ Addr ips[MAX_IPS];
+ Int i;
+ XPt* xpt = alloc_xpt;
- // Now do the search/insertion of the XCon. 'L' is the loop counter,
- // being the index into ips[].
- while (True) {
+ // After this call, the IPs we want are in ips[0]..ips[n_ips-1].
+ Int n_ips = get_IPs(tid, is_custom_alloc, ips);
+
+ // Now do the search/insertion of the XCon.
+ for (i = 0; i < n_ips; i++) {
+ Addr ip = ips[i];
+ Int ch;
// Look for IP in xpt's children.
- // XXX: linear search, ugh -- about 10% of time for konqueror startup
- // XXX: tried cacheing last result, only hit about 4% for konqueror
+ // Linear search, ugh -- about 10% of time for konqueror startup tried
+ // caching last result, only hit about 4% for konqueror.
// Nb: this search hits about 98% of the time for konqueror
+ for (ch = 0; True; ch++) {
+ if (ch == xpt->n_children) {
+ // IP not found in the children.
+ // Create and add new child XPt, then stop.
+ XPt* new_child_xpt = new_XPt(ip, xpt);
+ add_child_xpt(xpt, new_child_xpt);
+ xpt = new_child_xpt;
+ break;
- // If we've searched/added deep enough, or run out of EIPs, this is
- // the bottom XPt.
- if (L - A + 1 == clo_depth || L == B)
- reached_bottom = True;
-
- nC = 0;
- while (True) {
- if (nC == xpt->n_children) {
- // not found, insert new XPt
- tl_assert(xpt->max_children != 0);
- tl_assert(xpt->n_children <= xpt->max_children);
- // Expand 'children' if necessary
- if (xpt->n_children == xpt->max_children) {
- xpt->max_children *= 2;
- xpt->children = VG_(realloc)( xpt->children,
- xpt->max_children * sizeof(XPt*) );
- n_children_reallocs++;
- }
- // Make new XPt for IP, insert in list
- xpt->children[ xpt->n_children++ ] =
- new_XPt(ips[L], xpt, reached_bottom);
+ } else if (ip == xpt->children[ch]->ip) {
+ // Found the IP in the children, stop.
+ xpt = xpt->children[ch];
break;
}
- if (ips[L] == xpt->children[nC]->ip) break; // found the IP
- nC++; // keep looking
}
-
- // Return found/built bottom-XPt.
- if (reached_bottom) {
- tl_assert(0 == xpt->children[nC]->n_children); // Must be bottom-XPt
- return xpt->children[nC];
- }
-
- // Descend to next level in XTree, the newly found/built non-bottom-XPt
- xpt = xpt->children[nC];
- L++;
}
+ tl_assert(0 == xpt->n_children); // Must be bottom-XPt
+ return xpt;
}
-// Update 'curr_space' of every XPt in the XCon, by percolating upwards.
-static void update_XCon(XPt* xpt, Int space_delta)
+// Update 'szB' of every XPt in the XCon, by percolating upwards.
+static void update_XCon(XPt* xpt, SSizeT space_delta)
{
tl_assert(True == clo_heap);
- tl_assert(0 != space_delta);
tl_assert(NULL != xpt);
tl_assert(0 == xpt->n_children); // must be bottom-XPt
+ if (0 == space_delta)
+ return;
+
while (xpt != alloc_xpt) {
- if (space_delta < 0) tl_assert(xpt->curr_space >= -space_delta);
- xpt->curr_space += space_delta;
+ if (space_delta < 0) tl_assert(xpt->szB >= -space_delta);
+ xpt->szB += space_delta;
xpt = xpt->parent;
- }
- if (space_delta < 0) tl_assert(alloc_xpt->curr_space >= -space_delta);
- alloc_xpt->curr_space += space_delta;
-}
-
-// Actually want a reverse sort, biggest to smallest
-static Int XPt_cmp_approx_ST(void* n1, void* n2)
-{
- XPt* xpt1 = *(XPt**)n1;
- XPt* xpt2 = *(XPt**)n2;
- return (xpt1->approx_ST < xpt2->approx_ST ? 1 : -1);
-}
-
-static Int XPt_cmp_exact_ST_dbld(void* n1, void* n2)
-{
- XPt* xpt1 = *(XPt**)n1;
- XPt* xpt2 = *(XPt**)n2;
- return (xpt1->exact_ST_dbld < xpt2->exact_ST_dbld ? 1 : -1);
+ }
+ if (space_delta < 0) tl_assert(alloc_xpt->szB >= -space_delta);
+ alloc_xpt->szB += space_delta;
}
-/*------------------------------------------------------------*/
-/*--- A generic Queue ---*/
-/*------------------------------------------------------------*/
+//------------------------------------------------------------//
+//--- Snapshots ---//
+//------------------------------------------------------------//
+
+// Snapshots are done in a way so that we always have a reasonable number of
+// them. We start by taking them quickly. Once we hit our limit, we cull
+// some (eg. half), and start taking them more slowly. Once we hit the
+// limit again, we again cull and then take them even more slowly, and so
+// on.
+
+// Time is measured either in ms or bytes, depending on the --time-unit
+// option. It's a Long because it can exceed 32-bits reasonably easily, and
+// because we need to allow negative values to represent unset times.
+typedef Long Time;
+
+#define UNUSED_SNAPSHOT_TIME -333 // A conspicuous negative number.
+
+typedef
+ enum {
+ Normal = 77,
+ Peak,
+ Unused
+ }
+ SnapshotKind;
typedef
struct {
- UInt head; // Index of first entry
- UInt tail; // Index of final+1 entry, ie. next free slot
- UInt max_elems;
- void** elems;
- }
- Queue;
+ SnapshotKind kind;
+ Time time;
+ SizeT heap_szB;
+ SizeT heap_admin_szB;
+ SizeT stacks_szB;
+ SXPt* alloc_sxpt; // Heap XTree root, if a detailed snapshot,
+ } // otherwise NULL
+ Snapshot;
-static Queue* construct_queue(UInt size)
+static UInt next_snapshot_i = 0; // Index of where next snapshot will go.
+static Snapshot* snapshots; // Array of snapshots.
+
+static Bool is_snapshot_in_use(Snapshot* snapshot)
{
- UInt i;
- Queue* q = VG_(malloc)(sizeof(Queue));
- q->head = 0;
- q->tail = 0;
- q->max_elems = size;
- q->elems = VG_(malloc)(size * sizeof(void*));
- for (i = 0; i < size; i++)
- q->elems[i] = NULL;
-
- return q;
-}
-
-static void destruct_queue(Queue* q)
-{
- VG_(free)(q->elems);
- VG_(free)(q);
-}
-
-static void shuffle(Queue* dest_q, void** old_elems)
-{
- UInt i, j;
- for (i = 0, j = dest_q->head; j < dest_q->tail; i++, j++)
- dest_q->elems[i] = old_elems[j];
- dest_q->head = 0;
- dest_q->tail = i;
- for ( ; i < dest_q->max_elems; i++)
- dest_q->elems[i] = NULL; // paranoia
-}
-
-// Shuffles elements down. If not enough slots free, increase size. (We
-// don't wait until we've completely run out of space, because there could
-// be lots of shuffling just before that point which would be slow.)
-static void adjust(Queue* q)
-{
- void** old_elems;
-
- tl_assert(q->tail == q->max_elems);
- if (q->head < 10) {
- old_elems = q->elems;
- q->max_elems *= 2;
- q->elems = VG_(malloc)(q->max_elems * sizeof(void*));
- shuffle(q, old_elems);
- VG_(free)(old_elems);
+ if (Unused == snapshot->kind) {
+ // If snapshot is unused, check all the fields are unset.
+ tl_assert(snapshot->time == UNUSED_SNAPSHOT_TIME);
+ tl_assert(snapshot->heap_admin_szB == 0);
+ tl_assert(snapshot->heap_szB == 0);
+ tl_assert(snapshot->stacks_szB == 0);
+ tl_assert(snapshot->alloc_sxpt == NULL);
+ return False;
} else {
- shuffle(q, q->elems);
+ tl_assert(snapshot->time != UNUSED_SNAPSHOT_TIME);
+ return True;
}
}
-static void enqueue(Queue* q, void* elem)
+static Bool is_detailed_snapshot(Snapshot* snapshot)
{
- if (q->tail == q->max_elems)
- adjust(q);
- q->elems[q->tail++] = elem;
+ return (snapshot->alloc_sxpt ? True : False);
}
-static Bool is_empty_queue(Queue* q)
+static Bool is_uncullable_snapshot(Snapshot* snapshot)
{
- return (q->head == q->tail);
+ return &snapshots[0] == snapshot // First snapshot
+ || &snapshots[next_snapshot_i-1] == snapshot // Last snapshot
+ || snapshot->kind == Peak; // Peak snapshot
}
-static void* dequeue(Queue* q)
+static void sanity_check_snapshot(Snapshot* snapshot)
{
- if (is_empty_queue(q))
- return NULL; // Queue empty
- else
- return q->elems[q->head++];
+ if (snapshot->alloc_sxpt) {
+ sanity_check_SXTree(snapshot->alloc_sxpt);
+ }
}
-/*------------------------------------------------------------*/
-/*--- malloc() et al replacement wrappers ---*/
-/*------------------------------------------------------------*/
+// All the used entries should look used, all the unused ones should be clear.
+static void sanity_check_snapshots_array(void)
+{
+ Int i;
+ for (i = 0; i < next_snapshot_i; i++) {
+ tl_assert( is_snapshot_in_use( & snapshots[i] ));
+ }
+ for ( ; i < clo_max_snapshots; i++) {
+ tl_assert(!is_snapshot_in_use( & snapshots[i] ));
+ }
+}
-// Forward declaration
-static void hp_census(void);
+// This zeroes all the fields in the snapshot, but does not free the heap
+// XTree if present. It also does a sanity check unless asked not to; we
+// can't sanity check at startup when clearing the initial snapshots because
+// they're full of junk.
+static void clear_snapshot(Snapshot* snapshot, Bool do_sanity_check)
+{
+ if (do_sanity_check) sanity_check_snapshot(snapshot);
+ snapshot->kind = Unused;
+ snapshot->time = UNUSED_SNAPSHOT_TIME;
+ snapshot->heap_admin_szB = 0;
+ snapshot->heap_szB = 0;
+ snapshot->stacks_szB = 0;
+ snapshot->alloc_sxpt = NULL;
+}
+
+// This zeroes all the fields in the snapshot, and frees the heap XTree if
+// present.
+static void delete_snapshot(Snapshot* snapshot)
+{
+ // Nb: if there's an XTree, we free it after calling clear_snapshot,
+ // because clear_snapshot does a sanity check which includes checking the
+ // XTree.
+ SXPt* tmp_sxpt = snapshot->alloc_sxpt;
+ clear_snapshot(snapshot, /*do_sanity_check*/True);
+ if (tmp_sxpt) {
+ free_SXTree(tmp_sxpt);
+ }
+}
+
+static void VERB_snapshot(Int verbosity, Char* prefix, Int i)
+{
+ Snapshot* snapshot = &snapshots[i];
+ Char* suffix;
+ switch (snapshot->kind) {
+ case Peak: suffix = "p"; break;
+ case Normal: suffix = ( is_detailed_snapshot(snapshot) ? "d" : "." ); break;
+ case Unused: suffix = "u"; break;
+ default:
+ tl_assert2(0, "VERB_snapshot: unknown snapshot kind: %d", snapshot->kind);
+ }
+ VERB(verbosity, "%s S%s%3d (t:%lld, hp:%ld, ad:%ld, st:%ld)",
+ prefix, suffix, i,
+ snapshot->time,
+ snapshot->heap_szB,
+ snapshot->heap_admin_szB,
+ snapshot->stacks_szB
+ );
+}
+
+// Cull half the snapshots; we choose those that represent the smallest
+// time-spans, because that gives us the most even distribution of snapshots
+// over time. (It's possible to lose interesting spikes, however.)
+//
+// Algorithm for N snapshots: We find the snapshot representing the smallest
+// timeframe, and remove it. We repeat this until (N/2) snapshots are gone.
+// We have to do this one snapshot at a time, rather than finding the (N/2)
+// smallest snapshots in one hit, because when a snapshot is removed, its
+// neighbours immediately cover greater timespans. So it's O(N^2), but N is
+// small, and it's not done very often.
+//
+// Once we're done, we return the new smallest interval between snapshots.
+// That becomes our minimum time interval.
+static UInt cull_snapshots(void)
+{
+ Int i, jp, j, jn, min_timespan_i;
+ Int n_deleted = 0;
+ Time min_timespan;
+
+ n_cullings++;
+
+ // Sets j to the index of the first not-yet-removed snapshot at or after i
+ #define FIND_SNAPSHOT(i, j) \
+ for (j = i; \
+ j < clo_max_snapshots && !is_snapshot_in_use(&snapshots[j]); \
+ j++) { }
+
+ VERB(2, "Culling...");
+
+ // First we remove enough snapshots by clearing them in-place. Once
+ // that's done, we can slide the remaining ones down.
+ for (i = 0; i < clo_max_snapshots/2; i++) {
+ // Find the snapshot representing the smallest timespan. The timespan
+ // for snapshot n = d(N-1,N)+d(N,N+1), where d(A,B) is the time between
+ // snapshot A and B. We don't consider the first and last snapshots for
+ // removal.
+ Snapshot* min_snapshot;
+ Int min_j;
+
+ // Initial triple: (prev, curr, next) == (jp, j, jn)
+ // Initial min_timespan is the first one.
+ jp = 0;
+ FIND_SNAPSHOT(1, j);
+ FIND_SNAPSHOT(j+1, jn);
+ min_timespan = 0x7fffffffffffffffLL;
+ min_j = -1;
+ while (jn < clo_max_snapshots) {
+ Time timespan = snapshots[jn].time - snapshots[jp].time;
+ tl_assert(timespan >= 0);
+ // Nb: We never cull the peak snapshot.
+ if (Peak != snapshots[j].kind && timespan < min_timespan) {
+ min_timespan = timespan;
+ min_j = j;
+ }
+ // Move on to next triple
+ jp = j;
+ j = jn;
+ FIND_SNAPSHOT(jn+1, jn);
+ }
+ // We've found the least important snapshot, now delete it. First
+ // print it if necessary.
+ tl_assert(-1 != min_j); // Check we found a minimum.
+ min_snapshot = & snapshots[ min_j ];
+ if (VG_(clo_verbosity) > 1) {
+ Char buf[64];
+ VG_(snprintf)(buf, 64, " %3d (t-span = %lld)", i, min_timespan);
+ VERB_snapshot(2, buf, min_j);
+ }
+ delete_snapshot(min_snapshot);
+ n_deleted++;
+ }
+
+ // Slide down the remaining snapshots over the removed ones. First set i
+ // to point to the first empty slot, and j to the first full slot after
+ // i. Then slide everything down.
+ for (i = 0; is_snapshot_in_use( &snapshots[i] ); i++) { }
+ for (j = i; !is_snapshot_in_use( &snapshots[j] ); j++) { }
+ for ( ; j < clo_max_snapshots; j++) {
+ if (is_snapshot_in_use( &snapshots[j] )) {
+ snapshots[i++] = snapshots[j];
+ clear_snapshot(&snapshots[j], /*do_sanity_check*/True);
+ }
+ }
+ next_snapshot_i = i;
+
+ // Check snapshots array looks ok after changes.
+ sanity_check_snapshots_array();
+
+ // Find the minimum timespan remaining; that will be our new minimum
+ // time interval. Note that above we were finding timespans by measuring
+ // two intervals around a snapshot that was under consideration for
+ // deletion. Here we only measure single intervals because all the
+ // deletions have occurred.
+ //
+ // But we have to be careful -- some snapshots (eg. snapshot 0, and the
+ // peak snapshot) are uncullable. If two uncullable snapshots end up
+ // next to each other, they'll never be culled (assuming the peak doesn't
+ // change), and the time gap between them will not change. However, the
+ // time between the remaining cullable snapshots will grow ever larger.
+ // This means that the min_timespan found will always be that between the
+ // two uncullable snapshots, and it will be much smaller than it should
+ // be. To avoid this problem, when computing the minimum timespan, we
+ // ignore any timespans between two uncullable snapshots.
+ tl_assert(next_snapshot_i > 1);
+ min_timespan = 0x7fffffffffffffffLL;
+ min_timespan_i = -1;
+ for (i = 1; i < next_snapshot_i; i++) {
+ if (is_uncullable_snapshot(&snapshots[i]) &&
+ is_uncullable_snapshot(&snapshots[i-1]))
+ {
+ VERB(2, "(Ignoring interval %d--%d when computing minimum)", i-1, i);
+ } else {
+ Time timespan = snapshots[i].time - snapshots[i-1].time;
+ tl_assert(timespan >= 0);
+ if (timespan < min_timespan) {
+ min_timespan = timespan;
+ min_timespan_i = i;
+ }
+ }
+ }
+ tl_assert(-1 != min_timespan_i); // Check we found a minimum.
+
+ // Print remaining snapshots, if necessary.
+ if (VG_(clo_verbosity) > 1) {
+ VERB(2, "Finished culling (%3d of %3d deleted)",
+ n_deleted, clo_max_snapshots);
+ for (i = 0; i < next_snapshot_i; i++) {
+ VERB_snapshot(2, " post-cull", i);
+ }
+ VERB(2, "New time interval = %lld (between snapshots %d and %d)",
+ min_timespan, min_timespan_i-1, min_timespan_i);
+ }
+
+ return min_timespan;
+}
+
+static Time get_time(void)
+{
+ // Get current time, in whatever time unit we're using.
+ if (clo_time_unit == TimeMS) {
+ // Some stuff happens between the millisecond timer being initialised
+ // to zero and us taking our first snapshot. We determine that time
+ // gap so we can subtract it from all subsequent times so that our
+ // first snapshot is considered to be at t = 0ms. Unfortunately, a
+ // bunch of symbols get read after the first snapshot is taken but
+ // before the second one (which is triggered by the first allocation),
+ // so when the time-unit is 'ms' we always have a big gap between the
+ // first two snapshots. But at least users won't have to wonder why
+ // the first snapshot isn't at t=0.
+ static Bool is_first_get_time = True;
+ static Time start_time_ms;
+ if (is_first_get_time) {
+ start_time_ms = VG_(read_millisecond_timer)();
+ is_first_get_time = False;
+ return 0;
+ } else {
+ return VG_(read_millisecond_timer)() - start_time_ms;
+ }
+ } else if (clo_time_unit == TimeB) {
+ return total_allocs_deallocs_szB;
+ } else {
+ tl_assert2(0, "bad --time-unit value");
+ }
+}
+
+// Take a snapshot, and only that -- decisions on whether to take a
+// snapshot, or what kind of snapshot, are made elsewhere.
+static void
+take_snapshot(Snapshot* snapshot, SnapshotKind kind, Time time,
+ Bool is_detailed, Char* what)
+{
+ tl_assert(!is_snapshot_in_use(snapshot));
+ tl_assert(have_started_executing_code);
+
+ // Heap and heap admin.
+ if (clo_heap) {
+ snapshot->heap_szB = heap_szB;
+ if (is_detailed) {
+ // XXX: total_szB computed in various places -- factor it out
+ SizeT total_szB = heap_szB + clo_heap_admin*n_heap_blocks + stacks_szB;
+ snapshot->alloc_sxpt = dup_XTree(alloc_xpt, total_szB);
+ tl_assert( alloc_xpt->szB == heap_szB);
+ tl_assert(snapshot->alloc_sxpt->szB == heap_szB);
+ }
+ snapshot->heap_admin_szB = clo_heap_admin * n_heap_blocks;
+ }
+
+ // Stack(s).
+ if (clo_stacks) {
+ snapshot->stacks_szB = stacks_szB;
+ }
+
+ // Rest of snapshot.
+ snapshot->kind = kind;
+ snapshot->time = time;
+ sanity_check_snapshot(snapshot);
+
+ // Update stats.
+ if (Peak == kind) n_peak_snapshots++;
+ if (is_detailed) n_detailed_snapshots++;
+ n_real_snapshots++;
+}
+
+
+// Take a snapshot, if it's time, or if we've hit a peak.
+static void
+maybe_take_snapshot(SnapshotKind kind, Char* what)
+{
+ // 'min_time_interval' is the minimum time interval between snapshots.
+ // If we try to take a snapshot and less than this much time has passed,
+ // we don't take it. It gets larger as the program runs longer. It's
+ // initialised to zero so that we begin by taking snapshots as quickly as
+ // possible.
+ static Time min_time_interval = 0;
+ // Zero allows startup snapshot.
+ static Time earliest_possible_time_of_next_snapshot = 0;
+ static Int n_snapshots_since_last_detailed = 0;
+ static Int n_skipped_snapshots_since_last_snapshot = 0;
+
+ Snapshot* snapshot;
+ Bool is_detailed;
+ Time time = get_time();
+
+ switch (kind) {
+ case Normal:
+ // Only do a snapshot if it's time.
+ if (time < earliest_possible_time_of_next_snapshot) {
+ n_skipped_snapshots++;
+ n_skipped_snapshots_since_last_snapshot++;
+ return;
+ }
+ is_detailed = (clo_detailed_freq-1 == n_snapshots_since_last_detailed);
+ break;
+
+ case Peak: {
+ // Because we're about to do a deallocation, we're coming down from a
+ // local peak. If it is (a) actually a global peak, and (b) a certain
+ // amount bigger than the previous peak, then we take a peak snapshot.
+ // By not taking a snapshot for every peak, we save a lot of effort --
+ // because many peaks remain peak only for a short time.
+ SizeT total_szB = heap_szB + clo_heap_admin*n_heap_blocks + stacks_szB;
+ SizeT excess_szB_for_new_peak =
+ (((ULong)peak_snapshot_total_szB) * clo_peak_inaccuracy) / 10000ULL;
+ if (total_szB <= peak_snapshot_total_szB + excess_szB_for_new_peak) {
+ return;
+ }
+ is_detailed = True;
+ break;
+ }
+
+ default:
+ tl_assert2(0, "maybe_take_snapshot: unrecognised snapshot kind");
+ }
+
+ // Take the snapshot.
+ snapshot = & snapshots[next_snapshot_i];
+ take_snapshot(snapshot, kind, time, is_detailed, what);
+
+ // Record if it was detailed.
+ if (is_detailed) {
+ n_snapshots_since_last_detailed = 0;
+ } else {
+ n_snapshots_since_last_detailed++;
+ }
+
+ // Update peak data, if it's a Peak snapshot.
+ if (Peak == kind) {
+ Int i, number_of_peaks_snapshots_found = 0;
+
+ // Sanity check the size, then update our recorded peak.
+ SizeT snapshot_total_szB =
+ snapshot->heap_szB + snapshot->heap_admin_szB + snapshot->stacks_szB;
+ tl_assert2(snapshot_total_szB > peak_snapshot_total_szB,
+ "%ld, %ld\n", snapshot_total_szB, peak_snapshot_total_szB);
+ peak_snapshot_total_szB = snapshot_total_szB;
+
+ // Find the old peak snapshot, if it exists, and mark it as normal.
+ for (i = 0; i < next_snapshot_i; i++) {
+ if (Peak == snapshots[i].kind) {
+ snapshots[i].kind = Normal;
+ number_of_peaks_snapshots_found++;
+ }
+ }
+ tl_assert(number_of_peaks_snapshots_found <= 1);
+ }
+
+ // Finish up verbosity and stats stuff.
+ if (n_skipped_snapshots_since_last_snapshot > 0) {
+ VERB(2, " (skipped %d snapshot%s)",
+ n_skipped_snapshots_since_last_snapshot,
+ ( n_skipped_snapshots_since_last_snapshot == 1 ? "" : "s") );
+ }
+ VERB_snapshot(2, what, next_snapshot_i);
+ n_skipped_snapshots_since_last_snapshot = 0;
+
+ // Cull the entries, if our snapshot table is full.
+ next_snapshot_i++;
+ if (clo_max_snapshots == next_snapshot_i) {
+ min_time_interval = cull_snapshots();
+ }
+
+ // Work out the earliest time when the next snapshot can happen.
+ earliest_possible_time_of_next_snapshot = time + min_time_interval;
+}
+
+
+//------------------------------------------------------------//
+//--- Sanity checking ---//
+//------------------------------------------------------------//
+
+static Bool ms_cheap_sanity_check ( void )
+{
+ return True; // Nothing useful we can cheaply check.
+}
+
+static Bool ms_expensive_sanity_check ( void )
+{
+ sanity_check_XTree(alloc_xpt, /*parent*/NULL);
+ sanity_check_snapshots_array();
+ return True;
+}
+
+
+//------------------------------------------------------------//
+//--- Heap management ---//
+//------------------------------------------------------------//
+
+// Metadata for heap blocks. Each one contains a pointer to a bottom-XPt,
+// which is a foothold into the XCon at which it was allocated. From
+// HP_Chunks, XPt 'space' fields are incremented (at allocation) and
+// decremented (at deallocation).
+//
+// Nb: first two fields must match core's VgHashNode.
+typedef
+ struct _HP_Chunk {
+ struct _HP_Chunk* next;
+ Addr data; // Ptr to actual block
+ SizeT szB; // Size requested
+ XPt* where; // Where allocated; bottom-XPt
+ }
+ HP_Chunk;
+
+static VgHashTable malloc_list = NULL; // HP_Chunks
+
+static void update_alloc_stats(SSizeT szB_delta)
+{
+ // Update total_allocs_deallocs_szB.
+ if (szB_delta < 0) szB_delta = -szB_delta;
+ total_allocs_deallocs_szB += szB_delta;
+}
+
+static void update_heap_stats(SSizeT heap_szB_delta, Int n_heap_blocks_delta)
+{
+ if (n_heap_blocks_delta<0) tl_assert(n_heap_blocks >= -n_heap_blocks_delta);
+ if (heap_szB_delta <0) tl_assert(heap_szB >= -heap_szB_delta );
+ n_heap_blocks += n_heap_blocks_delta;
+ heap_szB += heap_szB_delta;
+
+ update_alloc_stats(heap_szB_delta + clo_heap_admin*n_heap_blocks_delta);
+}
static
-void* new_block ( ThreadId tid, void* p, SizeT size, SizeT align,
+void* new_block ( ThreadId tid, void* p, SizeT szB, SizeT alignB,
Bool is_zeroed )
{
HP_Chunk* hc;
- Bool custom_alloc = (NULL == p);
- if (size < 0) return NULL;
-
- // Update statistics
- n_allocs++;
- if (0 == size) n_zero_allocs++;
+ Bool is_custom_alloc = (NULL != p);
+ if (szB < 0) return NULL;
// Allocate and zero if necessary
if (!p) {
- p = VG_(cli_malloc)( align, size );
+ p = VG_(cli_malloc)( alignB, szB );
if (!p) {
return NULL;
}
- if (is_zeroed) VG_(memset)(p, 0, size);
+ if (is_zeroed) VG_(memset)(p, 0, szB);
}
// Make new HP_Chunk node, add to malloc_list
hc = VG_(malloc)(sizeof(HP_Chunk));
- hc->size = size;
+ hc->szB = szB;
hc->data = (Addr)p;
- hc->where = NULL; // paranoia
- if (clo_heap) {
- hc->where = get_XCon( tid, custom_alloc );
- if (0 != size)
- update_XCon(hc->where, size);
- }
+ hc->where = NULL;
VG_(HT_add_node)(malloc_list, hc);
- n_heap_blocks++;
- // do a census!
- hp_census();
+ if (clo_heap) {
+ VERB(3, "<<< new_mem_heap (%lu)", szB);
+
+ // Update statistics.
+ n_heap_allocs++;
+
+ // Update heap stats.
+ update_heap_stats(hc->szB, /*n_heap_blocks_delta*/1);
+
+ // Update XTree.
+ hc->where = get_XCon( tid, is_custom_alloc );
+ update_XCon(hc->where, szB);
+
+ // Maybe take a snapshot.
+ maybe_take_snapshot(Normal, " alloc");
+
+ VERB(3, ">>>");
+ }
return p;
}
@@ -677,54 +1499,148 @@
void die_block ( void* p, Bool custom_free )
{
HP_Chunk* hc;
-
- // Update statistics
- n_frees++;
+ SizeT die_szB;
// Remove HP_Chunk from malloc_list
hc = VG_(HT_remove)(malloc_list, (UWord)p);
- if (NULL == hc)
+ if (NULL == hc) {
return; // must have been a bogus free()
- tl_assert(n_heap_blocks > 0);
- n_heap_blocks--;
+ }
+ die_szB = hc->szB;
- if (clo_heap && hc->size != 0)
- update_XCon(hc->where, -hc->size);
+ if (clo_heap) {
+ VERB(3, "<<< die_mem_heap");
- VG_(free)( hc );
+ // Update statistics
+ n_heap_frees++;
- // Actually free the heap block, if necessary
+ // Maybe take a peak snapshot, since it's a deallocation.
+ maybe_take_snapshot(Peak, "de-PEAK");
+
+ // Update heap stats.
+ update_heap_stats(-die_szB, /*n_heap_blocks_delta*/-1);
+
+ // Update XTree.
+ update_XCon(hc->where, -hc->szB);
+
+ // Maybe take a snapshot.
+ maybe_take_snapshot(Normal, "dealloc");
+
+ VERB(3, ">>> (-%lu)", die_szB);
+ }
+
+ // Actually free the chunk, and the heap block (if necessary)
+ VG_(free)( hc ); hc = NULL;
if (!custom_free)
VG_(cli_free)( p );
-
- // do a census!
- hp_census();
-}
-
-
-static void* ms_malloc ( ThreadId tid, SizeT n )
-{
- return new_block( tid, NULL, n, VG_(clo_alignment), /*is_zeroed*/False );
}
-static void* ms___builtin_new ( ThreadId tid, SizeT n )
+static __inline__
+void* renew_block ( ThreadId tid, void* p_old, SizeT new_szB )
{
- return new_block( tid, NULL, n, VG_(clo_alignment), /*is_zeroed*/False );
+ HP_Chunk* hc;
+ void* p_new;
+ SizeT old_szB;
+ XPt *old_where, *new_where;
+
+ // Remove the old block
+ hc = VG_(HT_remove)(malloc_list, (UWord)p_old);
+ if (hc == NULL) {
+ return NULL; // must have been a bogus realloc()
+ }
+
+ old_szB = hc->szB;
+
+ if (clo_heap) {
+ VERB(3, "<<< renew_mem_heap (%lu)", new_szB);
+
+ // Update statistics
+ n_heap_reallocs++;
+
+ // Maybe take a peak snapshot, if it's (effectively) a deallocation.
+ if (new_szB < old_szB) {
+ maybe_take_snapshot(Peak, "re-PEAK");
+ }
+
+ // Update heap stats.
+ update_heap_stats(new_szB - old_szB, /*n_heap_blocks_delta*/0);
+ }
+
+ // Actually do the allocation, if necessary.
+ if (new_szB <= old_szB) {
+ // new size is smaller or same; block not moved
+ 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_szB);
+ if (p_new) {
+ VG_(memcpy)(p_new, p_old, old_szB);
+ VG_(cli_free)(p_old);
+ }
+ }
+
+ if (p_new) {
+ // Update HP_Chunk.
+ hc->data = (Addr)p_new;
+ hc->szB = new_szB;
+ old_where = hc->where;
+ hc->where = NULL;
+
+ // Update XTree.
+ if (clo_heap) {
+ new_where = get_XCon( tid, /*custom_malloc*/False);
+ hc->where = new_where;
+ update_XCon(old_where, -old_szB);
+ update_XCon(new_where, new_szB);
+ }
+ }
+
+ // Now insert the new hc (with a possibly new 'data' field) into
+ // malloc_list. If this realloc() did not increase the memory size, we
+ // will have removed and then re-added hc unnecessarily. But that's ok
+ // because shrinking a block with realloc() is (presumably) much rarer
+ // than growing it, and this way simplifies the growing case.
+ VG_(HT_add_node)(malloc_list, hc);
+
+ // Maybe take a snapshot.
+ if (clo_heap) {
+ maybe_take_snapshot(Normal, "realloc");
+
+ VERB(3, ">>> (%ld)", new_szB - old_szB);
+ }
+
+ return p_new;
}
-static void* ms___builtin_vec_new ( ThreadId tid, SizeT n )
+
+//------------------------------------------------------------//
+//--- malloc() et al replacement wrappers ---//
+//------------------------------------------------------------//
+
+static void* ms_malloc ( ThreadId tid, SizeT szB )
{
- return new_block( tid, NULL, n, VG_(clo_alignment), /*is_zeroed*/False );
+ return new_block( tid, NULL, szB, VG_(clo_alignment), /*is_zeroed*/False );
}
-static void* ms_calloc ( ThreadId tid, SizeT m, SizeT size )
+static void* ms___builtin_new ( ThreadId tid, SizeT szB )
{
- return new_block( tid, NULL, m*size, VG_(clo_alignment), /*is_zeroed*/True );
+ return new_block( tid, NULL, szB, VG_(clo_alignment), /*is_zeroed*/False );
}
-static void *ms_memalign ( ThreadId tid, SizeT align, SizeT n )
+static void* ms___builtin_vec_new ( ThreadId tid, SizeT szB )
{
- return new_block( tid, NULL, n, align, False );
+ return new_block( tid, NULL, szB, VG_(clo_alignment), /*is_zeroed*/False );
+}
+
+static void* ms_calloc ( ThreadId tid, SizeT m, SizeT szB )
+{
+ return new_block( tid, NULL, m*szB, VG_(clo_alignment), /*is_zeroed*/True );
+}
+
+static void *ms_memalign ( ThreadId tid, SizeT alignB, SizeT szB )
+{
+ return new_block( tid, NULL, szB, alignB, False );
}
static void ms_free ( ThreadId tid, void* p )
@@ -742,348 +1658,91 @@
die_block( p, /*custom_free*/False );
}
-static void* ms_realloc ( ThreadId tid, void* p_old, SizeT new_size )
+static void* ms_realloc ( ThreadId tid, void* p_old, SizeT new_szB )
{
- HP_Chunk* hc;
- void* p_new;
- SizeT old_size;
- XPt *old_where, *new_where;
-
- // Remove the old block
- hc = VG_(HT_remove)(malloc_list, (UWord)p_old);
- if (hc == NULL) {
- return NULL; // must have been a bogus realloc()
- }
-
- old_size = hc->size;
-
- if (new_size <= old_size) {
- // new size is smaller or same; block not moved
- 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_size);
- if (p_new) {
- VG_(memcpy)(p_new, p_old, old_size);
- VG_(cli_free)(p_old);
- }
- }
-
- if (p_new) {
- old_where = hc->where;
- new_where = get_XCon( tid, /*custom_malloc*/False);
-
- // Update HP_Chunk
- hc->data = (Addr)p_new;
- hc->size = new_size;
- hc->where = new_where;
-
- // Update XPt curr_space fields
- if (clo_heap) {
- if (0 != old_size) update_XCon(old_where, -old_size);
- if (0 != new_size) update_XCon(new_where, new_size);
- }
- }
-
- // Now insert the new hc (with a possibly new 'data' field) into
- // malloc_list. If this realloc() did not increase the memory size, we
- // will have removed and then re-added mc unnecessarily. But that's ok
- // because shrinking a block with realloc() is (presumably) much rarer
- // than growing it, and this way simplifies the growing case.
- VG_(HT_add_node)(malloc_list, hc);
-
- return p_new;
+ return renew_block(tid, p_old, new_szB);
}
-/*------------------------------------------------------------*/
-/*--- Taking a census ---*/
-/*------------------------------------------------------------*/
+//------------------------------------------------------------//
+//--- Stacks ---//
+//------------------------------------------------------------//
-static Census censi[MAX_N_CENSI];
-static UInt curr_census = 0;
+// We really want the inlining to occur...
+#define INLINE inline __attribute__((always_inline))
-static UInt get_xtree_size(XPt* xpt, UInt ix)
+static void update_stack_stats(SSizeT stack_szB_delta)
{
- UInt i;
+ if (stack_szB_delta < 0) tl_assert(stacks_szB >= -stack_szB_delta);
+ stacks_szB += stack_szB_delta;
- // If no memory allocated at all, nothing interesting to record.
- if (alloc_xpt->curr_space == 0) return 0;
-
- // Ignore sub-XTrees that account for a miniscule fraction of current
- // allocated space.
- if (xpt->curr_space / (double)alloc_xpt->curr_space > 0.002) {
- ix++;
-
- // Count all (non-zero) descendent XPts
- for (i = 0; i < xpt->n_children; i++)
- ix = get_xtree_size(xpt->children[i], ix);
- }
- return ix;
+ update_alloc_stats(stack_szB_delta);
}
-static
-UInt do_space_snapshot(XPt xpt[], XTreeSnapshot xtree_snapshot, UInt ix)
+static INLINE void new_mem_stack_2(Addr a, SizeT len, Char* what)
{
- UInt i;
-
- // Structure of this function mirrors that of get_xtree_size().
-
- if (alloc_xpt->curr_space == 0) return 0;
-
- if (xpt->curr_space / (double)alloc_xpt->curr_space > 0.002) {
- xtree_snapshot[ix].xpt = xpt;
- xtree_snapshot[ix].space = xpt->curr_space;
- ix++;
-
- for (i = 0; i < xpt->n_children; i++)
- ix = do_space_snapshot(xpt->children[i], xtree_snapshot, ix);
+ if (have_started_executing_code) {
+ VERB(3, "<<< new_mem_stack (%ld)", len);
+ n_stack_allocs++;
+ update_stack_stats(len);
+ maybe_take_snapshot(Normal, what);
+ VERB(3, ">>>");
}
- return ix;
}
-static UInt ms_interval;
-static UInt do_every_nth_census = 30;
-
-// Weed out half the censi; we choose those that represent the smallest
-// time-spans, because that loses the least information.
-//
-// Algorithm for N censi: We find the census representing the smallest
-// timeframe, and remove it. We repeat this until (N/2)-1 censi are gone.
-// (It's (N/2)-1 because we never remove the first and last censi.)
-// We have to do this one census at a time, rather than finding the (N/2)-1
-// smallest censi in one hit, because when a census is removed, it's
-// neighbours immediately cover greater timespans. So it's N^2, but N only
-// equals 200, and this is only done every 100 censi, which is not too often.
-static void halve_censi(void)
+static INLINE void die_mem_stack_2(Addr a, SizeT len, Char* what)
{
- Int i, jp, j, jn, k;
- Census* min_census;
-
- n_halvings++;
- if (VG_(clo_verbosity) > 1)
- VG_(message)(Vg_UserMsg, "Halving censi...");
-
- // Sets j to the index of the first not-yet-removed census at or after i
- #define FIND_CENSUS(i, j) \
- for (j = i; j < MAX_N_CENSI && -1 == censi[j].ms_time; j++) { }
-
- for (i = 2; i < MAX_N_CENSI; i += 2) {
- // Find the censi representing the smallest timespan. The timespan
- // for census n = d(N-1,N)+d(N,N+1), where d(A,B) is the time between
- // censi A and B. We don't consider the first and last censi for
- // removal.
- Int min_span = 0x7fffffff;
- Int min_j = 0;
-
- // Initial triple: (prev, curr, next) == (jp, j, jn)
- jp = 0;
- FIND_CENSUS(1, j);
- FIND_CENSUS(j+1, jn);
- while (jn < MAX_N_CENSI) {
- Int timespan = censi[jn].ms_time - censi[jp].ms_time;
- tl_assert(timespan >= 0);
- if (timespan < min_span) {
- min_span = timespan;
- min_j = j;
- }
- // Move on to next triple
- jp = j;
- j = jn;
- FIND_CENSUS(jn+1, jn);
- }
- // We've found the least important census, now remove it
- min_census = & censi[ min_j ];
- for (k = 0; NULL != min_census->xtree_snapshots[k]; k++) {
- n_snapshot_frees++;
- VG_(free)(min_census->xtree_snapshots[k]);
- min_census->xtree_snapshots[k] = NULL;
- }
- min_census->ms_time = -1;
+ if (have_started_executing_code) {
+ VERB(3, "<<< die_mem_stack (%ld)", -len);
+ n_stack_frees++;
+ maybe_take_snapshot(Peak, "stkPEAK");
+ update_stack_stats(-len);
+ maybe_take_snapshot(Normal, what);
+ VERB(3, ">>>");
}
-
- // Slide down the remaining censi over the removed ones. The '<=' is
- // because we are removing on (N/2)-1, rather than N/2.
- for (i = 0, j = 0; i <= MAX_N_CENSI / 2; i++, j++) {
- FIND_CENSUS(j, j);
- if (i != j) {
- censi[i] = censi[j];
- }
- }
- curr_census = i;
-
- // Double intervals
- ms_interval *= 2;
- do_every_nth_census *= 2;
-
- if (VG_(clo_verbosity) > 1)
- VG_(message)(Vg_UserMsg, "...done");
}
-// Take a census. Census time seems to be insignificant (usually <= 0 ms,
-// almost always <= 1ms) so don't have to worry about subtracting it from
-// running time in any way.
-//
-// XXX: NOT TRUE! with bigger depths, konqueror censuses can easily take
-// 50ms!
-static void hp_census(void)
+static void new_mem_stack(Addr a, SizeT len)
{
- static UInt ms_prev_census = 0;
- static UInt ms_next_census = 0; // zero allows startup census
+ new_mem_stack_2(a, len, "stk-new");
+}
- Int ms_time, ms_time_since_prev;
- Census* census;
-
- // Only do a census if it's time
- ms_time = VG_(read_millisecond_timer)();
- ms_time_since_prev = ms_time - ms_prev_census;
- if (ms_time < ms_next_census) {
- n_fake_censi++;
- return;
- }
- n_real_censi++;
-
- census = & censi[curr_census];
-
- census->ms_time = ms_time;
-
- // Heap: snapshot the K most significant XTrees -------------------
- if (clo_heap) {
- Int i, K;
- K = ( alloc_xpt->n_children < MAX_SNAPSHOTS
- ? alloc_xpt->n_children
- : MAX_SNAPSHOTS); // max out
-
- // Update .approx_ST field (approximatively) for all top-XPts.
- // We *do not* do it for any non-top-XPTs.
- for (i = 0; i < alloc_xpt->n_children; i++) {
- XPt* top_XPt = alloc_xpt->children[i];
- top_XPt->approx_ST += top_XPt->curr_space * ms_time_since_prev;
- }
- // Sort top-XPts by approx_ST field.
- VG_(ssort)(alloc_xpt->children, alloc_xpt->n_children, sizeof(XPt*),
- XPt_cmp_approx_ST);
-
- // For each significant top-level XPt, record space info about its
- // entire XTree, in a single census entry.
- // Nb: the xtree_size count/snapshot buffer allocation, and the actual
- // snapshot, take similar amounts of time (measured with the
- // millisecond counter).
- for (i = 0; i < K; i++) {
- UInt xtree_size, xtree_size2;
-// VG_(printf)("%7u ", alloc_xpt->children[i]->approx_ST);
- // Count how many XPts are in the XTree
- xtree_size = get_xtree_size( alloc_xpt->children[i], 0 );
-
- // If no XPts counted (ie. alloc_xpt.curr_space==0 or XTree
- // insignificant) then don't take any more snapshots.
- if (0 == xtree_size) break;
-
- // Make array of the appropriate size (+1 for zero termination,
- // which calloc() does for us).
- census->xtree_snapshots[i] =
- VG_(calloc)(xtree_size+1, sizeof(XPtSnapshot));
- if (0 && VG_(clo_verbosity) > 1)
- VG_(printf)("calloc: %d (%d B)\n", xtree_size+1,
- (xtree_size+1) * sizeof(XPtSnapshot));
-
- // Take space-snapshot: copy 'curr_space' for every XPt in the
- // XTree into the snapshot array, along with pointers to the XPts.
- // (Except for ones with curr_space==0, which wouldn't contribute
- // to the final exact_ST_dbld calculation anyway; excluding them
- // saves a lot of memory and up to 40% time with big --depth valus.
- xtree_size2 = do_space_snapshot(alloc_xpt->children[i],
- census->xtree_snapshots[i], 0);
- tl_assert(xtree_size == xtree_size2);
- }
-// VG_(printf)("\n\n");
- // Zero-terminate 'xtree_snapshot' array
- census->xtree_snapshots[i] = NULL;
-
- //VG_(printf)("printed %d censi\n", K);
-
- // Lump the rest into a single "others" entry.
- census->others_space = 0;
- for (i = K; i < alloc_xpt->n_children; i++) {
- census->others_space += alloc_xpt->children[i]->curr_space;
- }
- }
-
- // Heap admin -------------------------------------------------------
- if (clo_heap_admin > 0)
- census->heap_admin_space = clo_heap_admin * n_heap_blocks;
-
- // Stack(s) ---------------------------------------------------------
- if (clo_stacks) {
- ThreadId tid;
- Addr stack_min, stack_max;
- census->stacks_space = sigstacks_space;
- VG_(thread_stack_reset_iter)();
- while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
- census->stacks_space += (stack_max - stack_min);
- }
- }
-
- // Finish, update interval if necessary -----------------------------
- curr_census++;
- census = NULL; // don't use again now that curr_census changed
-
- // Halve the entries, if our census table is full
- if (MAX_N_CENSI == curr_census) {
- halve_censi();
- }
-
- // Take time for next census from now, rather than when this census
- // should have happened. Because, if there's a big gap due to a kernel
- // operation, there's no point doing catch-up censi every BB for a while
- // -- that would just give N censi at almost the same time.
- if (VG_(clo_verbosity) > 1) {
- VG_(message)(Vg_UserMsg, "census: %d ms (took %d ms)", ms_time,
- VG_(read_millisecond_timer)() - ms_time );
- }
- ms_prev_census = ms_time;
- ms_next_census = ms_time + ms_interval;
- //ms_next_census += ms_interval;
-
- //VG_(printf)("Next: %d ms\n", ms_next_census);
-}
-
-/*------------------------------------------------------------*/
-/*--- Tracked events ---*/
-/*------------------------------------------------------------*/
+static void die_mem_stack(Addr a, SizeT len)
+{
+ die_mem_stack_2(a, len, "stk-die");
+}
static void new_mem_stack_signal(Addr a, SizeT len)
{
- sigstacks_space += len;
+ new_mem_stack_2(a, len, "sig-new");
}
static void die_mem_stack_signal(Addr a, SizeT len)
{
- tl_assert(sigstacks_space >= len);
- sigstacks_space -= len;
+ die_mem_stack_2(a, len, "sig-die");
}
-/*------------------------------------------------------------*/
-/*--- Client Requests ---*/
-/*------------------------------------------------------------*/
+
+//------------------------------------------------------------//
+//--- Client Requests ---//
+//------------------------------------------------------------//
static Bool ms_handle_client_request ( ThreadId tid, UWord* argv, UWord* ret )
{
switch (argv[0]) {
case VG_USERREQ__MALLOCLIKE_BLOCK: {
void* res;
- void* p = (void*)argv[1];
- SizeT sizeB = argv[2];
- *ret = 0;
- res = new_block( tid, p, sizeB, /*align--ignored*/0, /*is_zeroed*/False );
+ void* p = (void*)argv[1];
+ SizeT szB = argv[2];
+ res = new_block( tid, p, szB, /*alignB--ignored*/0, /*is_zeroed*/False );
tl_assert(res == p);
+ *ret = 0;
return True;
}
case VG_USERREQ__FREELIKE_BLOCK: {
- void* p = (void*)argv[1];
- *ret = 0;
+ void* p = (void*)argv[1];
die_block( p, /*custom_free*/True );
+ *ret = 0;
return True;
}
default:
@@ -1092,641 +1751,338 @@
}
}
-/*------------------------------------------------------------*/
-/*--- Instrumentation ---*/
-/*------------------------------------------------------------*/
+//------------------------------------------------------------//
+//--- Instrumentation ---//
+//------------------------------------------------------------//
static
IRSB* ms_instrument ( VgCallbackClosure* closure,
- IRSB* bb_in,
- VexGuestLayout* layout,
+ IRSB* bb_in,
+ VexGuestLayout* layout,
VexGuestExtents* vge,
IRType gWordTy, IRType hWordTy )
{
- /* XXX Will Massif work when gWordTy != hWordTy ? */
+ if (! have_started_executing_code) {
+ // Do an initial sample to guarantee that we have at least one.
+ // We use 'maybe_take_snapshot' instead of 'take_snapshot' to ensure
+ // 'maybe_take_snapshot's internal static variables are initialised.
+ have_started_executing_code = True;
+ maybe_take_snapshot(Normal, "startup");
+ }
return bb_in;
}
-/*------------------------------------------------------------*/
-/*--- Spacetime recomputation ---*/
-/*------------------------------------------------------------*/
-// Although we've been calculating space-time along the way, because the
-// earlier calculations were done at a finer timescale, the .approx_ST field
-// might not agree with what hp2ps sees, because we've thrown away some of
-// the information. So recompute it at the scale that hp2ps sees, so we can
-// confidently determine which contexts hp2ps will choose for displaying as
-// distinct bands. This recomputation only happens to the significant ones
-// that get printed in the .hp file, so it's cheap.
-//
-// The approx_ST calculation:
-// ( a[0]*d(0,1) + a[1]*(d(0,1) + d(1,2)) + ... + a[N-1]*d(N-2,N-1) ) / 2
-// where
-// a[N] is the space at census N
-// d(A,B) is the time interval between censi A and B
-// and
-// d(A,B) + d(B,C) == d(A,C)
-//
-// Key point: we can calculate the area for a census without knowing the
-// previous or subsequent censi's space; because any over/underestimates
-// for this census will be reversed in the next, balancing out. This is
-// important, as getting the previous/next census entry for a particular
-// AP is a pain with this data structure, but getting the prev/next
-// census time is easy.
-//
-// Each heap calculation gets added to its context's exact_ST_dbld field.
-// The ULong* values are all running totals, hence the use of "+=" everywhere.
+//------------------------------------------------------------//
+//--- Writing snapshots ---//
+//------------------------------------------------------------//
-// This does the calculations for a single census.
-static void calc_exact_ST_dbld2(Census* census, UInt d_t1_t2,
- ULong* twice_heap_ST,
- ULong* twice_heap_admin_ST,
- ULong* twice_stack_ST)
-{
- UInt i, j;
- XPtSnapshot* xpt_snapshot;
+// XXX: do the filename properly, eventually
+static Char* massif_out_file = "massif.out";
- // Heap --------------------------------------------------------
- if (clo_heap) {
- for (i = 0; NULL != census->xtree_snapshots[i]; i++) {
- // Compute total heap exact_ST_dbld for the entire XTree using only
- // the top-XPt (the first XPt in xtree_snapshot).
- *twice_heap_ST += d_t1_t2 * census->xtree_snapshots[i][0].space;
+#define FP_BUF_SIZE 1024
+Char FP_buf[FP_BUF_SIZE];
- // Increment exact_ST_dbld for every XPt in xtree_snapshot (inc.
- // top one)
- for (j = 0; NULL != census->xtree_snapshots[i][j].xpt; j++) {
- xpt_snapshot = & census->xtree_snapshots[i][j];
- xpt_snapshot->xpt->exact_ST_dbld += d_t1_t2 * xpt_snapshot->space;
- }
- }
- *twice_heap_ST += d_t1_t2 * census->others_space;
- }
-
- // Heap admin --------------------------------------------------
- if (clo_heap_admin > 0)
- *twice_heap_admin_ST += d_t1_t2 * census->heap_admin_space;
-
- // Stack(s) ----------------------------------------------------
- if (clo_stacks)
- *twice_stack_ST += d_t1_t2 * census->stacks_space;
-}
-
-// This does the calculations for all censi.
-static void calc_exact_ST_dbld(ULong* heap2, ULong* heap_admin2, ULong* stack2)
-{
- UInt i, N = curr_census;
-
- *heap2 = 0;
- *heap_admin2 = 0;
- *stack2 = 0;
-
- if (N <= 1)
- return;
-
- calc_exact_ST_dbld2( &censi[0], censi[1].ms_time - censi[0].ms_time,
- heap2, heap_admin2, stack2 );
-
- for (i = 1; i <= N-2; i++) {
- calc_exact_ST_dbld2( & censi[i], censi[i+1].ms_time - censi[i-1].ms_time,
- heap2, heap_admin2, stack2 );
- }
-
- calc_exact_ST_dbld2( & censi[N-1], censi[N-1].ms_time - censi[N-2].ms_time,
- heap2, heap_admin2, stack2 );
- // Now get rid of the halves. May lose a 0.5 on each, doesn't matter.
- *heap2 /= 2;
- *heap_admin2 /= 2;
- *stack2 /= 2;
-}
-
-/*------------------------------------------------------------*/
-/*--- Writing the graph file ---*/
-/*------------------------------------------------------------*/
-
-static Char* make_filename(Char* dir, Char* suffix)
-{
- Char* filename;
-
- /* Block is big enough for dir name + massif.<pid>.<suffix> */
- filename = VG_(malloc)((VG_(strlen)(dir) + 32)*sizeof(Char));
- VG_(sprintf)(filename, "%s/massif.%d%s", dir, VG_(getpid)(), suffix);
-
- return filename;
-}
-
-// Make string acceptable to hp2ps (sigh): remove spaces, escape parentheses.
-static Char* clean_fnname(Char *d, Char* s)
-{
- Char* dorig = d;
- while (*s) {
- if (' ' == *s) { *d = '%'; }
- else if ('(' == *s) { *d++ = '\\'; *d = '('; }
- else if (')' == *s) { *d++ = '\\'; *d = ')'; }
- else { *d = *s; };
- s++;
- d++;
- }
- *d = '\0';
- return dorig;
-}
-
-static void file_err ( Char* file )
-{
- VG_(message)(Vg_UserMsg, "error: can't open output file '%s'", file );
- VG_(message)(Vg_UserMsg, " ... so profile results will be missing.");
-}
-
-/* Format, by example:
-
- JOB "a.out -p"
- DATE "Fri Apr 17 11:43:45 1992"
- SAMPLE_UNIT "seconds"
- VALUE_UNIT "bytes"
- BEGIN_SAMPLE 0.00
- SYSTEM 24
- END_SAMPLE 0.00
- BEGIN_SAMPLE 1.00
- elim 180
- insert 24
- intersect 12
- disin 60
- main 12
- reduce 20
- SYSTEM 12
- END_SAMPLE 1.00
- MARK 1.50
- MARK 1.75
- MARK 1.80
- BEGIN_SAMPLE 2.00
- elim 192
- insert 24
- intersect 12
- disin 84
- main 12
- SYSTEM 24
- END_SAMPLE 2.00
- BEGIN_SAMPLE 2.82
- END_SAMPLE 2.82
- */
-static void write_hp_file(void)
-{
- Int i, j;
- Int fd, res;
- SysRes sres;
- Char *hp_file, *ps_file, *aux_file;
- Char* cmdfmt;
- Char* cmdbuf;
- Int cmdlen;
-
- // Open file
- hp_file = make_filename( base_dir, ".hp" );
- ps_file = make_filename( base_dir, ".ps" );
- aux_file = make_filename( base_dir, ".aux" );
- sres = VG_(open)(hp_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
- VKI_S_IRUSR|VKI_S_IWUSR);
- if (sres.isError) {
- file_err( hp_file );
- return;
- } else {
- fd = sres.res;
- }
-
- // File header, including command line
- SPRINTF(buf, "JOB \"");
- if (VG_(args_the_exename)) {
- SPRINTF(buf, "%s", VG_(args_the_exename));
- }
- for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
- HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
- if (arg)
- SPRINTF(buf, " %s", arg);
- }
- SPRINTF(buf, /*" (%d ms/sample)\"\n"*/ "\"\n"
- "DATE \"\"\n"
- "SAMPLE_UNIT \"ms\"\n"
- "VALUE_UNIT \"bytes\"\n" /*, ms_interval*/);
-
- // Censi
- for (i = 0; i < curr_census; i++) {
- Census* census = & censi[i];
-
- // Census start
- SPRINTF(buf, "MARK %d.0\n"
- "BEGIN_SAMPLE %d.0\n",
- census->ms_time, census->ms_time);
-
- // Heap -----------------------------------------------------------
- if (clo_heap) {
- // Print all the significant XPts from that census
- for (j = 0; NULL != census->xtree_snapshots[j]; j++) {
- // Grab the jth top-XPt
- XTreeSnapshot xtree_snapshot = & census->xtree_snapshots[j][0];
- if ( ! VG_(get_fnname)(xtree_snapshot->xpt->ip, buf2, 16)) {
- VG_(sprintf)(buf2, "???");
- }
- SPRINTF(buf, "x%lx:%s %d\n", xtree_snapshot->xpt->ip,
- clean_fnname(buf3, buf2), xtree_snapshot->space);
- }
-
- // Remaining heap block alloc points, combined
- if (census->others_space > 0)
- SPRINTF(buf, "other %d\n", census->others_space);
- }
-
- // Heap admin -----------------------------------------------------
- if (clo_heap_admin > 0 && census->heap_admin_space)
- SPRINTF(buf, "heap-admin %d\n", census->heap_admin_space);
-
- // Stack(s) -------------------------------------------------------
- if (clo_stacks)
- SPRINTF(buf, "stack(s) %d\n", census->stacks_space);
-
- // Census end
- SPRINTF(buf, "END_SAMPLE %d.0\n", census->ms_time);
- }
-
- // Close file
- tl_assert(fd >= 0);
- VG_(close)(fd);
-
- // Attempt to convert file using hp2ps
- cmdfmt = "%s/hp2ps -c -t1 %s";
- cmdlen = VG_(strlen)(VG_(libdir)) + VG_(strlen)(hp_file)
- + VG_(strlen)(cmdfmt);
- cmdbuf = VG_(malloc)( sizeof(Char) * cmdlen );
- VG_(sprintf)(cmdbuf, cmdfmt, VG_(libdir), hp_file);
- res = VG_(system)(cmdbuf);
- VG_(free)(cmdbuf);
- if (res != 0) {
- VG_(message)(Vg_UserMsg,
- "Conversion to PostScript failed. Try converting manually.");
- } else {
- // remove the .hp and .aux file
- VG_(unlink)(hp_file);
- VG_(unlink)(aux_file);
- }
-
- VG_(free)(hp_file);
- VG_(free)(ps_file);
- VG_(free)(aux_file);
-}
-
-/*------------------------------------------------------------*/
-/*--- Writing the XPt text/HTML file ---*/
-/*------------------------------------------------------------*/
-
-static void percentify(Int n, Int pow, Int field_width, char xbuf[])
-{
- int i, len, space;
-
- VG_(sprintf)(xbuf, "%d.%d%%", n / pow, n % pow);
- len = VG_(strlen)(xbuf);
- space = field_width - len;
- if (space < 0) space = 0; /* Allow for v. small field_width */
- i = len;
-
- /* Right justify in field */
- for ( ; i >= 0; i--) xbuf[i + space] = xbuf[i];
- for (i = 0; i < space; i++) xbuf[i] = ' ';
-}
+// XXX: implement f{,n}printf in m_libcprint.c eventually, and use it here.
+// Then change Cachegrind to use it too.
+#define FP(format, args...) ({ \
+ VG_(snprintf)(FP_buf, FP_BUF_SIZE, format, ##args); \
+ VG_(write)(fd, (void*)FP_buf, VG_(strlen)(FP_buf)); \
+})
// Nb: uses a static buffer, each call trashes the last string returned.
-static Char* make_perc(ULong spacetime, ULong total_spacetime)
+static Char* make_perc(ULong x, ULong y)
{
static Char mbuf[32];
-
- UInt p = 10;
- tl_assert(0 != total_spacetime);
- percentify(spacetime * 100 * p / total_spacetime, p, 5, mbuf);
+
+// tl_assert(x <= y); XXX; put back in later...
+
+// XXX: I'm not confident that VG_(percentify) works as it should...
+ VG_(percentify)(x, y, 2, 6, mbuf);
+ // XXX: this is bogus if the denominator was zero -- resulting string is
+ // something like "0 --%")
+ if (' ' == mbuf[0]) mbuf[0] = '0';
return mbuf;
}
-// Nb: passed in XPt is a lower-level XPt; IPs are grabbed from
-// bottom-to-top of XCon, and then printed in the reverse order.
-static UInt pp_XCon(Int fd, XPt* xpt)
+static void pp_snapshot_SXPt(Int fd, SXPt* sxpt, Int depth, Char* depth_str,
+ Int depth_str_len,
+ SizeT snapshot_heap_szB, SizeT snapshot_total_szB)
{
- Addr rev_ips[clo_depth+1];
- Int i = 0;
- Int n = 0;
- Bool is_HTML = ( XHTML == clo_format );
- Char* maybe_br = ( is_HTML ? "<br>" : "" );
- Char* maybe_indent = ( is_HTML ? " " : "" );
+ #define BUF_LEN 1024
+ Int i, n_insig_children_sxpts;
+ Char* perc;
+ Char ip_desc_array[BUF_LEN];
+ Char* ip_desc = ip_desc_array;
+ SXPt* pred = NULL;
+ SXPt* child = NULL;
- tl_assert(NULL != xpt);
+ switch (sxpt->tag) {
+ case SigSXPt:
+ // Print the SXPt itself.
+ if (sxpt->Sig.ip == 0) {
+ ip_desc =
+ "(heap allocation functions) malloc/new/new[], --alloc-fns, etc.";
+ } else {
+ // If it's main-or-below-main, we (if appropriate) ignore everything
+ // below it by pretending it has no children.
+ // XXX: get this properly. Also, don't hard-code "(below main)"
+ // here -- look at the "(below main)"/"__libc_start_main" mess
+ // (m_stacktrace.c and m_demangle.c).
+ // [Nb: Josef wants --show-below-main to work for his fn entry/exit
+ // tracing]
+ Bool should_hide_below_main = /*!VG_(clo_show_below_main)*/True;
+ if (should_hide_below_main &&
+ VG_(get_fnname)(sxpt->Sig.ip, ip_desc, BUF_LEN) &&
+ (VG_STREQ(ip_desc, "main") || VG_STREQ(ip_desc, "(below main)")))
+ {
+ sxpt->Sig.n_children = 0;
+ }
+ // We need the -1 to get the line number right, But I'm not sure why.
+ ip_desc = VG_(describe_IP)(sxpt->Sig.ip-1, ip_desc, BUF_LEN);
+ }
+ perc = make_perc(sxpt->szB, snapshot_total_szB);
+ FP("%sn%d: %lu %s\n",
+ depth_str, sxpt->Sig.n_children, sxpt->szB, ip_desc);
- while (True) {
- rev_ips[i] = xpt->ip;
- n++;
- if (alloc_xpt == xpt->parent) break;
- i++;
- xpt = xpt->parent;
+ // Indent.
+ tl_assert(depth+1 < depth_str_len-1); // -1 for end NUL char
+ depth_str[depth+0] = ' ';
+ depth_str[depth+1] = '\0';
+
+ // Sort SXPt's children by szB (reverse order: biggest to smallest).
+ // Nb: we sort them here, rather than earlier (eg. in dup_XTree), for
+ // two reasons. First, if we do it during dup_XTree, it can get
+ // expensive (eg. 15% of execution time for konqueror
+ // startup/shutdown). Second, this way we get the Insig SXPt (if one
+ // is present) in its sorted position, not at the end.
+ VG_(ssort)(sxpt->Sig.children, sxpt->Sig.n_children, sizeof(SXPt*),
+ SXPt_revcmp_szB);
+
+ // Print the SXPt's children. They should already be in sorted order.
+ n_insig_children_sxpts = 0;
+ for (i = 0; i < sxpt->Sig.n_children; i++) {
+ pred = child;
+ child = sxpt->Sig.children[i];
+
+ if (InsigSXPt == child->tag)
+ n_insig_children_sxpts++;
+
+ // Ok, print the child.
+ pp_snapshot_SXPt(fd, child, depth+1, depth_str, depth_str_len,
+ snapshot_heap_szB, snapshot_total_szB);
+
+ // Unindent.
+ depth_str[depth+0] = '\0';
+ depth_str[depth+1] = '\0';
+ }
+ // There should be 0 or 1 Insig children SXPts.
+ tl_assert(n_insig_children_sxpts <= 1);
+ break;
+
+ case InsigSXPt: {
+ Char* s = ( sxpt->Insig.n_xpts == 1 ? "," : "s, all" );
+ perc = make_perc(sxpt->szB, snapshot_total_szB);
+ FP("%sn0: %lu in %d place%s below massif's threshold (%s)\n",
+ depth_str, sxpt->szB, sxpt->Insig.n_xpts, s,
+ make_perc(clo_threshold, 10000));
+ break;
+ }
+
+ default:
+ tl_assert2(0, "pp_snapshot_SXPt: unrecognised SXPt tag");
}
-
- for (i = n-1; i >= 0; i--) {
- // -1 means point to calling line
- VG_(describe_IP)(rev_ips[i]-1, buf2, BUF_LEN);
- SPRINTF(buf, " %s%s%s\n", maybe_indent, buf2, maybe_br);
- }
-
- return n;
}
-// Important point: for HTML, each XPt must be identified uniquely for the
-// HTML links to all match up correctly. Using xpt->ip is not
-// sufficient, because function pointers mean that you can call more than
-// one other function from a single code location. So instead we use the
-// address of the xpt struct itself, which is guaranteed to be unique.
-
-static void pp_all_XPts2(Int fd, Queue* q, ULong heap_spacetime,
- ULong total_spacetime)
+static void pp_snapshot(Int fd, Snapshot* snapshot, Int snapshot_n)
{
- UInt i;
- XPt *xpt, *child;
- UInt L = 0;
- UInt c1 = 1;
- UInt c2 = 0;
- ULong sum = 0;
- UInt n;
- Char *ip_desc, *perc;
- Bool is_HTML = ( XHTML == clo_format );
- Char* maybe_br = ( is_HTML ? "<br>" : "" );
- Char* maybe_p = ( is_HTML ? "<p>" : "" );
- Char* maybe_ul = ( is_HTML ? "<ul>" : "" );
- Char* maybe_li = ( is_HTML ? "<li>" : "" );
- Char* maybe_fli = ( is_HTML ? "</li>" : "" );
- Char* maybe_ful = ( is_HTML ? "</ul>" : "" );
- Char* end_hr = ( is_HTML ? "<hr>" :
- "=================================" );
- Char* depth = ( is_HTML ? "<code>--depth</code>" : "--depth" );
+ sanity_check_snapshot(snapshot);
- if (total_spacetime == 0) {
- SPRINTF(buf, "(No heap memory allocated)\n");
- return;
+ FP("#-----------\n");
+ FP("snapshot=%d\n", snapshot_n);
+ FP("#-----------\n");
+ FP("time=%lld\n", snapshot->time);
+ FP("mem_heap_B=%lu\n", snapshot->heap_szB);
+ FP("mem_heap_admin_B=%lu\n", snapshot->heap_admin_szB);
+ FP("mem_stacks_B=%lu\n", snapshot->stacks_szB);
+
+ if (is_detailed_snapshot(snapshot)) {
+ // Detailed snapshot -- print heap tree.
+ Int depth_str_len = clo_depth + 3;
+ Char* depth_str = VG_(malloc)(sizeof(Char) * depth_str_len);
+ SizeT snapshot_total_szB =
+ snapshot->heap_szB + snapshot->heap_admin_szB + snapshot->stacks_szB;
+ depth_str[0] = '\0'; // Initialise depth_str to "".
+
+ FP("heap_tree=%s\n", ( Peak == snapshot->kind ? "peak" : "detailed" ));
+ pp_snapshot_SXPt(fd, snapshot->alloc_sxpt, 0, depth_str,
+ depth_str_len, snapshot->heap_szB,
+ snapshot_total_szB);
+
+ VG_(free)(depth_str);
+
+ } else {
+ FP("heap_tree=empty\n");
}
-
-
- SPRINTF(buf, "== %d ===========================%s\n", L, maybe_br);
-
- while (NULL != (xpt = (XPt*)dequeue(q))) {
- // Check that non-top-level XPts have a zero .approx_ST field.
- if (xpt->parent != alloc_xpt) tl_assert( 0 == xpt->approx_ST );
-
- // Check that the sum of all children .exact_ST_dbld fields equals
- // parent's (unless alloc_xpt, when it should == 0).
- if (alloc_xpt == xpt) {
- tl_assert(0 == xpt->exact_ST_dbld);
- } else {
- sum = 0;
- for (i = 0; i < xpt->n_children; i++) {
- sum += xpt->children[i]->exact_ST_dbld;
- }
- //tl_assert(sum == xpt->exact_ST_dbld);
- // It's possible that not all the children were included in the
- // exact_ST_dbld calculations. Hopefully almost all of them were, and
- // all the important ones.
-// tl_assert(sum <= xpt->exact_ST_dbld);
-// tl_assert(sum * 1.05 > xpt->exact_ST_dbld );
-// if (sum != xpt->exact_ST_dbld) {
-// VG_(printf)("%lld, %lld\n", sum, xpt->exact_ST_dbld);
-// }
- }
-
- if (xpt == alloc_xpt) {
- SPRINTF(buf, "Heap allocation functions accounted for "
- "%s of measured spacetime%s\n",
- make_perc(heap_spacetime, total_spacetime), maybe_br);
- } else {
- // Remember: exact_ST_dbld is space.time *doubled*
- perc = make_perc(xpt->exact_ST_dbld / 2, total_spacetime);
- if (is_HTML) {
- SPRINTF(buf, "<a name=\"b%p\"></a>"
- "Context accounted for "
- "<a href=\"#a%p\">%s</a> of measured spacetime<br>\n",
- xpt, xpt, perc);
- } else {
- SPRINTF(buf, "Context accounted for %s of measured spacetime\n",
- perc);
- }
- n = pp_XCon(fd, xpt);
- tl_assert(n == L);
- }
-
- // Sort children by exact_ST_dbld
- VG_(ssort)(xpt->children, xpt->n_children, sizeof(XPt*),
- XPt_cmp_exact_ST_dbld);
-
- SPRINTF(buf, "%s\nCalled from:%s\n", maybe_p, maybe_ul);
- for (i = 0; i < xpt->n_children; i++) {
- child = xpt->children[i];
-
- // Stop when <1% of total spacetime
- if (child->exact_ST_dbld * 1000 / (total_spacetime * 2) < 5) {
- UInt n_insig = xpt->n_children - i;
- Char* s = ( n_insig == 1 ? "" : "s" );
- Char* and = ( 0 == i ? "" : "and " );
- Char* other = ( 0 == i ? "" : "other " );
- SPRINTF(buf, " %s%s%d %sinsignificant place%s%s\n\n",
- maybe_li, and, n_insig, other, s, maybe_fli);
- break;
- }
-
- // Remember: exact_ST_dbld is space.time *doubled*
- perc = make_perc(child->exact_ST_dbld / 2, total_spacetime);
- ip_desc = VG_(describe_IP)(child->ip-1, buf2, BUF_LEN);
- if (is_HTML) {
- SPRINTF(buf, "<li><a name=\"a%p\"></a>", child );
-
- if (child->n_children > 0) {
- SPRINTF(buf, "<a href=\"#b%p\">%s</a>", child, perc);
- } else {
- SPRINTF(buf, "%s", perc);
- }
- SPRINTF(buf, ": %s\n", ip_desc);
- } else {
- SPRINTF(buf, " %6s: %s\n\n", perc, ip_desc);
- }
-
- if (child->n_children > 0) {
- enqueue(q, (void*)child);
- c2++;
- }
- }
- SPRINTF(buf, "%s%s", maybe_ful, maybe_p);
- c1--;
-
- // Putting markers between levels of the structure:
- // c1 tracks how many to go on this level, c2 tracks how many we've
- // queued up for the next level while finishing off this level.
- // When c1 gets to zero, we've changed levels, so print a marker,
- // move c2 into c1, and zero c2.
- if (0 == c1) {
- L++;
- c1 = c2;
- c2 = 0;
- if (! is_empty_queue(q) ) { // avoid empty one at end
- SPRINTF(buf, "== %d ===========================%s\n", L, maybe_br);
- }
- } else {
- SPRINTF(buf, "---------------------------------%s\n", maybe_br);
- }
- }
- SPRINTF(buf, "%s\n\nEnd of information. Rerun with a bigger "
- "%s value for more.\n", end_hr, depth);
}
-static void pp_all_XPts(Int fd, XPt* xpt, ULong heap_spacetime,
- ULong total_spacetime)
+static void write_snapshots_to_file(void)
{
- Queue* q = construct_queue(100);
-
- enqueue(q, xpt);
- pp_all_XPts2(fd, q, heap_spacetime, total_spacetime);
- destruct_queue(q);
-}
-
-static void
-write_text_file(ULong total_ST, ULong heap_ST)
-{
+ Int i, fd;
SysRes sres;
- Int fd, i;
- Char* text_file;
- Char* maybe_p = ( XHTML == clo_format ? "<p>" : "" );
- // Open file
- text_file = make_filename( base_dir,
- ( XText == clo_format ? ".txt" : ".html" ) );
-
- sres = VG_(open)(text_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
- VKI_S_IRUSR|VKI_S_IWUSR);
+ sres = VG_(open)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+ VKI_S_IRUSR|VKI_S_IWUSR);
if (sres.isError) {
- file_err( text_file );
+ // If the file can't be opened for whatever reason (conflict
+ // between multiple cachegrinded processes?), give up now.
+ VG_(message)(Vg_UserMsg,
+ "error: can't open output file '%s'", massif_out_file );
+ VG_(message)(Vg_UserMsg,
+ " ... so profiling results will be missing.");
return;
} else {
fd = sres.res;
}
- // Header
- if (XHTML == clo_format) {
- SPRINTF(buf, "<html>\n"
- "<head>\n"
- "<title>%s</title>\n"
- "</head>\n"
- "<body>\n",
- text_file);
+ // Print massif-specific options that were used.
+ // XXX: is it worth having a "desc:" line? Could just call it "options:"
+ // -- this file format isn't as generic as Cachegrind's, so the
+ // implied genericity of "desc:" is bogus.
+ FP("desc:");
+ for (i = 0; i < VG_(sizeXA)(args_for_massif); i++) {
+ Char* arg = *(Char**)VG_(indexXA)(args_for_massif, i);
+ FP(" %s", arg);
}
+ if (0 == i) FP(" (none)");
+ FP("\n");
- // Command line
- SPRINTF(buf, "Command:");
+ // Print "cmd:" line.
+ FP("cmd: ");
if (VG_(args_the_exename)) {
- SPRINTF(buf, " %s", VG_(args_the_exename));
+ FP("%s", VG_(args_the_exename));
+ for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
+ HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
+ if (arg)
+ FP(" %s", arg);
+ }
+ } else {
+ FP(" ???");
}
- for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
- HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
- if (arg)
- SPRINTF(buf, " %s", arg);
- }
- SPRINTF(buf, "\n%s\n", maybe_p);
+ FP("\n");
- if (clo_heap)
- pp_all_XPts(fd, alloc_xpt, heap_ST, total_ST);
+ FP("time_unit: %s\n", TimeUnit_to_string(clo_time_unit));
- tl_assert(fd >= 0);
- VG_(close)(fd);
-}
-
-/*------------------------------------------------------------*/
-/*--- Finalisation ---*/
-/*------------------------------------------------------------*/
-
-static void
-print_summary(ULong total_ST, ULong heap_ST, ULong heap_admin_ST,
- ULong stack_ST)
-{
- VG_(message)(Vg_UserMsg, "Total spacetime: %,llu ms.B", total_ST);
-
- // Heap --------------------------------------------------------------
- if (clo_heap)
- VG_(message)(Vg_UserMsg, "heap: %s",
- ( 0 == total_ST ? (Char*)"(n/a)"
- : make_perc(heap_ST, total_ST) ) );
-
- // Heap admin --------------------------------------------------------
- if (clo_heap_admin)
- VG_(message)(Vg_UserMsg, "heap admin: %s",
- ( 0 == total_ST ? (Char*)"(n/a)"
- : make_perc(heap_admin_ST, total_ST) ) );
-
- tl_assert( VG_(HT_count_nodes)(malloc_list) == n_heap_blocks );
-
- // Stack(s) ----------------------------------------------------------
- if (clo_stacks) {
- VG_(message)(Vg_UserMsg, "stack(s): %s",
- ( 0 == stack_ST ? (Char*)"0%"
- : make_perc(stack_ST, total_ST) ) );
- }
-
- if (VG_(clo_verbosity) > 1) {
- tl_assert(n_xpts > 0); // always have alloc_xpt
- VG_(message)(Vg_DebugMsg, " allocs: %u", n_allocs);
- if ( n_allocs )
- VG_(message)(Vg_DebugMsg, "zeroallocs: %u (%d%%)", n_zero_allocs,
- n_zero_allocs * 100 / n_allocs );
- VG_(message)(Vg_DebugMsg, " frees: %u", n_frees);
- VG_(message)(Vg_DebugMsg, " XPts: %u (%d B)", n_xpts,
- n_xpts*sizeof(XPt));
- if ( n_xpts )
- VG_(message)(Vg_DebugMsg, " bot-XPts: %u (%d%%)", n_bot_xpts,
- n_bot_xpts * 100 / n_xpts);
- if ( n_xpts )
- VG_(message)(Vg_DebugMsg, " top-XPts: %u (%d%%)", alloc_xpt->n_children,
- alloc_xpt->n_children * 100 / n_xpts);
- VG_(message)(Vg_DebugMsg, "c-reallocs: %u", n_children_reallocs);
- VG_(message)(Vg_DebugMsg, "snap-frees: %u", n_snapshot_frees);
- VG_(message)(Vg_DebugMsg, "atmp censi: %u", n_attempted_censi);
- VG_(message)(Vg_DebugMsg, "fake censi: %u", n_fake_censi);
- VG_(message)(Vg_DebugMsg, "real censi: %u", n_real_censi);
- VG_(message)(Vg_DebugMsg, " halvings: %u", n_halvings);
+ for (i = 0; i < next_snapshot_i; i++) {
+ Snapshot* snapshot = & snapshots[i];
+ pp_snapshot(fd, snapshot, i); // Detailed snapshot!
}
}
+
+//------------------------------------------------------------//
+//--- Finalisation ---//
+//------------------------------------------------------------//
+
static void ms_fini(Int exit_status)
{
- ULong total_ST = 0;
- ULong heap_ST = 0;
- ULong heap_admin_ST = 0;
- ULong stack_ST = 0;
+ // Output.
+ write_snapshots_to_file();
- // Do a final (empty) sample to show program's end
- hp_census();
-
- // Redo spacetimes of significant contexts to match the .hp file.
- calc_exact_ST_dbld(&heap_ST, &heap_admin_ST, &stack_ST);
- total_ST = heap_ST + heap_admin_ST + stack_ST;
- write_hp_file ( );
- write_text_file( total_ST, heap_ST );
- print_summary ( total_ST, heap_ST, heap_admin_ST, stack_ST );
+ // Stats
+ tl_assert(n_xpts > 0); // always have alloc_xpt
+ VERB(1, "heap allocs: %u", n_heap_allocs);
+ VERB(1, "heap reallocs: %u", n_heap_reallocs);
+ VERB(1, "heap frees: %u", n_heap_frees);
+ VERB(1, "stack allocs: %u", n_stack_allocs);
+ VERB(1, "stack frees: %u", n_stack_frees);
+ VERB(1, "XPts: %u", n_xpts);
+ VERB(1, "top-XPts: %u (%d%%)",
+ alloc_xpt->n_children,
+ ( n_xpts ? alloc_xpt->n_children * 100 / n_xpts : 0));
+ VERB(1, "XPt-init-expansions: %u", n_xpt_init_expansions);
+ VERB(1, "XPt-later-expansions: %u", n_xpt_later_expansions);
+ VERB(1, "SXPt allocs: %u", n_sxpt_allocs);
+ VERB(1, "SXPt frees: %u", n_sxpt_frees);
+ VERB(1, "skipped snapshots: %u", n_skipped_snapshots);
+ VERB(1, "real snapshots: %u", n_real_snapshots);
+ VERB(1, "detailed snapshots: %u", n_detailed_snapshots);
+ VERB(1, "peak snapshots: %u", n_peak_snapshots);
+ VERB(1, "cullings: %u", n_cullings);
+ VERB(1, "XCon_redos: %u", n_XCon_redos);
}
-/*------------------------------------------------------------*/
-/*--- Initialisation ---*/
-/*------------------------------------------------------------*/
+
+//------------------------------------------------------------//
+//--- Initialisation ---//
+//------------------------------------------------------------//
static void ms_post_clo_init(void)
{
- ms_interval = 1;
+ Int i;
- // Do an initial sample for t = 0
- hp_census();
+ // Check options.
+ if (clo_heap_admin < 0 || clo_heap_admin > 1024) {
+ VG_(message)(Vg_UserMsg, "--heap-admin must be between 0 and 1024");
+ VG_(err_bad_option)("--heap-admin");
+ }
+ if (clo_depth < 1 || clo_depth > MAX_DEPTH) {
+ VG_(message)(Vg_UserMsg, "--depth must be between 1 and %d", MAX_DEPTH);
+ VG_(err_bad_option)("--depth");
+ }
+ if (clo_threshold < 0 || clo_threshold > 10000) {
+ VG_(message)(Vg_UserMsg, "--threshold must be between 0 and 10000");
+ VG_(err_bad_option)("--threshold");
+ }
+ if (clo_detailed_freq < 1 || clo_detailed_freq > 10000) {
+ VG_(message)(Vg_UserMsg, "--detailed-freq must be between 1 and 10000");
+ VG_(err_bad_option)("--detailed-freq");
+ }
+ if (clo_max_snapshots < 10 || clo_max_snapshots > 1000) {
+ VG_(message)(Vg_UserMsg, "--max-snapshots must be between 10 and 1000");
+ VG_(err_bad_option)("--max-snapshots");
+ }
+
+ // If we have --heap=no, set --heap-admin to zero, just to make sure we
+ // don't accidentally use a non-zero heap-admin size somewhere.
+ if (!clo_heap) {
+ clo_heap_admin = 0;
+ }
+
+ // Print alloc-fns, if necessary.
+ if (VG_(clo_verbosity) > 1) {
+ VERB(1, "alloc-fns:");
+ for (i = 0; i < VG_(sizeXA)(alloc_fns); i++) {
+ Char** alloc_fn_ptr = VG_(indexXA)(alloc_fns, i);
+ VERB(1, " %d: %s", i, *alloc_fn_ptr);
+ }
+ }
+
+ // Events to track.
+ if (clo_stacks) {
+ VG_(track_new_mem_stack) ( new_mem_stack );
+ VG_(track_die_mem_stack) ( die_mem_stack );
+ VG_(track_new_mem_stack_signal) ( new_mem_stack_signal );
+ VG_(track_die_mem_stack_signal) ( die_mem_stack_signal );
+ }
+
+ // Initialise snapshot array, and sanity-check it.
+ snapshots = VG_(malloc)(sizeof(Snapshot) * clo_max_snapshots);
+ // We don't want to do snapshot sanity checks here, because they're
+ // currently uninitialised.
+ for (i = 0; i < clo_max_snapshots; i++) {
+ clear_snapshot( & snapshots[i], /*do_sanity_check*/False );
+ }
+ sanity_check_snapshots_array();
}
static void ms_pre_clo_init(void)
-{
+{
VG_(details_name) ("Massif");
VG_(details_version) (NULL);
VG_(details_description) ("a space profiler");
VG_(details_copyright_author)(
- "Copyright (C) 2003-2007, Nicholas Nethercote");
+ "Copyright (C) 2003-2007, and GNU GPL'd, by Nicholas Nethercote");
VG_(details_bug_reports_to) (VG_BUGS_TO);
// Basic functions
@@ -1740,6 +2096,8 @@
ms_print_usage,
ms_print_debug_usage);
VG_(needs_client_requests) (ms_handle_client_request);
+ VG_(needs_sanity_checks) (ms_cheap_sanity_check,
+ ms_expensive_sanity_check);
VG_(needs_malloc_replacement) (ms_malloc,
ms___builtin_new,
ms___builtin_vec_new,
@@ -1751,22 +2109,23 @@
ms_realloc,
0 );
- // Events to track
- VG_(track_new_mem_stack_signal)( new_mem_stack_signal );
- VG_(track_die_mem_stack_signal)( die_mem_stack_signal );
-
// HP_Chunks
- malloc_list = VG_(HT_construct)( "Massif's malloc list" );
+ malloc_list = VG_(HT_construct)( "Massif's malloc list" );
// Dummy node at top of the context structure.
- alloc_xpt = new_XPt(0, NULL, /*is_bottom*/False);
+ alloc_xpt = new_XPt(/*ip*/0, /*parent*/NULL);
+
+ // Initialise alloc_fns.
+ init_alloc_fns();
+
+ // Initialise args_for_massif.
+ args_for_massif = VG_(newXA)(VG_(malloc), VG_(free), sizeof(HChar*));
tl_assert( VG_(get_startup_wd)(base_dir, VKI_PATH_MAX) );
}
VG_DETERMINE_INTERFACE_VERSION(ms_pre_clo_init)
-/*--------------------------------------------------------------------*/
-/*--- end ---*/
-/*--------------------------------------------------------------------*/
-
+//--------------------------------------------------------------------//
+//--- end ---//
+//--------------------------------------------------------------------//
diff --git a/massif/ms_print b/massif/ms_print
new file mode 100755
index 0000000..b836f24
--- /dev/null
+++ b/massif/ms_print
@@ -0,0 +1,649 @@
+#! /usr/bin/perl
+
+##--------------------------------------------------------------------##
+##--- Massif's results printer ms_print.in ---##
+##--------------------------------------------------------------------##
+
+# This file is part of Massif, a Valgrind tool for profiling memory
+# usage of programs.
+#
+# Copyright (C) 2007-2007 Nicholas Nethercote
+# njn@valgrind.org
+#
+# 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.
+
+use warnings;
+use strict;
+
+#----------------------------------------------------------------------------
+# Global variables, main data structures
+#----------------------------------------------------------------------------
+
+# Command line of profiled program.
+my $cmd;
+
+# Time unit used in profile.
+my $time_unit;
+
+# Threshold dictating what percentage an entry must represent for us to
+# bother showing it.
+my $threshold = 1.0;
+
+# Graph x and y dimensions.
+my $graph_x = 72;
+my $graph_y = 20;
+
+# Input file name
+my $input_file = undef;
+
+# Tmp file name.
+my $tmp_file = "ms_print.tmp.$$";
+
+# Version number (XXX: change it when I convert this file to ms_print.in)
+my $version = "XXX"; # "@VERSION@";
+
+# Args passed, for printing.
+my $ms_print_args;
+
+# Usage message.
+my $usage = <<END
+usage: ms_print [options] <file>
+
+ options for the user, with defaults in [ ], are:
+ -h --help show this message
+ -v --version show version
+ --threshold=<n.n> significance threshold, in percent [$threshold]
+ --x=<n> graph width, in columns; min=4, max=1000 [72]
+ --y=<n> graph height, in rows; min=4, max=1000 [20]
+
+ ms_print is Copyright (C) 2007-2007 Nicholas Nethercote.
+ and licensed under the GNU General Public License, version 2.
+ Bug reports, feedback, admiration, abuse, etc, to: njn\@valgrind.org.
+
+END
+;
+
+# Used in various places of output.
+my $fancy = '-' x 80;
+my $fancy_nl = $fancy . "\n";
+
+# Returns 0 if the denominator is 0.
+sub safe_div_0($$)
+{
+ my ($x, $y) = @_;
+ return ($y ? $x / $y : 0);
+}
+
+#-----------------------------------------------------------------------------
+# Argument and option handling
+#-----------------------------------------------------------------------------
+sub process_cmd_line()
+{
+ my @files;
+
+ # Grab a copy of the arguments, for printing later.
+ for my $arg (@ARGV) {
+ $ms_print_args .= " $arg"; # The arguments.
+ }
+
+ for my $arg (@ARGV) {
+
+ # Option handling
+ if ($arg =~ /^-/) {
+
+ # --version
+ if ($arg =~ /^-v$|^--version$/) {
+ die("ms_print-$version\n");
+
+ # --threshold=X (tolerates a trailing '%')
+ } elsif ($arg =~ /^--threshold=([\d\.]+)%?$/) {
+ $threshold = $1;
+ ($1 >= 0 && $1 <= 100) or die($usage);
+
+ } elsif ($arg =~ /^--x=(\d+)$/) {
+ $graph_x = $1;
+ (4 <= $graph_x && $graph_x <= 1000) or die($usage);
+
+ } elsif ($arg =~ /^--y=(\d+)$/) {
+ $graph_y = $1;
+ (4 <= $graph_y && $graph_y <= 1000) or die($usage);
+
+ } else { # -h and --help fall under this case
+ die($usage);
+ }
+ } else {
+ # Not an option. Remember it as a filename.
+ push(@files, $arg);
+ }
+ }
+
+ # Must have chosen exactly one input file.
+ if (scalar @files) {
+ $input_file = $files[0];
+ } else {
+ die($usage);
+ }
+}
+
+#-----------------------------------------------------------------------------
+# Reading the input file: auxiliary functions
+#-----------------------------------------------------------------------------
+
+# Gets the next line, stripping comments and skipping blanks.
+# Returns undef at EOF.
+sub get_line()
+{
+ while (my $line = <INPUTFILE>) {
+ $line =~ s/#.*$//; # remove comments
+ if ($line !~ /^\s*$/) {
+ return $line; # return $line if non-empty
+ }
+ }
+ return undef; # EOF: return undef
+}
+
+sub equals_num_line($$)
+{
+ my ($line, $fieldname) = @_;
+ defined($line)
+ or die("Line $.: expected \"$fieldname\" line, got end of file\n");
+ $line =~ s/^$fieldname=(.*)\s*$//
+ or die("Line $.: expected \"$fieldname\" line, got:\n$line");
+ return $1;
+}
+
+sub is_significant_XPt($$$)
+{
+ my ($is_top_node, $xpt_szB, $total_szB) = @_;
+ ($xpt_szB <= $total_szB) or die;
+ # Nb: we always consider the alloc-XPt significant, even if the size is
+ # zero.
+ return $is_top_node || 0 == $threshold ||
+ ( $total_szB != 0 && $xpt_szB * 100 / $total_szB >= $threshold );
+}
+
+#-----------------------------------------------------------------------------
+# Reading the input file: reading heap trees
+#-----------------------------------------------------------------------------
+
+# Forward declaration, because it's recursive.
+sub read_heap_tree($$$$$);
+
+# Return pair: if the tree was significant, both are zero. If it was
+# insignificant, the first element is 1 and the second is the number of
+# bytes.
+sub read_heap_tree($$$$$)
+{
+ # Read the line and determine if it is significant.
+ my ($is_top_node, $this_prefix, $child_midfix, $arrow, $mem_total_B) = @_;
+ my $line = get_line();
+ (defined $line and $line =~ /^\s*n(\d+):\s*(\d+)(.*)$/)
+ or die("Line $.: expected a tree node line, got:\n$line\n");
+ my $n_children = $1;
+ my $bytes = $2;
+ my $details = $3;
+ my $perc = safe_div_0(100 * $bytes, $mem_total_B);
+ # Nb: we always print the alloc-XPt, even if its size is zero.
+ my $is_significant = is_significant_XPt($is_top_node, $bytes, $mem_total_B);
+
+ # We precede this node's line with "$this_prefix.$arrow". We precede
+ # any children of this node with "$this_prefix$child_midfix$arrow".
+ if ($is_significant) {
+ # Nb: $details might have '%' in it, so don't embed directly in the
+ # format string.
+ printf(TMPFILE
+ "$this_prefix$arrow%05.2f%% (%sB)%s\n", $perc, commify($bytes),
+ $details);
+ }
+
+ # Now read all the children.
+ my $n_insig_children = 0;
+ my $total_insig_children_szB = 0;
+ my $this_prefix2 = $this_prefix . $child_midfix;
+ for (my $i = 0; $i < $n_children; $i++) {
+ # If child is the last sibling, the midfix is empty.
+ my $child_midfix2 = ( $i+1 == $n_children ? " " : "| " );
+ my ($is_child_insignificant, $child_insig_bytes) =
+ # '0' means it's not the top node of the tree.
+ read_heap_tree(0, $this_prefix2, $child_midfix2, "->",
+ $mem_total_B);
+ $n_insig_children += $is_child_insignificant;
+ $total_insig_children_szB += $child_insig_bytes;
+ }
+
+ if ($is_significant) {
+ # If this was significant but any children were insignificant, print
+ # the "in N places" line for them.
+ if ($n_insig_children > 0) {
+ $perc = safe_div_0(100 * $total_insig_children_szB, $mem_total_B);
+ printf(TMPFILE "%s->%05.2f%% (%sB) in %d+ places, all below "
+ . "ms_print's threshold (%05.2f%%)\n",
+ $this_prefix2, $perc, commify($total_insig_children_szB),
+ $n_insig_children, $threshold);
+ print(TMPFILE "$this_prefix2\n");
+ }
+
+ # If this node has no children, print an extra (mostly) empty line.
+ if (0 == $n_children) {
+ print(TMPFILE "$this_prefix2\n");
+ }
+ return (0, 0);
+
+ } else {
+ return (1, $bytes);
+ }
+}
+
+#-----------------------------------------------------------------------------
+# Reading the input file: main
+#-----------------------------------------------------------------------------
+
+sub max_label_2($$)
+{
+ my ($szB, $szB_scaled) = @_;
+
+ # For the label, if $szB is 999B or below, we print it as an integer.
+ # Otherwise, we print it as a float with 5 characters (including the '.').
+ # Examples (for bytes):
+ # 1 --> 1 B
+ # 999 --> 999 B
+ # 1000 --> 0.977 KB
+ # 1024 --> 1.000 KB
+ # 10240 --> 10.00 KB
+ # 102400 --> 100.0 KB
+ # 1024000 --> 0.977 MB
+ # 1048576 --> 1.000 MB
+ #
+ if ($szB < 1000) { return sprintf("%5d", $szB); }
+ elsif ($szB_scaled < 10) { return sprintf("%5.3f", $szB_scaled); }
+ elsif ($szB_scaled < 100) { return sprintf("%5.2f", $szB_scaled); }
+ else { return sprintf("%5.1f", $szB_scaled); }
+}
+
+# Work out the units for the max value, measured in bytes.
+sub B_max_label($)
+{
+ my ($szB) = @_;
+
+ # We repeat until the number is less than 1000, but we divide by 1024 on
+ # each scaling.
+ my $szB_scaled = $szB;
+ my $unit = "B";
+ if ($szB_scaled >= 1000) { $unit = "KB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "MB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "GB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "TB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "PB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "EB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "ZB"; $szB_scaled /= 1024; }
+ if ($szB_scaled >= 1000) { $unit = "YB"; $szB_scaled /= 1024; }
+
+ return (max_label_2($szB, $szB_scaled), $unit);
+}
+
+# Work out the units for the max value, measured in ms/s/h.
+sub t_max_label($)
+{
+ my ($szB) = @_;
+
+ # We scale from millisecond to seconds to hours.
+ #
+ # XXX: this allows a number with 6 chars, eg. "3599.0 s"
+ my $szB_scaled = $szB;
+ my $unit = "ms";
+ if ($szB_scaled >= 1000) { $unit = "s"; $szB_scaled /= 1000; }
+ if ($szB_scaled >= 3600) { $unit = "h"; $szB_scaled /= 3600; }
+
+ return (max_label_2($szB, $szB_scaled), $unit);
+}
+
+# This prints four things:
+# - the output header
+# - the graph
+# - the snapshot summaries (number, list of detailed ones)
+# - the snapshots
+#
+# The first three parts can't be printed until we've read the whole input file;
+# but the fourth part is much easier to print while we're reading the file. So
+# we print the fourth part to a tmp file, and then dump the tmp file at the
+# end.
+#
+sub read_input_file()
+{
+ my $desc = ""; # Concatenated description lines.
+ my $peak_mem_total_szB = 0;
+
+ # Info about each snapshot.
+ my @snapshot_nums = ();
+ my @times = ();
+ my @mem_total_Bs = ();
+ my @is_detaileds = ();
+ my $peak_num = -1; # An initial value that will be ok if no peak
+ # entry is in the file.
+
+ #-------------------------------------------------------------------------
+ # Read start of input file.
+ #-------------------------------------------------------------------------
+ open(INPUTFILE, "< $input_file")
+ || die "Cannot open $input_file for reading\n";
+
+ # Read "desc:" lines.
+ my $line;
+ while ($line = get_line()) {
+ if ($line =~ s/^desc://) {
+ $desc .= $line;
+ } else {
+ last;
+ }
+ }
+
+ # Read "cmd:" line (Nb: will already be in $line from "desc:" loop above).
+ ($line =~ /^cmd:\s*(.*)$/) or die("Line $.: missing 'cmd' line\n");
+ $cmd = $1;
+
+ # Read "time_unit:" line.
+ $line = get_line();
+ ($line =~ /^time_unit:\s*(.*)$/) or
+ die("Line $.: missing 'time_unit' line\n");
+ $time_unit = $1;
+
+ #-------------------------------------------------------------------------
+ # Print snapshot list header to $tmp_file.
+ #-------------------------------------------------------------------------
+ open(TMPFILE, "> $tmp_file")
+ || die "Cannot open $tmp_file for reading\n";
+
+ my $time_column = sprintf("%14s", "time($time_unit)");
+ my $column_format = "%3s %14s %16s %16s %13s %12s\n";
+ my $header =
+ $fancy_nl .
+ sprintf($column_format
+ , "n"
+ , $time_column
+ , "total(B)"
+ , "useful-heap(B)"
+ , "admin-heap(B)"
+ , "stacks(B)"
+ ) .
+ $fancy_nl;
+ print(TMPFILE $header);
+
+ #-------------------------------------------------------------------------
+ # Read body of input file.
+ #-------------------------------------------------------------------------
+ $line = get_line();
+ while (defined $line) {
+ my $snapshot_num = equals_num_line($line, "snapshot");
+ my $time = equals_num_line(get_line(), "time");
+ my $mem_heap_B = equals_num_line(get_line(), "mem_heap_B");
+ my $mem_heap_admin_B = equals_num_line(get_line(), "mem_heap_admin_B");
+ my $mem_stacks_B = equals_num_line(get_line(), "mem_stacks_B");
+ my $mem_total_B = $mem_heap_B + $mem_heap_admin_B + $mem_stacks_B;
+ my $heap_tree = equals_num_line(get_line(), "heap_tree");
+
+ # Print the snapshot data to $tmp_file.
+ printf(TMPFILE $column_format,
+ , $snapshot_num
+ , commify($time)
+ , commify($mem_total_B)
+ , commify($mem_heap_B)
+ , commify($mem_heap_admin_B)
+ , commify($mem_stacks_B)
+ );
+
+ # Remember the snapshot data.
+ push(@snapshot_nums, $snapshot_num);
+ push(@times, $time);
+ push(@mem_total_Bs, $mem_total_B);
+ push(@is_detaileds, ( $heap_tree eq "empty" ? 0 : 1 ));
+ $peak_mem_total_szB = $mem_total_B
+ if $mem_total_B > $peak_mem_total_szB;
+
+ # Read the heap tree, and if it's detailed, print it and a subsequent
+ # snapshot list header to $tmp_file.
+ if ($heap_tree eq "empty") {
+ $line = get_line();
+ } elsif ($heap_tree =~ "(detailed|peak)") {
+ # If "peak", remember the number.
+ if ($heap_tree eq "peak") {
+ $peak_num = $snapshot_num;
+ }
+ # '1' means it's the top node of the tree.
+ read_heap_tree(1, "", "", "", $mem_total_B);
+
+ # Print the header, unless there are no more snapshots.
+ $line = get_line();
+ if (defined $line) {
+ print(TMPFILE $header);
+ }
+ } else {
+ die("Line $.: expected 'empty' or '...' after 'heap_tree='\n");
+ }
+ }
+
+ close(INPUTFILE);
+ close(TMPFILE);
+
+ #-------------------------------------------------------------------------
+ # Print header.
+ #-------------------------------------------------------------------------
+ print($fancy_nl);
+ print("Command: $cmd\n");
+ print("Massif arguments: $desc");
+ print("ms_print arguments:$ms_print_args\n");
+ print($fancy_nl);
+ print("\n\n");
+
+ #-------------------------------------------------------------------------
+ # Setup for graph.
+ #-------------------------------------------------------------------------
+ # The ASCII graph.
+ # Row 0 ([0..graph_x][0]) is the X-axis.
+ # Column 0 ([0][0..graph_y]) is the Y-axis.
+ # The rest ([1][1]..[graph_x][graph_y]) is the usable graph area.
+ my @graph;
+ my $x;
+ my $y;
+
+ my $n_snapshots = scalar(@snapshot_nums);
+ ($n_snapshots > 0) or die;
+ my $end_time = $times[$n_snapshots-1];
+ ($end_time >= 0) or die;
+
+ # Setup graph[][].
+ $graph[0][0] = '+'; # axes join point
+ for ($x = 1; $x <= $graph_x; $x++) { $graph[$x][0] = '-'; } # X-axis
+ for ($y = 1; $y <= $graph_y; $y++) { $graph[0][$y] = '|'; } # Y-axis
+ $graph[$graph_x][0] = '>'; # X-axis arrow
+ $graph[0][$graph_y] = '^'; # Y-axis arrow
+ for ($x = 1; $x <= $graph_x; $x++) { # usable area
+ for ($y = 1; $y <= $graph_y; $y++) {
+ $graph[$x][$y] = ' ';
+ }
+ }
+
+ #-------------------------------------------------------------------------
+ # Write snapshot bars into graph[][].
+ #-------------------------------------------------------------------------
+ # Each row represents K bytes, which is 1/graph_y of the peak size
+ # (and K can be non-integral). When drawing the column for a snapshot,
+ # in order to fill the slot in row y (where the first row drawn on is
+ # row 1) with a half-char (eg. '.'), it must be >= (y - 1/2)*K. In
+ # order to fill a row/column spot with a full-char (eg. ':'), it must be
+ # >= y*K. For example, if K = 10 bytes, then the values 0, 4, 5, 9, 10,
+ # 14, 15, 19, 20, 24, 25, 29, 30 would be drawn like this (showing one
+ # per column):
+ #
+ # y (y - 1/2) * K y * K
+ # - ------------- -----------
+ # 30 | ..: 3 (3 - 1/2) * 10 = 25 3 * 10 = 30
+ # 20 | ..::::: 2 (2 - 1/2) * 10 = 15 2 * 10 = 20
+ # 10 | ..::::::::: 1 (1 - 1/2) * 10 = 5 1 * 10 = 10
+ # 0 +-------------
+
+ my $peak_full_char = '#';
+ my $detailed_full_char = '@';
+ my $normal_full_char = ':';
+ my $half_char = '.';
+
+ # Work out how many bytes each row represents. If the peak size was 0,
+ # make it 1 so that the Y-axis covers a non-zero range of values.
+ # Likewise for end_time.
+ if (0 == $peak_mem_total_szB) { $peak_mem_total_szB = 1; }
+ if (0 == $end_time ) { $end_time = 1; }
+ my $K = $peak_mem_total_szB / $graph_y;
+
+ # If we leave end_time as is, the final snapshot will spill over past
+ # the last column. So we add a small epsilon to it to prevent this from
+ # happening.
+ $end_time += 0.001;
+
+ for (my $i = 0; $i < $n_snapshots; $i++) {
+
+ # Work out which column this snapshot belongs to.
+ my $x_pos_frac = ($times[$i] / ($end_time)) * $graph_x;
+ $x = int($x_pos_frac) + 1; # +1 due to Y-axis
+ # The final snapshot will spill over into the n+1th column, which
+ # doesn't get shown. So we fudge that one and pull it back a
+ # column, as if the end_time was actually end_time+epsilon.
+ if ($times[$i] == $end_time) {
+ ($x == $graph_x+1) or die;
+ $x = $graph_x;
+ }
+
+ # Draw the column if:
+ # - it's the peak column, or
+ # - it's a detailed column, and we won't overwrite the peak column, or
+ # - it's a normal column, and we won't overwrite the peak column or a
+ # detailed column.
+ my $should_draw_column =
+ (($i == $peak_num) or
+ ($is_detaileds[$i] and $graph[$x][0] ne $peak_full_char) or
+ ($graph[$x][0] ne $peak_full_char and
+ $graph[$x][0] ne $detailed_full_char));
+
+ if ($should_draw_column) {
+ # If it's detailed, mark the X-axis. Also choose the full-slot
+ # char.
+ my $full_char;
+ if ($i == $peak_num) {
+ $full_char = $peak_full_char;
+ $graph[$x][0] = $full_char;
+ } elsif ($is_detaileds[$i]) {
+ $full_char = $detailed_full_char;
+ $graph[$x][0] = $full_char;
+ } else {
+ $full_char = $normal_full_char;
+ }
+ # Grow this snapshot bar from bottom to top.
+ for ($y = 1; $y <= $graph_y; $y++) {
+ if ($mem_total_Bs[$i] >= ($y - 1/2) * $K) {
+ $graph[$x][$y] = $half_char;
+ }
+ if ($mem_total_Bs[$i] >= $y * $K) {
+ $graph[$x][$y] = $full_char;
+ }
+ }
+ }
+ }
+
+ #-------------------------------------------------------------------------
+ # Print graph[][].
+ #-------------------------------------------------------------------------
+ my ($y_label, $y_unit) = B_max_label($peak_mem_total_szB);
+ my ($x_label, $x_unit) = ( $time_unit eq "ms"
+ ? t_max_label($end_time)
+ : B_max_label($end_time) );
+
+ printf(" %2s\n", $y_unit);
+ for ($y = $graph_y; $y >= 0; $y--) {
+ if ($graph_y == $y) { # top row
+ print($y_label);
+ } elsif (0 == $y) { # bottom row
+ print(" 0 ");
+ } else { # anywhere else
+ print(" ");
+ }
+
+ # Axis and data for the row.
+ for ($x = 0; $x <= $graph_x; $x++) {
+ printf("%s", $graph[$x][$y]);
+ }
+ if (0 == $y) {
+ print("$x_unit\n");
+ } else {
+ print("\n");
+ }
+ }
+ printf(" 0%s%5s\n", ' ' x ($graph_x-5), $x_label);
+
+ #-------------------------------------------------------------------------
+ # Print snapshot numbers.
+ #-------------------------------------------------------------------------
+ print("\n");
+ print("Number of snapshots: $n_snapshots\n");
+ print(" Detailed snapshots: [");
+ my $first_detailed = 1;
+ for (my $i = 0; $i < $n_snapshots; $i++) {
+ if ($is_detaileds[$i]) {
+ if ($first_detailed) {
+ printf("$i");
+ $first_detailed = 0;
+ } else {
+ printf(", $i");
+ }
+ if ($i == $peak_num) {
+ print(" (peak)");
+ }
+ }
+ }
+ print("]\n");
+
+ #-------------------------------------------------------------------------
+ # Print snapshots, from $tmp_file.
+ #-------------------------------------------------------------------------
+ open(TMPFILE, "< $tmp_file")
+ || die "Cannot open $tmp_file for reading\n";
+
+ while (my $line = <TMPFILE>) {
+ print($line);
+ }
+ unlink($tmp_file);
+}
+
+#-----------------------------------------------------------------------------
+# Misc functions
+#-----------------------------------------------------------------------------
+sub commify ($) {
+ my ($val) = @_;
+ 1 while ($val =~ s/^(\d+)(\d{3})/$1,$2/);
+ return $val;
+}
+
+
+#----------------------------------------------------------------------------
+# "main()"
+#----------------------------------------------------------------------------
+process_cmd_line();
+read_input_file();
+
+##--------------------------------------------------------------------##
+##--- end ms_print.in ---##
+##--------------------------------------------------------------------##
+
+
diff --git a/massif/perf/Makefile.am b/massif/perf/Makefile.am
new file mode 100644
index 0000000..a5c1303
--- /dev/null
+++ b/massif/perf/Makefile.am
@@ -0,0 +1,13 @@
+
+# For AM_FLAG_M3264_PRI
+include $(top_srcdir)/Makefile.flags.am
+
+EXTRA_DIST = $(noinst_SCRIPTS) \
+ many-xpts.vgperf
+
+check_PROGRAMS = \
+ many-xpts
+
+AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -g -O $(AM_FLAG_M3264_PRI)
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_builddir)/include
+AM_CXXFLAGS = $(AM_CFLAGS)
diff --git a/massif/perf/many-xpts.c b/massif/perf/many-xpts.c
new file mode 100644
index 0000000..e5e3e86
--- /dev/null
+++ b/massif/perf/many-xpts.c
@@ -0,0 +1,52 @@
+#include <stdlib.h>
+
+#define nth_bit(x, n) ((x >> n) & 1)
+#define Fn(N, Np1) \
+ void* a##N(int x) { return ( nth_bit(x, N) ? a##Np1(x) : a##Np1(x) ); }
+
+// This test allocates a lot of heap memory, and every allocation features a
+// different stack trace -- the stack traces are effectively a
+// representation of the number 'i', where each function represents a bit in
+// 'i', and if it's a 1 the first function is called, and if it's a 0 the
+// second function is called.
+
+void* a999(int x)
+{
+ return malloc(100);
+}
+
+Fn(17, 999)
+Fn(16, 17)
+Fn(15, 16)
+Fn(14, 15)
+Fn(13, 14)
+Fn(12, 13)
+Fn(11, 12)
+Fn(10, 11)
+Fn( 9, 10)
+Fn( 8, 9)
+Fn( 7, 8)
+Fn( 6, 7)
+Fn( 5, 6)
+Fn( 4, 5)
+Fn( 3, 4)
+Fn( 2, 3)
+Fn( 1, 2)
+Fn( 0, 1)
+
+int main(void)
+{
+ int i;
+
+ // Create a large XTree.
+ for (i = 0; i < (1 << 18); i++)
+ a0(i);
+
+ // Do a lot of allocations so it gets dup'd a lot of times.
+ for (i = 0; i < 100000; i++) {
+ free(a1(234));
+ free(a2(111));
+ }
+
+ return 0;
+}
diff --git a/massif/perf/many-xpts.vgperf b/massif/perf/many-xpts.vgperf
new file mode 100644
index 0000000..d6ce056
--- /dev/null
+++ b/massif/perf/many-xpts.vgperf
@@ -0,0 +1,2 @@
+prog: many-xpts
+vgopts: --time-unit=B --depth=100
diff --git a/massif/tests/Makefile.am b/massif/tests/Makefile.am
index ea5ae33..3f54d45 100644
--- a/massif/tests/Makefile.am
+++ b/massif/tests/Makefile.am
@@ -2,16 +2,68 @@
# For AM_FLAG_M3264_PRI
include $(top_srcdir)/Makefile.flags.am
-noinst_SCRIPTS = filter_stderr
+noinst_SCRIPTS = filter_stderr filter_verbose
EXTRA_DIST = $(noinst_SCRIPTS) \
- basic_malloc.stderr.exp basic_malloc.vgtest \
+ alloc-fns-A.post.exp alloc-fns-A.stderr.exp alloc-fns-A.vgtest \
+ alloc-fns-B.post.exp alloc-fns-B.stderr.exp alloc-fns-B.vgtest \
+ basic.post.exp basic.stderr.exp basic.vgtest \
+ insig.post.exp insig.stderr.exp insig.vgtest \
+ big-alloc.post.exp big-alloc.stderr.exp big-alloc.vgtest \
+ deep-A.post.exp deep-A.stderr.exp deep-A.vgtest \
+ deep-B.post.exp deep-B.stderr.exp deep-B.vgtest \
+ deep-C.post.exp deep-C.stderr.exp deep-C.vgtest \
+ deep-D.post.exp deep-D.stderr.exp deep-D.vgtest \
+ culling1.stderr.exp culling1.vgtest \
+ culling2.stderr.exp culling2.vgtest \
+ custom_alloc.post.exp custom_alloc.stderr.exp custom_alloc.vgtest
+ ignoring.post.exp ignoring.stderr.exp ignoring.vgtest \
+ long-time.post.exp long-time.stderr.exp long-time.vgtest \
+ new-cpp.post.exp new-cpp.stderr.exp new-cpp.vgtest \
+ no-stack-no-heap.post.exp no-stack-no-heap.stderr.exp no-stack-no-heap.vgtest \
+ null.post.exp null.stderr.exp null.vgtest \
+ one.post.exp one.stderr.exp one.vgtest \
+ overloaded-new.post.exp overloaded-new.stderr.exp overloaded-new.vgtest \
+ params.post.exp params.stderr.exp params.vgtest \
+ peak.post.exp peak.stderr.exp peak.vgtest \
+ peak2.post.exp peak2.stderr.exp peak2.vgtest \
+ realloc.post.exp realloc.stderr.exp realloc.vgtest \
+ thresholds_0_0.post.exp thresholds_0_0.stderr.exp thresholds_0_0.vgtest \
+ thresholds_0_10.post.exp thresholds_0_10.stderr.exp thresholds_0_10.vgtest \
+ thresholds_10_0.post.exp thresholds_10_0.stderr.exp thresholds_10_0.vgtest \
+ thresholds_5_0.post.exp thresholds_5_0.stderr.exp thresholds_5_0.vgtest \
+ thresholds_5_10.post.exp thresholds_5_10.stderr.exp thresholds_5_10.vgtest \
+ thresholds_10_10.post.exp thresholds_10_10.stderr.exp thresholds_10_10.vgtest \
toobig-allocs.stderr.exp toobig-allocs.vgtest \
- true_html.stderr.exp true_html.vgtest \
- true_text.stderr.exp true_text.vgtest
+ zero1.post.exp zero1.stderr.exp zero1.vgtest
+ zero2.post.exp zero2.stderr.exp zero2.vgtest
AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -g $(AM_FLAG_M3264_PRI)
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/include \
+ -I$(top_srcdir)/coregrind -I$(top_builddir)/include \
+ -I@VEX_DIR@/pub
+
check_PROGRAMS = \
- basic_malloc
+ alloc-fns \
+ basic \
+ big-alloc \
+ culling1 culling2 \
+ custom_alloc \
+ deep \
+ ignoring \
+ insig \
+ long-time \
+ new-cpp \
+ null \
+ one \
+ overloaded-new \
+ peak \
+ realloc \
+ thresholds \
+ zero
+
+# C++ tests
+new_cpp_SOURCES = new-cpp.cpp
+overloaded_new_SOURCES = overloaded-new.cpp
diff --git a/massif/tests/alloc-fns-A.post.exp b/massif/tests/alloc-fns-A.post.exp
new file mode 100644
index 0000000..bf5f795
--- /dev/null
+++ b/massif/tests/alloc-fns-A.post.exp
@@ -0,0 +1,81 @@
+--------------------------------------------------------------------------------
+Command: ./alloc-fns
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 900^ @
+ | @
+ | . @
+ | : @
+ | . : @
+ | : : @
+ | : : @
+ | : : : @
+ | : : : @
+ | : : : : @
+ | : : : : @
+ | . : : : : @
+ | : : : : : @
+ | . : : : : : @
+ | : : : : : : @
+ | : : : : : : @
+ | : : : : : : : @
+ | : : : : : : : @
+ | : : : : : : : : @
+ | : : : : : : : : @
+ 0 +-----------------------------------------------------------------------@B
+ 0 900
+
+Number of snapshots: 10
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 100 100 100 0 0
+ 2 200 200 200 0 0
+ 3 300 300 300 0 0
+ 4 400 400 400 0 0
+ 5 500 500 500 0 0
+ 6 600 600 600 0 0
+ 7 700 700 700 0 0
+ 8 800 800 800 0 0
+ 9 900 900 900 0 0
+100.00% (900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->44.44% (400B) 0x........: d4 (alloc-fns.c:18)
+| ->33.33% (300B) 0x........: d3 (alloc-fns.c:19)
+| | ->22.22% (200B) 0x........: d2 (alloc-fns.c:20)
+| | | ->11.11% (100B) 0x........: d1 (alloc-fns.c:21)
+| | | | ->11.11% (100B) 0x........: main (alloc-fns.c:30)
+| | | |
+| | | ->11.11% (100B) 0x........: main (alloc-fns.c:31)
+| | |
+| | ->11.11% (100B) 0x........: main (alloc-fns.c:32)
+| |
+| ->11.11% (100B) 0x........: main (alloc-fns.c:33)
+|
+->33.33% (300B) 0x........: a4 (alloc-fns.c:3)
+| ->33.33% (300B) 0x........: a3 (alloc-fns.c:4)
+| ->33.33% (300B) 0x........: a2 (alloc-fns.c:5)
+| ->33.33% (300B) 0x........: a1 (alloc-fns.c:6)
+| ->11.11% (100B) 0x........: main (alloc-fns.c:25)
+| |
+| ->11.11% (100B) 0x........: main (alloc-fns.c:26)
+| |
+| ->11.11% (100B) 0x........: main (alloc-fns.c:27)
+|
+->11.11% (100B) 0x........: b4 (alloc-fns.c:8)
+| ->11.11% (100B) 0x........: b3 (alloc-fns.c:9)
+| ->11.11% (100B) 0x........: b2 (alloc-fns.c:10)
+| ->11.11% (100B) 0x........: b1 (alloc-fns.c:11)
+| ->11.11% (100B) 0x........: main (alloc-fns.c:28)
+|
+->11.11% (100B) 0x........: c4 (alloc-fns.c:13)
+ ->11.11% (100B) 0x........: c3 (alloc-fns.c:14)
+ ->11.11% (100B) 0x........: c2 (alloc-fns.c:15)
+ ->11.11% (100B) 0x........: c1 (alloc-fns.c:16)
+ ->11.11% (100B) 0x........: main (alloc-fns.c:29)
+
diff --git a/massif/tests/alloc-fns-A.stderr.exp b/massif/tests/alloc-fns-A.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/alloc-fns-A.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/alloc-fns-A.vgtest b/massif/tests/alloc-fns-A.vgtest
new file mode 100644
index 0000000..9200a80
--- /dev/null
+++ b/massif/tests/alloc-fns-A.vgtest
@@ -0,0 +1,4 @@
+prog: alloc-fns
+vgopts: --stacks=no --time-unit=B --heap-admin=0
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/alloc-fns-B.post.exp b/massif/tests/alloc-fns-B.post.exp
new file mode 100644
index 0000000..c997843
--- /dev/null
+++ b/massif/tests/alloc-fns-B.post.exp
@@ -0,0 +1,71 @@
+--------------------------------------------------------------------------------
+Command: ./alloc-fns
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0 --alloc-fn=a4 --alloc-fn=b4 --alloc-fn=b3 --alloc-fn=c4 --alloc-fn=c3 --alloc-fn=c2 --alloc-fn=d4 --alloc-fn=d3 --alloc-fn=d2 --alloc-fn=d1
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 900^ @
+ | @
+ | . @
+ | : @
+ | . : @
+ | : : @
+ | : : @
+ | : : : @
+ | : : : @
+ | : : : : @
+ | : : : : @
+ | . : : : : @
+ | : : : : : @
+ | . : : : : : @
+ | : : : : : : @
+ | : : : : : : @
+ | : : : : : : : @
+ | : : : : : : : @
+ | : : : : : : : : @
+ | : : : : : : : : @
+ 0 +-----------------------------------------------------------------------@B
+ 0 900
+
+Number of snapshots: 10
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 100 100 100 0 0
+ 2 200 200 200 0 0
+ 3 300 300 300 0 0
+ 4 400 400 400 0 0
+ 5 500 500 500 0 0
+ 6 600 600 600 0 0
+ 7 700 700 700 0 0
+ 8 800 800 800 0 0
+ 9 900 900 900 0 0
+100.00% (900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->33.33% (300B) 0x........: a3 (alloc-fns.c:4)
+| ->33.33% (300B) 0x........: a2 (alloc-fns.c:5)
+| ->33.33% (300B) 0x........: a1 (alloc-fns.c:6)
+| ->11.11% (100B) 0x........: main (alloc-fns.c:25)
+| |
+| ->11.11% (100B) 0x........: main (alloc-fns.c:26)
+| |
+| ->11.11% (100B) 0x........: main (alloc-fns.c:27)
+|
+->11.11% (100B) 0x........: b2 (alloc-fns.c:10)
+| ->11.11% (100B) 0x........: b1 (alloc-fns.c:11)
+| ->11.11% (100B) 0x........: main (alloc-fns.c:28)
+|
+->11.11% (100B) 0x........: c1 (alloc-fns.c:16)
+| ->11.11% (100B) 0x........: main (alloc-fns.c:29)
+|
+->11.11% (100B) 0x........: main (alloc-fns.c:30)
+|
+->11.11% (100B) 0x........: main (alloc-fns.c:31)
+|
+->11.11% (100B) 0x........: main (alloc-fns.c:32)
+|
+->11.11% (100B) 0x........: main (alloc-fns.c:33)
+
diff --git a/massif/tests/alloc-fns-B.stderr.exp b/massif/tests/alloc-fns-B.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/alloc-fns-B.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/alloc-fns-B.vgtest b/massif/tests/alloc-fns-B.vgtest
new file mode 100644
index 0000000..fab2b46
--- /dev/null
+++ b/massif/tests/alloc-fns-B.vgtest
@@ -0,0 +1,4 @@
+prog: alloc-fns
+vgopts: --stacks=no --time-unit=B --heap-admin=0 --alloc-fn=a4 --alloc-fn=b4 --alloc-fn=b3 --alloc-fn=c4 --alloc-fn=c3 --alloc-fn=c2 --alloc-fn=d4 --alloc-fn=d3 --alloc-fn=d2 --alloc-fn=d1
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/alloc-fns.c b/massif/tests/alloc-fns.c
new file mode 100644
index 0000000..15785e1
--- /dev/null
+++ b/massif/tests/alloc-fns.c
@@ -0,0 +1,35 @@
+#include <stdlib.h>
+
+void a4(int n) { malloc(n); }
+void a3(int n) { a4(n); }
+void a2(int n) { a3(n); }
+void a1(int n) { a2(n); }
+
+void b4(int n) { malloc(n); }
+void b3(int n) { b4(n); }
+void b2(int n) { b3(n); }
+void b1(int n) { b2(n); }
+
+void c4(int n) { malloc(n); }
+void c3(int n) { c4(n); }
+void c2(int n) { c3(n); }
+void c1(int n) { c2(n); }
+
+void d4(int n) { malloc(n); }
+void d3(int n) { d4(n); }
+void d2(int n) { d3(n); }
+void d1(int n) { d2(n); }
+
+int main(void)
+{
+ a1(100);
+ a1(100);
+ a1(100);
+ b1(100);
+ c1(100);
+ d1(100);
+ d2(100);
+ d3(100);
+ d4(100);
+ return 0;
+}
diff --git a/massif/tests/basic.c b/massif/tests/basic.c
new file mode 100644
index 0000000..303f7ab
--- /dev/null
+++ b/massif/tests/basic.c
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+
+// Allocate some memory and then deallocate it, to get a nice up-then-down
+// graph.
+
+int main(void)
+{
+ // N=36 gives us 72 snapshots, which fills the text graph nicely.
+ #define N 36
+ int i;
+ int* a[N];
+
+ for (i = 0; i < N; i++) {
+ a[i] = malloc(100);
+ }
+ for (i = 0; i < N-1; i++) {
+ free(a[i]);
+ }
+
+ return 0;
+}
diff --git a/massif/tests/basic.post.exp b/massif/tests/basic.post.exp
new file mode 100644
index 0000000..42af051
--- /dev/null
+++ b/massif/tests/basic.post.exp
@@ -0,0 +1,151 @@
+--------------------------------------------------------------------------------
+Command: ./basic
+Massif arguments: --stacks=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+3.797^ #
+ | .:#:.
+ | .:::#:::.
+ | .:::::#:::::.
+ | .@::::::#:::::::.
+ | ::@::::::#:::::::::
+ | .:::@::::::#:::::::::@.
+ | .:::::@::::::#:::::::::@::.
+ | .:::::::@::::::#:::::::::@::::.
+ | .:::::::::@::::::#:::::::::@::::::.
+ | :@:::::::::@::::::#:::::::::@::::::::
+ | .::@:::::::::@::::::#:::::::::@:::::::::.
+ | .::::@:::::::::@::::::#:::::::::@:::::::::@:.
+ | .::::::@:::::::::@::::::#:::::::::@:::::::::@:::.
+ | .::::::::@:::::::::@::::::#:::::::::@:::::::::@:::::.
+ | @:::::::::@:::::::::@::::::#:::::::::@:::::::::@:::::::
+ | .:@:::::::::@:::::::::@::::::#:::::::::@:::::::::@::::::::.
+ | .:::@:::::::::@:::::::::@::::::#:::::::::@:::::::::@:::::::::@.
+ | .:::::@:::::::::@:::::::::@::::::#:::::::::@:::::::::@:::::::::@::.
+ | .:::::::@:::::::::@:::::::::@::::::#:::::::::@:::::::::@:::::::::@::::.
+ 0 +---------@---------@---------@------#---------@---------@---------@---->KB
+ 0 7.488
+
+Number of snapshots: 73
+ Detailed snapshots: [9, 19, 29, 37 (peak), 47, 57, 67]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 108 108 100 8 0
+ 2 216 216 200 16 0
+ 3 324 324 300 24 0
+ 4 432 432 400 32 0
+ 5 540 540 500 40 0
+ 6 648 648 600 48 0
+ 7 756 756 700 56 0
+ 8 864 864 800 64 0
+ 9 972 972 900 72 0
+92.59% (900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (900B) 0x........: main (basic.c:14)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 1,080 1,080 1,000 80 0
+ 11 1,188 1,188 1,100 88 0
+ 12 1,296 1,296 1,200 96 0
+ 13 1,404 1,404 1,300 104 0
+ 14 1,512 1,512 1,400 112 0
+ 15 1,620 1,620 1,500 120 0
+ 16 1,728 1,728 1,600 128 0
+ 17 1,836 1,836 1,700 136 0
+ 18 1,944 1,944 1,800 144 0
+ 19 2,052 2,052 1,900 152 0
+92.59% (1,900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (1,900B) 0x........: main (basic.c:14)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 20 2,160 2,160 2,000 160 0
+ 21 2,268 2,268 2,100 168 0
+ 22 2,376 2,376 2,200 176 0
+ 23 2,484 2,484 2,300 184 0
+ 24 2,592 2,592 2,400 192 0
+ 25 2,700 2,700 2,500 200 0
+ 26 2,808 2,808 2,600 208 0
+ 27 2,916 2,916 2,700 216 0
+ 28 3,024 3,024 2,800 224 0
+ 29 3,132 3,132 2,900 232 0
+92.59% (2,900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (2,900B) 0x........: main (basic.c:14)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 30 3,240 3,240 3,000 240 0
+ 31 3,348 3,348 3,100 248 0
+ 32 3,456 3,456 3,200 256 0
+ 33 3,564 3,564 3,300 264 0
+ 34 3,672 3,672 3,400 272 0
+ 35 3,780 3,780 3,500 280 0
+ 36 3,888 3,888 3,600 288 0
+ 37 3,888 3,888 3,600 288 0
+92.59% (3,600B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (3,600B) 0x........: main (basic.c:14)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 38 3,996 3,780 3,500 280 0
+ 39 4,104 3,672 3,400 272 0
+ 40 4,212 3,564 3,300 264 0
+ 41 4,320 3,456 3,200 256 0
+ 42 4,428 3,348 3,100 248 0
+ 43 4,536 3,240 3,000 240 0
+ 44 4,644 3,132 2,900 232 0
+ 45 4,752 3,024 2,800 224 0
+ 46 4,860 2,916 2,700 216 0
+ 47 4,968 2,808 2,600 208 0
+92.59% (2,600B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (2,600B) 0x........: main (basic.c:14)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 48 5,076 2,700 2,500 200 0
+ 49 5,184 2,592 2,400 192 0
+ 50 5,292 2,484 2,300 184 0
+ 51 5,400 2,376 2,200 176 0
+ 52 5,508 2,268 2,100 168 0
+ 53 5,616 2,160 2,000 160 0
+ 54 5,724 2,052 1,900 152 0
+ 55 5,832 1,944 1,800 144 0
+ 56 5,940 1,836 1,700 136 0
+ 57 6,048 1,728 1,600 128 0
+92.59% (1,600B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (1,600B) 0x........: main (basic.c:14)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 58 6,156 1,620 1,500 120 0
+ 59 6,264 1,512 1,400 112 0
+ 60 6,372 1,404 1,300 104 0
+ 61 6,480 1,296 1,200 96 0
+ 62 6,588 1,188 1,100 88 0
+ 63 6,696 1,080 1,000 80 0
+ 64 6,804 972 900 72 0
+ 65 6,912 864 800 64 0
+ 66 7,020 756 700 56 0
+ 67 7,128 648 600 48 0
+92.59% (600B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (600B) 0x........: main (basic.c:14)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 68 7,236 540 500 40 0
+ 69 7,344 432 400 32 0
+ 70 7,452 324 300 24 0
+ 71 7,560 216 200 16 0
+ 72 7,668 108 100 8 0
diff --git a/massif/tests/basic.stderr.exp b/massif/tests/basic.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/basic.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/basic.vgtest b/massif/tests/basic.vgtest
new file mode 100644
index 0000000..41124cd
--- /dev/null
+++ b/massif/tests/basic.vgtest
@@ -0,0 +1,4 @@
+prog: basic
+vgopts: --stacks=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/basic_malloc.c b/massif/tests/basic_malloc.c
deleted file mode 100644
index 7cb452c..0000000
--- a/massif/tests/basic_malloc.c
+++ /dev/null
@@ -1,31 +0,0 @@
-// In 3.0.0, Massif was badly broken on 64-bit platforms because it asked
-// zero-sized redzones, and the allocator was forgetting to round the size
-// up to sizeof(void*), which is the minimum. This caused bugs #111090 and
-// #111285. This test is just a gentle allocation exercise which was
-// failing.
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#define NN 100
-
-int main(void)
-{
- int i;
- char* a[NN];
-
- for (i = i; i < NN; i++) {
- a[i] = malloc(i);
- }
-
- for (i = i; i < NN; i++) {
- a[i] = realloc(a[i], NN - i);
- }
-
- for (i = i; i < NN; i++) {
- free(a[i]);
- }
-
- return 0;
-}
-
diff --git a/massif/tests/basic_malloc.stderr.exp b/massif/tests/basic_malloc.stderr.exp
deleted file mode 100644
index c3baf21..0000000
--- a/massif/tests/basic_malloc.stderr.exp
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-Total spacetime:
-heap:
-heap admin:
-stack(s):
diff --git a/massif/tests/basic_malloc.vgtest b/massif/tests/basic_malloc.vgtest
deleted file mode 100644
index c63d481..0000000
--- a/massif/tests/basic_malloc.vgtest
+++ /dev/null
@@ -1,2 +0,0 @@
-prog: basic_malloc
-cleanup: rm massif.*.*
diff --git a/massif/tests/big-alloc.c b/massif/tests/big-alloc.c
new file mode 100644
index 0000000..a6811ea
--- /dev/null
+++ b/massif/tests/big-alloc.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+
+// Do some big allocations. At one point, the threshold calculation was
+// multiplying the szB by 10000 without using a Long, which was causing this
+// was causing the threshold calculation to go wrong due to a 32-bit
+// overflow.
+
+int main(void)
+{
+ // 100MB all up.
+ int i;
+ for (i = 0; i < 10; i++) {
+ malloc(10 * 1024 * 1024);
+ }
+
+ return 0;
+}
diff --git a/massif/tests/big-alloc.post.exp b/massif/tests/big-alloc.post.exp
new file mode 100644
index 0000000..2d5b75e
--- /dev/null
+++ b/massif/tests/big-alloc.post.exp
@@ -0,0 +1,53 @@
+--------------------------------------------------------------------------------
+Command: ./big-alloc
+Massif arguments: --stacks=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ MB
+100.0^ :
+ | :
+ | @ :
+ | @ :
+ | : @ :
+ | : @ :
+ | : : @ :
+ | : : @ :
+ | : : : @ :
+ | : : : @ :
+ | : : : : @ :
+ | : : : : @ :
+ | : : : : : @ :
+ | : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : : @ :
+ | : : : : : : : : @ :
+ 0 +----------------------------------------------------------------@------>MB
+ 0 100.0
+
+Number of snapshots: 11
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 10,485,768 10,485,768 10,485,760 8 0
+ 2 20,971,536 20,971,536 20,971,520 16 0
+ 3 31,457,304 31,457,304 31,457,280 24 0
+ 4 41,943,072 41,943,072 41,943,040 32 0
+ 5 52,428,840 52,428,840 52,428,800 40 0
+ 6 62,914,608 62,914,608 62,914,560 48 0
+ 7 73,400,376 73,400,376 73,400,320 56 0
+ 8 83,886,144 83,886,144 83,886,080 64 0
+ 9 94,371,912 94,371,912 94,371,840 72 0
+100.00% (94,371,840B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (94,371,840B) 0x........: main (big-alloc.c:13)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 104,857,680 104,857,680 104,857,600 80 0
diff --git a/massif/tests/big-alloc.stderr.exp b/massif/tests/big-alloc.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/big-alloc.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/big-alloc.vgtest b/massif/tests/big-alloc.vgtest
new file mode 100644
index 0000000..b765673
--- /dev/null
+++ b/massif/tests/big-alloc.vgtest
@@ -0,0 +1,4 @@
+prog: big-alloc
+vgopts: --stacks=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/culling1.c b/massif/tests/culling1.c
new file mode 100644
index 0000000..ea33c47
--- /dev/null
+++ b/massif/tests/culling1.c
@@ -0,0 +1,10 @@
+#include <stdlib.h>
+
+int main(void)
+{
+ int i;
+ for (i = 0; i < 200; i++) {
+ malloc(10);
+ }
+ return 0;
+}
diff --git a/massif/tests/culling1.stderr.exp b/massif/tests/culling1.stderr.exp
new file mode 100644
index 0000000..d39df3c
--- /dev/null
+++ b/massif/tests/culling1.stderr.exp
@@ -0,0 +1,438 @@
+Massif: alloc-fns:
+Massif: 0: malloc
+Massif: 1: __builtin_new
+Massif: 2: operator new(unsigned)
+Massif: 3: operator new(unsigned long)
+Massif: 4: __builtin_vec_new
+Massif: 5: operator new[](unsigned)
+Massif: 6: operator new[](unsigned long)
+Massif: 7: calloc
+Massif: 8: realloc
+Massif: 9: memalign
+Massif: 10: operator new(unsigned, std::nothrow_t const&)
+Massif: 11: operator new[](unsigned, std::nothrow_t const&)
+Massif: 12: operator new(unsigned long, std::nothrow_t const&)
+Massif: 13: operator new[](unsigned long, std::nothrow_t const&)
+Massif: startup S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: alloc S. 1 (t:18, hp:10, ad:8, st:0)
+Massif: alloc S. 2 (t:36, hp:20, ad:16, st:0)
+Massif: alloc S. 3 (t:54, hp:30, ad:24, st:0)
+Massif: alloc S. 4 (t:72, hp:40, ad:32, st:0)
+Massif: alloc S. 5 (t:90, hp:50, ad:40, st:0)
+Massif: alloc S. 6 (t:108, hp:60, ad:48, st:0)
+Massif: alloc S. 7 (t:126, hp:70, ad:56, st:0)
+Massif: alloc S. 8 (t:144, hp:80, ad:64, st:0)
+Massif: alloc Sd 9 (t:162, hp:90, ad:72, st:0)
+Massif: alloc S. 10 (t:180, hp:100, ad:80, st:0)
+Massif: alloc S. 11 (t:198, hp:110, ad:88, st:0)
+Massif: alloc S. 12 (t:216, hp:120, ad:96, st:0)
+Massif: alloc S. 13 (t:234, hp:130, ad:104, st:0)
+Massif: alloc S. 14 (t:252, hp:140, ad:112, st:0)
+Massif: alloc S. 15 (t:270, hp:150, ad:120, st:0)
+Massif: alloc S. 16 (t:288, hp:160, ad:128, st:0)
+Massif: alloc S. 17 (t:306, hp:170, ad:136, st:0)
+Massif: alloc S. 18 (t:324, hp:180, ad:144, st:0)
+Massif: alloc Sd 19 (t:342, hp:190, ad:152, st:0)
+Massif: alloc S. 20 (t:360, hp:200, ad:160, st:0)
+Massif: alloc S. 21 (t:378, hp:210, ad:168, st:0)
+Massif: alloc S. 22 (t:396, hp:220, ad:176, st:0)
+Massif: alloc S. 23 (t:414, hp:230, ad:184, st:0)
+Massif: alloc S. 24 (t:432, hp:240, ad:192, st:0)
+Massif: alloc S. 25 (t:450, hp:250, ad:200, st:0)
+Massif: alloc S. 26 (t:468, hp:260, ad:208, st:0)
+Massif: alloc S. 27 (t:486, hp:270, ad:216, st:0)
+Massif: alloc S. 28 (t:504, hp:280, ad:224, st:0)
+Massif: alloc Sd 29 (t:522, hp:290, ad:232, st:0)
+Massif: alloc S. 30 (t:540, hp:300, ad:240, st:0)
+Massif: alloc S. 31 (t:558, hp:310, ad:248, st:0)
+Massif: alloc S. 32 (t:576, hp:320, ad:256, st:0)
+Massif: alloc S. 33 (t:594, hp:330, ad:264, st:0)
+Massif: alloc S. 34 (t:612, hp:340, ad:272, st:0)
+Massif: alloc S. 35 (t:630, hp:350, ad:280, st:0)
+Massif: alloc S. 36 (t:648, hp:360, ad:288, st:0)
+Massif: alloc S. 37 (t:666, hp:370, ad:296, st:0)
+Massif: alloc S. 38 (t:684, hp:380, ad:304, st:0)
+Massif: alloc Sd 39 (t:702, hp:390, ad:312, st:0)
+Massif: alloc S. 40 (t:720, hp:400, ad:320, st:0)
+Massif: alloc S. 41 (t:738, hp:410, ad:328, st:0)
+Massif: alloc S. 42 (t:756, hp:420, ad:336, st:0)
+Massif: alloc S. 43 (t:774, hp:430, ad:344, st:0)
+Massif: alloc S. 44 (t:792, hp:440, ad:352, st:0)
+Massif: alloc S. 45 (t:810, hp:450, ad:360, st:0)
+Massif: alloc S. 46 (t:828, hp:460, ad:368, st:0)
+Massif: alloc S. 47 (t:846, hp:470, ad:376, st:0)
+Massif: alloc S. 48 (t:864, hp:480, ad:384, st:0)
+Massif: alloc Sd 49 (t:882, hp:490, ad:392, st:0)
+Massif: alloc S. 50 (t:900, hp:500, ad:400, st:0)
+Massif: alloc S. 51 (t:918, hp:510, ad:408, st:0)
+Massif: alloc S. 52 (t:936, hp:520, ad:416, st:0)
+Massif: alloc S. 53 (t:954, hp:530, ad:424, st:0)
+Massif: alloc S. 54 (t:972, hp:540, ad:432, st:0)
+Massif: alloc S. 55 (t:990, hp:550, ad:440, st:0)
+Massif: alloc S. 56 (t:1008, hp:560, ad:448, st:0)
+Massif: alloc S. 57 (t:1026, hp:570, ad:456, st:0)
+Massif: alloc S. 58 (t:1044, hp:580, ad:464, st:0)
+Massif: alloc Sd 59 (t:1062, hp:590, ad:472, st:0)
+Massif: alloc S. 60 (t:1080, hp:600, ad:480, st:0)
+Massif: alloc S. 61 (t:1098, hp:610, ad:488, st:0)
+Massif: alloc S. 62 (t:1116, hp:620, ad:496, st:0)
+Massif: alloc S. 63 (t:1134, hp:630, ad:504, st:0)
+Massif: alloc S. 64 (t:1152, hp:640, ad:512, st:0)
+Massif: alloc S. 65 (t:1170, hp:650, ad:520, st:0)
+Massif: alloc S. 66 (t:1188, hp:660, ad:528, st:0)
+Massif: alloc S. 67 (t:1206, hp:670, ad:536, st:0)
+Massif: alloc S. 68 (t:1224, hp:680, ad:544, st:0)
+Massif: alloc Sd 69 (t:1242, hp:690, ad:552, st:0)
+Massif: alloc S. 70 (t:1260, hp:700, ad:560, st:0)
+Massif: alloc S. 71 (t:1278, hp:710, ad:568, st:0)
+Massif: alloc S. 72 (t:1296, hp:720, ad:576, st:0)
+Massif: alloc S. 73 (t:1314, hp:730, ad:584, st:0)
+Massif: alloc S. 74 (t:1332, hp:740, ad:592, st:0)
+Massif: alloc S. 75 (t:1350, hp:750, ad:600, st:0)
+Massif: alloc S. 76 (t:1368, hp:760, ad:608, st:0)
+Massif: alloc S. 77 (t:1386, hp:770, ad:616, st:0)
+Massif: alloc S. 78 (t:1404, hp:780, ad:624, st:0)
+Massif: alloc Sd 79 (t:1422, hp:790, ad:632, st:0)
+Massif: alloc S. 80 (t:1440, hp:800, ad:640, st:0)
+Massif: alloc S. 81 (t:1458, hp:810, ad:648, st:0)
+Massif: alloc S. 82 (t:1476, hp:820, ad:656, st:0)
+Massif: alloc S. 83 (t:1494, hp:830, ad:664, st:0)
+Massif: alloc S. 84 (t:1512, hp:840, ad:672, st:0)
+Massif: alloc S. 85 (t:1530, hp:850, ad:680, st:0)
+Massif: alloc S. 86 (t:1548, hp:860, ad:688, st:0)
+Massif: alloc S. 87 (t:1566, hp:870, ad:696, st:0)
+Massif: alloc S. 88 (t:1584, hp:880, ad:704, st:0)
+Massif: alloc Sd 89 (t:1602, hp:890, ad:712, st:0)
+Massif: alloc S. 90 (t:1620, hp:900, ad:720, st:0)
+Massif: alloc S. 91 (t:1638, hp:910, ad:728, st:0)
+Massif: alloc S. 92 (t:1656, hp:920, ad:736, st:0)
+Massif: alloc S. 93 (t:1674, hp:930, ad:744, st:0)
+Massif: alloc S. 94 (t:1692, hp:940, ad:752, st:0)
+Massif: alloc S. 95 (t:1710, hp:950, ad:760, st:0)
+Massif: alloc S. 96 (t:1728, hp:960, ad:768, st:0)
+Massif: alloc S. 97 (t:1746, hp:970, ad:776, st:0)
+Massif: alloc S. 98 (t:1764, hp:980, ad:784, st:0)
+Massif: alloc Sd 99 (t:1782, hp:990, ad:792, st:0)
+Massif: Culling...
+Massif: 0 (t-span = 36) S. 1 (t:18, hp:10, ad:8, st:0)
+Massif: 1 (t-span = 36) S. 3 (t:54, hp:30, ad:24, st:0)
+Massif: 2 (t-span = 36) S. 5 (t:90, hp:50, ad:40, st:0)
+Massif: 3 (t-span = 36) S. 7 (t:126, hp:70, ad:56, st:0)
+Massif: 4 (t-span = 36) Sd 9 (t:162, hp:90, ad:72, st:0)
+Massif: 5 (t-span = 36) S. 11 (t:198, hp:110, ad:88, st:0)
+Massif: 6 (t-span = 36) S. 13 (t:234, hp:130, ad:104, st:0)
+Massif: 7 (t-span = 36) S. 15 (t:270, hp:150, ad:120, st:0)
+Massif: 8 (t-span = 36) S. 17 (t:306, hp:170, ad:136, st:0)
+Massif: 9 (t-span = 36) Sd 19 (t:342, hp:190, ad:152, st:0)
+Massif: 10 (t-span = 36) S. 21 (t:378, hp:210, ad:168, st:0)
+Massif: 11 (t-span = 36) S. 23 (t:414, hp:230, ad:184, st:0)
+Massif: 12 (t-span = 36) S. 25 (t:450, hp:250, ad:200, st:0)
+Massif: 13 (t-span = 36) S. 27 (t:486, hp:270, ad:216, st:0)
+Massif: 14 (t-span = 36) Sd 29 (t:522, hp:290, ad:232, st:0)
+Massif: 15 (t-span = 36) S. 31 (t:558, hp:310, ad:248, st:0)
+Massif: 16 (t-span = 36) S. 33 (t:594, hp:330, ad:264, st:0)
+Massif: 17 (t-span = 36) S. 35 (t:630, hp:350, ad:280, st:0)
+Massif: 18 (t-span = 36) S. 37 (t:666, hp:370, ad:296, st:0)
+Massif: 19 (t-span = 36) Sd 39 (t:702, hp:390, ad:312, st:0)
+Massif: 20 (t-span = 36) S. 41 (t:738, hp:410, ad:328, st:0)
+Massif: 21 (t-span = 36) S. 43 (t:774, hp:430, ad:344, st:0)
+Massif: 22 (t-span = 36) S. 45 (t:810, hp:450, ad:360, st:0)
+Massif: 23 (t-span = 36) S. 47 (t:846, hp:470, ad:376, st:0)
+Massif: 24 (t-span = 36) Sd 49 (t:882, hp:490, ad:392, st:0)
+Massif: 25 (t-span = 36) S. 51 (t:918, hp:510, ad:408, st:0)
+Massif: 26 (t-span = 36) S. 53 (t:954, hp:530, ad:424, st:0)
+Massif: 27 (t-span = 36) S. 55 (t:990, hp:550, ad:440, st:0)
+Massif: 28 (t-span = 36) S. 57 (t:1026, hp:570, ad:456, st:0)
+Massif: 29 (t-span = 36) Sd 59 (t:1062, hp:590, ad:472, st:0)
+Massif: 30 (t-span = 36) S. 61 (t:1098, hp:610, ad:488, st:0)
+Massif: 31 (t-span = 36) S. 63 (t:1134, hp:630, ad:504, st:0)
+Massif: 32 (t-span = 36) S. 65 (t:1170, hp:650, ad:520, st:0)
+Massif: 33 (t-span = 36) S. 67 (t:1206, hp:670, ad:536, st:0)
+Massif: 34 (t-span = 36) Sd 69 (t:1242, hp:690, ad:552, st:0)
+Massif: 35 (t-span = 36) S. 71 (t:1278, hp:710, ad:568, st:0)
+Massif: 36 (t-span = 36) S. 73 (t:1314, hp:730, ad:584, st:0)
+Massif: 37 (t-span = 36) S. 75 (t:1350, hp:750, ad:600, st:0)
+Massif: 38 (t-span = 36) S. 77 (t:1386, hp:770, ad:616, st:0)
+Massif: 39 (t-span = 36) Sd 79 (t:1422, hp:790, ad:632, st:0)
+Massif: 40 (t-span = 36) S. 81 (t:1458, hp:810, ad:648, st:0)
+Massif: 41 (t-span = 36) S. 83 (t:1494, hp:830, ad:664, st:0)
+Massif: 42 (t-span = 36) S. 85 (t:1530, hp:850, ad:680, st:0)
+Massif: 43 (t-span = 36) S. 87 (t:1566, hp:870, ad:696, st:0)
+Massif: 44 (t-span = 36) Sd 89 (t:1602, hp:890, ad:712, st:0)
+Massif: 45 (t-span = 36) S. 91 (t:1638, hp:910, ad:728, st:0)
+Massif: 46 (t-span = 36) S. 93 (t:1674, hp:930, ad:744, st:0)
+Massif: 47 (t-span = 36) S. 95 (t:1710, hp:950, ad:760, st:0)
+Massif: 48 (t-span = 36) S. 97 (t:1746, hp:970, ad:776, st:0)
+Massif: 49 (t-span = 54) S. 98 (t:1764, hp:980, ad:784, st:0)
+Massif: Finished culling ( 50 of 100 deleted)
+Massif: post-cull S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: post-cull S. 1 (t:36, hp:20, ad:16, st:0)
+Massif: post-cull S. 2 (t:72, hp:40, ad:32, st:0)
+Massif: post-cull S. 3 (t:108, hp:60, ad:48, st:0)
+Massif: post-cull S. 4 (t:144, hp:80, ad:64, st:0)
+Massif: post-cull S. 5 (t:180, hp:100, ad:80, st:0)
+Massif: post-cull S. 6 (t:216, hp:120, ad:96, st:0)
+Massif: post-cull S. 7 (t:252, hp:140, ad:112, st:0)
+Massif: post-cull S. 8 (t:288, hp:160, ad:128, st:0)
+Massif: post-cull S. 9 (t:324, hp:180, ad:144, st:0)
+Massif: post-cull S. 10 (t:360, hp:200, ad:160, st:0)
+Massif: post-cull S. 11 (t:396, hp:220, ad:176, st:0)
+Massif: post-cull S. 12 (t:432, hp:240, ad:192, st:0)
+Massif: post-cull S. 13 (t:468, hp:260, ad:208, st:0)
+Massif: post-cull S. 14 (t:504, hp:280, ad:224, st:0)
+Massif: post-cull S. 15 (t:540, hp:300, ad:240, st:0)
+Massif: post-cull S. 16 (t:576, hp:320, ad:256, st:0)
+Massif: post-cull S. 17 (t:612, hp:340, ad:272, st:0)
+Massif: post-cull S. 18 (t:648, hp:360, ad:288, st:0)
+Massif: post-cull S. 19 (t:684, hp:380, ad:304, st:0)
+Massif: post-cull S. 20 (t:720, hp:400, ad:320, st:0)
+Massif: post-cull S. 21 (t:756, hp:420, ad:336, st:0)
+Massif: post-cull S. 22 (t:792, hp:440, ad:352, st:0)
+Massif: post-cull S. 23 (t:828, hp:460, ad:368, st:0)
+Massif: post-cull S. 24 (t:864, hp:480, ad:384, st:0)
+Massif: post-cull S. 25 (t:900, hp:500, ad:400, st:0)
+Massif: post-cull S. 26 (t:936, hp:520, ad:416, st:0)
+Massif: post-cull S. 27 (t:972, hp:540, ad:432, st:0)
+Massif: post-cull S. 28 (t:1008, hp:560, ad:448, st:0)
+Massif: post-cull S. 29 (t:1044, hp:580, ad:464, st:0)
+Massif: post-cull S. 30 (t:1080, hp:600, ad:480, st:0)
+Massif: post-cull S. 31 (t:1116, hp:620, ad:496, st:0)
+Massif: post-cull S. 32 (t:1152, hp:640, ad:512, st:0)
+Massif: post-cull S. 33 (t:1188, hp:660, ad:528, st:0)
+Massif: post-cull S. 34 (t:1224, hp:680, ad:544, st:0)
+Massif: post-cull S. 35 (t:1260, hp:700, ad:560, st:0)
+Massif: post-cull S. 36 (t:1296, hp:720, ad:576, st:0)
+Massif: post-cull S. 37 (t:1332, hp:740, ad:592, st:0)
+Massif: post-cull S. 38 (t:1368, hp:760, ad:608, st:0)
+Massif: post-cull S. 39 (t:1404, hp:780, ad:624, st:0)
+Massif: post-cull S. 40 (t:1440, hp:800, ad:640, st:0)
+Massif: post-cull S. 41 (t:1476, hp:820, ad:656, st:0)
+Massif: post-cull S. 42 (t:1512, hp:840, ad:672, st:0)
+Massif: post-cull S. 43 (t:1548, hp:860, ad:688, st:0)
+Massif: post-cull S. 44 (t:1584, hp:880, ad:704, st:0)
+Massif: post-cull S. 45 (t:1620, hp:900, ad:720, st:0)
+Massif: post-cull S. 46 (t:1656, hp:920, ad:736, st:0)
+Massif: post-cull S. 47 (t:1692, hp:940, ad:752, st:0)
+Massif: post-cull S. 48 (t:1728, hp:960, ad:768, st:0)
+Massif: post-cull Sd 49 (t:1782, hp:990, ad:792, st:0)
+Massif: New time interval = 36 (between snapshots 0 and 1)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 50 (t:1818, hp:1010, ad:808, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 51 (t:1854, hp:1030, ad:824, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 52 (t:1890, hp:1050, ad:840, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 53 (t:1926, hp:1070, ad:856, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 54 (t:1962, hp:1090, ad:872, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 55 (t:1998, hp:1110, ad:888, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 56 (t:2034, hp:1130, ad:904, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 57 (t:2070, hp:1150, ad:920, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 58 (t:2106, hp:1170, ad:936, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc Sd 59 (t:2142, hp:1190, ad:952, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 60 (t:2178, hp:1210, ad:968, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 61 (t:2214, hp:1230, ad:984, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 62 (t:2250, hp:1250, ad:1000, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 63 (t:2286, hp:1270, ad:1016, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 64 (t:2322, hp:1290, ad:1032, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 65 (t:2358, hp:1310, ad:1048, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 66 (t:2394, hp:1330, ad:1064, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 67 (t:2430, hp:1350, ad:1080, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 68 (t:2466, hp:1370, ad:1096, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc Sd 69 (t:2502, hp:1390, ad:1112, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 70 (t:2538, hp:1410, ad:1128, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 71 (t:2574, hp:1430, ad:1144, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 72 (t:2610, hp:1450, ad:1160, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 73 (t:2646, hp:1470, ad:1176, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 74 (t:2682, hp:1490, ad:1192, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 75 (t:2718, hp:1510, ad:1208, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 76 (t:2754, hp:1530, ad:1224, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 77 (t:2790, hp:1550, ad:1240, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 78 (t:2826, hp:1570, ad:1256, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc Sd 79 (t:2862, hp:1590, ad:1272, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 80 (t:2898, hp:1610, ad:1288, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 81 (t:2934, hp:1630, ad:1304, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 82 (t:2970, hp:1650, ad:1320, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 83 (t:3006, hp:1670, ad:1336, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 84 (t:3042, hp:1690, ad:1352, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 85 (t:3078, hp:1710, ad:1368, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 86 (t:3114, hp:1730, ad:1384, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 87 (t:3150, hp:1750, ad:1400, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 88 (t:3186, hp:1770, ad:1416, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc Sd 89 (t:3222, hp:1790, ad:1432, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 90 (t:3258, hp:1810, ad:1448, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 91 (t:3294, hp:1830, ad:1464, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 92 (t:3330, hp:1850, ad:1480, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 93 (t:3366, hp:1870, ad:1496, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 94 (t:3402, hp:1890, ad:1512, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 95 (t:3438, hp:1910, ad:1528, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 96 (t:3474, hp:1930, ad:1544, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 97 (t:3510, hp:1950, ad:1560, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc S. 98 (t:3546, hp:1970, ad:1576, st:0)
+Massif: (skipped 1 snapshot)
+Massif: alloc Sd 99 (t:3582, hp:1990, ad:1592, st:0)
+Massif: Culling...
+Massif: 0 (t-span = 72) S. 1 (t:36, hp:20, ad:16, st:0)
+Massif: 1 (t-span = 72) S. 3 (t:108, hp:60, ad:48, st:0)
+Massif: 2 (t-span = 72) S. 5 (t:180, hp:100, ad:80, st:0)
+Massif: 3 (t-span = 72) S. 7 (t:252, hp:140, ad:112, st:0)
+Massif: 4 (t-span = 72) S. 9 (t:324, hp:180, ad:144, st:0)
+Massif: 5 (t-span = 72) S. 11 (t:396, hp:220, ad:176, st:0)
+Massif: 6 (t-span = 72) S. 13 (t:468, hp:260, ad:208, st:0)
+Massif: 7 (t-span = 72) S. 15 (t:540, hp:300, ad:240, st:0)
+Massif: 8 (t-span = 72) S. 17 (t:612, hp:340, ad:272, st:0)
+Massif: 9 (t-span = 72) S. 19 (t:684, hp:380, ad:304, st:0)
+Massif: 10 (t-span = 72) S. 21 (t:756, hp:420, ad:336, st:0)
+Massif: 11 (t-span = 72) S. 23 (t:828, hp:460, ad:368, st:0)
+Massif: 12 (t-span = 72) S. 25 (t:900, hp:500, ad:400, st:0)
+Massif: 13 (t-span = 72) S. 27 (t:972, hp:540, ad:432, st:0)
+Massif: 14 (t-span = 72) S. 29 (t:1044, hp:580, ad:464, st:0)
+Massif: 15 (t-span = 72) S. 31 (t:1116, hp:620, ad:496, st:0)
+Massif: 16 (t-span = 72) S. 33 (t:1188, hp:660, ad:528, st:0)
+Massif: 17 (t-span = 72) S. 35 (t:1260, hp:700, ad:560, st:0)
+Massif: 18 (t-span = 72) S. 37 (t:1332, hp:740, ad:592, st:0)
+Massif: 19 (t-span = 72) S. 39 (t:1404, hp:780, ad:624, st:0)
+Massif: 20 (t-span = 72) S. 41 (t:1476, hp:820, ad:656, st:0)
+Massif: 21 (t-span = 72) S. 43 (t:1548, hp:860, ad:688, st:0)
+Massif: 22 (t-span = 72) S. 45 (t:1620, hp:900, ad:720, st:0)
+Massif: 23 (t-span = 72) S. 47 (t:1692, hp:940, ad:752, st:0)
+Massif: 24 (t-span = 72) S. 50 (t:1818, hp:1010, ad:808, st:0)
+Massif: 25 (t-span = 72) S. 52 (t:1890, hp:1050, ad:840, st:0)
+Massif: 26 (t-span = 72) S. 54 (t:1962, hp:1090, ad:872, st:0)
+Massif: 27 (t-span = 72) S. 56 (t:2034, hp:1130, ad:904, st:0)
+Massif: 28 (t-span = 72) S. 58 (t:2106, hp:1170, ad:936, st:0)
+Massif: 29 (t-span = 72) S. 60 (t:2178, hp:1210, ad:968, st:0)
+Massif: 30 (t-span = 72) S. 62 (t:2250, hp:1250, ad:1000, st:0)
+Massif: 31 (t-span = 72) S. 64 (t:2322, hp:1290, ad:1032, st:0)
+Massif: 32 (t-span = 72) S. 66 (t:2394, hp:1330, ad:1064, st:0)
+Massif: 33 (t-span = 72) S. 68 (t:2466, hp:1370, ad:1096, st:0)
+Massif: 34 (t-span = 72) S. 70 (t:2538, hp:1410, ad:1128, st:0)
+Massif: 35 (t-span = 72) S. 72 (t:2610, hp:1450, ad:1160, st:0)
+Massif: 36 (t-span = 72) S. 74 (t:2682, hp:1490, ad:1192, st:0)
+Massif: 37 (t-span = 72) S. 76 (t:2754, hp:1530, ad:1224, st:0)
+Massif: 38 (t-span = 72) S. 78 (t:2826, hp:1570, ad:1256, st:0)
+Massif: 39 (t-span = 72) S. 80 (t:2898, hp:1610, ad:1288, st:0)
+Massif: 40 (t-span = 72) S. 82 (t:2970, hp:1650, ad:1320, st:0)
+Massif: 41 (t-span = 72) S. 84 (t:3042, hp:1690, ad:1352, st:0)
+Massif: 42 (t-span = 72) S. 86 (t:3114, hp:1730, ad:1384, st:0)
+Massif: 43 (t-span = 72) S. 88 (t:3186, hp:1770, ad:1416, st:0)
+Massif: 44 (t-span = 72) S. 90 (t:3258, hp:1810, ad:1448, st:0)
+Massif: 45 (t-span = 72) S. 92 (t:3330, hp:1850, ad:1480, st:0)
+Massif: 46 (t-span = 72) S. 94 (t:3402, hp:1890, ad:1512, st:0)
+Massif: 47 (t-span = 72) S. 96 (t:3474, hp:1930, ad:1544, st:0)
+Massif: 48 (t-span = 72) S. 98 (t:3546, hp:1970, ad:1576, st:0)
+Massif: 49 (t-span = 126) S. 48 (t:1728, hp:960, ad:768, st:0)
+Massif: Finished culling ( 50 of 100 deleted)
+Massif: post-cull S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: post-cull S. 1 (t:72, hp:40, ad:32, st:0)
+Massif: post-cull S. 2 (t:144, hp:80, ad:64, st:0)
+Massif: post-cull S. 3 (t:216, hp:120, ad:96, st:0)
+Massif: post-cull S. 4 (t:288, hp:160, ad:128, st:0)
+Massif: post-cull S. 5 (t:360, hp:200, ad:160, st:0)
+Massif: post-cull S. 6 (t:432, hp:240, ad:192, st:0)
+Massif: post-cull S. 7 (t:504, hp:280, ad:224, st:0)
+Massif: post-cull S. 8 (t:576, hp:320, ad:256, st:0)
+Massif: post-cull S. 9 (t:648, hp:360, ad:288, st:0)
+Massif: post-cull S. 10 (t:720, hp:400, ad:320, st:0)
+Massif: post-cull S. 11 (t:792, hp:440, ad:352, st:0)
+Massif: post-cull S. 12 (t:864, hp:480, ad:384, st:0)
+Massif: post-cull S. 13 (t:936, hp:520, ad:416, st:0)
+Massif: post-cull S. 14 (t:1008, hp:560, ad:448, st:0)
+Massif: post-cull S. 15 (t:1080, hp:600, ad:480, st:0)
+Massif: post-cull S. 16 (t:1152, hp:640, ad:512, st:0)
+Massif: post-cull S. 17 (t:1224, hp:680, ad:544, st:0)
+Massif: post-cull S. 18 (t:1296, hp:720, ad:576, st:0)
+Massif: post-cull S. 19 (t:1368, hp:760, ad:608, st:0)
+Massif: post-cull S. 20 (t:1440, hp:800, ad:640, st:0)
+Massif: post-cull S. 21 (t:1512, hp:840, ad:672, st:0)
+Massif: post-cull S. 22 (t:1584, hp:880, ad:704, st:0)
+Massif: post-cull S. 23 (t:1656, hp:920, ad:736, st:0)
+Massif: post-cull Sd 24 (t:1782, hp:990, ad:792, st:0)
+Massif: post-cull S. 25 (t:1854, hp:1030, ad:824, st:0)
+Massif: post-cull S. 26 (t:1926, hp:1070, ad:856, st:0)
+Massif: post-cull S. 27 (t:1998, hp:1110, ad:888, st:0)
+Massif: post-cull S. 28 (t:2070, hp:1150, ad:920, st:0)
+Massif: post-cull Sd 29 (t:2142, hp:1190, ad:952, st:0)
+Massif: post-cull S. 30 (t:2214, hp:1230, ad:984, st:0)
+Massif: post-cull S. 31 (t:2286, hp:1270, ad:1016, st:0)
+Massif: post-cull S. 32 (t:2358, hp:1310, ad:1048, st:0)
+Massif: post-cull S. 33 (t:2430, hp:1350, ad:1080, st:0)
+Massif: post-cull Sd 34 (t:2502, hp:1390, ad:1112, st:0)
+Massif: post-cull S. 35 (t:2574, hp:1430, ad:1144, st:0)
+Massif: post-cull S. 36 (t:2646, hp:1470, ad:1176, st:0)
+Massif: post-cull S. 37 (t:2718, hp:1510, ad:1208, st:0)
+Massif: post-cull S. 38 (t:2790, hp:1550, ad:1240, st:0)
+Massif: post-cull Sd 39 (t:2862, hp:1590, ad:1272, st:0)
+Massif: post-cull S. 40 (t:2934, hp:1630, ad:1304, st:0)
+Massif: post-cull S. 41 (t:3006, hp:1670, ad:1336, st:0)
+Massif: post-cull S. 42 (t:3078, hp:1710, ad:1368, st:0)
+Massif: post-cull S. 43 (t:3150, hp:1750, ad:1400, st:0)
+Massif: post-cull Sd 44 (t:3222, hp:1790, ad:1432, st:0)
+Massif: post-cull S. 45 (t:3294, hp:1830, ad:1464, st:0)
+Massif: post-cull S. 46 (t:3366, hp:1870, ad:1496, st:0)
+Massif: post-cull S. 47 (t:3438, hp:1910, ad:1528, st:0)
+Massif: post-cull S. 48 (t:3510, hp:1950, ad:1560, st:0)
+Massif: post-cull Sd 49 (t:3582, hp:1990, ad:1592, st:0)
+Massif: New time interval = 72 (between snapshots 0 and 1)
+Massif: heap allocs: 200
+Massif: heap reallocs: 0
+Massif: heap frees: 0
+Massif: stack allocs: 0
+Massif: stack frees: 0
+Massif: XPts: 4
+Massif: top-XPts: 1 (25%)
+Massif: XPt-init-expansions: 3
+Massif: XPt-later-expansions: 0
+Massif: SXPt allocs: 60
+Massif: SXPt frees: 36
+Massif: skipped snapshots: 51
+Massif: real snapshots: 150
+Massif: detailed snapshots: 15
+Massif: peak snapshots: 0
+Massif: cullings: 2
+Massif: XCon_redos: 0
diff --git a/massif/tests/culling1.vgtest b/massif/tests/culling1.vgtest
new file mode 100644
index 0000000..50918cd
--- /dev/null
+++ b/massif/tests/culling1.vgtest
@@ -0,0 +1,4 @@
+prog: culling1
+vgopts: -v -v --stacks=no --time-unit=B
+stderr_filter: filter_verbose
+cleanup: rm massif.out
diff --git a/massif/tests/culling2.c b/massif/tests/culling2.c
new file mode 100644
index 0000000..0536ee4
--- /dev/null
+++ b/massif/tests/culling2.c
@@ -0,0 +1,10 @@
+#include <stdlib.h>
+
+int main(void)
+{
+ int i;
+ for (i = 0; i < 200; i++) {
+ malloc(i);
+ }
+ return 0;
+}
diff --git a/massif/tests/culling2.stderr.exp b/massif/tests/culling2.stderr.exp
new file mode 100644
index 0000000..f5f13d3
--- /dev/null
+++ b/massif/tests/culling2.stderr.exp
@@ -0,0 +1,541 @@
+Massif: alloc-fns:
+Massif: 0: malloc
+Massif: 1: __builtin_new
+Massif: 2: operator new(unsigned)
+Massif: 3: operator new(unsigned long)
+Massif: 4: __builtin_vec_new
+Massif: 5: operator new[](unsigned)
+Massif: 6: operator new[](unsigned long)
+Massif: 7: calloc
+Massif: 8: realloc
+Massif: 9: memalign
+Massif: 10: operator new(unsigned, std::nothrow_t const&)
+Massif: 11: operator new[](unsigned, std::nothrow_t const&)
+Massif: 12: operator new(unsigned long, std::nothrow_t const&)
+Massif: 13: operator new[](unsigned long, std::nothrow_t const&)
+Massif: startup S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: alloc S. 1 (t:8, hp:0, ad:8, st:0)
+Massif: alloc S. 2 (t:17, hp:1, ad:16, st:0)
+Massif: alloc S. 3 (t:27, hp:3, ad:24, st:0)
+Massif: alloc S. 4 (t:38, hp:6, ad:32, st:0)
+Massif: alloc S. 5 (t:50, hp:10, ad:40, st:0)
+Massif: alloc S. 6 (t:63, hp:15, ad:48, st:0)
+Massif: alloc S. 7 (t:77, hp:21, ad:56, st:0)
+Massif: alloc S. 8 (t:92, hp:28, ad:64, st:0)
+Massif: alloc Sd 9 (t:108, hp:36, ad:72, st:0)
+Massif: alloc S. 10 (t:125, hp:45, ad:80, st:0)
+Massif: alloc S. 11 (t:143, hp:55, ad:88, st:0)
+Massif: alloc S. 12 (t:162, hp:66, ad:96, st:0)
+Massif: alloc S. 13 (t:182, hp:78, ad:104, st:0)
+Massif: alloc S. 14 (t:203, hp:91, ad:112, st:0)
+Massif: alloc S. 15 (t:225, hp:105, ad:120, st:0)
+Massif: alloc S. 16 (t:248, hp:120, ad:128, st:0)
+Massif: alloc S. 17 (t:272, hp:136, ad:136, st:0)
+Massif: alloc S. 18 (t:297, hp:153, ad:144, st:0)
+Massif: alloc Sd 19 (t:323, hp:171, ad:152, st:0)
+Massif: alloc S. 20 (t:350, hp:190, ad:160, st:0)
+Massif: alloc S. 21 (t:378, hp:210, ad:168, st:0)
+Massif: alloc S. 22 (t:407, hp:231, ad:176, st:0)
+Massif: alloc S. 23 (t:437, hp:253, ad:184, st:0)
+Massif: alloc S. 24 (t:468, hp:276, ad:192, st:0)
+Massif: alloc S. 25 (t:500, hp:300, ad:200, st:0)
+Massif: alloc S. 26 (t:533, hp:325, ad:208, st:0)
+Massif: alloc S. 27 (t:567, hp:351, ad:216, st:0)
+Massif: alloc S. 28 (t:602, hp:378, ad:224, st:0)
+Massif: alloc Sd 29 (t:638, hp:406, ad:232, st:0)
+Massif: alloc S. 30 (t:675, hp:435, ad:240, st:0)
+Massif: alloc S. 31 (t:713, hp:465, ad:248, st:0)
+Massif: alloc S. 32 (t:752, hp:496, ad:256, st:0)
+Massif: alloc S. 33 (t:792, hp:528, ad:264, st:0)
+Massif: alloc S. 34 (t:833, hp:561, ad:272, st:0)
+Massif: alloc S. 35 (t:875, hp:595, ad:280, st:0)
+Massif: alloc S. 36 (t:918, hp:630, ad:288, st:0)
+Massif: alloc S. 37 (t:962, hp:666, ad:296, st:0)
+Massif: alloc S. 38 (t:1007, hp:703, ad:304, st:0)
+Massif: alloc Sd 39 (t:1053, hp:741, ad:312, st:0)
+Massif: alloc S. 40 (t:1100, hp:780, ad:320, st:0)
+Massif: alloc S. 41 (t:1148, hp:820, ad:328, st:0)
+Massif: alloc S. 42 (t:1197, hp:861, ad:336, st:0)
+Massif: alloc S. 43 (t:1247, hp:903, ad:344, st:0)
+Massif: alloc S. 44 (t:1298, hp:946, ad:352, st:0)
+Massif: alloc S. 45 (t:1350, hp:990, ad:360, st:0)
+Massif: alloc S. 46 (t:1403, hp:1035, ad:368, st:0)
+Massif: alloc S. 47 (t:1457, hp:1081, ad:376, st:0)
+Massif: alloc S. 48 (t:1512, hp:1128, ad:384, st:0)
+Massif: alloc Sd 49 (t:1568, hp:1176, ad:392, st:0)
+Massif: alloc S. 50 (t:1625, hp:1225, ad:400, st:0)
+Massif: alloc S. 51 (t:1683, hp:1275, ad:408, st:0)
+Massif: alloc S. 52 (t:1742, hp:1326, ad:416, st:0)
+Massif: alloc S. 53 (t:1802, hp:1378, ad:424, st:0)
+Massif: alloc S. 54 (t:1863, hp:1431, ad:432, st:0)
+Massif: alloc S. 55 (t:1925, hp:1485, ad:440, st:0)
+Massif: alloc S. 56 (t:1988, hp:1540, ad:448, st:0)
+Massif: alloc S. 57 (t:2052, hp:1596, ad:456, st:0)
+Massif: alloc S. 58 (t:2117, hp:1653, ad:464, st:0)
+Massif: alloc Sd 59 (t:2183, hp:1711, ad:472, st:0)
+Massif: alloc S. 60 (t:2250, hp:1770, ad:480, st:0)
+Massif: alloc S. 61 (t:2318, hp:1830, ad:488, st:0)
+Massif: alloc S. 62 (t:2387, hp:1891, ad:496, st:0)
+Massif: alloc S. 63 (t:2457, hp:1953, ad:504, st:0)
+Massif: alloc S. 64 (t:2528, hp:2016, ad:512, st:0)
+Massif: alloc S. 65 (t:2600, hp:2080, ad:520, st:0)
+Massif: alloc S. 66 (t:2673, hp:2145, ad:528, st:0)
+Massif: alloc S. 67 (t:2747, hp:2211, ad:536, st:0)
+Massif: alloc S. 68 (t:2822, hp:2278, ad:544, st:0)
+Massif: alloc Sd 69 (t:2898, hp:2346, ad:552, st:0)
+Massif: alloc S. 70 (t:2975, hp:2415, ad:560, st:0)
+Massif: alloc S. 71 (t:3053, hp:2485, ad:568, st:0)
+Massif: alloc S. 72 (t:3132, hp:2556, ad:576, st:0)
+Massif: alloc S. 73 (t:3212, hp:2628, ad:584, st:0)
+Massif: alloc S. 74 (t:3293, hp:2701, ad:592, st:0)
+Massif: alloc S. 75 (t:3375, hp:2775, ad:600, st:0)
+Massif: alloc S. 76 (t:3458, hp:2850, ad:608, st:0)
+Massif: alloc S. 77 (t:3542, hp:2926, ad:616, st:0)
+Massif: alloc S. 78 (t:3627, hp:3003, ad:624, st:0)
+Massif: alloc Sd 79 (t:3713, hp:3081, ad:632, st:0)
+Massif: alloc S. 80 (t:3800, hp:3160, ad:640, st:0)
+Massif: alloc S. 81 (t:3888, hp:3240, ad:648, st:0)
+Massif: alloc S. 82 (t:3977, hp:3321, ad:656, st:0)
+Massif: alloc S. 83 (t:4067, hp:3403, ad:664, st:0)
+Massif: alloc S. 84 (t:4158, hp:3486, ad:672, st:0)
+Massif: alloc S. 85 (t:4250, hp:3570, ad:680, st:0)
+Massif: alloc S. 86 (t:4343, hp:3655, ad:688, st:0)
+Massif: alloc S. 87 (t:4437, hp:3741, ad:696, st:0)
+Massif: alloc S. 88 (t:4532, hp:3828, ad:704, st:0)
+Massif: alloc Sd 89 (t:4628, hp:3916, ad:712, st:0)
+Massif: alloc S. 90 (t:4725, hp:4005, ad:720, st:0)
+Massif: alloc S. 91 (t:4823, hp:4095, ad:728, st:0)
+Massif: alloc S. 92 (t:4922, hp:4186, ad:736, st:0)
+Massif: alloc S. 93 (t:5022, hp:4278, ad:744, st:0)
+Massif: alloc S. 94 (t:5123, hp:4371, ad:752, st:0)
+Massif: alloc S. 95 (t:5225, hp:4465, ad:760, st:0)
+Massif: alloc S. 96 (t:5328, hp:4560, ad:768, st:0)
+Massif: alloc S. 97 (t:5432, hp:4656, ad:776, st:0)
+Massif: alloc S. 98 (t:5537, hp:4753, ad:784, st:0)
+Massif: alloc Sd 99 (t:5643, hp:4851, ad:792, st:0)
+Massif: Culling...
+Massif: 0 (t-span = 17) S. 1 (t:8, hp:0, ad:8, st:0)
+Massif: 1 (t-span = 21) S. 3 (t:27, hp:3, ad:24, st:0)
+Massif: 2 (t-span = 25) S. 5 (t:50, hp:10, ad:40, st:0)
+Massif: 3 (t-span = 29) S. 7 (t:77, hp:21, ad:56, st:0)
+Massif: 4 (t-span = 33) Sd 9 (t:108, hp:36, ad:72, st:0)
+Massif: 5 (t-span = 37) S. 11 (t:143, hp:55, ad:88, st:0)
+Massif: 6 (t-span = 38) S. 2 (t:17, hp:1, ad:16, st:0)
+Massif: 7 (t-span = 41) S. 13 (t:182, hp:78, ad:104, st:0)
+Massif: 8 (t-span = 45) S. 15 (t:225, hp:105, ad:120, st:0)
+Massif: 9 (t-span = 49) S. 17 (t:272, hp:136, ad:136, st:0)
+Massif: 10 (t-span = 53) Sd 19 (t:323, hp:171, ad:152, st:0)
+Massif: 11 (t-span = 54) S. 6 (t:63, hp:15, ad:48, st:0)
+Massif: 12 (t-span = 57) S. 21 (t:378, hp:210, ad:168, st:0)
+Massif: 13 (t-span = 61) S. 23 (t:437, hp:253, ad:184, st:0)
+Massif: 14 (t-span = 65) S. 25 (t:500, hp:300, ad:200, st:0)
+Massif: 15 (t-span = 69) S. 27 (t:567, hp:351, ad:216, st:0)
+Massif: 16 (t-span = 70) S. 10 (t:125, hp:45, ad:80, st:0)
+Massif: 17 (t-span = 73) Sd 29 (t:638, hp:406, ad:232, st:0)
+Massif: 18 (t-span = 77) S. 31 (t:713, hp:465, ad:248, st:0)
+Massif: 19 (t-span = 81) S. 33 (t:792, hp:528, ad:264, st:0)
+Massif: 20 (t-span = 85) S. 35 (t:875, hp:595, ad:280, st:0)
+Massif: 21 (t-span = 86) S. 14 (t:203, hp:91, ad:112, st:0)
+Massif: 22 (t-span = 89) S. 37 (t:962, hp:666, ad:296, st:0)
+Massif: 23 (t-span = 92) S. 4 (t:38, hp:6, ad:32, st:0)
+Massif: 24 (t-span = 93) Sd 39 (t:1053, hp:741, ad:312, st:0)
+Massif: 25 (t-span = 97) S. 41 (t:1148, hp:820, ad:328, st:0)
+Massif: 26 (t-span = 101) S. 43 (t:1247, hp:903, ad:344, st:0)
+Massif: 27 (t-span = 102) S. 18 (t:297, hp:153, ad:144, st:0)
+Massif: 28 (t-span = 105) S. 45 (t:1350, hp:990, ad:360, st:0)
+Massif: 29 (t-span = 109) S. 47 (t:1457, hp:1081, ad:376, st:0)
+Massif: 30 (t-span = 113) Sd 49 (t:1568, hp:1176, ad:392, st:0)
+Massif: 31 (t-span = 117) S. 51 (t:1683, hp:1275, ad:408, st:0)
+Massif: 32 (t-span = 118) S. 22 (t:407, hp:231, ad:176, st:0)
+Massif: 33 (t-span = 121) S. 53 (t:1802, hp:1378, ad:424, st:0)
+Massif: 34 (t-span = 125) S. 55 (t:1925, hp:1485, ad:440, st:0)
+Massif: 35 (t-span = 129) S. 57 (t:2052, hp:1596, ad:456, st:0)
+Massif: 36 (t-span = 133) Sd 59 (t:2183, hp:1711, ad:472, st:0)
+Massif: 37 (t-span = 134) S. 26 (t:533, hp:325, ad:208, st:0)
+Massif: 38 (t-span = 137) S. 61 (t:2318, hp:1830, ad:488, st:0)
+Massif: 39 (t-span = 141) S. 63 (t:2457, hp:1953, ad:504, st:0)
+Massif: 40 (t-span = 145) S. 65 (t:2600, hp:2080, ad:520, st:0)
+Massif: 41 (t-span = 149) S. 67 (t:2747, hp:2211, ad:536, st:0)
+Massif: 42 (t-span = 150) S. 30 (t:675, hp:435, ad:240, st:0)
+Massif: 43 (t-span = 153) Sd 69 (t:2898, hp:2346, ad:552, st:0)
+Massif: 44 (t-span = 156) S. 12 (t:162, hp:66, ad:96, st:0)
+Massif: 45 (t-span = 157) S. 71 (t:3053, hp:2485, ad:568, st:0)
+Massif: 46 (t-span = 161) S. 73 (t:3212, hp:2628, ad:584, st:0)
+Massif: 47 (t-span = 165) S. 75 (t:3375, hp:2775, ad:600, st:0)
+Massif: 48 (t-span = 166) S. 34 (t:833, hp:561, ad:272, st:0)
+Massif: 49 (t-span = 169) S. 77 (t:3542, hp:2926, ad:616, st:0)
+Massif: Finished culling ( 50 of 100 deleted)
+Massif: post-cull S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: post-cull S. 1 (t:92, hp:28, ad:64, st:0)
+Massif: post-cull S. 2 (t:248, hp:120, ad:128, st:0)
+Massif: post-cull S. 3 (t:350, hp:190, ad:160, st:0)
+Massif: post-cull S. 4 (t:468, hp:276, ad:192, st:0)
+Massif: post-cull S. 5 (t:602, hp:378, ad:224, st:0)
+Massif: post-cull S. 6 (t:752, hp:496, ad:256, st:0)
+Massif: post-cull S. 7 (t:918, hp:630, ad:288, st:0)
+Massif: post-cull S. 8 (t:1007, hp:703, ad:304, st:0)
+Massif: post-cull S. 9 (t:1100, hp:780, ad:320, st:0)
+Massif: post-cull S. 10 (t:1197, hp:861, ad:336, st:0)
+Massif: post-cull S. 11 (t:1298, hp:946, ad:352, st:0)
+Massif: post-cull S. 12 (t:1403, hp:1035, ad:368, st:0)
+Massif: post-cull S. 13 (t:1512, hp:1128, ad:384, st:0)
+Massif: post-cull S. 14 (t:1625, hp:1225, ad:400, st:0)
+Massif: post-cull S. 15 (t:1742, hp:1326, ad:416, st:0)
+Massif: post-cull S. 16 (t:1863, hp:1431, ad:432, st:0)
+Massif: post-cull S. 17 (t:1988, hp:1540, ad:448, st:0)
+Massif: post-cull S. 18 (t:2117, hp:1653, ad:464, st:0)
+Massif: post-cull S. 19 (t:2250, hp:1770, ad:480, st:0)
+Massif: post-cull S. 20 (t:2387, hp:1891, ad:496, st:0)
+Massif: post-cull S. 21 (t:2528, hp:2016, ad:512, st:0)
+Massif: post-cull S. 22 (t:2673, hp:2145, ad:528, st:0)
+Massif: post-cull S. 23 (t:2822, hp:2278, ad:544, st:0)
+Massif: post-cull S. 24 (t:2975, hp:2415, ad:560, st:0)
+Massif: post-cull S. 25 (t:3132, hp:2556, ad:576, st:0)
+Massif: post-cull S. 26 (t:3293, hp:2701, ad:592, st:0)
+Massif: post-cull S. 27 (t:3458, hp:2850, ad:608, st:0)
+Massif: post-cull S. 28 (t:3627, hp:3003, ad:624, st:0)
+Massif: post-cull Sd 29 (t:3713, hp:3081, ad:632, st:0)
+Massif: post-cull S. 30 (t:3800, hp:3160, ad:640, st:0)
+Massif: post-cull S. 31 (t:3888, hp:3240, ad:648, st:0)
+Massif: post-cull S. 32 (t:3977, hp:3321, ad:656, st:0)
+Massif: post-cull S. 33 (t:4067, hp:3403, ad:664, st:0)
+Massif: post-cull S. 34 (t:4158, hp:3486, ad:672, st:0)
+Massif: post-cull S. 35 (t:4250, hp:3570, ad:680, st:0)
+Massif: post-cull S. 36 (t:4343, hp:3655, ad:688, st:0)
+Massif: post-cull S. 37 (t:4437, hp:3741, ad:696, st:0)
+Massif: post-cull S. 38 (t:4532, hp:3828, ad:704, st:0)
+Massif: post-cull Sd 39 (t:4628, hp:3916, ad:712, st:0)
+Massif: post-cull S. 40 (t:4725, hp:4005, ad:720, st:0)
+Massif: post-cull S. 41 (t:4823, hp:4095, ad:728, st:0)
+Massif: post-cull S. 42 (t:4922, hp:4186, ad:736, st:0)
+Massif: post-cull S. 43 (t:5022, hp:4278, ad:744, st:0)
+Massif: post-cull S. 44 (t:5123, hp:4371, ad:752, st:0)
+Massif: post-cull S. 45 (t:5225, hp:4465, ad:760, st:0)
+Massif: post-cull S. 46 (t:5328, hp:4560, ad:768, st:0)
+Massif: post-cull S. 47 (t:5432, hp:4656, ad:776, st:0)
+Massif: post-cull S. 48 (t:5537, hp:4753, ad:784, st:0)
+Massif: post-cull Sd 49 (t:5643, hp:4851, ad:792, st:0)
+Massif: New time interval = 86 (between snapshots 28 and 29)
+Massif: alloc S. 50 (t:5750, hp:4950, ad:800, st:0)
+Massif: alloc S. 51 (t:5858, hp:5050, ad:808, st:0)
+Massif: alloc S. 52 (t:5967, hp:5151, ad:816, st:0)
+Massif: alloc S. 53 (t:6077, hp:5253, ad:824, st:0)
+Massif: alloc S. 54 (t:6188, hp:5356, ad:832, st:0)
+Massif: alloc S. 55 (t:6300, hp:5460, ad:840, st:0)
+Massif: alloc S. 56 (t:6413, hp:5565, ad:848, st:0)
+Massif: alloc S. 57 (t:6527, hp:5671, ad:856, st:0)
+Massif: alloc S. 58 (t:6642, hp:5778, ad:864, st:0)
+Massif: alloc Sd 59 (t:6758, hp:5886, ad:872, st:0)
+Massif: alloc S. 60 (t:6875, hp:5995, ad:880, st:0)
+Massif: alloc S. 61 (t:6993, hp:6105, ad:888, st:0)
+Massif: alloc S. 62 (t:7112, hp:6216, ad:896, st:0)
+Massif: alloc S. 63 (t:7232, hp:6328, ad:904, st:0)
+Massif: alloc S. 64 (t:7353, hp:6441, ad:912, st:0)
+Massif: alloc S. 65 (t:7475, hp:6555, ad:920, st:0)
+Massif: alloc S. 66 (t:7598, hp:6670, ad:928, st:0)
+Massif: alloc S. 67 (t:7722, hp:6786, ad:936, st:0)
+Massif: alloc S. 68 (t:7847, hp:6903, ad:944, st:0)
+Massif: alloc Sd 69 (t:7973, hp:7021, ad:952, st:0)
+Massif: alloc S. 70 (t:8100, hp:7140, ad:960, st:0)
+Massif: alloc S. 71 (t:8228, hp:7260, ad:968, st:0)
+Massif: alloc S. 72 (t:8357, hp:7381, ad:976, st:0)
+Massif: alloc S. 73 (t:8487, hp:7503, ad:984, st:0)
+Massif: alloc S. 74 (t:8618, hp:7626, ad:992, st:0)
+Massif: alloc S. 75 (t:8750, hp:7750, ad:1000, st:0)
+Massif: alloc S. 76 (t:8883, hp:7875, ad:1008, st:0)
+Massif: alloc S. 77 (t:9017, hp:8001, ad:1016, st:0)
+Massif: alloc S. 78 (t:9152, hp:8128, ad:1024, st:0)
+Massif: alloc Sd 79 (t:9288, hp:8256, ad:1032, st:0)
+Massif: alloc S. 80 (t:9425, hp:8385, ad:1040, st:0)
+Massif: alloc S. 81 (t:9563, hp:8515, ad:1048, st:0)
+Massif: alloc S. 82 (t:9702, hp:8646, ad:1056, st:0)
+Massif: alloc S. 83 (t:9842, hp:8778, ad:1064, st:0)
+Massif: alloc S. 84 (t:9983, hp:8911, ad:1072, st:0)
+Massif: alloc S. 85 (t:10125, hp:9045, ad:1080, st:0)
+Massif: alloc S. 86 (t:10268, hp:9180, ad:1088, st:0)
+Massif: alloc S. 87 (t:10412, hp:9316, ad:1096, st:0)
+Massif: alloc S. 88 (t:10557, hp:9453, ad:1104, st:0)
+Massif: alloc Sd 89 (t:10703, hp:9591, ad:1112, st:0)
+Massif: alloc S. 90 (t:10850, hp:9730, ad:1120, st:0)
+Massif: alloc S. 91 (t:10998, hp:9870, ad:1128, st:0)
+Massif: alloc S. 92 (t:11147, hp:10011, ad:1136, st:0)
+Massif: alloc S. 93 (t:11297, hp:10153, ad:1144, st:0)
+Massif: alloc S. 94 (t:11448, hp:10296, ad:1152, st:0)
+Massif: alloc S. 95 (t:11600, hp:10440, ad:1160, st:0)
+Massif: alloc S. 96 (t:11753, hp:10585, ad:1168, st:0)
+Massif: alloc S. 97 (t:11907, hp:10731, ad:1176, st:0)
+Massif: alloc S. 98 (t:12062, hp:10878, ad:1184, st:0)
+Massif: alloc Sd 99 (t:12218, hp:11026, ad:1192, st:0)
+Massif: Culling...
+Massif: 0 (t-span = 173) Sd 29 (t:3713, hp:3081, ad:632, st:0)
+Massif: 1 (t-span = 177) S. 31 (t:3888, hp:3240, ad:648, st:0)
+Massif: 2 (t-span = 181) S. 33 (t:4067, hp:3403, ad:664, st:0)
+Massif: 3 (t-span = 182) S. 8 (t:1007, hp:703, ad:304, st:0)
+Massif: 4 (t-span = 185) S. 35 (t:4250, hp:3570, ad:680, st:0)
+Massif: 5 (t-span = 189) S. 37 (t:4437, hp:3741, ad:696, st:0)
+Massif: 6 (t-span = 193) Sd 39 (t:4628, hp:3916, ad:712, st:0)
+Massif: 7 (t-span = 197) S. 41 (t:4823, hp:4095, ad:728, st:0)
+Massif: 8 (t-span = 198) S. 10 (t:1197, hp:861, ad:336, st:0)
+Massif: 9 (t-span = 201) S. 43 (t:5022, hp:4278, ad:744, st:0)
+Massif: 10 (t-span = 205) S. 45 (t:5225, hp:4465, ad:760, st:0)
+Massif: 11 (t-span = 209) S. 47 (t:5432, hp:4656, ad:776, st:0)
+Massif: 12 (t-span = 213) Sd 49 (t:5643, hp:4851, ad:792, st:0)
+Massif: 13 (t-span = 214) S. 12 (t:1403, hp:1035, ad:368, st:0)
+Massif: 14 (t-span = 217) S. 51 (t:5858, hp:5050, ad:808, st:0)
+Massif: 15 (t-span = 220) S. 3 (t:350, hp:190, ad:160, st:0)
+Massif: 16 (t-span = 221) S. 53 (t:6077, hp:5253, ad:824, st:0)
+Massif: 17 (t-span = 225) S. 55 (t:6300, hp:5460, ad:840, st:0)
+Massif: 18 (t-span = 229) S. 57 (t:6527, hp:5671, ad:856, st:0)
+Massif: 19 (t-span = 230) S. 14 (t:1625, hp:1225, ad:400, st:0)
+Massif: 20 (t-span = 233) Sd 59 (t:6758, hp:5886, ad:872, st:0)
+Massif: 21 (t-span = 237) S. 61 (t:6993, hp:6105, ad:888, st:0)
+Massif: 22 (t-span = 241) S. 63 (t:7232, hp:6328, ad:904, st:0)
+Massif: 23 (t-span = 245) S. 65 (t:7475, hp:6555, ad:920, st:0)
+Massif: 24 (t-span = 246) S. 16 (t:1863, hp:1431, ad:432, st:0)
+Massif: 25 (t-span = 248) S. 1 (t:92, hp:28, ad:64, st:0)
+Massif: 26 (t-span = 249) S. 67 (t:7722, hp:6786, ad:936, st:0)
+Massif: 27 (t-span = 253) Sd 69 (t:7973, hp:7021, ad:952, st:0)
+Massif: 28 (t-span = 257) S. 71 (t:8228, hp:7260, ad:968, st:0)
+Massif: 29 (t-span = 261) S. 73 (t:8487, hp:7503, ad:984, st:0)
+Massif: 30 (t-span = 262) S. 18 (t:2117, hp:1653, ad:464, st:0)
+Massif: 31 (t-span = 265) S. 75 (t:8750, hp:7750, ad:1000, st:0)
+Massif: 32 (t-span = 269) S. 77 (t:9017, hp:8001, ad:1016, st:0)
+Massif: 33 (t-span = 273) Sd 79 (t:9288, hp:8256, ad:1032, st:0)
+Massif: 34 (t-span = 277) S. 81 (t:9563, hp:8515, ad:1048, st:0)
+Massif: 35 (t-span = 278) S. 20 (t:2387, hp:1891, ad:496, st:0)
+Massif: 36 (t-span = 281) S. 83 (t:9842, hp:8778, ad:1064, st:0)
+Massif: 37 (t-span = 284) S. 5 (t:602, hp:378, ad:224, st:0)
+Massif: 38 (t-span = 285) S. 85 (t:10125, hp:9045, ad:1080, st:0)
+Massif: 39 (t-span = 289) S. 87 (t:10412, hp:9316, ad:1096, st:0)
+Massif: 40 (t-span = 293) Sd 89 (t:10703, hp:9591, ad:1112, st:0)
+Massif: 41 (t-span = 294) S. 22 (t:2673, hp:2145, ad:528, st:0)
+Massif: 42 (t-span = 297) S. 91 (t:10998, hp:9870, ad:1128, st:0)
+Massif: 43 (t-span = 301) S. 93 (t:11297, hp:10153, ad:1144, st:0)
+Massif: 44 (t-span = 305) S. 95 (t:11600, hp:10440, ad:1160, st:0)
+Massif: 45 (t-span = 309) S. 97 (t:11907, hp:10731, ad:1176, st:0)
+Massif: 46 (t-span = 310) S. 24 (t:2975, hp:2415, ad:560, st:0)
+Massif: 47 (t-span = 326) S. 26 (t:3293, hp:2701, ad:592, st:0)
+Massif: 48 (t-span = 342) S. 28 (t:3627, hp:3003, ad:624, st:0)
+Massif: 49 (t-span = 348) S. 7 (t:918, hp:630, ad:288, st:0)
+Massif: Finished culling ( 50 of 100 deleted)
+Massif: post-cull S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: post-cull S. 1 (t:248, hp:120, ad:128, st:0)
+Massif: post-cull S. 2 (t:468, hp:276, ad:192, st:0)
+Massif: post-cull S. 3 (t:752, hp:496, ad:256, st:0)
+Massif: post-cull S. 4 (t:1100, hp:780, ad:320, st:0)
+Massif: post-cull S. 5 (t:1298, hp:946, ad:352, st:0)
+Massif: post-cull S. 6 (t:1512, hp:1128, ad:384, st:0)
+Massif: post-cull S. 7 (t:1742, hp:1326, ad:416, st:0)
+Massif: post-cull S. 8 (t:1988, hp:1540, ad:448, st:0)
+Massif: post-cull S. 9 (t:2250, hp:1770, ad:480, st:0)
+Massif: post-cull S. 10 (t:2528, hp:2016, ad:512, st:0)
+Massif: post-cull S. 11 (t:2822, hp:2278, ad:544, st:0)
+Massif: post-cull S. 12 (t:3132, hp:2556, ad:576, st:0)
+Massif: post-cull S. 13 (t:3458, hp:2850, ad:608, st:0)
+Massif: post-cull S. 14 (t:3800, hp:3160, ad:640, st:0)
+Massif: post-cull S. 15 (t:3977, hp:3321, ad:656, st:0)
+Massif: post-cull S. 16 (t:4158, hp:3486, ad:672, st:0)
+Massif: post-cull S. 17 (t:4343, hp:3655, ad:688, st:0)
+Massif: post-cull S. 18 (t:4532, hp:3828, ad:704, st:0)
+Massif: post-cull S. 19 (t:4725, hp:4005, ad:720, st:0)
+Massif: post-cull S. 20 (t:4922, hp:4186, ad:736, st:0)
+Massif: post-cull S. 21 (t:5123, hp:4371, ad:752, st:0)
+Massif: post-cull S. 22 (t:5328, hp:4560, ad:768, st:0)
+Massif: post-cull S. 23 (t:5537, hp:4753, ad:784, st:0)
+Massif: post-cull S. 24 (t:5750, hp:4950, ad:800, st:0)
+Massif: post-cull S. 25 (t:5967, hp:5151, ad:816, st:0)
+Massif: post-cull S. 26 (t:6188, hp:5356, ad:832, st:0)
+Massif: post-cull S. 27 (t:6413, hp:5565, ad:848, st:0)
+Massif: post-cull S. 28 (t:6642, hp:5778, ad:864, st:0)
+Massif: post-cull S. 29 (t:6875, hp:5995, ad:880, st:0)
+Massif: post-cull S. 30 (t:7112, hp:6216, ad:896, st:0)
+Massif: post-cull S. 31 (t:7353, hp:6441, ad:912, st:0)
+Massif: post-cull S. 32 (t:7598, hp:6670, ad:928, st:0)
+Massif: post-cull S. 33 (t:7847, hp:6903, ad:944, st:0)
+Massif: post-cull S. 34 (t:8100, hp:7140, ad:960, st:0)
+Massif: post-cull S. 35 (t:8357, hp:7381, ad:976, st:0)
+Massif: post-cull S. 36 (t:8618, hp:7626, ad:992, st:0)
+Massif: post-cull S. 37 (t:8883, hp:7875, ad:1008, st:0)
+Massif: post-cull S. 38 (t:9152, hp:8128, ad:1024, st:0)
+Massif: post-cull S. 39 (t:9425, hp:8385, ad:1040, st:0)
+Massif: post-cull S. 40 (t:9702, hp:8646, ad:1056, st:0)
+Massif: post-cull S. 41 (t:9983, hp:8911, ad:1072, st:0)
+Massif: post-cull S. 42 (t:10268, hp:9180, ad:1088, st:0)
+Massif: post-cull S. 43 (t:10557, hp:9453, ad:1104, st:0)
+Massif: post-cull S. 44 (t:10850, hp:9730, ad:1120, st:0)
+Massif: post-cull S. 45 (t:11147, hp:10011, ad:1136, st:0)
+Massif: post-cull S. 46 (t:11448, hp:10296, ad:1152, st:0)
+Massif: post-cull S. 47 (t:11753, hp:10585, ad:1168, st:0)
+Massif: post-cull S. 48 (t:12062, hp:10878, ad:1184, st:0)
+Massif: post-cull Sd 49 (t:12218, hp:11026, ad:1192, st:0)
+Massif: New time interval = 156 (between snapshots 48 and 49)
+Massif: alloc S. 50 (t:12375, hp:11175, ad:1200, st:0)
+Massif: alloc S. 51 (t:12533, hp:11325, ad:1208, st:0)
+Massif: alloc S. 52 (t:12692, hp:11476, ad:1216, st:0)
+Massif: alloc S. 53 (t:12852, hp:11628, ad:1224, st:0)
+Massif: alloc S. 54 (t:13013, hp:11781, ad:1232, st:0)
+Massif: alloc S. 55 (t:13175, hp:11935, ad:1240, st:0)
+Massif: alloc S. 56 (t:13338, hp:12090, ad:1248, st:0)
+Massif: alloc S. 57 (t:13502, hp:12246, ad:1256, st:0)
+Massif: alloc S. 58 (t:13667, hp:12403, ad:1264, st:0)
+Massif: alloc Sd 59 (t:13833, hp:12561, ad:1272, st:0)
+Massif: alloc S. 60 (t:14000, hp:12720, ad:1280, st:0)
+Massif: alloc S. 61 (t:14168, hp:12880, ad:1288, st:0)
+Massif: alloc S. 62 (t:14337, hp:13041, ad:1296, st:0)
+Massif: alloc S. 63 (t:14507, hp:13203, ad:1304, st:0)
+Massif: alloc S. 64 (t:14678, hp:13366, ad:1312, st:0)
+Massif: alloc S. 65 (t:14850, hp:13530, ad:1320, st:0)
+Massif: alloc S. 66 (t:15023, hp:13695, ad:1328, st:0)
+Massif: alloc S. 67 (t:15197, hp:13861, ad:1336, st:0)
+Massif: alloc S. 68 (t:15372, hp:14028, ad:1344, st:0)
+Massif: alloc Sd 69 (t:15548, hp:14196, ad:1352, st:0)
+Massif: alloc S. 70 (t:15725, hp:14365, ad:1360, st:0)
+Massif: alloc S. 71 (t:15903, hp:14535, ad:1368, st:0)
+Massif: alloc S. 72 (t:16082, hp:14706, ad:1376, st:0)
+Massif: alloc S. 73 (t:16262, hp:14878, ad:1384, st:0)
+Massif: alloc S. 74 (t:16443, hp:15051, ad:1392, st:0)
+Massif: alloc S. 75 (t:16625, hp:15225, ad:1400, st:0)
+Massif: alloc S. 76 (t:16808, hp:15400, ad:1408, st:0)
+Massif: alloc S. 77 (t:16992, hp:15576, ad:1416, st:0)
+Massif: alloc S. 78 (t:17177, hp:15753, ad:1424, st:0)
+Massif: alloc Sd 79 (t:17363, hp:15931, ad:1432, st:0)
+Massif: alloc S. 80 (t:17550, hp:16110, ad:1440, st:0)
+Massif: alloc S. 81 (t:17738, hp:16290, ad:1448, st:0)
+Massif: alloc S. 82 (t:17927, hp:16471, ad:1456, st:0)
+Massif: alloc S. 83 (t:18117, hp:16653, ad:1464, st:0)
+Massif: alloc S. 84 (t:18308, hp:16836, ad:1472, st:0)
+Massif: alloc S. 85 (t:18500, hp:17020, ad:1480, st:0)
+Massif: alloc S. 86 (t:18693, hp:17205, ad:1488, st:0)
+Massif: alloc S. 87 (t:18887, hp:17391, ad:1496, st:0)
+Massif: alloc S. 88 (t:19082, hp:17578, ad:1504, st:0)
+Massif: alloc Sd 89 (t:19278, hp:17766, ad:1512, st:0)
+Massif: alloc S. 90 (t:19475, hp:17955, ad:1520, st:0)
+Massif: alloc S. 91 (t:19673, hp:18145, ad:1528, st:0)
+Massif: alloc S. 92 (t:19872, hp:18336, ad:1536, st:0)
+Massif: alloc S. 93 (t:20072, hp:18528, ad:1544, st:0)
+Massif: alloc S. 94 (t:20273, hp:18721, ad:1552, st:0)
+Massif: alloc S. 95 (t:20475, hp:18915, ad:1560, st:0)
+Massif: alloc S. 96 (t:20678, hp:19110, ad:1568, st:0)
+Massif: alloc S. 97 (t:20882, hp:19306, ad:1576, st:0)
+Massif: alloc S. 98 (t:21087, hp:19503, ad:1584, st:0)
+Massif: alloc Sd 99 (t:21293, hp:19701, ad:1592, st:0)
+Massif: Culling...
+Massif: 0 (t-span = 313) Sd 49 (t:12218, hp:11026, ad:1192, st:0)
+Massif: 1 (t-span = 317) S. 51 (t:12533, hp:11325, ad:1208, st:0)
+Massif: 2 (t-span = 321) S. 53 (t:12852, hp:11628, ad:1224, st:0)
+Massif: 3 (t-span = 325) S. 55 (t:13175, hp:11935, ad:1240, st:0)
+Massif: 4 (t-span = 329) S. 57 (t:13502, hp:12246, ad:1256, st:0)
+Massif: 5 (t-span = 333) Sd 59 (t:13833, hp:12561, ad:1272, st:0)
+Massif: 6 (t-span = 337) S. 61 (t:14168, hp:12880, ad:1288, st:0)
+Massif: 7 (t-span = 341) S. 63 (t:14507, hp:13203, ad:1304, st:0)
+Massif: 8 (t-span = 345) S. 65 (t:14850, hp:13530, ad:1320, st:0)
+Massif: 9 (t-span = 349) S. 67 (t:15197, hp:13861, ad:1336, st:0)
+Massif: 10 (t-span = 353) Sd 69 (t:15548, hp:14196, ad:1352, st:0)
+Massif: 11 (t-span = 357) S. 71 (t:15903, hp:14535, ad:1368, st:0)
+Massif: 12 (t-span = 358) S. 15 (t:3977, hp:3321, ad:656, st:0)
+Massif: 13 (t-span = 361) S. 73 (t:16262, hp:14878, ad:1384, st:0)
+Massif: 14 (t-span = 365) S. 75 (t:16625, hp:15225, ad:1400, st:0)
+Massif: 15 (t-span = 369) S. 77 (t:16992, hp:15576, ad:1416, st:0)
+Massif: 16 (t-span = 373) Sd 79 (t:17363, hp:15931, ad:1432, st:0)
+Massif: 17 (t-span = 374) S. 17 (t:4343, hp:3655, ad:688, st:0)
+Massif: 18 (t-span = 377) S. 81 (t:17738, hp:16290, ad:1448, st:0)
+Massif: 19 (t-span = 381) S. 83 (t:18117, hp:16653, ad:1464, st:0)
+Massif: 20 (t-span = 385) S. 85 (t:18500, hp:17020, ad:1480, st:0)
+Massif: 21 (t-span = 389) S. 87 (t:18887, hp:17391, ad:1496, st:0)
+Massif: 22 (t-span = 390) S. 19 (t:4725, hp:4005, ad:720, st:0)
+Massif: 23 (t-span = 393) Sd 89 (t:19278, hp:17766, ad:1512, st:0)
+Massif: 24 (t-span = 397) S. 91 (t:19673, hp:18145, ad:1528, st:0)
+Massif: 25 (t-span = 401) S. 93 (t:20072, hp:18528, ad:1544, st:0)
+Massif: 26 (t-span = 405) S. 95 (t:20475, hp:18915, ad:1560, st:0)
+Massif: 27 (t-span = 406) S. 21 (t:5123, hp:4371, ad:752, st:0)
+Massif: 28 (t-span = 409) S. 97 (t:20882, hp:19306, ad:1576, st:0)
+Massif: 29 (t-span = 412) S. 5 (t:1298, hp:946, ad:352, st:0)
+Massif: 30 (t-span = 422) S. 23 (t:5537, hp:4753, ad:784, st:0)
+Massif: 31 (t-span = 438) S. 25 (t:5967, hp:5151, ad:816, st:0)
+Massif: 32 (t-span = 454) S. 27 (t:6413, hp:5565, ad:848, st:0)
+Massif: 33 (t-span = 468) S. 1 (t:248, hp:120, ad:128, st:0)
+Massif: 34 (t-span = 470) S. 29 (t:6875, hp:5995, ad:880, st:0)
+Massif: 35 (t-span = 476) S. 7 (t:1742, hp:1326, ad:416, st:0)
+Massif: 36 (t-span = 486) S. 31 (t:7353, hp:6441, ad:912, st:0)
+Massif: 37 (t-span = 502) S. 33 (t:7847, hp:6903, ad:944, st:0)
+Massif: 38 (t-span = 518) S. 35 (t:8357, hp:7381, ad:976, st:0)
+Massif: 39 (t-span = 534) S. 37 (t:8883, hp:7875, ad:1008, st:0)
+Massif: 40 (t-span = 540) S. 9 (t:2250, hp:1770, ad:480, st:0)
+Massif: 41 (t-span = 550) S. 39 (t:9425, hp:8385, ad:1040, st:0)
+Massif: 42 (t-span = 566) S. 41 (t:9983, hp:8911, ad:1072, st:0)
+Massif: 43 (t-span = 582) S. 43 (t:10557, hp:9453, ad:1104, st:0)
+Massif: 44 (t-span = 598) S. 45 (t:11147, hp:10011, ad:1136, st:0)
+Massif: 45 (t-span = 604) S. 11 (t:2822, hp:2278, ad:544, st:0)
+Massif: 46 (t-span = 614) S. 47 (t:11753, hp:10585, ad:1168, st:0)
+Massif: 47 (t-span = 615) S. 98 (t:21087, hp:19503, ad:1584, st:0)
+Massif: 48 (t-span = 630) S. 50 (t:12375, hp:11175, ad:1200, st:0)
+Massif: 49 (t-span = 632) S. 3 (t:752, hp:496, ad:256, st:0)
+Massif: Finished culling ( 50 of 100 deleted)
+Massif: post-cull S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: post-cull S. 1 (t:468, hp:276, ad:192, st:0)
+Massif: post-cull S. 2 (t:1100, hp:780, ad:320, st:0)
+Massif: post-cull S. 3 (t:1512, hp:1128, ad:384, st:0)
+Massif: post-cull S. 4 (t:1988, hp:1540, ad:448, st:0)
+Massif: post-cull S. 5 (t:2528, hp:2016, ad:512, st:0)
+Massif: post-cull S. 6 (t:3132, hp:2556, ad:576, st:0)
+Massif: post-cull S. 7 (t:3458, hp:2850, ad:608, st:0)
+Massif: post-cull S. 8 (t:3800, hp:3160, ad:640, st:0)
+Massif: post-cull S. 9 (t:4158, hp:3486, ad:672, st:0)
+Massif: post-cull S. 10 (t:4532, hp:3828, ad:704, st:0)
+Massif: post-cull S. 11 (t:4922, hp:4186, ad:736, st:0)
+Massif: post-cull S. 12 (t:5328, hp:4560, ad:768, st:0)
+Massif: post-cull S. 13 (t:5750, hp:4950, ad:800, st:0)
+Massif: post-cull S. 14 (t:6188, hp:5356, ad:832, st:0)
+Massif: post-cull S. 15 (t:6642, hp:5778, ad:864, st:0)
+Massif: post-cull S. 16 (t:7112, hp:6216, ad:896, st:0)
+Massif: post-cull S. 17 (t:7598, hp:6670, ad:928, st:0)
+Massif: post-cull S. 18 (t:8100, hp:7140, ad:960, st:0)
+Massif: post-cull S. 19 (t:8618, hp:7626, ad:992, st:0)
+Massif: post-cull S. 20 (t:9152, hp:8128, ad:1024, st:0)
+Massif: post-cull S. 21 (t:9702, hp:8646, ad:1056, st:0)
+Massif: post-cull S. 22 (t:10268, hp:9180, ad:1088, st:0)
+Massif: post-cull S. 23 (t:10850, hp:9730, ad:1120, st:0)
+Massif: post-cull S. 24 (t:11448, hp:10296, ad:1152, st:0)
+Massif: post-cull S. 25 (t:12062, hp:10878, ad:1184, st:0)
+Massif: post-cull S. 26 (t:12692, hp:11476, ad:1216, st:0)
+Massif: post-cull S. 27 (t:13013, hp:11781, ad:1232, st:0)
+Massif: post-cull S. 28 (t:13338, hp:12090, ad:1248, st:0)
+Massif: post-cull S. 29 (t:13667, hp:12403, ad:1264, st:0)
+Massif: post-cull S. 30 (t:14000, hp:12720, ad:1280, st:0)
+Massif: post-cull S. 31 (t:14337, hp:13041, ad:1296, st:0)
+Massif: post-cull S. 32 (t:14678, hp:13366, ad:1312, st:0)
+Massif: post-cull S. 33 (t:15023, hp:13695, ad:1328, st:0)
+Massif: post-cull S. 34 (t:15372, hp:14028, ad:1344, st:0)
+Massif: post-cull S. 35 (t:15725, hp:14365, ad:1360, st:0)
+Massif: post-cull S. 36 (t:16082, hp:14706, ad:1376, st:0)
+Massif: post-cull S. 37 (t:16443, hp:15051, ad:1392, st:0)
+Massif: post-cull S. 38 (t:16808, hp:15400, ad:1408, st:0)
+Massif: post-cull S. 39 (t:17177, hp:15753, ad:1424, st:0)
+Massif: post-cull S. 40 (t:17550, hp:16110, ad:1440, st:0)
+Massif: post-cull S. 41 (t:17927, hp:16471, ad:1456, st:0)
+Massif: post-cull S. 42 (t:18308, hp:16836, ad:1472, st:0)
+Massif: post-cull S. 43 (t:18693, hp:17205, ad:1488, st:0)
+Massif: post-cull S. 44 (t:19082, hp:17578, ad:1504, st:0)
+Massif: post-cull S. 45 (t:19475, hp:17955, ad:1520, st:0)
+Massif: post-cull S. 46 (t:19872, hp:18336, ad:1536, st:0)
+Massif: post-cull S. 47 (t:20273, hp:18721, ad:1552, st:0)
+Massif: post-cull S. 48 (t:20678, hp:19110, ad:1568, st:0)
+Massif: post-cull Sd 49 (t:21293, hp:19701, ad:1592, st:0)
+Massif: New time interval = 321 (between snapshots 26 and 27)
+Massif: heap allocs: 200
+Massif: heap reallocs: 0
+Massif: heap frees: 0
+Massif: stack allocs: 0
+Massif: stack frees: 0
+Massif: XPts: 4
+Massif: top-XPts: 1 (25%)
+Massif: XPt-init-expansions: 3
+Massif: XPt-later-expansions: 0
+Massif: SXPt allocs: 80
+Massif: SXPt frees: 76
+Massif: skipped snapshots: 1
+Massif: real snapshots: 200
+Massif: detailed snapshots: 20
+Massif: peak snapshots: 0
+Massif: cullings: 3
+Massif: XCon_redos: 0
diff --git a/massif/tests/culling2.vgtest b/massif/tests/culling2.vgtest
new file mode 100644
index 0000000..29f13ff
--- /dev/null
+++ b/massif/tests/culling2.vgtest
@@ -0,0 +1,4 @@
+prog: culling2
+vgopts: -v -v --stacks=no --time-unit=B
+stderr_filter: filter_verbose
+cleanup: rm massif.out
diff --git a/massif/tests/custom_alloc.c b/massif/tests/custom_alloc.c
new file mode 100644
index 0000000..d93ec56
--- /dev/null
+++ b/massif/tests/custom_alloc.c
@@ -0,0 +1,73 @@
+#include <unistd.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "valgrind.h"
+
+#define SUPERBLOCK_SIZE 100000
+
+//-------------------------------------------------------------------------
+// Allocator
+//-------------------------------------------------------------------------
+
+void* get_superblock(void)
+{
+ void* p = mmap( 0, SUPERBLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_PRIVATE|MAP_ANON, -1, 0 );
+
+ assert(p != ((void*)(-1)));
+
+ return p;
+}
+
+// has a redzone
+static void* custom_alloc(int size)
+{
+#define RZ 8
+ static void* hp = 0; // current heap pointer
+ static void* hp_lim = 0; // maximum usable byte in current block
+ int size2 = size + RZ*2;
+ void* p;
+
+ if (hp + size2 > hp_lim) {
+ hp = get_superblock();
+ hp_lim = hp + SUPERBLOCK_SIZE - 1;
+ }
+
+ p = hp + RZ;
+ hp += size2;
+
+ VALGRIND_MALLOCLIKE_BLOCK( p, size, RZ, /*is_zeroed*/1 );
+ return (void*)p;
+}
+
+static void custom_free(void* p)
+{
+ // don't actually free any memory... but mark it as freed
+ VALGRIND_FREELIKE_BLOCK( p, RZ );
+}
+#undef RZ
+
+
+
+//-------------------------------------------------------------------------
+// Rest
+//-------------------------------------------------------------------------
+
+int main(void)
+{
+ int* a = custom_alloc(100);
+ custom_free(a);
+
+ a = custom_alloc(200);
+ custom_free(a);
+
+ a = malloc(100);
+ free(a);
+
+ a = malloc(200);
+ free(a);
+
+ return 0;
+}
diff --git a/massif/tests/custom_alloc.post.exp b/massif/tests/custom_alloc.post.exp
new file mode 100644
index 0000000..0709025
--- /dev/null
+++ b/massif/tests/custom_alloc.post.exp
@@ -0,0 +1,63 @@
+--------------------------------------------------------------------------------
+Command: ./custom_alloc
+Massif arguments: --stacks=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 208^ # :
+ | # :
+ | # :
+ | # :
+ | # :
+ | # :
+ | # :
+ | # :
+ | # :
+ | # :
+ | @ # : :
+ | @ # : :
+ | @ # : :
+ | @ # : :
+ | @ # : :
+ | @ # : :
+ | @ # : :
+ | @ # : :
+ | @ # : :
+ | @ # : :
+ 0 +------@-----------------#---------------------------------------------->KB
+ 0 1.234
+
+Number of snapshots: 11
+ Detailed snapshots: [2, 5 (peak)]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 108 108 100 8 0
+ 2 108 108 100 8 0
+92.59% (100B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (100B) 0x........: custom_alloc (custom_alloc.c:41)
+ ->92.59% (100B) 0x........: main (custom_alloc.c:60)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 3 216 0 0 0 0
+ 4 424 208 200 8 0
+ 5 424 208 200 8 0
+96.15% (200B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->96.15% (200B) 0x........: custom_alloc (custom_alloc.c:41)
+ ->96.15% (200B) 0x........: main (custom_alloc.c:63)
+ |
+ ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 6 632 0 0 0 0
+ 7 740 108 100 8 0
+ 8 848 0 0 0 0
+ 9 1,056 208 200 8 0
+ 10 1,264 0 0 0 0
diff --git a/massif/tests/custom_alloc.stderr.exp b/massif/tests/custom_alloc.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/custom_alloc.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/custom_alloc.vgtest b/massif/tests/custom_alloc.vgtest
new file mode 100644
index 0000000..b83b4c0
--- /dev/null
+++ b/massif/tests/custom_alloc.vgtest
@@ -0,0 +1,4 @@
+prog: custom_alloc
+vgopts: --stacks=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/deep-A.post.exp b/massif/tests/deep-A.post.exp
new file mode 100644
index 0000000..a940fd0
--- /dev/null
+++ b/massif/tests/deep-A.post.exp
@@ -0,0 +1,60 @@
+--------------------------------------------------------------------------------
+Command: ./deep
+Massif arguments: --stacks=no --time-unit=B --depth=8
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+1.055^ :
+ | :
+ | @ :
+ | @ :
+ | : @ :
+ | : @ :
+ | : : @ :
+ | : : @ :
+ | : : : @ :
+ | : : : @ :
+ | : : : : @ :
+ | : : : : @ :
+ | : : : : : @ :
+ | : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : : @ :
+ | : : : : : : : : @ :
+ 0 +----------------------------------------------------------------@------>KB
+ 0 1.055
+
+Number of snapshots: 11
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 108 108 100 8 0
+ 2 216 216 200 16 0
+ 3 324 324 300 24 0
+ 4 432 432 400 32 0
+ 5 540 540 500 40 0
+ 6 648 648 600 48 0
+ 7 756 756 700 56 0
+ 8 864 864 800 64 0
+ 9 972 972 900 72 0
+92.59% (900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (900B) 0x........: a12 (deep.c:16)
+ ->92.59% (900B) 0x........: a11 (deep.c:17)
+ ->92.59% (900B) 0x........: a10 (deep.c:18)
+ ->92.59% (900B) 0x........: a9 (deep.c:19)
+ ->92.59% (900B) 0x........: a8 (deep.c:20)
+ ->92.59% (900B) 0x........: a7 (deep.c:21)
+ ->92.59% (900B) 0x........: a6 (deep.c:22)
+ ->92.59% (900B) 0x........: a5 (deep.c:23)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 1,080 1,080 1,000 80 0
diff --git a/massif/tests/deep-A.stderr.exp b/massif/tests/deep-A.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/deep-A.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/deep-A.vgtest b/massif/tests/deep-A.vgtest
new file mode 100644
index 0000000..2126c95
--- /dev/null
+++ b/massif/tests/deep-A.vgtest
@@ -0,0 +1,4 @@
+prog: deep
+vgopts: --stacks=no --time-unit=B --depth=8
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/deep-B.post.exp b/massif/tests/deep-B.post.exp
new file mode 100644
index 0000000..a797f30
--- /dev/null
+++ b/massif/tests/deep-B.post.exp
@@ -0,0 +1,58 @@
+--------------------------------------------------------------------------------
+Command: ./deep
+Massif arguments: --stacks=no --time-unit=B --alloc-fn=a6 --alloc-fn=a7 --alloc-fn=a8 --alloc-fn=a9 --alloc-fn=a10 --alloc-fn=a11 --alloc-fn=a12 --depth=8
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+1.055^ :
+ | :
+ | @ :
+ | @ :
+ | : @ :
+ | : @ :
+ | : : @ :
+ | : : @ :
+ | : : : @ :
+ | : : : @ :
+ | : : : : @ :
+ | : : : : @ :
+ | : : : : : @ :
+ | : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : : @ :
+ | : : : : : : : : @ :
+ 0 +----------------------------------------------------------------@------>KB
+ 0 1.055
+
+Number of snapshots: 11
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 108 108 100 8 0
+ 2 216 216 200 16 0
+ 3 324 324 300 24 0
+ 4 432 432 400 32 0
+ 5 540 540 500 40 0
+ 6 648 648 600 48 0
+ 7 756 756 700 56 0
+ 8 864 864 800 64 0
+ 9 972 972 900 72 0
+92.59% (900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (900B) 0x........: a5 (deep.c:23)
+ ->92.59% (900B) 0x........: a4 (deep.c:24)
+ ->92.59% (900B) 0x........: a3 (deep.c:25)
+ ->92.59% (900B) 0x........: a2 (deep.c:26)
+ ->92.59% (900B) 0x........: a1 (deep.c:27)
+ ->92.59% (900B) 0x........: main (deep.c:35)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 1,080 1,080 1,000 80 0
diff --git a/massif/tests/deep-B.stderr.exp b/massif/tests/deep-B.stderr.exp
new file mode 100644
index 0000000..638c834
--- /dev/null
+++ b/massif/tests/deep-B.stderr.exp
@@ -0,0 +1,50 @@
+Massif: alloc-fns:
+Massif: 0: malloc
+Massif: 1: __builtin_new
+Massif: 2: operator new(unsigned)
+Massif: 3: operator new(unsigned long)
+Massif: 4: __builtin_vec_new
+Massif: 5: operator new[](unsigned)
+Massif: 6: operator new[](unsigned long)
+Massif: 7: calloc
+Massif: 8: realloc
+Massif: 9: memalign
+Massif: 10: operator new(unsigned, std::nothrow_t const&)
+Massif: 11: operator new[](unsigned, std::nothrow_t const&)
+Massif: 12: operator new(unsigned long, std::nothrow_t const&)
+Massif: 13: operator new[](unsigned long, std::nothrow_t const&)
+Massif: 14: a6
+Massif: 15: a7
+Massif: 16: a8
+Massif: 17: a9
+Massif: 18: a10
+Massif: 19: a11
+Massif: 20: a12
+Massif: startup S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: alloc S. 1 (t:108, hp:100, ad:8, st:0)
+Massif: alloc S. 2 (t:216, hp:200, ad:16, st:0)
+Massif: alloc S. 3 (t:324, hp:300, ad:24, st:0)
+Massif: alloc S. 4 (t:432, hp:400, ad:32, st:0)
+Massif: alloc S. 5 (t:540, hp:500, ad:40, st:0)
+Massif: alloc S. 6 (t:648, hp:600, ad:48, st:0)
+Massif: alloc S. 7 (t:756, hp:700, ad:56, st:0)
+Massif: alloc S. 8 (t:864, hp:800, ad:64, st:0)
+Massif: alloc Sd 9 (t:972, hp:900, ad:72, st:0)
+Massif: alloc S. 10 (t:1080, hp:1000, ad:80, st:0)
+Massif: heap allocs: 10
+Massif: heap reallocs: 0
+Massif: heap frees: 0
+Massif: stack allocs: 0
+Massif: stack frees: 0
+Massif: XPts: 9
+Massif: top-XPts: 1 (11%)
+Massif: XPt-init-expansions: 8
+Massif: XPt-later-expansions: 0
+Massif: SXPt allocs: 9
+Massif: SXPt frees: 0
+Massif: skipped snapshots: 0
+Massif: real snapshots: 11
+Massif: detailed snapshots: 1
+Massif: peak snapshots: 0
+Massif: cullings: 0
+Massif: XCon_redos: 10
diff --git a/massif/tests/deep-B.vgtest b/massif/tests/deep-B.vgtest
new file mode 100644
index 0000000..6f89e2d
--- /dev/null
+++ b/massif/tests/deep-B.vgtest
@@ -0,0 +1,5 @@
+prog: deep
+vgopts: --stacks=no --time-unit=B --alloc-fn=a6 --alloc-fn=a7 --alloc-fn=a8 --alloc-fn=a9 --alloc-fn=a10 --alloc-fn=a11 --alloc-fn=a12 -v -v --depth=8
+stderr_filter: filter_verbose
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/deep-C.post.exp b/massif/tests/deep-C.post.exp
new file mode 100644
index 0000000..917e411
--- /dev/null
+++ b/massif/tests/deep-C.post.exp
@@ -0,0 +1,55 @@
+--------------------------------------------------------------------------------
+Command: ./deep
+Massif arguments: --stacks=no --time-unit=B --alloc-fn=a3 --alloc-fn=a4 --alloc-fn=a5 --alloc-fn=a6 --alloc-fn=a7 --alloc-fn=a8 --alloc-fn=a9 --alloc-fn=a10 --alloc-fn=a11 --alloc-fn=a12 --depth=8
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+1.055^ :
+ | :
+ | @ :
+ | @ :
+ | : @ :
+ | : @ :
+ | : : @ :
+ | : : @ :
+ | : : : @ :
+ | : : : @ :
+ | : : : : @ :
+ | : : : : @ :
+ | : : : : : @ :
+ | : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : : @ :
+ | : : : : : : : : @ :
+ 0 +----------------------------------------------------------------@------>KB
+ 0 1.055
+
+Number of snapshots: 11
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 108 108 100 8 0
+ 2 216 216 200 16 0
+ 3 324 324 300 24 0
+ 4 432 432 400 32 0
+ 5 540 540 500 40 0
+ 6 648 648 600 48 0
+ 7 756 756 700 56 0
+ 8 864 864 800 64 0
+ 9 972 972 900 72 0
+92.59% (900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (900B) 0x........: a2 (deep.c:26)
+ ->92.59% (900B) 0x........: a1 (deep.c:27)
+ ->92.59% (900B) 0x........: main (deep.c:35)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 1,080 1,080 1,000 80 0
diff --git a/massif/tests/deep-C.stderr.exp b/massif/tests/deep-C.stderr.exp
new file mode 100644
index 0000000..9f1b022
--- /dev/null
+++ b/massif/tests/deep-C.stderr.exp
@@ -0,0 +1,53 @@
+Massif: alloc-fns:
+Massif: 0: malloc
+Massif: 1: __builtin_new
+Massif: 2: operator new(unsigned)
+Massif: 3: operator new(unsigned long)
+Massif: 4: __builtin_vec_new
+Massif: 5: operator new[](unsigned)
+Massif: 6: operator new[](unsigned long)
+Massif: 7: calloc
+Massif: 8: realloc
+Massif: 9: memalign
+Massif: 10: operator new(unsigned, std::nothrow_t const&)
+Massif: 11: operator new[](unsigned, std::nothrow_t const&)
+Massif: 12: operator new(unsigned long, std::nothrow_t const&)
+Massif: 13: operator new[](unsigned long, std::nothrow_t const&)
+Massif: 14: a3
+Massif: 15: a4
+Massif: 16: a5
+Massif: 17: a6
+Massif: 18: a7
+Massif: 19: a8
+Massif: 20: a9
+Massif: 21: a10
+Massif: 22: a11
+Massif: 23: a12
+Massif: startup S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: alloc S. 1 (t:108, hp:100, ad:8, st:0)
+Massif: alloc S. 2 (t:216, hp:200, ad:16, st:0)
+Massif: alloc S. 3 (t:324, hp:300, ad:24, st:0)
+Massif: alloc S. 4 (t:432, hp:400, ad:32, st:0)
+Massif: alloc S. 5 (t:540, hp:500, ad:40, st:0)
+Massif: alloc S. 6 (t:648, hp:600, ad:48, st:0)
+Massif: alloc S. 7 (t:756, hp:700, ad:56, st:0)
+Massif: alloc S. 8 (t:864, hp:800, ad:64, st:0)
+Massif: alloc Sd 9 (t:972, hp:900, ad:72, st:0)
+Massif: alloc S. 10 (t:1080, hp:1000, ad:80, st:0)
+Massif: heap allocs: 10
+Massif: heap reallocs: 0
+Massif: heap frees: 0
+Massif: stack allocs: 0
+Massif: stack frees: 0
+Massif: XPts: 6
+Massif: top-XPts: 1 (16%)
+Massif: XPt-init-expansions: 5
+Massif: XPt-later-expansions: 0
+Massif: SXPt allocs: 6
+Massif: SXPt frees: 0
+Massif: skipped snapshots: 0
+Massif: real snapshots: 11
+Massif: detailed snapshots: 1
+Massif: peak snapshots: 0
+Massif: cullings: 0
+Massif: XCon_redos: 10
diff --git a/massif/tests/deep-C.vgtest b/massif/tests/deep-C.vgtest
new file mode 100644
index 0000000..cea898b
--- /dev/null
+++ b/massif/tests/deep-C.vgtest
@@ -0,0 +1,5 @@
+prog: deep
+vgopts: --stacks=no --time-unit=B --alloc-fn=a3 --alloc-fn=a4 --alloc-fn=a5 --alloc-fn=a6 --alloc-fn=a7 --alloc-fn=a8 --alloc-fn=a9 --alloc-fn=a10 --alloc-fn=a11 --alloc-fn=a12 -v -v --depth=8
+stderr_filter: filter_verbose
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/deep-D.post.exp b/massif/tests/deep-D.post.exp
new file mode 100644
index 0000000..a654640
--- /dev/null
+++ b/massif/tests/deep-D.post.exp
@@ -0,0 +1,53 @@
+--------------------------------------------------------------------------------
+Command: ./deep
+Massif arguments: --stacks=no --time-unit=B --alloc-fn=a1 --alloc-fn=a2 --alloc-fn=a3 --alloc-fn=a4 --alloc-fn=a5 --alloc-fn=a6 --alloc-fn=a7 --alloc-fn=a8 --alloc-fn=a9 --alloc-fn=a10 --alloc-fn=a11 --alloc-fn=a12 --alloc-fn=main --depth=20
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+1.055^ :
+ | :
+ | @ :
+ | @ :
+ | : @ :
+ | : @ :
+ | : : @ :
+ | : : @ :
+ | : : : @ :
+ | : : : @ :
+ | : : : : @ :
+ | : : : : @ :
+ | : : : : : @ :
+ | : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : @ :
+ | : : : : : : : : @ :
+ | : : : : : : : : @ :
+ 0 +----------------------------------------------------------------@------>KB
+ 0 1.055
+
+Number of snapshots: 11
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 108 108 100 8 0
+ 2 216 216 200 16 0
+ 3 324 324 300 24 0
+ 4 432 432 400 32 0
+ 5 540 540 500 40 0
+ 6 648 648 600 48 0
+ 7 756 756 700 56 0
+ 8 864 864 800 64 0
+ 9 972 972 900 72 0
+92.59% (900B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.59% (900B) 0x........: (below main) (in /lib/libc-2.3.5.so)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 1,080 1,080 1,000 80 0
diff --git a/massif/tests/deep-D.stderr.exp b/massif/tests/deep-D.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/deep-D.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/deep-D.vgtest b/massif/tests/deep-D.vgtest
new file mode 100644
index 0000000..a095894
--- /dev/null
+++ b/massif/tests/deep-D.vgtest
@@ -0,0 +1,4 @@
+prog: deep
+vgopts: --stacks=no --time-unit=B --alloc-fn=a1 --alloc-fn=a2 --alloc-fn=a3 --alloc-fn=a4 --alloc-fn=a5 --alloc-fn=a6 --alloc-fn=a7 --alloc-fn=a8 --alloc-fn=a9 --alloc-fn=a10 --alloc-fn=a11 --alloc-fn=a12 --alloc-fn=main --depth=20
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/deep.c b/massif/tests/deep.c
new file mode 100644
index 0000000..b358860
--- /dev/null
+++ b/massif/tests/deep.c
@@ -0,0 +1,38 @@
+// This is a test for complicated stack traces.
+//
+// - In deep-A.vgtest, the stack trace is larger than the asked-for depth
+// (12 vs. 8) so not all of the trace is shown.
+// - In deep-B.vgtest, we have --alloc-fn=a6..a12, which means that get_XCon
+// needs to redo the IP getting, because 7 functions get removed from the
+// trace, which is more than the initial overestimate of 3.
+// - In deep-C.vgtest, we have --alloc-fn=a3..a12, which means that get_XCon
+// ends up with an empty stack trace after removing all the alloc-fns.
+// It then redoes it.
+// - In deep-D.vgtest, we have --alloc-fn=main..a12, which means we have a
+// stack trace with a single "(below main)" entry.
+
+#include <stdlib.h>
+
+void a12(int n) { malloc(n); }
+void a11(int n) { a12(n); }
+void a10(int n) { a11(n); }
+void a9 (int n) { a10(n); }
+void a8 (int n) { a9 (n); }
+void a7 (int n) { a8 (n); }
+void a6 (int n) { a7 (n); }
+void a5 (int n) { a6 (n); }
+void a4 (int n) { a5 (n); }
+void a3 (int n) { a4 (n); }
+void a2 (int n) { a3 (n); }
+void a1 (int n) { a2 (n); }
+
+int main(void)
+{
+ int i;
+
+ // This one exceeds the default --depth.
+ for (i = 0; i < 10; i++)
+ a1(100);
+
+ return 0;
+}
diff --git a/massif/tests/filter_stderr b/massif/tests/filter_stderr
index 852c699..793b158 100755
--- a/massif/tests/filter_stderr
+++ b/massif/tests/filter_stderr
@@ -5,11 +5,5 @@
$dir/../../tests/filter_stderr_basic |
# Remove "Massif, ..." line and the following copyright line.
-sed "/^Massif, a space profiler./ , /./ d" |
-
-# Remove numbers from all lines (and "(n/a)" strings)
-sed "s/\(Total spacetime: \).*$/\1/" |
-sed "s/\(heap: \).*$/\1/" |
-sed "s/\(heap admin: \).*$/\1/" |
-sed "s/\(stack(s): \).*$/\1/"
+sed "/^Massif, a space profiler./ , /./ d"
diff --git a/massif/tests/filter_verbose b/massif/tests/filter_verbose
new file mode 100755
index 0000000..d14f371
--- /dev/null
+++ b/massif/tests/filter_verbose
@@ -0,0 +1,12 @@
+#! /bin/sh
+
+# This filters out all the lines that don't have "Massif:" in them. For
+# testing the -v option.
+
+dir=`dirname $0`
+
+$dir/filter_stderr |
+
+# Only print lines that contain "Massif:". The -n means don't print any
+# lines by default, and the 'p' means do print those that match the pattern.
+sed -n "/Massif:/p"
diff --git a/massif/tests/ignoring.c b/massif/tests/ignoring.c
new file mode 100644
index 0000000..270d084
--- /dev/null
+++ b/massif/tests/ignoring.c
@@ -0,0 +1,31 @@
+// When we cull and compute the new minimum time between snapshots, we want
+// to ignore any gap between two uncullable snapshots, because it is not
+// representative. This program tests that.
+
+
+#include <stdlib.h>
+
+int main(void)
+{
+ int i;
+
+ // The peak is from the first allocation.
+ int* x = malloc(1000);
+ free(x);
+
+ // Now do an allocation to provide the post-peak baseline.
+ malloc(500);
+
+ // Now we do lots of allocations below the peak. With the proper
+ // handling, the allocations should still be smoothly distributed.
+ // Without it, the snapshots in the second half of the graph would be
+ // clustered much more closely than those in the first half.
+ //
+
+ for (i = 0; i < 350; i++) {
+ int* y = malloc(250);
+ free(y);
+ }
+
+ return 0;
+}
diff --git a/massif/tests/ignoring.post.exp b/massif/tests/ignoring.post.exp
new file mode 100644
index 0000000..06bb2f5
--- /dev/null
+++ b/massif/tests/ignoring.post.exp
@@ -0,0 +1,236 @@
+--------------------------------------------------------------------------------
+Command: ./ignoring
+Massif arguments: --stacks=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+0.984^#
+ |#
+ |#
+ |#
+ |#
+ |# ::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# ::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# ::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# ::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# ::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ |# @:::@:::::::::::::::@:::@:::@:::@:::@: ::@:::::::@:::::::@:::::::@::::
+ 0 +#-@---@---------------@---@---@---@---@----@-------@-------@-------@--->KB
+ 0 178.6
+
+Number of snapshots: 88
+ Detailed snapshots: [1 (peak), 3, 8, 26, 31, 36, 41, 46, 52, 62, 72, 82]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 1,008 1,008 1,000 8 0
+99.21% (1,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->99.21% (1,000B) 0x........: main (ignoring.c:13)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 2 5,104 508 500 8 0
+ 3 7,168 508 500 8 0
+98.43% (500B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->98.43% (500B) 0x........: main (ignoring.c:17)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 4 9,232 508 500 8 0
+ 5 11,296 508 500 8 0
+ 6 13,360 508 500 8 0
+ 7 15,424 508 500 8 0
+ 8 17,488 508 500 8 0
+98.43% (500B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->98.43% (500B) 0x........: main (ignoring.c:17)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 9 19,552 508 500 8 0
+ 10 21,616 508 500 8 0
+ 11 23,680 508 500 8 0
+ 12 27,034 766 750 16 0
+ 13 29,098 766 750 16 0
+ 14 31,162 766 750 16 0
+ 15 33,226 766 750 16 0
+ 16 35,290 766 750 16 0
+ 17 37,354 766 750 16 0
+ 18 39,418 766 750 16 0
+ 19 41,482 766 750 16 0
+ 20 43,546 766 750 16 0
+ 21 45,610 766 750 16 0
+ 22 47,674 766 750 16 0
+ 23 49,738 766 750 16 0
+ 24 51,802 766 750 16 0
+ 25 53,866 766 750 16 0
+ 26 55,930 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 27 57,994 766 750 16 0
+ 28 60,058 766 750 16 0
+ 29 62,122 766 750 16 0
+ 30 64,186 766 750 16 0
+ 31 66,250 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 32 68,314 766 750 16 0
+ 33 70,378 766 750 16 0
+ 34 72,442 766 750 16 0
+ 35 74,506 766 750 16 0
+ 36 76,570 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 37 78,634 766 750 16 0
+ 38 80,698 766 750 16 0
+ 39 82,762 766 750 16 0
+ 40 84,826 766 750 16 0
+ 41 86,890 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 42 88,954 766 750 16 0
+ 43 91,018 766 750 16 0
+ 44 93,082 766 750 16 0
+ 45 95,146 766 750 16 0
+ 46 97,210 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 47 99,274 766 750 16 0
+ 48 101,338 766 750 16 0
+ 49 104,434 766 750 16 0
+ 50 106,498 766 750 16 0
+ 51 108,562 766 750 16 0
+ 52 110,626 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 53 112,690 766 750 16 0
+ 54 114,754 766 750 16 0
+ 55 116,818 766 750 16 0
+ 56 118,882 766 750 16 0
+ 57 120,946 766 750 16 0
+ 58 123,010 766 750 16 0
+ 59 125,074 766 750 16 0
+ 60 127,138 766 750 16 0
+ 61 129,202 766 750 16 0
+ 62 131,266 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 63 133,330 766 750 16 0
+ 64 135,394 766 750 16 0
+ 65 137,458 766 750 16 0
+ 66 139,522 766 750 16 0
+ 67 141,586 766 750 16 0
+ 68 143,650 766 750 16 0
+ 69 145,714 766 750 16 0
+ 70 147,778 766 750 16 0
+ 71 149,842 766 750 16 0
+ 72 151,906 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 73 153,970 766 750 16 0
+ 74 156,034 766 750 16 0
+ 75 158,098 766 750 16 0
+ 76 160,162 766 750 16 0
+ 77 162,226 766 750 16 0
+ 78 164,290 766 750 16 0
+ 79 166,354 766 750 16 0
+ 80 168,418 766 750 16 0
+ 81 170,482 766 750 16 0
+ 82 172,546 766 750 16 0
+97.91% (750B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->65.27% (500B) 0x........: main (ignoring.c:17)
+|
+->32.64% (250B) 0x........: main (ignoring.c:26)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 83 174,610 766 750 16 0
+ 84 176,674 766 750 16 0
+ 85 178,738 766 750 16 0
+ 86 180,802 766 750 16 0
+ 87 182,866 766 750 16 0
diff --git a/massif/tests/ignoring.stderr.exp b/massif/tests/ignoring.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/ignoring.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/ignoring.vgtest b/massif/tests/ignoring.vgtest
new file mode 100644
index 0000000..62084fe
--- /dev/null
+++ b/massif/tests/ignoring.vgtest
@@ -0,0 +1,4 @@
+prog: ignoring
+vgopts: --stacks=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/insig.c b/massif/tests/insig.c
new file mode 100644
index 0000000..ee89259
--- /dev/null
+++ b/massif/tests/insig.c
@@ -0,0 +1,34 @@
+#include <stdlib.h>
+
+// In this test, the size of the insignificant nodes is greater than the
+// size of two of the significant nodes. This is quite common in big
+// programs, but not so common in small tests, so we test for it here.
+int main(void)
+{
+ malloc(1000);
+ malloc(15);
+ malloc(12);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+ malloc(1);
+
+
+ return 0;
+}
diff --git a/massif/tests/insig.post.exp b/massif/tests/insig.post.exp
new file mode 100644
index 0000000..23921b2
--- /dev/null
+++ b/massif/tests/insig.post.exp
@@ -0,0 +1,84 @@
+--------------------------------------------------------------------------------
+Command: ./insig
+Massif arguments: --stacks=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+1.202^ .:
+ | ..:@::
+ | ..::::@::
+ | .:::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ | : ::::@::::@::
+ 0 +----------------------------------------------------------------@----@->KB
+ 0 1.202
+
+Number of snapshots: 24
+ Detailed snapshots: [9, 19]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 1,008 1,008 1,000 8 0
+ 2 1,031 1,031 1,015 16 0
+ 3 1,051 1,051 1,027 24 0
+ 4 1,060 1,060 1,028 32 0
+ 5 1,069 1,069 1,029 40 0
+ 6 1,078 1,078 1,030 48 0
+ 7 1,087 1,087 1,031 56 0
+ 8 1,096 1,096 1,032 64 0
+ 9 1,105 1,105 1,033 72 0
+93.48% (1,033B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->90.50% (1,000B) 0x........: main (insig.c:8)
+|
+->01.36% (15B) 0x........: main (insig.c:9)
+|
+->01.09% (12B) 0x........: main (insig.c:10)
+|
+->00.54% (6B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 1,114 1,114 1,034 80 0
+ 11 1,123 1,123 1,035 88 0
+ 12 1,132 1,132 1,036 96 0
+ 13 1,141 1,141 1,037 104 0
+ 14 1,150 1,150 1,038 112 0
+ 15 1,159 1,159 1,039 120 0
+ 16 1,168 1,168 1,040 128 0
+ 17 1,177 1,177 1,041 136 0
+ 18 1,186 1,186 1,042 144 0
+ 19 1,195 1,195 1,043 152 0
+87.28% (1,043B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->83.68% (1,000B) 0x........: main (insig.c:8)
+|
+->01.34% (16B) in 16 places, all below massif's threshold (01.00%)
+|
+->01.26% (15B) 0x........: main (insig.c:9)
+|
+->01.00% (12B) 0x........: main (insig.c:10)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 20 1,204 1,204 1,044 160 0
+ 21 1,213 1,213 1,045 168 0
+ 22 1,222 1,222 1,046 176 0
+ 23 1,231 1,231 1,047 184 0
diff --git a/massif/tests/insig.stderr.exp b/massif/tests/insig.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/insig.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/insig.vgtest b/massif/tests/insig.vgtest
new file mode 100644
index 0000000..e767b95
--- /dev/null
+++ b/massif/tests/insig.vgtest
@@ -0,0 +1,4 @@
+prog: insig
+vgopts: --stacks=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/long-time.c b/massif/tests/long-time.c
new file mode 100644
index 0000000..de55d51
--- /dev/null
+++ b/massif/tests/long-time.c
@@ -0,0 +1,22 @@
+// This test does enough allocation and deallocation that the time-unit,
+// when measured in bytes -- 6,000,000,000 -- exceeds 32-bits. It also does
+// it in a slightly uneven fashion so we get a range of different totals
+// for the snapshots, including a zero-sized detailed snapshot.
+
+#include <stdlib.h>
+
+int main(void)
+{
+ int i;
+ for (i = 0; i < 1500; i++) {
+ int* x1 = malloc( 800 * 1000);
+ int* x2 = malloc(1100 * 1000);
+ free(x1);
+ int* x3 = malloc(1200 * 1000);
+ free(x2);
+ free(x3);
+ int* x4 = malloc( 900 * 1000);
+ free(x4);
+ }
+ return 0;
+}
diff --git a/massif/tests/long-time.post.exp b/massif/tests/long-time.post.exp
new file mode 100644
index 0000000..91d178e
--- /dev/null
+++ b/massif/tests/long-time.post.exp
@@ -0,0 +1,218 @@
+--------------------------------------------------------------------------------
+Command: ./long-time
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ MB
+2.193^#: : : @ : :
+ |#: : : @ : :
+ |#: : : @ : :
+ |#: :. :. . @. :. .
+ |#: :: :: : @: :@ :
+ |#: :: :: : @: :@ :
+ |#: :: :: : @: :@ :
+ |#: :: :: : @: :@ :
+ |#: :: :: : @: :@ :
+ |#: :: :: : @: :@ :
+ |#: :: :: : @: :@ : :. :. :. :. :. :. :. . :. :. :. :
+ |#: :: :: : @: :@ : :: :: :: :: :@ :: :: : :: :@ :: :
+ |#:..................:: :: : @: :@ : ::.::.::.:: :@ :: :: .: :: :@ :: :
+ |#::::@:::::::::::::::: :: : @: :@ : :::::@:::::.:@.::.::.@:.::.:@.::.:
+ |#::::@:::::::::::::::: :: : @: :@ : :::::@:::::::@:::::::@::::::@:::::
+ |#::::@:::::::::::::::: :: : @: :@ : :::::@:::::::@:::::::@::::::@:::::
+ |#::::@:::::::::::::::: :: : @: :@ : :::::@:::::::@:::::::@::::::@:::::
+ |#::::@:::::::::::::::: :: : @: :@ : :::::@:::::::@:::::::@::::::@:::::
+ |#::::@:::::::::::::::: :: : @: :@ : :::::@:::::::@:::::::@::::::@:::::
+ |#::::@:::::::::::::::: :: : @: :@ : :::::@:::::::@:::::::@::::::@:::::
+ 0 +#----@----------------@---@--@---@---@-----@-------@-------@------@---->GB
+ 0 11.15
+
+Number of snapshots: 94
+ Detailed snapshots: [1 (peak), 7, 28, 33, 38, 43, 48, 56, 66, 76, 86]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 3,900,000 2,300,000 2,300,000 0 0
+100.00% (2,300,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->52.17% (1,200,000B) 0x........: main (long-time.c:15)
+|
+->47.83% (1,100,000B) 0x........: main (long-time.c:13)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 2 227,900,000 2,300,000 2,300,000 0 0
+ 3 383,100,000 900,000 900,000 0 0
+ 4 607,100,000 900,000 900,000 0 0
+ 5 735,100,000 900,000 900,000 0 0
+ 6 863,100,000 900,000 900,000 0 0
+ 7 991,100,000 900,000 900,000 0 0
+100.00% (900,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (900,000B) 0x........: main (long-time.c:18)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 8 1,119,100,000 900,000 900,000 0 0
+ 9 1,247,100,000 900,000 900,000 0 0
+ 10 1,375,100,000 900,000 900,000 0 0
+ 11 1,503,100,000 900,000 900,000 0 0
+ 12 1,679,100,000 900,000 900,000 0 0
+ 13 1,807,100,000 900,000 900,000 0 0
+ 14 1,935,100,000 900,000 900,000 0 0
+ 15 2,063,100,000 900,000 900,000 0 0
+ 16 2,191,100,000 900,000 900,000 0 0
+ 17 2,319,100,000 900,000 900,000 0 0
+ 18 2,447,100,000 900,000 900,000 0 0
+ 19 2,575,100,000 900,000 900,000 0 0
+ 20 2,703,100,000 900,000 900,000 0 0
+ 21 2,831,100,000 900,000 900,000 0 0
+ 22 2,959,100,000 900,000 900,000 0 0
+ 23 3,087,100,000 900,000 900,000 0 0
+ 24 3,215,100,000 900,000 900,000 0 0
+ 25 3,342,200,000 0 0 0 0
+ 26 3,467,900,000 2,300,000 2,300,000 0 0
+ 27 3,593,900,000 1,900,000 1,900,000 0 0
+ 28 3,720,000,000 0 0 0 0
+00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 29 3,846,200,000 0 0 0 0
+ 30 3,971,900,000 2,300,000 2,300,000 0 0
+ 31 4,097,900,000 1,900,000 1,900,000 0 0
+ 32 4,224,000,000 0 0 0 0
+ 33 4,350,200,000 0 0 0 0
+00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 34 4,475,900,000 2,300,000 2,300,000 0 0
+ 35 4,601,900,000 1,900,000 1,900,000 0 0
+ 36 4,728,000,000 0 0 0 0
+ 37 4,854,200,000 0 0 0 0
+ 38 4,979,900,000 2,300,000 2,300,000 0 0
+100.00% (2,300,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->52.17% (1,200,000B) 0x........: main (long-time.c:15)
+|
+->47.83% (1,100,000B) 0x........: main (long-time.c:13)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 39 5,105,900,000 1,900,000 1,900,000 0 0
+ 40 5,232,000,000 0 0 0 0
+ 41 5,358,200,000 0 0 0 0
+ 42 5,483,900,000 2,300,000 2,300,000 0 0
+ 43 5,609,900,000 1,900,000 1,900,000 0 0
+100.00% (1,900,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->57.89% (1,100,000B) 0x........: main (long-time.c:13)
+|
+->42.11% (800,000B) 0x........: main (long-time.c:12)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 44 5,736,000,000 0 0 0 0
+ 45 5,862,200,000 0 0 0 0
+ 46 5,987,900,000 2,300,000 2,300,000 0 0
+ 47 6,113,900,000 1,900,000 1,900,000 0 0
+ 48 6,240,000,000 0 0 0 0
+00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 49 6,429,000,000 1,200,000 1,200,000 0 0
+ 50 6,554,700,000 1,100,000 1,100,000 0 0
+ 51 6,680,800,000 800,000 800,000 0 0
+ 52 6,807,100,000 900,000 900,000 0 0
+ 53 6,933,000,000 1,200,000 1,200,000 0 0
+ 54 7,058,700,000 1,100,000 1,100,000 0 0
+ 55 7,184,800,000 800,000 800,000 0 0
+ 56 7,311,100,000 900,000 900,000 0 0
+100.00% (900,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (900,000B) 0x........: main (long-time.c:18)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 57 7,437,000,000 1,200,000 1,200,000 0 0
+ 58 7,562,700,000 1,100,000 1,100,000 0 0
+ 59 7,688,800,000 800,000 800,000 0 0
+ 60 7,815,100,000 900,000 900,000 0 0
+ 61 7,941,000,000 1,200,000 1,200,000 0 0
+ 62 8,066,700,000 1,100,000 1,100,000 0 0
+ 63 8,192,800,000 800,000 800,000 0 0
+ 64 8,319,100,000 900,000 900,000 0 0
+ 65 8,445,000,000 1,200,000 1,200,000 0 0
+ 66 8,570,700,000 1,100,000 1,100,000 0 0
+100.00% (1,100,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (1,100,000B) 0x........: main (long-time.c:13)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 67 8,696,800,000 800,000 800,000 0 0
+ 68 8,823,100,000 900,000 900,000 0 0
+ 69 8,949,000,000 1,200,000 1,200,000 0 0
+ 70 9,074,700,000 1,100,000 1,100,000 0 0
+ 71 9,200,800,000 800,000 800,000 0 0
+ 72 9,327,100,000 900,000 900,000 0 0
+ 73 9,453,000,000 1,200,000 1,200,000 0 0
+ 74 9,578,700,000 1,100,000 1,100,000 0 0
+ 75 9,704,800,000 800,000 800,000 0 0
+ 76 9,831,100,000 900,000 900,000 0 0
+100.00% (900,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (900,000B) 0x........: main (long-time.c:18)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 77 9,957,000,000 1,200,000 1,200,000 0 0
+ 78 10,082,700,000 1,100,000 1,100,000 0 0
+ 79 10,208,800,000 800,000 800,000 0 0
+ 80 10,335,100,000 900,000 900,000 0 0
+ 81 10,461,000,000 1,200,000 1,200,000 0 0
+ 82 10,586,700,000 1,100,000 1,100,000 0 0
+ 83 10,712,800,000 800,000 800,000 0 0
+ 84 10,839,100,000 900,000 900,000 0 0
+ 85 10,965,000,000 1,200,000 1,200,000 0 0
+ 86 11,090,700,000 1,100,000 1,100,000 0 0
+100.00% (1,100,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (1,100,000B) 0x........: main (long-time.c:13)
+|
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 87 11,216,800,000 800,000 800,000 0 0
+ 88 11,343,100,000 900,000 900,000 0 0
+ 89 11,469,000,000 1,200,000 1,200,000 0 0
+ 90 11,594,700,000 1,100,000 1,100,000 0 0
+ 91 11,720,800,000 800,000 800,000 0 0
+ 92 11,847,100,000 900,000 900,000 0 0
+ 93 11,973,000,000 1,200,000 1,200,000 0 0
diff --git a/massif/tests/long-time.stderr.exp b/massif/tests/long-time.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/long-time.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/long-time.vgtest b/massif/tests/long-time.vgtest
new file mode 100644
index 0000000..121ab4b
--- /dev/null
+++ b/massif/tests/long-time.vgtest
@@ -0,0 +1,4 @@
+prog: long-time
+vgopts: --stacks=no --time-unit=B --heap-admin=0
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/new-cpp.cpp b/massif/tests/new-cpp.cpp
new file mode 100644
index 0000000..defdb26
--- /dev/null
+++ b/massif/tests/new-cpp.cpp
@@ -0,0 +1,30 @@
+// operator new(unsigned)
+// operator new[](unsigned)
+// operator new(unsigned, std::nothrow_t const&)
+// operator new[](unsigned, std::nothrow_t const&)
+
+#include <stdlib.h>
+
+#include <new>
+
+using std::nothrow_t;
+
+// A big structure. Its details don't matter.
+struct s {
+ int array[1000];
+};
+
+int main(void)
+{
+ struct s* p1 = new struct s;
+ struct s* p2 = new (std::nothrow) struct s;
+ char* c1 = new char[2000];
+ char* c2 = new (std::nothrow) char[2000];
+ delete p1;
+ delete p2;
+ delete [] c1;
+ delete [] c2;
+ return 0;
+}
+
+
diff --git a/massif/tests/new-cpp.post.exp b/massif/tests/new-cpp.post.exp
new file mode 100644
index 0000000..6088f5e
--- /dev/null
+++ b/massif/tests/new-cpp.post.exp
@@ -0,0 +1,58 @@
+--------------------------------------------------------------------------------
+Command: ./new-cpp
+Massif arguments: --stacks=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+11.75^ #
+ | #
+ | #
+ | . #
+ | : #
+ | : #
+ | : #
+ | : : # :
+ | : : # :
+ | : : # :
+ | : : # :
+ | : : # :
+ | : : # :
+ | . : : # : .
+ | : : : # : :
+ | : : : # : :
+ | : : : # : :
+ | : : : # : : :
+ | : : : # : : :
+ | : : : # : : :
+ 0 +-----------------------------------#----------------------------------->KB
+ 0 23.50
+
+Number of snapshots: 10
+ Detailed snapshots: [5 (peak)]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 4,008 4,008 4,000 8 0
+ 2 8,016 8,016 8,000 16 0
+ 3 10,024 10,024 10,000 24 0
+ 4 12,032 12,032 12,000 32 0
+ 5 12,032 12,032 12,000 32 0
+99.73% (12,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->33.24% (4,000B) 0x........: main (new-cpp.cpp:19)
+|
+->33.24% (4,000B) 0x........: main (new-cpp.cpp:20)
+|
+->16.62% (2,000B) 0x........: main (new-cpp.cpp:21)
+|
+->16.62% (2,000B) 0x........: main (new-cpp.cpp:22)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 6 16,040 8,024 8,000 24 0
+ 7 20,048 4,016 4,000 16 0
+ 8 22,056 2,008 2,000 8 0
+ 9 24,064 0 0 0 0
diff --git a/massif/tests/new-cpp.stderr.exp b/massif/tests/new-cpp.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/new-cpp.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/new-cpp.vgtest b/massif/tests/new-cpp.vgtest
new file mode 100644
index 0000000..a31d764
--- /dev/null
+++ b/massif/tests/new-cpp.vgtest
@@ -0,0 +1,4 @@
+prog: new-cpp
+vgopts: --stacks=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/no-stack-no-heap.post.exp b/massif/tests/no-stack-no-heap.post.exp
new file mode 100644
index 0000000..a13b65f
--- /dev/null
+++ b/massif/tests/no-stack-no-heap.post.exp
@@ -0,0 +1,37 @@
+--------------------------------------------------------------------------------
+Command: ./basic
+Massif arguments: --stacks=no --heap=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 1^
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ 0 +----------------------------------------------------------------------->B
+ 0 1
+
+Number of snapshots: 1
+ Detailed snapshots: []
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
diff --git a/massif/tests/no-stack-no-heap.stderr.exp b/massif/tests/no-stack-no-heap.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/no-stack-no-heap.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/no-stack-no-heap.vgtest b/massif/tests/no-stack-no-heap.vgtest
new file mode 100644
index 0000000..c07f03c
--- /dev/null
+++ b/massif/tests/no-stack-no-heap.vgtest
@@ -0,0 +1,4 @@
+prog: basic
+vgopts: --stacks=no --heap=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/null.c b/massif/tests/null.c
new file mode 100644
index 0000000..380b04f
--- /dev/null
+++ b/massif/tests/null.c
@@ -0,0 +1,7 @@
+// This test does no allocations, to make sure that case is handled ok (eg.
+// no div-by-zero errors).
+
+int main(void)
+{
+ return 0;
+}
diff --git a/massif/tests/null.post.exp b/massif/tests/null.post.exp
new file mode 100644
index 0000000..a5a0c3e
--- /dev/null
+++ b/massif/tests/null.post.exp
@@ -0,0 +1,37 @@
+--------------------------------------------------------------------------------
+Command: ./null
+Massif arguments: --stacks=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 1^
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ 0 +----------------------------------------------------------------------->B
+ 0 1
+
+Number of snapshots: 1
+ Detailed snapshots: []
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
diff --git a/massif/tests/null.stderr.exp b/massif/tests/null.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/null.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/null.vgtest b/massif/tests/null.vgtest
new file mode 100644
index 0000000..4e8b80d
--- /dev/null
+++ b/massif/tests/null.vgtest
@@ -0,0 +1,4 @@
+prog: null
+vgopts: --stacks=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/one.c b/massif/tests/one.c
new file mode 100644
index 0000000..923606d
--- /dev/null
+++ b/massif/tests/one.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+// A test for a single allocation.
+
+int main(void)
+{
+ malloc(1);
+ return 0;
+}
diff --git a/massif/tests/one.post.exp b/massif/tests/one.post.exp
new file mode 100644
index 0000000..6a31733
--- /dev/null
+++ b/massif/tests/one.post.exp
@@ -0,0 +1,38 @@
+--------------------------------------------------------------------------------
+Command: ./one
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 1^ :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ | :
+ 0 +----------------------------------------------------------------------->B
+ 0 1
+
+Number of snapshots: 2
+ Detailed snapshots: []
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 1 1 1 0 0
diff --git a/massif/tests/one.stderr.exp b/massif/tests/one.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/one.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/one.vgtest b/massif/tests/one.vgtest
new file mode 100644
index 0000000..2d3171d
--- /dev/null
+++ b/massif/tests/one.vgtest
@@ -0,0 +1,4 @@
+prog: one
+vgopts: --stacks=no --time-unit=B --heap-admin=0
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/overloaded-new.cpp b/massif/tests/overloaded-new.cpp
new file mode 100644
index 0000000..f90096b
--- /dev/null
+++ b/massif/tests/overloaded-new.cpp
@@ -0,0 +1,60 @@
+// operator new(unsigned)
+// operator new[](unsigned)
+// operator new(unsigned, std::nothrow_t const&)
+// operator new[](unsigned, std::nothrow_t const&)
+
+#include <stdlib.h>
+
+#include <new>
+
+using std::nothrow_t;
+
+// A big structure. Its details don't matter.
+struct s {
+ int array[1000];
+};
+
+void* operator new (std::size_t n) throw (std::bad_alloc)
+{
+ return malloc(n);
+}
+
+void* operator new (std::size_t n, std::nothrow_t const &) throw ()
+{
+ return malloc(n);
+}
+
+void* operator new[] (std::size_t n) throw (std::bad_alloc)
+{
+ return malloc(n);
+}
+
+void* operator new[] (std::size_t n, std::nothrow_t const &) throw ()
+{
+ return malloc(n);
+}
+
+void operator delete (void* p)
+{
+ return free(p);
+}
+
+void operator delete[] (void* p)
+{
+ return free(p);
+}
+
+int main(void)
+{
+ struct s* p1 = new struct s;
+ struct s* p2 = new (std::nothrow) struct s;
+ char* c1 = new char[2000];
+ char* c2 = new (std::nothrow) char[2000];
+ delete p1;
+ delete p2;
+ delete [] c1;
+ delete [] c2;
+ return 0;
+}
+
+
diff --git a/massif/tests/overloaded-new.post.exp b/massif/tests/overloaded-new.post.exp
new file mode 100644
index 0000000..4fd9db9
--- /dev/null
+++ b/massif/tests/overloaded-new.post.exp
@@ -0,0 +1,58 @@
+--------------------------------------------------------------------------------
+Command: ./overloaded-new
+Massif arguments: --stacks=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+11.75^ #
+ | #
+ | #
+ | . #
+ | : #
+ | : #
+ | : #
+ | : : # :
+ | : : # :
+ | : : # :
+ | : : # :
+ | : : # :
+ | : : # :
+ | . : : # : .
+ | : : : # : :
+ | : : : # : :
+ | : : : # : :
+ | : : : # : : :
+ | : : : # : : :
+ | : : : # : : :
+ 0 +-----------------------------------#----------------------------------->KB
+ 0 23.50
+
+Number of snapshots: 10
+ Detailed snapshots: [5 (peak)]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 4,008 4,008 4,000 8 0
+ 2 8,016 8,016 8,000 16 0
+ 3 10,024 10,024 10,000 24 0
+ 4 12,032 12,032 12,000 32 0
+ 5 12,032 12,032 12,000 32 0
+99.73% (12,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->33.24% (4,000B) 0x........: main (overloaded-new.cpp:49)
+|
+->33.24% (4,000B) 0x........: main (overloaded-new.cpp:50)
+|
+->16.62% (2,000B) 0x........: main (overloaded-new.cpp:51)
+|
+->16.62% (2,000B) 0x........: main (overloaded-new.cpp:52)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 6 16,040 8,024 8,000 24 0
+ 7 20,048 4,016 4,000 16 0
+ 8 22,056 2,008 2,000 8 0
+ 9 24,064 0 0 0 0
diff --git a/massif/tests/overloaded-new.stderr.exp b/massif/tests/overloaded-new.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/overloaded-new.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/overloaded-new.vgtest b/massif/tests/overloaded-new.vgtest
new file mode 100644
index 0000000..e12eaae
--- /dev/null
+++ b/massif/tests/overloaded-new.vgtest
@@ -0,0 +1,4 @@
+prog: overloaded-new
+vgopts: --stacks=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/peak.c b/massif/tests/peak.c
new file mode 100644
index 0000000..cd38cd7
--- /dev/null
+++ b/massif/tests/peak.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+
+int main(void)
+{
+ int i;
+ for (i = 0; i < 20; i++) {
+ int* p;
+ p = malloc(100); // With --peak-inaccuracy=1000, the first 10 of
+ p = malloc(1); // 'free' calls result in peaks, but after that,
+ free(p); // only every second one does.
+ }
+ return 0;
+}
diff --git a/massif/tests/peak.post.exp b/massif/tests/peak.post.exp
new file mode 100644
index 0000000..e374792
--- /dev/null
+++ b/massif/tests/peak.post.exp
@@ -0,0 +1,277 @@
+--------------------------------------------------------------------------------
+Command: ./peak
+Massif arguments: --stacks=no --time-unit=B --peak-inaccuracy=0
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+2.118^ #
+ | .@ #
+ | @ :@ #
+ | @. @ :@ #
+ | @ @: @ :@ #
+ | @ @ @: @ :@ #
+ | .@ @ @ @: @ :@ #
+ | @ :@ @ @ @: @ :@ #
+ | @. @ :@ @ @ @: @ :@ #
+ | @ @: @ :@ @ @ @: @ :@ #
+ | @ @ @: @ :@ @ @ @: @ :@ #
+ | .@ @ @ @: @ :@ @ @ @: @ :@ #
+ | @ :@ @ @ @: @ :@ @ @ @: @ :@ #
+ | @. @ :@ @ @ @: @ :@ @ @ @: @ :@ #
+ | @ @: @ :@ @ @ @: @ :@ @ @ @: @ :@ #
+ | @ @ @: @ :@ @ @ @: @ :@ @ @ @: @ :@ #
+ | .@ @ @ @: @ :@ @ @ @: @ :@ @ @ @: @ :@ #
+ | @ :@ @ @ @: @ :@ @ @ @: @ :@ @ @ @: @ :@ #
+ | @. @ :@ @ @ @: @ :@ @ @ @: @ :@ @ @ @: @ :@ #
+ | @ @: @ :@ @ @ @: @ :@ @ @ @: @ :@ @ @ @: @ :@ #
+ 0 +---@--@---@---@--@---@--@---@---@--@---@--@---@---@--@---@--@---@---@--#KB
+ 0 2.461
+
+Number of snapshots: 81
+ Detailed snapshots: [3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, 67, 71, 75, 79 (peak)]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 108 108 100 8 0
+ 2 117 117 101 16 0
+ 3 117 117 101 16 0
+86.32% (101B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->85.47% (100B) 0x........: main (peak.c:8)
+|
+->00.85% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 4 126 108 100 8 0
+ 5 234 216 200 16 0
+ 6 243 225 201 24 0
+ 7 243 225 201 24 0
+89.33% (201B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->88.89% (200B) 0x........: main (peak.c:8)
+|
+->00.44% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 8 252 216 200 16 0
+ 9 360 324 300 24 0
+ 10 369 333 301 32 0
+ 11 369 333 301 32 0
+90.39% (301B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->90.09% (300B) 0x........: main (peak.c:8)
+|
+->00.30% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 12 378 324 300 24 0
+ 13 486 432 400 32 0
+ 14 495 441 401 40 0
+ 15 495 441 401 40 0
+90.93% (401B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->90.70% (400B) 0x........: main (peak.c:8)
+|
+->00.23% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 16 504 432 400 32 0
+ 17 612 540 500 40 0
+ 18 621 549 501 48 0
+ 19 621 549 501 48 0
+91.26% (501B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.07% (500B) 0x........: main (peak.c:8)
+|
+->00.18% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 20 630 540 500 40 0
+ 21 738 648 600 48 0
+ 22 747 657 601 56 0
+ 23 747 657 601 56 0
+91.48% (601B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.32% (600B) 0x........: main (peak.c:8)
+|
+->00.15% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 24 756 648 600 48 0
+ 25 864 756 700 56 0
+ 26 873 765 701 64 0
+ 27 873 765 701 64 0
+91.63% (701B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.50% (700B) 0x........: main (peak.c:8)
+|
+->00.13% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 28 882 756 700 56 0
+ 29 990 864 800 64 0
+ 30 999 873 801 72 0
+ 31 999 873 801 72 0
+91.75% (801B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.64% (800B) 0x........: main (peak.c:8)
+|
+->00.11% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 32 1,008 864 800 64 0
+ 33 1,116 972 900 72 0
+ 34 1,125 981 901 80 0
+ 35 1,125 981 901 80 0
+91.85% (901B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.74% (900B) 0x........: main (peak.c:8)
+|
+->00.10% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 36 1,134 972 900 72 0
+ 37 1,242 1,080 1,000 80 0
+ 38 1,251 1,089 1,001 88 0
+ 39 1,251 1,089 1,001 88 0
+91.92% (1,001B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.83% (1,000B) 0x........: main (peak.c:8)
+|
+->00.09% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 40 1,260 1,080 1,000 80 0
+ 41 1,368 1,188 1,100 88 0
+ 42 1,377 1,197 1,101 96 0
+ 43 1,377 1,197 1,101 96 0
+91.98% (1,101B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.90% (1,100B) 0x........: main (peak.c:8)
+|
+->00.08% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 44 1,386 1,188 1,100 88 0
+ 45 1,494 1,296 1,200 96 0
+ 46 1,503 1,305 1,201 104 0
+ 47 1,503 1,305 1,201 104 0
+92.03% (1,201B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.95% (1,200B) 0x........: main (peak.c:8)
+|
+->00.08% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 48 1,512 1,296 1,200 96 0
+ 49 1,620 1,404 1,300 104 0
+ 50 1,629 1,413 1,301 112 0
+ 51 1,629 1,413 1,301 112 0
+92.07% (1,301B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.00% (1,300B) 0x........: main (peak.c:8)
+|
+->00.07% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 52 1,638 1,404 1,300 104 0
+ 53 1,746 1,512 1,400 112 0
+ 54 1,755 1,521 1,401 120 0
+ 55 1,755 1,521 1,401 120 0
+92.11% (1,401B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.04% (1,400B) 0x........: main (peak.c:8)
+|
+->00.07% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 56 1,764 1,512 1,400 112 0
+ 57 1,872 1,620 1,500 120 0
+ 58 1,881 1,629 1,501 128 0
+ 59 1,881 1,629 1,501 128 0
+92.14% (1,501B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.08% (1,500B) 0x........: main (peak.c:8)
+|
+->00.06% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 60 1,890 1,620 1,500 120 0
+ 61 1,998 1,728 1,600 128 0
+ 62 2,007 1,737 1,601 136 0
+ 63 2,007 1,737 1,601 136 0
+92.17% (1,601B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.11% (1,600B) 0x........: main (peak.c:8)
+|
+->00.06% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 64 2,016 1,728 1,600 128 0
+ 65 2,124 1,836 1,700 136 0
+ 66 2,133 1,845 1,701 144 0
+ 67 2,133 1,845 1,701 144 0
+92.20% (1,701B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.14% (1,700B) 0x........: main (peak.c:8)
+|
+->00.05% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 68 2,142 1,836 1,700 136 0
+ 69 2,250 1,944 1,800 144 0
+ 70 2,259 1,953 1,801 152 0
+ 71 2,259 1,953 1,801 152 0
+92.22% (1,801B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.17% (1,800B) 0x........: main (peak.c:8)
+|
+->00.05% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 72 2,268 1,944 1,800 144 0
+ 73 2,376 2,052 1,900 152 0
+ 74 2,385 2,061 1,901 160 0
+ 75 2,385 2,061 1,901 160 0
+92.24% (1,901B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.19% (1,900B) 0x........: main (peak.c:8)
+|
+->00.05% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 76 2,394 2,052 1,900 152 0
+ 77 2,502 2,160 2,000 160 0
+ 78 2,511 2,169 2,001 168 0
+ 79 2,511 2,169 2,001 168 0
+92.25% (2,001B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.21% (2,000B) 0x........: main (peak.c:8)
+|
+->00.05% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 80 2,520 2,160 2,000 160 0
diff --git a/massif/tests/peak.stderr.exp b/massif/tests/peak.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/peak.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/peak.vgtest b/massif/tests/peak.vgtest
new file mode 100644
index 0000000..d3552c7
--- /dev/null
+++ b/massif/tests/peak.vgtest
@@ -0,0 +1,4 @@
+prog: peak
+vgopts: --stacks=no --time-unit=B --peak-inaccuracy=0
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/peak2.post.exp b/massif/tests/peak2.post.exp
new file mode 100644
index 0000000..d40bc35
--- /dev/null
+++ b/massif/tests/peak2.post.exp
@@ -0,0 +1,232 @@
+--------------------------------------------------------------------------------
+Command: ./peak
+Massif arguments: --stacks=no --time-unit=B --peak-inaccuracy=1000
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ KB
+2.118^ #
+ | .. #
+ | @ :: #
+ | :. @ :: #
+ | @ :: @ :: #
+ | . @ :: @ :: #
+ | .@ : @ :: @ :: #
+ | . :@ : @ :: @ :: #
+ | @. : :@ : @ :: @ :: #
+ | . @: : :@ : @ :: @ :: #
+ | @ : @: : :@ : @ :: @ :: #
+ | .@ @ : @: : :@ : @ :: @ :: #
+ | @ :@ @ : @: : :@ : @ :: @ :: #
+ | @. @ :@ @ : @: : :@ : @ :: @ :: #
+ | @ @: @ :@ @ : @: : :@ : @ :: @ :: #
+ | @ @ @: @ :@ @ : @: : :@ : @ :: @ :: #
+ | .@ @ @ @: @ :@ @ : @: : :@ : @ :: @ :: #
+ | @ :@ @ @ @: @ :@ @ : @: : :@ : @ :: @ :: #
+ | @. @ :@ @ @ @: @ :@ @ : @: : :@ : @ :: @ :: #
+ | @ @: @ :@ @ @ @: @ :@ @ : @: : :@ : @ :: @ :: #
+ 0 +---@--@---@---@--@---@--@---@---@--@------@-------@------@------@------#KB
+ 0 2.461
+
+Number of snapshots: 76
+ Detailed snapshots: [3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 46, 53, 60, 67, 74 (peak)]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 108 108 100 8 0
+ 2 117 117 101 16 0
+ 3 117 117 101 16 0
+86.32% (101B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->85.47% (100B) 0x........: main (peak.c:8)
+|
+->00.85% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 4 126 108 100 8 0
+ 5 234 216 200 16 0
+ 6 243 225 201 24 0
+ 7 243 225 201 24 0
+89.33% (201B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->88.89% (200B) 0x........: main (peak.c:8)
+|
+->00.44% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 8 252 216 200 16 0
+ 9 360 324 300 24 0
+ 10 369 333 301 32 0
+ 11 369 333 301 32 0
+90.39% (301B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->90.09% (300B) 0x........: main (peak.c:8)
+|
+->00.30% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 12 378 324 300 24 0
+ 13 486 432 400 32 0
+ 14 495 441 401 40 0
+ 15 495 441 401 40 0
+90.93% (401B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->90.70% (400B) 0x........: main (peak.c:8)
+|
+->00.23% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 16 504 432 400 32 0
+ 17 612 540 500 40 0
+ 18 621 549 501 48 0
+ 19 621 549 501 48 0
+91.26% (501B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.07% (500B) 0x........: main (peak.c:8)
+|
+->00.18% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 20 630 540 500 40 0
+ 21 738 648 600 48 0
+ 22 747 657 601 56 0
+ 23 747 657 601 56 0
+91.48% (601B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.32% (600B) 0x........: main (peak.c:8)
+|
+->00.15% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 24 756 648 600 48 0
+ 25 864 756 700 56 0
+ 26 873 765 701 64 0
+ 27 873 765 701 64 0
+91.63% (701B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.50% (700B) 0x........: main (peak.c:8)
+|
+->00.13% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 28 882 756 700 56 0
+ 29 990 864 800 64 0
+ 30 999 873 801 72 0
+ 31 999 873 801 72 0
+91.75% (801B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.64% (800B) 0x........: main (peak.c:8)
+|
+->00.11% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 32 1,008 864 800 64 0
+ 33 1,116 972 900 72 0
+ 34 1,125 981 901 80 0
+ 35 1,125 981 901 80 0
+91.85% (901B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.74% (900B) 0x........: main (peak.c:8)
+|
+->00.10% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 36 1,134 972 900 72 0
+ 37 1,242 1,080 1,000 80 0
+ 38 1,251 1,089 1,001 88 0
+ 39 1,251 1,089 1,001 88 0
+91.92% (1,001B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.83% (1,000B) 0x........: main (peak.c:8)
+|
+->00.09% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 40 1,260 1,080 1,000 80 0
+ 41 1,368 1,188 1,100 88 0
+ 42 1,377 1,197 1,101 96 0
+ 43 1,386 1,188 1,100 88 0
+ 44 1,494 1,296 1,200 96 0
+ 45 1,503 1,305 1,201 104 0
+ 46 1,503 1,305 1,201 104 0
+92.03% (1,201B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->91.95% (1,200B) 0x........: main (peak.c:8)
+|
+->00.08% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 47 1,512 1,296 1,200 96 0
+ 48 1,620 1,404 1,300 104 0
+ 49 1,629 1,413 1,301 112 0
+ 50 1,638 1,404 1,300 104 0
+ 51 1,746 1,512 1,400 112 0
+ 52 1,755 1,521 1,401 120 0
+ 53 1,755 1,521 1,401 120 0
+92.11% (1,401B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.04% (1,400B) 0x........: main (peak.c:8)
+|
+->00.07% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 54 1,764 1,512 1,400 112 0
+ 55 1,872 1,620 1,500 120 0
+ 56 1,881 1,629 1,501 128 0
+ 57 1,890 1,620 1,500 120 0
+ 58 1,998 1,728 1,600 128 0
+ 59 2,007 1,737 1,601 136 0
+ 60 2,007 1,737 1,601 136 0
+92.17% (1,601B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.11% (1,600B) 0x........: main (peak.c:8)
+|
+->00.06% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 61 2,016 1,728 1,600 128 0
+ 62 2,124 1,836 1,700 136 0
+ 63 2,133 1,845 1,701 144 0
+ 64 2,142 1,836 1,700 136 0
+ 65 2,250 1,944 1,800 144 0
+ 66 2,259 1,953 1,801 152 0
+ 67 2,259 1,953 1,801 152 0
+92.22% (1,801B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.17% (1,800B) 0x........: main (peak.c:8)
+|
+->00.05% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 68 2,268 1,944 1,800 144 0
+ 69 2,376 2,052 1,900 152 0
+ 70 2,385 2,061 1,901 160 0
+ 71 2,394 2,052 1,900 152 0
+ 72 2,502 2,160 2,000 160 0
+ 73 2,511 2,169 2,001 168 0
+ 74 2,511 2,169 2,001 168 0
+92.25% (2,001B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->92.21% (2,000B) 0x........: main (peak.c:8)
+|
+->00.05% (1B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 75 2,520 2,160 2,000 160 0
diff --git a/massif/tests/peak2.stderr.exp b/massif/tests/peak2.stderr.exp
new file mode 100644
index 0000000..28ce90e
--- /dev/null
+++ b/massif/tests/peak2.stderr.exp
@@ -0,0 +1,108 @@
+Massif: alloc-fns:
+Massif: 0: malloc
+Massif: 1: __builtin_new
+Massif: 2: operator new(unsigned)
+Massif: 3: operator new(unsigned long)
+Massif: 4: __builtin_vec_new
+Massif: 5: operator new[](unsigned)
+Massif: 6: operator new[](unsigned long)
+Massif: 7: calloc
+Massif: 8: realloc
+Massif: 9: memalign
+Massif: 10: operator new(unsigned, std::nothrow_t const&)
+Massif: 11: operator new[](unsigned, std::nothrow_t const&)
+Massif: 12: operator new(unsigned long, std::nothrow_t const&)
+Massif: 13: operator new[](unsigned long, std::nothrow_t const&)
+Massif: startup S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: alloc S. 1 (t:108, hp:100, ad:8, st:0)
+Massif: alloc S. 2 (t:117, hp:101, ad:16, st:0)
+Massif: de-PEAK Sp 3 (t:117, hp:101, ad:16, st:0)
+Massif: dealloc S. 4 (t:126, hp:100, ad:8, st:0)
+Massif: alloc S. 5 (t:234, hp:200, ad:16, st:0)
+Massif: alloc S. 6 (t:243, hp:201, ad:24, st:0)
+Massif: de-PEAK Sp 7 (t:243, hp:201, ad:24, st:0)
+Massif: dealloc S. 8 (t:252, hp:200, ad:16, st:0)
+Massif: alloc S. 9 (t:360, hp:300, ad:24, st:0)
+Massif: alloc S. 10 (t:369, hp:301, ad:32, st:0)
+Massif: de-PEAK Sp 11 (t:369, hp:301, ad:32, st:0)
+Massif: dealloc S. 12 (t:378, hp:300, ad:24, st:0)
+Massif: alloc S. 13 (t:486, hp:400, ad:32, st:0)
+Massif: alloc S. 14 (t:495, hp:401, ad:40, st:0)
+Massif: de-PEAK Sp 15 (t:495, hp:401, ad:40, st:0)
+Massif: dealloc S. 16 (t:504, hp:400, ad:32, st:0)
+Massif: alloc S. 17 (t:612, hp:500, ad:40, st:0)
+Massif: alloc S. 18 (t:621, hp:501, ad:48, st:0)
+Massif: de-PEAK Sp 19 (t:621, hp:501, ad:48, st:0)
+Massif: dealloc S. 20 (t:630, hp:500, ad:40, st:0)
+Massif: alloc S. 21 (t:738, hp:600, ad:48, st:0)
+Massif: alloc S. 22 (t:747, hp:601, ad:56, st:0)
+Massif: de-PEAK Sp 23 (t:747, hp:601, ad:56, st:0)
+Massif: dealloc S. 24 (t:756, hp:600, ad:48, st:0)
+Massif: alloc S. 25 (t:864, hp:700, ad:56, st:0)
+Massif: alloc S. 26 (t:873, hp:701, ad:64, st:0)
+Massif: de-PEAK Sp 27 (t:873, hp:701, ad:64, st:0)
+Massif: dealloc S. 28 (t:882, hp:700, ad:56, st:0)
+Massif: alloc S. 29 (t:990, hp:800, ad:64, st:0)
+Massif: alloc S. 30 (t:999, hp:801, ad:72, st:0)
+Massif: de-PEAK Sp 31 (t:999, hp:801, ad:72, st:0)
+Massif: dealloc S. 32 (t:1008, hp:800, ad:64, st:0)
+Massif: alloc S. 33 (t:1116, hp:900, ad:72, st:0)
+Massif: alloc S. 34 (t:1125, hp:901, ad:80, st:0)
+Massif: de-PEAK Sp 35 (t:1125, hp:901, ad:80, st:0)
+Massif: dealloc S. 36 (t:1134, hp:900, ad:72, st:0)
+Massif: alloc S. 37 (t:1242, hp:1000, ad:80, st:0)
+Massif: alloc S. 38 (t:1251, hp:1001, ad:88, st:0)
+Massif: de-PEAK Sp 39 (t:1251, hp:1001, ad:88, st:0)
+Massif: dealloc S. 40 (t:1260, hp:1000, ad:80, st:0)
+Massif: alloc S. 41 (t:1368, hp:1100, ad:88, st:0)
+Massif: alloc S. 42 (t:1377, hp:1101, ad:96, st:0)
+Massif: dealloc S. 43 (t:1386, hp:1100, ad:88, st:0)
+Massif: alloc S. 44 (t:1494, hp:1200, ad:96, st:0)
+Massif: alloc S. 45 (t:1503, hp:1201, ad:104, st:0)
+Massif: de-PEAK Sp 46 (t:1503, hp:1201, ad:104, st:0)
+Massif: dealloc S. 47 (t:1512, hp:1200, ad:96, st:0)
+Massif: alloc S. 48 (t:1620, hp:1300, ad:104, st:0)
+Massif: alloc S. 49 (t:1629, hp:1301, ad:112, st:0)
+Massif: dealloc S. 50 (t:1638, hp:1300, ad:104, st:0)
+Massif: alloc S. 51 (t:1746, hp:1400, ad:112, st:0)
+Massif: alloc S. 52 (t:1755, hp:1401, ad:120, st:0)
+Massif: de-PEAK Sp 53 (t:1755, hp:1401, ad:120, st:0)
+Massif: dealloc S. 54 (t:1764, hp:1400, ad:112, st:0)
+Massif: alloc S. 55 (t:1872, hp:1500, ad:120, st:0)
+Massif: alloc S. 56 (t:1881, hp:1501, ad:128, st:0)
+Massif: dealloc S. 57 (t:1890, hp:1500, ad:120, st:0)
+Massif: alloc S. 58 (t:1998, hp:1600, ad:128, st:0)
+Massif: alloc S. 59 (t:2007, hp:1601, ad:136, st:0)
+Massif: de-PEAK Sp 60 (t:2007, hp:1601, ad:136, st:0)
+Massif: dealloc S. 61 (t:2016, hp:1600, ad:128, st:0)
+Massif: alloc S. 62 (t:2124, hp:1700, ad:136, st:0)
+Massif: alloc S. 63 (t:2133, hp:1701, ad:144, st:0)
+Massif: dealloc S. 64 (t:2142, hp:1700, ad:136, st:0)
+Massif: alloc S. 65 (t:2250, hp:1800, ad:144, st:0)
+Massif: alloc S. 66 (t:2259, hp:1801, ad:152, st:0)
+Massif: de-PEAK Sp 67 (t:2259, hp:1801, ad:152, st:0)
+Massif: dealloc S. 68 (t:2268, hp:1800, ad:144, st:0)
+Massif: alloc S. 69 (t:2376, hp:1900, ad:152, st:0)
+Massif: alloc S. 70 (t:2385, hp:1901, ad:160, st:0)
+Massif: dealloc S. 71 (t:2394, hp:1900, ad:152, st:0)
+Massif: alloc S. 72 (t:2502, hp:2000, ad:160, st:0)
+Massif: alloc S. 73 (t:2511, hp:2001, ad:168, st:0)
+Massif: de-PEAK Sp 74 (t:2511, hp:2001, ad:168, st:0)
+Massif: dealloc S. 75 (t:2520, hp:2000, ad:160, st:0)
+Massif: heap allocs: 40
+Massif: heap reallocs: 0
+Massif: heap frees: 20
+Massif: stack allocs: 0
+Massif: stack frees: 0
+Massif: XPts: 7
+Massif: top-XPts: 2 (28%)
+Massif: XPt-init-expansions: 5
+Massif: XPt-later-expansions: 0
+Massif: SXPt allocs: 77
+Massif: SXPt frees: 0
+Massif: skipped snapshots: 0
+Massif: real snapshots: 76
+Massif: detailed snapshots: 15
+Massif: peak snapshots: 15
+Massif: cullings: 0
+Massif: XCon_redos: 0
diff --git a/massif/tests/peak2.vgtest b/massif/tests/peak2.vgtest
new file mode 100644
index 0000000..e64c201
--- /dev/null
+++ b/massif/tests/peak2.vgtest
@@ -0,0 +1,5 @@
+prog: peak
+vgopts: --stacks=no --time-unit=B -v -v --peak-inaccuracy=1000
+stderr_filter: filter_verbose
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/realloc.c b/massif/tests/realloc.c
new file mode 100644
index 0000000..010748e
--- /dev/null
+++ b/massif/tests/realloc.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+
+int main(void)
+{
+ int* x = realloc(NULL, 100); // equivalent to malloc(100), and ends up
+ // calling Valgrind's (and Massif's) malloc
+
+ x = realloc(x, 100); // same size
+
+ x = realloc(x, 50); // smaller
+
+ x = realloc(x, 150); // bigger
+
+ realloc(x+10, 200); // bogus realloc
+
+ x = realloc(x, 0); // equivalent to free(x), and ends up
+ // calling Valgrind's (and Massif's) free
+ return 0;
+}
diff --git a/massif/tests/realloc.post.exp b/massif/tests/realloc.post.exp
new file mode 100644
index 0000000..f3d1f90
--- /dev/null
+++ b/massif/tests/realloc.post.exp
@@ -0,0 +1,64 @@
+--------------------------------------------------------------------------------
+Command: ./realloc
+Massif arguments: --stacks=no --heap-admin=0 --time-unit=B --threshold=0
+ms_print arguments: --threshold=0 massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 150^ #
+ | #
+ | #
+ | #
+ | #
+ | #
+ | #
+ | @ #
+ | @ #
+ | @ #
+ | @ #
+ | @ #
+ | @ #
+ | @ . #
+ | @ : #
+ | @ : #
+ | @ : #
+ | @ : #
+ | @ : #
+ | @ : #
+ 0 +-----------------@--------------------------#-------------------------->B
+ 0 400
+
+Number of snapshots: 8
+ Detailed snapshots: [3, 6 (peak)]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 100 100 100 0 0
+ 2 100 100 100 0 0
+ 3 100 100 100 0 0
+100.00% (100B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (100B) 0x........: main (realloc.c:8)
+|
+->00.00% (0B) 0x........: main (realloc.c:5)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 4 150 50 50 0 0
+ 5 250 150 150 0 0
+ 6 250 150 150 0 0
+100.00% (150B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->100.00% (150B) 0x........: main (realloc.c:12)
+|
+->00.00% (0B) 0x........: main (realloc.c:5)
+|
+->00.00% (0B) 0x........: main (realloc.c:8)
+|
+->00.00% (0B) 0x........: main (realloc.c:10)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 7 400 0 0 0 0
diff --git a/massif/tests/realloc.stderr.exp b/massif/tests/realloc.stderr.exp
new file mode 100644
index 0000000..388aaff
--- /dev/null
+++ b/massif/tests/realloc.stderr.exp
@@ -0,0 +1,40 @@
+Massif: alloc-fns:
+Massif: 0: malloc
+Massif: 1: __builtin_new
+Massif: 2: operator new(unsigned)
+Massif: 3: operator new(unsigned long)
+Massif: 4: __builtin_vec_new
+Massif: 5: operator new[](unsigned)
+Massif: 6: operator new[](unsigned long)
+Massif: 7: calloc
+Massif: 8: realloc
+Massif: 9: memalign
+Massif: 10: operator new(unsigned, std::nothrow_t const&)
+Massif: 11: operator new[](unsigned, std::nothrow_t const&)
+Massif: 12: operator new(unsigned long, std::nothrow_t const&)
+Massif: 13: operator new[](unsigned long, std::nothrow_t const&)
+Massif: startup S. 0 (t:0, hp:0, ad:0, st:0)
+Massif: alloc S. 1 (t:100, hp:100, ad:0, st:0)
+Massif: realloc S. 2 (t:100, hp:100, ad:0, st:0)
+Massif: re-PEAK Sp 3 (t:100, hp:100, ad:0, st:0)
+Massif: realloc S. 4 (t:150, hp:50, ad:0, st:0)
+Massif: realloc S. 5 (t:250, hp:150, ad:0, st:0)
+Massif: de-PEAK Sp 6 (t:250, hp:150, ad:0, st:0)
+Massif: dealloc S. 7 (t:400, hp:0, ad:0, st:0)
+Massif: heap allocs: 1
+Massif: heap reallocs: 3
+Massif: heap frees: 1
+Massif: stack allocs: 0
+Massif: stack frees: 0
+Massif: XPts: 13
+Massif: top-XPts: 4 (30%)
+Massif: XPt-init-expansions: 9
+Massif: XPt-later-expansions: 0
+Massif: SXPt allocs: 20
+Massif: SXPt frees: 0
+Massif: skipped snapshots: 0
+Massif: real snapshots: 8
+Massif: detailed snapshots: 2
+Massif: peak snapshots: 2
+Massif: cullings: 0
+Massif: XCon_redos: 0
diff --git a/massif/tests/realloc.vgtest b/massif/tests/realloc.vgtest
new file mode 100644
index 0000000..8b7ba70
--- /dev/null
+++ b/massif/tests/realloc.vgtest
@@ -0,0 +1,5 @@
+prog: realloc
+vgopts: -v -v --stacks=no --heap-admin=0 --time-unit=B --threshold=0
+stderr_filter: filter_verbose
+post: perl ../../massif/ms_print --threshold=0 massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/thresholds.c b/massif/tests/thresholds.c
new file mode 100644
index 0000000..fa5dfa1
--- /dev/null
+++ b/massif/tests/thresholds.c
@@ -0,0 +1,58 @@
+// This test is for testing that the --threshold options in both Massif and
+// ms_print work as they should. A threshold of 10% is a good choice for
+// this file, because in some parts of the tree it renders all children
+// insignificant, and in others parts of the tree it renders only some
+// children insignificant.
+//
+// Also, it's deliberate that the 'malloc(2000)' and 'my_malloc1(500)' calls
+// are in 'main' -- at one point, ms_print was failing to connect some
+// children arrows when a more significant child didn't have any children of
+// its own, eg:
+//
+// |
+// ->20.00% (2000B) 0x804846A: main (thresholds.c:43)
+//
+// ->13.00% (1300B) 0x80483A4: my_malloc2 (thresholds.c:16)
+//
+// (There must be a '|' between the '->'s.)
+
+#include <stdlib.h>
+
+void my_malloc1(int n)
+{
+ malloc(n);
+}
+
+void my_malloc2(int n)
+{
+ malloc(n);
+}
+
+void my_malloc3(int n)
+{
+ malloc(n);
+}
+
+void a7550(void)
+{
+ my_malloc1(6000);
+ my_malloc2( 900);
+}
+
+void a450(void)
+{
+ my_malloc2( 300);
+ my_malloc1( 100);
+ my_malloc2( 100);
+ my_malloc1( 50);
+}
+
+int main(void)
+{
+ a7550();
+ a450();
+ my_malloc1(500);
+ malloc(2000);
+ my_malloc3(50);
+ return 0;
+}
diff --git a/massif/tests/thresholds_0_0.post.exp b/massif/tests/thresholds_0_0.post.exp
new file mode 100644
index 0000000..6ffabc3
--- /dev/null
+++ b/massif/tests/thresholds_0_0.post.exp
@@ -0,0 +1,74 @@
+--------------------------------------------------------------------------------
+Command: ./thresholds
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0 --threshold=0
+ms_print arguments: massif.out --threshold=0
+--------------------------------------------------------------------------------
+
+
+ KB
+9.766^ @
+ | @
+ | @
+ | @
+ | . @
+ | .. : @
+ | . ::: : @
+ | : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ 0 +-----------------------------------------------------------------------@KB
+ 0 9.766
+
+Number of snapshots: 10
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 6,000 6,000 6,000 0 0
+ 2 6,900 6,900 6,900 0 0
+ 3 7,200 7,200 7,200 0 0
+ 4 7,300 7,300 7,300 0 0
+ 5 7,400 7,400 7,400 0 0
+ 6 7,450 7,450 7,450 0 0
+ 7 7,950 7,950 7,950 0 0
+ 8 9,950 9,950 9,950 0 0
+ 9 10,000 10,000 10,000 0 0
+100.00% (10,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->66.50% (6,650B) 0x........: my_malloc1 (thresholds.c:23)
+| ->60.00% (6,000B) 0x........: a7550 (thresholds.c:38)
+| | ->60.00% (6,000B) 0x........: main (thresholds.c:52)
+| |
+| ->05.00% (500B) 0x........: main (thresholds.c:54)
+| |
+| ->01.00% (100B) 0x........: a450 (thresholds.c:45)
+| | ->01.00% (100B) 0x........: main (thresholds.c:53)
+| |
+| ->00.50% (50B) 0x........: a450 (thresholds.c:47)
+| ->00.50% (50B) 0x........: main (thresholds.c:53)
+|
+->20.00% (2,000B) 0x........: main (thresholds.c:55)
+|
+->13.00% (1,300B) 0x........: my_malloc2 (thresholds.c:28)
+| ->09.00% (900B) 0x........: a7550 (thresholds.c:39)
+| | ->09.00% (900B) 0x........: main (thresholds.c:52)
+| |
+| ->03.00% (300B) 0x........: a450 (thresholds.c:44)
+| | ->03.00% (300B) 0x........: main (thresholds.c:53)
+| |
+| ->01.00% (100B) 0x........: a450 (thresholds.c:46)
+| ->01.00% (100B) 0x........: main (thresholds.c:53)
+|
+->00.50% (50B) 0x........: my_malloc3 (thresholds.c:33)
+ ->00.50% (50B) 0x........: main (thresholds.c:56)
+
diff --git a/massif/tests/thresholds_0_0.stderr.exp b/massif/tests/thresholds_0_0.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/thresholds_0_0.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/thresholds_0_0.vgtest b/massif/tests/thresholds_0_0.vgtest
new file mode 100644
index 0000000..c6b3dd7
--- /dev/null
+++ b/massif/tests/thresholds_0_0.vgtest
@@ -0,0 +1,4 @@
+prog: thresholds
+vgopts: --stacks=no --time-unit=B --heap-admin=0 --threshold=0
+post: perl ../../massif/ms_print massif.out --threshold=0 | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/thresholds_0_10.post.exp b/massif/tests/thresholds_0_10.post.exp
new file mode 100644
index 0000000..c121ed7
--- /dev/null
+++ b/massif/tests/thresholds_0_10.post.exp
@@ -0,0 +1,60 @@
+--------------------------------------------------------------------------------
+Command: ./thresholds
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0 --threshold=0
+ms_print arguments: massif.out --threshold=10
+--------------------------------------------------------------------------------
+
+
+ KB
+9.766^ @
+ | @
+ | @
+ | @
+ | . @
+ | .. : @
+ | . ::: : @
+ | : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ 0 +-----------------------------------------------------------------------@KB
+ 0 9.766
+
+Number of snapshots: 10
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 6,000 6,000 6,000 0 0
+ 2 6,900 6,900 6,900 0 0
+ 3 7,200 7,200 7,200 0 0
+ 4 7,300 7,300 7,300 0 0
+ 5 7,400 7,400 7,400 0 0
+ 6 7,450 7,450 7,450 0 0
+ 7 7,950 7,950 7,950 0 0
+ 8 9,950 9,950 9,950 0 0
+ 9 10,000 10,000 10,000 0 0
+100.00% (10,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->66.50% (6,650B) 0x........: my_malloc1 (thresholds.c:23)
+| ->60.00% (6,000B) 0x........: a7550 (thresholds.c:38)
+| | ->60.00% (6,000B) 0x........: main (thresholds.c:52)
+| |
+| ->06.50% (650B) in 3+ places, all below ms_print's threshold (10.00%)
+|
+->20.00% (2,000B) 0x........: main (thresholds.c:55)
+|
+->13.00% (1,300B) 0x........: my_malloc2 (thresholds.c:28)
+| ->13.00% (1,300B) in 3+ places, all below ms_print's threshold (10.00%)
+|
+->00.50% (50B) in 1+ places, all below ms_print's threshold (10.00%)
+
diff --git a/massif/tests/thresholds_0_10.stderr.exp b/massif/tests/thresholds_0_10.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/thresholds_0_10.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/thresholds_0_10.vgtest b/massif/tests/thresholds_0_10.vgtest
new file mode 100644
index 0000000..85b8234
--- /dev/null
+++ b/massif/tests/thresholds_0_10.vgtest
@@ -0,0 +1,4 @@
+prog: thresholds
+vgopts: --stacks=no --time-unit=B --heap-admin=0 --threshold=0
+post: perl ../../massif/ms_print massif.out --threshold=10 | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/thresholds_10_0.post.exp b/massif/tests/thresholds_10_0.post.exp
new file mode 100644
index 0000000..cadf369
--- /dev/null
+++ b/massif/tests/thresholds_10_0.post.exp
@@ -0,0 +1,60 @@
+--------------------------------------------------------------------------------
+Command: ./thresholds
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0 --threshold=1000
+ms_print arguments: massif.out --threshold=0
+--------------------------------------------------------------------------------
+
+
+ KB
+9.766^ @
+ | @
+ | @
+ | @
+ | . @
+ | .. : @
+ | . ::: : @
+ | : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ 0 +-----------------------------------------------------------------------@KB
+ 0 9.766
+
+Number of snapshots: 10
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 6,000 6,000 6,000 0 0
+ 2 6,900 6,900 6,900 0 0
+ 3 7,200 7,200 7,200 0 0
+ 4 7,300 7,300 7,300 0 0
+ 5 7,400 7,400 7,400 0 0
+ 6 7,450 7,450 7,450 0 0
+ 7 7,950 7,950 7,950 0 0
+ 8 9,950 9,950 9,950 0 0
+ 9 10,000 10,000 10,000 0 0
+100.00% (10,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->66.50% (6,650B) 0x........: my_malloc1 (thresholds.c:23)
+| ->60.00% (6,000B) 0x........: a7550 (thresholds.c:38)
+| | ->60.00% (6,000B) 0x........: main (thresholds.c:52)
+| |
+| ->06.50% (650B) in 3 places, all below massif's threshold (10.00%)
+|
+->20.00% (2,000B) 0x........: main (thresholds.c:55)
+|
+->13.00% (1,300B) 0x........: my_malloc2 (thresholds.c:28)
+| ->13.00% (1,300B) in 3 places, all below massif's threshold (10.00%)
+|
+->00.50% (50B) in 1 place, below massif's threshold (10.00%)
+
diff --git a/massif/tests/thresholds_10_0.stderr.exp b/massif/tests/thresholds_10_0.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/thresholds_10_0.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/thresholds_10_0.vgtest b/massif/tests/thresholds_10_0.vgtest
new file mode 100644
index 0000000..2b6239d
--- /dev/null
+++ b/massif/tests/thresholds_10_0.vgtest
@@ -0,0 +1,4 @@
+prog: thresholds
+vgopts: --stacks=no --time-unit=B --heap-admin=0 --threshold=1000
+post: perl ../../massif/ms_print massif.out --threshold=0 | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/thresholds_10_10.post.exp b/massif/tests/thresholds_10_10.post.exp
new file mode 100644
index 0000000..6733125
--- /dev/null
+++ b/massif/tests/thresholds_10_10.post.exp
@@ -0,0 +1,60 @@
+--------------------------------------------------------------------------------
+Command: ./thresholds
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0 --threshold=1000
+ms_print arguments: massif.out --threshold=10
+--------------------------------------------------------------------------------
+
+
+ KB
+9.766^ @
+ | @
+ | @
+ | @
+ | . @
+ | .. : @
+ | . ::: : @
+ | : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ 0 +-----------------------------------------------------------------------@KB
+ 0 9.766
+
+Number of snapshots: 10
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 6,000 6,000 6,000 0 0
+ 2 6,900 6,900 6,900 0 0
+ 3 7,200 7,200 7,200 0 0
+ 4 7,300 7,300 7,300 0 0
+ 5 7,400 7,400 7,400 0 0
+ 6 7,450 7,450 7,450 0 0
+ 7 7,950 7,950 7,950 0 0
+ 8 9,950 9,950 9,950 0 0
+ 9 10,000 10,000 10,000 0 0
+100.00% (10,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->66.50% (6,650B) 0x........: my_malloc1 (thresholds.c:23)
+| ->60.00% (6,000B) 0x........: a7550 (thresholds.c:38)
+| | ->60.00% (6,000B) 0x........: main (thresholds.c:52)
+| |
+| ->06.50% (650B) in 1+ places, all below ms_print's threshold (10.00%)
+|
+->20.00% (2,000B) 0x........: main (thresholds.c:55)
+|
+->13.00% (1,300B) 0x........: my_malloc2 (thresholds.c:28)
+| ->13.00% (1,300B) in 3 places, all below massif's threshold (10.00%)
+|
+->00.50% (50B) in 1+ places, all below ms_print's threshold (10.00%)
+
diff --git a/massif/tests/thresholds_10_10.stderr.exp b/massif/tests/thresholds_10_10.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/thresholds_10_10.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/thresholds_10_10.vgtest b/massif/tests/thresholds_10_10.vgtest
new file mode 100644
index 0000000..40f0535
--- /dev/null
+++ b/massif/tests/thresholds_10_10.vgtest
@@ -0,0 +1,4 @@
+prog: thresholds
+vgopts: --stacks=no --time-unit=B --heap-admin=0 --threshold=1000
+post: perl ../../massif/ms_print massif.out --threshold=10 | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/thresholds_5_0.post.exp b/massif/tests/thresholds_5_0.post.exp
new file mode 100644
index 0000000..6bb2078
--- /dev/null
+++ b/massif/tests/thresholds_5_0.post.exp
@@ -0,0 +1,65 @@
+--------------------------------------------------------------------------------
+Command: ./thresholds
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0 --threshold=500
+ms_print arguments: massif.out --threshold=0
+--------------------------------------------------------------------------------
+
+
+ KB
+9.766^ @
+ | @
+ | @
+ | @
+ | . @
+ | .. : @
+ | . ::: : @
+ | : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ 0 +-----------------------------------------------------------------------@KB
+ 0 9.766
+
+Number of snapshots: 10
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 6,000 6,000 6,000 0 0
+ 2 6,900 6,900 6,900 0 0
+ 3 7,200 7,200 7,200 0 0
+ 4 7,300 7,300 7,300 0 0
+ 5 7,400 7,400 7,400 0 0
+ 6 7,450 7,450 7,450 0 0
+ 7 7,950 7,950 7,950 0 0
+ 8 9,950 9,950 9,950 0 0
+ 9 10,000 10,000 10,000 0 0
+100.00% (10,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->66.50% (6,650B) 0x........: my_malloc1 (thresholds.c:23)
+| ->60.00% (6,000B) 0x........: a7550 (thresholds.c:38)
+| | ->60.00% (6,000B) 0x........: main (thresholds.c:52)
+| |
+| ->05.00% (500B) 0x........: main (thresholds.c:54)
+| |
+| ->01.50% (150B) in 2 places, all below massif's threshold (05.00%)
+|
+->20.00% (2,000B) 0x........: main (thresholds.c:55)
+|
+->13.00% (1,300B) 0x........: my_malloc2 (thresholds.c:28)
+| ->09.00% (900B) 0x........: a7550 (thresholds.c:39)
+| | ->09.00% (900B) 0x........: main (thresholds.c:52)
+| |
+| ->04.00% (400B) in 2 places, all below massif's threshold (05.00%)
+|
+->00.50% (50B) in 1 place, below massif's threshold (05.00%)
+
diff --git a/massif/tests/thresholds_5_0.stderr.exp b/massif/tests/thresholds_5_0.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/thresholds_5_0.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/thresholds_5_0.vgtest b/massif/tests/thresholds_5_0.vgtest
new file mode 100644
index 0000000..32b5f9c
--- /dev/null
+++ b/massif/tests/thresholds_5_0.vgtest
@@ -0,0 +1,4 @@
+prog: thresholds
+vgopts: --stacks=no --time-unit=B --heap-admin=0 --threshold=500
+post: perl ../../massif/ms_print massif.out --threshold=0 | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/thresholds_5_10.post.exp b/massif/tests/thresholds_5_10.post.exp
new file mode 100644
index 0000000..1571fad
--- /dev/null
+++ b/massif/tests/thresholds_5_10.post.exp
@@ -0,0 +1,60 @@
+--------------------------------------------------------------------------------
+Command: ./thresholds
+Massif arguments: --stacks=no --time-unit=B --heap-admin=0 --threshold=500
+ms_print arguments: massif.out --threshold=10
+--------------------------------------------------------------------------------
+
+
+ KB
+9.766^ @
+ | @
+ | @
+ | @
+ | . @
+ | .. : @
+ | . ::: : @
+ | : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ | : : ::: : @
+ 0 +-----------------------------------------------------------------------@KB
+ 0 9.766
+
+Number of snapshots: 10
+ Detailed snapshots: [9]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 6,000 6,000 6,000 0 0
+ 2 6,900 6,900 6,900 0 0
+ 3 7,200 7,200 7,200 0 0
+ 4 7,300 7,300 7,300 0 0
+ 5 7,400 7,400 7,400 0 0
+ 6 7,450 7,450 7,450 0 0
+ 7 7,950 7,950 7,950 0 0
+ 8 9,950 9,950 9,950 0 0
+ 9 10,000 10,000 10,000 0 0
+100.00% (10,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->66.50% (6,650B) 0x........: my_malloc1 (thresholds.c:23)
+| ->60.00% (6,000B) 0x........: a7550 (thresholds.c:38)
+| | ->60.00% (6,000B) 0x........: main (thresholds.c:52)
+| |
+| ->06.50% (650B) in 2+ places, all below ms_print's threshold (10.00%)
+|
+->20.00% (2,000B) 0x........: main (thresholds.c:55)
+|
+->13.00% (1,300B) 0x........: my_malloc2 (thresholds.c:28)
+| ->13.00% (1,300B) in 2+ places, all below ms_print's threshold (10.00%)
+|
+->00.50% (50B) in 1+ places, all below ms_print's threshold (10.00%)
+
diff --git a/massif/tests/thresholds_5_10.stderr.exp b/massif/tests/thresholds_5_10.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/thresholds_5_10.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/thresholds_5_10.vgtest b/massif/tests/thresholds_5_10.vgtest
new file mode 100644
index 0000000..c7b076a
--- /dev/null
+++ b/massif/tests/thresholds_5_10.vgtest
@@ -0,0 +1,4 @@
+prog: thresholds
+vgopts: --stacks=no --time-unit=B --heap-admin=0 --threshold=500
+post: perl ../../massif/ms_print massif.out --threshold=10 | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/toobig-allocs.stderr.exp b/massif/tests/toobig-allocs.stderr.exp
index a5b2005..28c2b9e 100644
--- a/massif/tests/toobig-allocs.stderr.exp
+++ b/massif/tests/toobig-allocs.stderr.exp
@@ -2,7 +2,3 @@
Attempting too-big malloc()...
Attempting too-big mmap()...
-Total spacetime:
-heap:
-heap admin:
-stack(s):
diff --git a/massif/tests/toobig-allocs.vgtest b/massif/tests/toobig-allocs.vgtest
index 186cf5f..ca231b0 100644
--- a/massif/tests/toobig-allocs.vgtest
+++ b/massif/tests/toobig-allocs.vgtest
@@ -1 +1,2 @@
prog: ../../tests/toobig-allocs
+cleanup: rm massif.out
diff --git a/massif/tests/true_html.stderr.exp b/massif/tests/true_html.stderr.exp
deleted file mode 100644
index c3baf21..0000000
--- a/massif/tests/true_html.stderr.exp
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-Total spacetime:
-heap:
-heap admin:
-stack(s):
diff --git a/massif/tests/true_html.vgtest b/massif/tests/true_html.vgtest
deleted file mode 100644
index b698a3e..0000000
--- a/massif/tests/true_html.vgtest
+++ /dev/null
@@ -1,3 +0,0 @@
-prog: ../../tests/true
-vgopts: --format=html
-cleanup: rm massif.*.*
diff --git a/massif/tests/true_text.stderr.exp b/massif/tests/true_text.stderr.exp
deleted file mode 100644
index c3baf21..0000000
--- a/massif/tests/true_text.stderr.exp
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-Total spacetime:
-heap:
-heap admin:
-stack(s):
diff --git a/massif/tests/true_text.vgtest b/massif/tests/true_text.vgtest
deleted file mode 100644
index 2df33d7..0000000
--- a/massif/tests/true_text.vgtest
+++ /dev/null
@@ -1,3 +0,0 @@
-prog: ../../tests/true
-vgopts: --format=text
-cleanup: rm massif.*.*
diff --git a/massif/tests/zero.c b/massif/tests/zero.c
new file mode 100644
index 0000000..6c67dad
--- /dev/null
+++ b/massif/tests/zero.c
@@ -0,0 +1,19 @@
+// Test zero-size allocations -- shouldn't cause division by zero, that kind
+// of thing.
+
+#include <stdlib.h>
+
+int main(void)
+{
+ free(malloc(0));
+ free(malloc(0));
+ free(malloc(0));
+ free(malloc(0));
+ free(malloc(0));
+ free(malloc(0));
+ free(malloc(0));
+ free(malloc(0));
+ free(malloc(0));
+ free(malloc(0));
+ return 0;
+}
diff --git a/massif/tests/zero1.post.exp b/massif/tests/zero1.post.exp
new file mode 100644
index 0000000..207cd26
--- /dev/null
+++ b/massif/tests/zero1.post.exp
@@ -0,0 +1,69 @@
+--------------------------------------------------------------------------------
+Command: ./zero
+Massif arguments: --stacks=no --heap-admin=no --time-unit=B
+ms_print arguments: --threshold=0 massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 1^
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ 0 +@---------------------------------------------------------------------->B
+ 0 1
+
+Number of snapshots: 21
+ Detailed snapshots: [9, 19]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 0 0 0 0 0
+ 2 0 0 0 0 0
+ 3 0 0 0 0 0
+ 4 0 0 0 0 0
+ 5 0 0 0 0 0
+ 6 0 0 0 0 0
+ 7 0 0 0 0 0
+ 8 0 0 0 0 0
+ 9 0 0 0 0 0
+00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->00.00% (0B) in 5 places, all below massif's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 0 0 0 0 0
+ 11 0 0 0 0 0
+ 12 0 0 0 0 0
+ 13 0 0 0 0 0
+ 14 0 0 0 0 0
+ 15 0 0 0 0 0
+ 16 0 0 0 0 0
+ 17 0 0 0 0 0
+ 18 0 0 0 0 0
+ 19 0 0 0 0 0
+00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->00.00% (0B) in 10 places, all below massif's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 20 0 0 0 0 0
diff --git a/massif/tests/zero1.stderr.exp b/massif/tests/zero1.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/zero1.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/zero1.vgtest b/massif/tests/zero1.vgtest
new file mode 100644
index 0000000..b07738b
--- /dev/null
+++ b/massif/tests/zero1.vgtest
@@ -0,0 +1,4 @@
+prog: zero
+vgopts: --stacks=no --heap-admin=no --time-unit=B
+post: perl ../../massif/ms_print --threshold=0 massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/massif/tests/zero2.post.exp b/massif/tests/zero2.post.exp
new file mode 100644
index 0000000..f216ee5
--- /dev/null
+++ b/massif/tests/zero2.post.exp
@@ -0,0 +1,69 @@
+--------------------------------------------------------------------------------
+Command: ./zero
+Massif arguments: --stacks=no --heap-admin=no --time-unit=B
+ms_print arguments: massif.out
+--------------------------------------------------------------------------------
+
+
+ B
+ 1^
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ 0 +@---------------------------------------------------------------------->B
+ 0 1
+
+Number of snapshots: 21
+ Detailed snapshots: [9, 19]
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 0 0 0 0 0 0
+ 1 0 0 0 0 0
+ 2 0 0 0 0 0
+ 3 0 0 0 0 0
+ 4 0 0 0 0 0
+ 5 0 0 0 0 0
+ 6 0 0 0 0 0
+ 7 0 0 0 0 0
+ 8 0 0 0 0 0
+ 9 0 0 0 0 0
+00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 10 0 0 0 0 0
+ 11 0 0 0 0 0
+ 12 0 0 0 0 0
+ 13 0 0 0 0 0
+ 14 0 0 0 0 0
+ 15 0 0 0 0 0
+ 16 0 0 0 0 0
+ 17 0 0 0 0 0
+ 18 0 0 0 0 0
+ 19 0 0 0 0 0
+00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
+->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
+
+--------------------------------------------------------------------------------
+ n time(B) total(B) useful-heap(B) admin-heap(B) stacks(B)
+--------------------------------------------------------------------------------
+ 20 0 0 0 0 0
diff --git a/massif/tests/zero2.stderr.exp b/massif/tests/zero2.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/massif/tests/zero2.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/massif/tests/zero2.vgtest b/massif/tests/zero2.vgtest
new file mode 100644
index 0000000..2044bba
--- /dev/null
+++ b/massif/tests/zero2.vgtest
@@ -0,0 +1,4 @@
+prog: zero
+vgopts: --stacks=no --heap-admin=no --time-unit=B
+post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
+cleanup: rm massif.out
diff --git a/tests/vg_regtest.in b/tests/vg_regtest.in
index 2544724..d2d882c 100755
--- a/tests/vg_regtest.in
+++ b/tests/vg_regtest.in
@@ -55,8 +55,8 @@
# - stdout_filter: <filter to run stdout through> (default: none)
# - stderr_filter: <filter to run stderr through> (default: ./filter_stderr)
# - prereq: <prerequisite command> (default: none)
-# - posttest: <post-test check command> (default: none)
-# - cleanup: <post-test cleanup cmd to run> (default: none)
+# - post: <post-test check command> (default: none)
+# - cleanup: <post-test cleanup cmd> (default: none)
#
# Note that filters are necessary for stderr results to filter out things that
# always change, eg. process id numbers.
@@ -67,7 +67,7 @@
#
# The prerequisite command, if present, must return 0 otherwise the test is
# skipped. The post-test command, if present, must return 0 and its stdout
-# must match the expected stdout which is kept in <test>.posttest.exp[0-9]*.
+# must match the expected stdout which is kept in <test>.post.exp[0-9]*.
#
# If results don't match, the output can be found in <test>.std<strm>.out,
# and the diff between expected and actual in <test>.std<strm>.diff[0-9]*.
@@ -99,13 +99,13 @@
my $stdout_filter; # filter program to run stdout results file through
my $stderr_filter; # filter program to run stderr results file through
my $prereq; # prerequisite test to satisfy before running test
-my $posttest; # check command after running test
+my $post; # check command after running test
my $cleanup; # cleanup command to run
my @failures; # List of failed tests
my $num_tests_done = 0;
-my %num_failures = (stderr => 0, stdout => 0, posttest => 0);
+my %num_failures = (stderr => 0, stdout => 0, post => 0);
# Default valgrind to use is this build tree's (uninstalled) one
my $valgrind = "./coregrind/valgrind";
@@ -192,7 +192,7 @@
# Defaults.
($vgopts, $prog, $args) = ("", undef, "");
($stdout_filter, $stderr_filter) = (undef, undef);
- ($prereq, $posttest, $cleanup) = (undef, undef, undef);
+ ($prereq, $post, $cleanup) = (undef, undef, undef);
# Every test directory must have a "filter_stderr"
$stderr_filter = validate_program(".", $default_stderr_filter, 1, 1);
@@ -214,8 +214,8 @@
$stderr_filter = validate_program(".", $1, 1, 1);
} elsif ($line =~ /^\s*prereq:\s*(.*)$/) {
$prereq = $1;
- } elsif ($line =~ /^\s*posttest:\s*(.*)$/) {
- $posttest = $1;
+ } elsif ($line =~ /^\s*post:\s*(.*)$/) {
+ $post = $1;
} elsif ($line =~ /^\s*cleanup:\s*(.*)$/) {
$cleanup = $1;
} else {
@@ -236,7 +236,9 @@
# propagate a Ctrl-C enabling us to quit.
sub mysystem($)
{
- (system($_[0]) != 2) or exit 1; # 2 is SIGINT
+ my $exit_code = system($_[0]);
+ ($exit_code == 2) and exit 1; # 2 is SIGINT
+ return $exit_code;
}
# from a directory name like "/foo/cachesim/tests/" determine the tool name
@@ -332,15 +334,15 @@
do_diffs($fullname, $name, "stderr", \@stderr_exps);
# Maybe do post-test check
- if (defined $posttest) {
- if (mysystem("$posttest > $name.posttest.out") != 0) {
- print("posttest failed: $posttest\n");
- $num_failures{"posttest"}++;
+ if (defined $post) {
+ if (mysystem("$post > $name.post.out") != 0) {
+ print("post check failed: $post\n");
+ $num_failures{"post"}++;
} else {
- # Find all the .posttest.exp files. If none, use /dev/null.
- my @posttest_exps = <$name.posttest.exp*>;
- @posttest_exps = ( "/dev/null" ) if (0 == scalar @posttest_exps);
- do_diffs($fullname, $name, "posttest", \@posttest_exps);
+ # Find all the .post.exp files. If none, use /dev/null.
+ my @post_exps = <$name.post.exp*>;
+ @post_exps = ( "/dev/null" ) if (0 == scalar @post_exps);
+ do_diffs($fullname, $name, "post", \@post_exps);
}
}
@@ -413,11 +415,11 @@
my $x = ( $num_tests_done == 1 ? "test" : "tests" );
printf("\n== %d test%s, %d stderr failure%s, %d stdout failure%s, "
- . "%d posttest failure%s ==\n",
+ . "%d post failure%s ==\n",
$num_tests_done, plural($num_tests_done),
$num_failures{"stderr"}, plural($num_failures{"stderr"}),
$num_failures{"stdout"}, plural($num_failures{"stdout"}),
- $num_failures{"posttest"}, plural($num_failures{"posttest"}));
+ $num_failures{"post"}, plural($num_failures{"post"}));
foreach my $failure (@failures) {
print "$failure\n";
@@ -472,7 +474,7 @@
if (0 == $num_failures{"stdout"} &&
0 == $num_failures{"stderr"} &&
- 0 == $num_failures{"posttest"}) {
+ 0 == $num_failures{"post"}) {
exit 0;
} else {
exit 1;