Adding Massif, the heap profiler.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2245
This commit is contained in:
Nicholas Nethercote 2004-02-14 16:40:02 +00:00
parent 49c135649d
commit 563c4e566a
57 changed files with 5664 additions and 9 deletions

View File

@ -9,6 +9,7 @@ SUBDIRS = include coregrind . docs tests auxprogs \
cachegrind \
corecheck \
helgrind \
massif \
lackey \
none

View File

@ -373,12 +373,16 @@ AC_OUTPUT(
cachegrind/tests/Makefile
cachegrind/docs/Makefile
cachegrind/cg_annotate
corecheck/Makefile
corecheck/tests/Makefile
corecheck/docs/Makefile
helgrind/Makefile
helgrind/tests/Makefile
helgrind/docs/Makefile
massif/Makefile
massif/hp2ps/Makefile
massif/tests/Makefile
massif/docs/Makefile
corecheck/Makefile
corecheck/tests/Makefile
corecheck/docs/Makefile
lackey/Makefile
lackey/tests/Makefile
lackey/docs/Makefile

View File

@ -1365,9 +1365,6 @@ extern Int VG_(vgexecfd);
/* client executable file descriptor */
extern Int VG_(clexecfd);
/* Path to all our library/aux files */
extern const Char *VG_(libdir);
/* Determine if %esp adjustment must be noted */
extern Bool VG_(need_to_handle_esp_assignment) ( void );

View File

@ -98,12 +98,15 @@ An open-source tool for debugging and profiling Linux-x86 executables.
<h4>6&nbsp; <a href="hg_main.html#hg-top">
Helgrind: a data-race detector</a></h4>
<h4>7&nbsp; <a href="ms_main.html#ms-top">
Massif: a heap profiler</a></h4>
<p>
The following is not part of the user manual. It describes how you can
write tools for Valgrind, in order to make new program supervision
tools.
<h4>7&nbsp; <a href="coregrind_tools.html">
<h4>8&nbsp; <a href="coregrind_tools.html">
Valgrind Tools</a></h4>
<p>
@ -111,10 +114,10 @@ The following are not part of the user manual. They describe internal
details of how Valgrind works. Reading them may rot your brain. You
have been warned.
<h4>8&nbsp; <a href="mc_techdocs.html#mc-techdocs">
<h4>9&nbsp; <a href="mc_techdocs.html#mc-techdocs">
The design and implementation of Valgrind</a></h4>
<h4>9&nbsp; <a href="cg_techdocs.html#cg-techdocs">
<h4>10&nbsp; <a href="cg_techdocs.html#cg-techdocs">
How Cachegrind works</a></h4>
<hr width="100%">

View File

@ -114,6 +114,10 @@ typedef unsigned char Bool;
#include "vg_kerneliface.h"
/* Path to all our library/aux files */
extern const Char *VG_(libdir);
/*====================================================================*/
/*=== Core/skin interface version ===*/
/*====================================================================*/

24
massif/Makefile.am Normal file
View File

@ -0,0 +1,24 @@
SUBDIRS = . tests docs hp2ps
AM_CPPFLAGS = -I$(top_srcdir)/include -DVG_LIBDIR="\"$(libdir)"\"
AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer \
@PREFERRED_STACK_BOUNDARY@ -g
valdir = $(libdir)/valgrind
inplacedir = $(top_srcdir)/.in_place
val_PROGRAMS = vgskin_massif.so vgpreload_massif.so
vgskin_massif_so_SOURCES = ms_main.c
vgskin_massif_so_LDFLAGS = -shared
vgpreload_massif_so_SOURCES =
vgpreload_massif_so_LDADD = $(top_srcdir)/coregrind/vg_replace_malloc.o
vgpreload_massif_so_DEPENDENCIES = $(top_srcdir)/coregrind/vg_replace_malloc.o
vgpreload_massif_so_LDFLAGS = -shared -Wl,-z,interpose,-z,initfirst
all-local:
mkdir -p $(inplacedir)
-rm -f $(addprefix $(inplacedir)/,$(val_PROGRAMS))
ln -f -s $(addprefix $(top_srcdir)/$(subdir)/,$(val_PROGRAMS)) $(inplacedir)

5
massif/docs/Makefile.am Normal file
View File

@ -0,0 +1,5 @@
docdir = $(datadir)/doc/valgrind
doc_DATA = ms_main.html date.gif
EXTRA_DIST = $(doc_DATA)

BIN
massif/docs/date.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

331
massif/docs/ms_main.html Normal file
View File

@ -0,0 +1,331 @@
<html>
<head>
<title>Massif: a heap profiler</title>
</head>
<body>
<a name="ms-top"></a>
<h2>7&nbsp; <b>Massif</b>: a heap profiler</h2>
To use this tool, you must specify <code>--tool=massif</code>
on the Valgrind command line.
<a name="spaceprof"></a>
<h3>7.1&nbsp; Heap profiling</h3>
Massif is a heap profiler, i.e. it measures how much heap memory programs use.
In particular, it can give you information about:
<ul>
<li>Heap blocks;
<li>Heap administration blocks;
<li>Stack sizes.
</ul>
Heap profiling is useful to help you reduce the amount of memory your program
uses. On modern machines with virtual memory, this provides the following
benefits:
<ul>
<li>It can speed up your program -- a smaller program will interact better
with your machine's caches, avoid paging, and so on.
<li>If your program uses lots of memory, it will reduce the chance that it
exhausts your machine's swap space.
</ul>
Also, there are certain space leaks that aren't detected by traditional
leak-checkers, such as Memcheck's. That's because the memory isn't ever
actually lost -- a pointer remains to it -- but it's not in use. Programs
that have leaks like this can unnecessarily increase the amount of memory
they are using over time.
<p>
<a name="whyuse_heapprof"></a>
<h3>7.2&nbsp; Why Use a Heap Profiler?</h3>
Everybody knows how useful time profilers are for speeding up programs. They
are particularly useful because people are notoriously bad at predicting where
are the bottlenecks in their programs.
<p>
But the story is different for heap profilers. Some programming languages,
particularly lazy functional languages like <a
href="http://www.haskell.org">Haskell</a>, have quite sophisticated heap
profilers. But there are few tools as powerful for profiling C and C++
programs.
<p>
Why is this? Maybe it's because C and C++ programmers must think that
they know where the memory is being allocated. After all, you can see all the
calls to <code>malloc()</code> and <code>new</code> and <code>new[]</code>,
right? But, in a big program, do you really know which heap allocations are
being executed, how many times, and how large each allocation is? Can you give
even a vague estimate of the memory footprint for your program? Do you know
this for all the libraries your program uses? What about administration bytes
required by the heap allocator to track heap blocks -- have you thought about
them? What about the stack? If you are unsure about any of these things,
maybe you should think about heap profiling.
<p>
Massif can tell you these things.
<p>
Or maybe it's because it's relatively easy to add basic heap profiling
functionality into a program, to tell you how many bytes you have allocated for
certain objects, or similar. But this information might only be simple like
total counts for the whole program's execution. What about space usage at
different points in the program's execution, for example? And reimplementing
heap profiling code for each project is a pain.
<p>
Massif can save you this effort.
<p>
<a name="overview"></a>
<h3>7.3&nbsp; Overview</h3>
First off, as for normal Valgrind use, you probably want to compile with
debugging info (the <code>-g</code> flag). But, as opposed to Memcheck,
you probably <b>do</b> want to turn optimisation on, since you should profile
your program as it will be normally run.
<p>
Then, run your program with <code>valgrind --tool=massif</code> in front of the
normal command line invocation. When the program finishes, Massif will print
summary space statistics. It also creates a graph representing the program's
heap usage in a file called <code>massif.<i>pid</i>.ps</code>, which can
be read by any PostScript viewer, such as Ghostview.
<p>
It also puts detailed information about heap consumption in a file file
<code>massif.<i>pid</i>.txt</code> (text format) or
<code>massif.<i>pid</i>.html</code> (HTML format), where
<code><i>pid</i></code> is the program's process id.
<p>
<a name="basicresults"></a>
<h3>7.4&nbsp; Basic Results of Profiling</h3>
To gather heap profiling information about the program <code>prog</code>,
type:
<p>
<blockquote>
<code>valgrind --tool=massif prog</code>
</blockquote>
<p>
The program will execute (slowly). Upon completion, summary statistics
that look like this will be printed:
<pre>
==27519== Total spacetime: 2,258,106 ms.B
==27519== heap: 24.0%
==27519== heap admin: 2.2%
==27519== stack(s): 73.7%
</pre>
All measurements are done in <i>spacetime</i>, i.e. space (in bytes) multiplied
by time (in milliseconds). Note that because Massif slows a program down a
lot, the actual spacetime figure is fairly meaningless; it's the relative
values that are interesting.
<p>
Which entries you see in the breakdown depends on the command line options
given. The above example measures all the possible parts of memory:
<ul>
<li>Heap: number of words allocated on the heap, via <code>malloc()</code>,
<code>new</code> and <code>new[]</code>.
<p>
<li>Heap admin: each heap block allocated requires some administration data,
which lets the allocator track certain things about the block. It is easy
to forget about this, and if your program allocates lots of small blocks,
it can add up. This value is an estimate of the space required for this
administration data.
<p>
<li>Stack(s): the spacetime used by the programs' stack(s). (Threaded programs
can have multiple stacks.) This includes signal handler stacks.
<p>
</ul>
<p>
<a name="graphs"></a>
<h3>7.5&nbsp; Spacetime Graphs</h3>
As well as printing summary information, Massif also creates a file
representing a spacetime graph, <code>massif.<i>pid</i>.hp</code>.
It will produce a file called <code>massif.<i>pid</i>.ps</code>, which can be
viewed in a PostScript viewer.
<p>
Massif uses a program called <code>hp2ps</code> to convert the raw data into
the PostScript graph. It's distributed with Massif, but came originally
from the <a href="http://haskell.cs.yale.edu/ghc/">Glasgow Haskell
Compiler</a>. You shouldn't need to worry about this at all. However, if
the graph creation fails for any reason, Massif tell you, and will leave
behind a file named <code>massif.<i>pid</i>.hp</code>, containing the raw
heap profiling data.
<p>
Here's an example graph:<br>
<img src="date.gif" alt="spacetime graph">
<p>
The graph is broken into several bands. Most bands represent a single line of
your program that does some heap allocation; each such band represents all
the allocations and deallocations done from that line. Up to twenty bands are
shown; less significant allocation sites are merged into "other" and/or "OTHER"
bands. The accompanying text/HTML file produced by Massif has more detail
about these heap allocation bands. Then there are single bands for the
stack(s) and heap admin bytes.
<p>
Note: it's the height of a band that's important. Don't let the ups and downs
caused by other bands confuse you. For example, the
<code>read_alias_file</code> band in the example has the same height all the
time it's in existence.
<p>
The triangles on the x-axis show each point at which a memory census was taken.
These aren't necessarily evenly spread; Massif only takes a census when
memory is allocated or deallocated. The time on the x-axis is wallclock
time, which is not ideal because you can get different graphs for different
executions of the same program, due to random OS delays. But it's not too
bad, and it becomes less of a problem the longer a program runs.
<p>
Massif takes censuses at an appropriate timescale; censuses take place less
frequently as the program runs for longer. There is no point having more
than 100-200 censuses on a single graph.
<p>
The graphs give a good overview of where your program's space use comes from,
and how that varies over time. The accompanying text/HTML file gives a lot
more information about heap use.
<a name="detailsofheap"></a>
<h3>7.6&nbsp; Details of Heap Allocations</h3>
The text/HTML file contains information to help interpret the heap bands of the
graph. It also contains a lot of extra information about heap allocations that you don't see in the graph.
<p>
Here's part of the information that accompanies the above graph.
<hr>
== 0 ===========================<br>
Heap allocation functions accounted for 50.8% of measured spacetime<br>
<p>
Called from:
<ul>
<li><a name="a401767D1"></a><a href="#b401767D1">22.1%</a>: 0x401767D0: _nl_intern_locale_data (in /lib/i686/libc-2.3.2.so)
<li><a name="a4017C394"></a><a href="#b4017C394"> 8.6%</a>: 0x4017C393: read_alias_file (in /lib/i686/libc-2.3.2.so)
<li><i>(several entries omitted)</i>
<li>and 6 other insignificant places</li>
</ul>
<hr>
The first part shows the total spacetime due to heap allocations, and the
places in the program where most memory was allocated (nb: if this program had
been compiled with <code>-g</code>, actual line numbers would be given). These
places are sorted, from most significant to least, and correspond to the bands
seen in the graph. Insignificant sites (accounting for less than 0.5% of total
spacetime) are omitted.
<p>
That alone can be useful, but often isn't enough. What if one of these
functions was called from several different places in the program? Which one
of these is responsible for most of the memory used? For
<code>_nl_intern_locale_data()</code>, this question is answered by clicking on
the <a href="#b401767D1">22.1%</a> link, which takes us to the following part
of the file.
<hr>
<p>== 1 ===========================<br>
<a name="b401767D1"></a>Context accounted for <a href="#a401767D1">22.1%</a> of measured spacetime<br>
&nbsp;&nbsp;0x401767D0: _nl_intern_locale_data (in /lib/i686/libc-2.3.2.so)<br>
<p>
Called from:
<ul>
<li><a name="a40176F96"></a><a href="#b40176F96">22.1%</a>: 0x40176F95: _nl_load_locale_from_archive (in /lib/i686/libc-2.3.2.so)
</ul>
<hr>
At this level, we can see all the places from which
<code>_nl_load_locale_from_archive()</code> was called such that it allocated
memory at 0x401767D0. (We can click on the top <a href="#a40176F96">22.1%</a>
link to go back to the parent entry.) At this level, we have moved beyond the
information presented in the graph. In this case, it is only called from one
place. We can again follow the link for more detail, moving to the following
part of the file.
<hr>
<p>== 2 ===========================<br>
<a name="b40176F96"></a>Context accounted for <a href="#a40176F96">22.1%</a> of measured spacetime<br>
&nbsp;&nbsp;0x401767D0: _nl_intern_locale_data (in /lib/i686/libc-2.3.2.so)<br>
&nbsp;&nbsp;0x40176F95: _nl_load_locale_from_archive (in /lib/i686/libc-2.3.2.so)<br>
<p>
Called from:
<ul>
<li><a name="a40176185"></a>22.1%: 0x40176184: _nl_find_locale (in /lib/i686/libc-2.3.2.so)
</ul>
<hr>
In this way we can dig deeper into the call stack, to work out exactly what
sequence of calls led to some memory being allocated. At this point, with a
call depth of 3, the information runs out (thus the address of the child entry,
0x40176184, isn't a link). We could rerun the program with a greater
<code>--depth</code> value if we wanted more information.
<p>
Sometimes you will get a code location like this:
<ul>
<li>30.8% : 0xFFFFFFFF: ???
</ul>
The code address isn't really 0xFFFFFFFF -- that's impossible. This is what
Massif does when it can't work out what the real code address is.
<p>
Massif produces this information in a plain text file by default, or HTML with
the <code>--format=html</code> option. The plain text version obviously
doesn't have the links, but a similar effect can be achieved by searching on
the code addresses. (In Vim, the '*' and '#' searches are ideal for this.)
<a name="massifoptions"></a>
<h3>7.7&nbsp; Massif options</h3>
Massif-specific options are:
<ul>
<li><code>--heap=no</code><br>
<code>--heap=yes</code> [default]<br>
When enabled, profile heap usage in detail. Without it, the
<code>massif.<i>pid</i>.txt</code> or
<code>massif.<i>pid</i>.html</code> will be very short.
<p>
<li><code>--heap-admin=<i>n</i></code> [default: 8]<br>
The number of admin bytes per block to use. This can only be an
estimate of the average, since it may vary. The allocator used by
<code>glibc</code> requires somewhere between 4--15 bytes per block,
depending on various factors. It also requires admin space for freed
blocks, although Massif does not count this.
<p>
<li><code>--stacks=no</code><br>
<code>--stacks=yes</code> [default]<br>
When enabled, include stack(s) in the profile. Threaded programs can
have multiple stacks.
<p>
<li><code>--depth=<i>n</i></code> [default: 3]<br>
Depth of call chains to present in the detailed heap information.
Increasing it will give more information, but Massif will run the program
more slowly, using more memory, and produce a bigger
<code>.txt</code>/<code>.hp</code> file.
<p>
<li><code>--alloc-fn=<i>name</i></code><br>
Specify a function that allocates memory. This is useful for functions
that are wrappers to <code>malloc()</code>, which can fill up the context
information uselessly (and give very uninformative bands on the graph).
Functions specified will be ignored in contexts, i.e. treated as though
they were <code>malloc()</code>. This option can be specified multiple
times on the command line, to name multiple functions.
<p>
<li><code>--format=text</code> [default]<br>
<code>--format=html</code><br>
Produce the detailed heap information in text or HTML format. The file
suffix used will be either <code>.txt</code> or <code>.html</code>.
<p>
</ul>
<a name="accuracy"></a>
<h3>7.8&nbsp; Accuracy</h3>
The information should be pretty accurate. Some approximations made might
cause some allocation contexts to be attributed with less memory than they
actually allocated, but the amounts should be miniscule.
<p>
The heap admin spacetime figure is an approximation, as described above. If
anyone knows how to improve its accuracy, please let us know.
</body>
</html>

63
massif/hp2ps/AreaBelow.c Normal file
View File

@ -0,0 +1,63 @@
#include <stdio.h>
#include "Main.h"
#include "Defines.h"
#include "Error.h"
#include "HpFile.h"
#include "Utilities.h"
/* own stuff */
#include "AreaBelow.h"
extern void free();
/*
* 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;
}

6
massif/hp2ps/AreaBelow.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef AREA_BELOW_H
#define AREA_BELOW_H
floatish AreaBelow PROTO((void));
#endif /* AREA_BELOW_H */

168
massif/hp2ps/AuxFile.c Normal file
View File

@ -0,0 +1,168 @@
#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);
}

7
massif/hp2ps/AuxFile.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef AUX_FILE_H
#define AUX_FILE_H
void PutAuxFile PROTO((FILE *));
void GetAuxFile PROTO((FILE *));
#endif /* AUX_FILE_H */

241
massif/hp2ps/Axes.c Normal file
View File

@ -0,0 +1,241 @@
#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);
}
}

6
massif/hp2ps/Axes.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef AXES_H
#define AXES_H
void Axes PROTO((void));
#endif /* AXES_H */

39
massif/hp2ps/CHANGES Normal file
View File

@ -0,0 +1,39 @@
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.

164
massif/hp2ps/Curves.c Normal file
View File

@ -0,0 +1,164 @@
#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(); /* forward */
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;
}
}

10
massif/hp2ps/Curves.h Normal file
View File

@ -0,0 +1,10 @@
#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 */

61
massif/hp2ps/Defines.h Normal file
View File

@ -0,0 +1,61 @@
#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 */

140
massif/hp2ps/Deviation.c Normal file
View File

@ -0,0 +1,140 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "Main.h"
#include "Defines.h"
#include "Error.h"
#include "HpFile.h"
#include "Utilities.h"
extern void free();
/* 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;
}
}
}

7
massif/hp2ps/Deviation.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef DEVIATION_H
#define DEVIATION_H
void Deviation PROTO((void));
void Identorder PROTO((int));
#endif /* DEVIATION_H */

203
massif/hp2ps/Dimensions.c Normal file
View File

@ -0,0 +1,203 @@
#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;
}

22
massif/hp2ps/Dimensions.h Normal file
View File

@ -0,0 +1,22 @@
#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 */

55
massif/hp2ps/Error.c Normal file
View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include "Main.h"
#include "Defines.h"
/* own stuff */
#include "Error.h"
void exit PROTO((int));
/*VARARGS0*/
void
Error(a1,a2,a3,a4)
char* a1; char* a2; char* a3; char* a4;
{
fflush(stdout);
fprintf(stderr, "%s: ", programname);
fprintf(stderr, a1, a2, a3, a4);
fprintf(stderr, "\n");
exit(1);
}
/*VARARGS0*/
void
Disaster(a1,a2,a3,a4)
char* a1; char* a2; char* a3; char* a4;
{
fflush(stdout);
fprintf(stderr, "%s: ", programname);
fprintf(stderr, " Disaster! (");
fprintf(stderr, a1, a2, a3, a4);
fprintf(stderr, ")\n");
exit(1);
}
void
Usage(str)
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);
}

8
massif/hp2ps/Error.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ERROR_H
#define ERROR_H
extern void Error (); /*PROTO((char *, ...)); */
extern void Disaster (); /* PROTO((char *, ...)); */
extern void Usage (); /* PROTO((char *)); */
#endif /* ERROR_H */

587
massif/hp2ps/HpFile.c Normal file
View File

@ -0,0 +1,587 @@
#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 - 1 ];
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(s)
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()
{
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;
}
}
}

77
massif/hp2ps/HpFile.h Normal file
View File

@ -0,0 +1,77 @@
#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 */

17
massif/hp2ps/INSTALL Normal file
View File

@ -0,0 +1,17 @@
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"

63
massif/hp2ps/Key.c Normal file
View File

@ -0,0 +1,63 @@
#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);
}

6
massif/hp2ps/Key.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef KEY_H
#define KEY_H
void Key PROTO((void));
#endif /* KEY_H */

31
massif/hp2ps/LICENSE Normal file
View File

@ -0,0 +1,31 @@
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.

253
massif/hp2ps/Main.c Normal file
View File

@ -0,0 +1,253 @@
#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(argc, argv)
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;
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");
psfp = Fp(baseName, &psfile, ".ps", "w");
if (pflag) auxfp = Fp(baseName, &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

78
massif/hp2ps/Main.h Normal file
View File

@ -0,0 +1,78 @@
#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 */

43
massif/hp2ps/Marks.c Normal file
View File

@ -0,0 +1,43 @@
#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");
}

6
massif/hp2ps/Marks.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef MARKS_H
#define MARKS_H
void Marks PROTO((void));
#endif /* MARKS_H */

280
massif/hp2ps/PsFile.c Normal file
View File

@ -0,0 +1,280 @@
#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);
}
}

6
massif/hp2ps/PsFile.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef PS_FILE_H
#define PS_FILE_H
void PutPsFile PROTO((void));
#endif /* PS_FILE_H */

1
massif/hp2ps/README Normal file
View File

@ -0,0 +1 @@
This "hp2ps" program was written by Dave Wakeling at York.

89
massif/hp2ps/Reorder.c Normal file
View File

@ -0,0 +1,89 @@
#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;
}
}

8
massif/hp2ps/Reorder.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef REORDER_H
#define REORDER_H
void Reorder PROTO((void));
int OrderOf PROTO((char *));
void OrderFor PROTO((char *, int));
#endif /* REORDER_H */

87
massif/hp2ps/Scale.c Normal file
View File

@ -0,0 +1,87 @@
#include <stdio.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.
*/
extern void free();
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;
}
}
}
}

7
massif/hp2ps/Scale.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef SCALE_H
#define SCALE_H
floatish MaxCombinedHeight PROTO((void));
void Scale PROTO((void));
#endif /* SCALE_H */

130
massif/hp2ps/Shade.c Normal file
View File

@ -0,0 +1,130 @@
#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(shade,factor)
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);
}
}

8
massif/hp2ps/Shade.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef SHADE_H
#define SHADE_H
floatish ShadeOf PROTO((char *));
void ShadeFor PROTO((char *, floatish));
void SetPSColour PROTO((floatish));
#endif /* SHADE_H */

73
massif/hp2ps/TopTwenty.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdio.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.
*/
extern void free();
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);
}

6
massif/hp2ps/TopTwenty.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef TOP_TWENTY_H
#define TOP_TWENTY_H
void TopTwenty PROTO((void));
#endif /* TOP_TWENTY_H */

View File

@ -0,0 +1,97 @@
#include <stdio.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 void free();
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);
}

View File

@ -0,0 +1,6 @@
#ifndef TRACE_ELEMENT_H
#define TRACE_ELEMENT_H
void TraceElement PROTO((void));
#endif /* TRACE_ELEMENT_H */

132
massif/hp2ps/Utilities.c Normal file
View File

@ -0,0 +1,132 @@
#include <stdio.h>
#include <string.h>
#include "Main.h"
#include "Error.h"
extern void* malloc();
char*
Basename(name)
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)
int 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;
int n;
{
void *r;
extern void *realloc();
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;
}

13
massif/hp2ps/Utilities.h Normal file
View File

@ -0,0 +1,13 @@
#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((int));
void *xrealloc PROTO((void *, int));
#endif /* UTILITIES_H */

145
massif/hp2ps/hp2ps.1 Normal file
View File

@ -0,0 +1,145 @@
.\" 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.

1815
massif/ms_main.c Normal file

File diff suppressed because it is too large Load Diff

6
massif/tests/Makefile.am Normal file
View File

@ -0,0 +1,6 @@
noinst_SCRIPTS = filter_stderr
EXTRA_DIST = $(noinst_SCRIPTS) \
true_html.stderr.exp true_html.vgtest \
true_text.stderr.exp true_text.vgtest

View File

@ -0,0 +1,6 @@
Total spacetime:
heap:
heap admin:
stack(s):

View File

@ -0,0 +1,2 @@
prog: ../../tests/true
vgopts: --format=html

View File

@ -0,0 +1,6 @@
Total spacetime:
heap:
heap admin:
stack(s):

View File

@ -0,0 +1,2 @@
prog: ../../tests/true
vgopts: --format=text