Add support for memory profiling.

Estimated hours taken: 40 (+ unknown time by Zoltan)

Add support for memory profiling.

(A significant part of this change is actuallly Zoltan's work.  Zoltan
did the changes to the compiler and a first go at the changes to the
runtime and library.  I rewrote much of Zoltan's changes to the runtime
and library, added support for the new options/grades, added code to
interface with mprof, did the changes to the profiler, and wrote the
documentation.)

[TODO: add test cases.]

NEWS:
	Mention support for memory profiling.

runtime/mercury_heap_profile.h:
runtime/mercury_heap_profile.c:
	New files.  These contain code to record heap profiling information.

runtime/mercury_heap.h:
	Add new macros incr_hp_msg(), tag_incr_hp_msg(),
	incr_hp_atomic_msg(), and tag_incr_hp_atomic_msg().
	These are like the non-`msg' versions, except that if
	PROFILE_MEMORY is defined, they also call MR_record_allocation()
	from mercury_heap_profile.h to record heap profiling information.
	Also, fix up the indentation in lots of places.

runtime/mercury_prof.h:
runtime/mercury_prof.c:
	Added code to dump out memory profiling information to files
	`Prof.MemoryWords' and `Prof.MemoryCells' (for use by mprof).
	Change the format of the `Prof.Counts' file so that the
	first line says what it is counting, the units, and a scale
	factor.  Prof.MemoryWords and Prof.MemoryCells can thus have
	exactly the same format as Prof.Counts.
	Also cleaned up the interface to mercury_prof.c a bit, and did
	various other minor cleanups -- indentation changes, changes to
	use MR_ prefixes, additional comments, etc.

runtime/mercury_prof_mem.h:
runtime/mercury_prof_mem.c:
	Rename prof_malloc() as MR_prof_malloc().
	Rename prof_make() as MR_PROF_NEW() and add MR_PROF_NEW_ARRAY().

runtime/mercury_wrapper.h:
	Minor modifications to reflect the new interface to mercury_prof.c.

runtime/mercury_wrapper.c:
runtime/mercury_label.c:
	Rename the old `-p' (primary cache size) option as `-C'.
	Add a new `-p' option to disable profiling.

runtime/Mmakefile:
	Add mercury_heap_profile.[ch].
	Put the list of files in alphabetical order.
	Delete some obsolete stuff for supporting `.mod' files.
	Mention that libmer_dll.h and libmer_globals.h are
	produced by Makefile.DLLs.

runtime/mercury_imp.h:
	Mention that libmer_dll.h is produced by Makefile.DLLs.

runtime/mercury_dummy.c:
	Change a comment to refer to libmer_dll.h rather than
	libmer_globals.h.

compiler/llds.m:
	Add a new field to `create' and `incr_hp' instructions
	holding the name of the type, for heap profiling.

compiler/unify_gen.m:
	Initialize the new field of `create' instructions with
	the appropriate type name.

compiler/llds_out.m:
	Output incr_hp_msg() / tag_incr_hp_msg() instead of
	incr_hp() / tag_incr_hp().

compiler/*.m:
	Minor changes to most files in the compiler back-end to
	accomodate the new field in `incr_hp' and `create' instructions.

library/io.m:
	Add `io__report_full_memory_stats'.

library/benchmarking.m:
	Add `report_full_memory_stats'.  This uses the information saved
	by runtime/mercury_heap_profile.{c,h} to print out a report
	of memory usage by procedures and by types.
	Also modify `report_stats' to print out some of that information.

compiler/mercury_compile.m:
	If `--statistics' is enabled, call io__report_full_memory_stats
	at the end of main/2.  This will print out full memory statistics,
	if the compiler was compiled with memory profiling enabled.

compiler/options.m:
compiler/handle_options.m:
runtime/mercury_grade.h:
scripts/ml.in:
scripts/mgnuc.in:
scripts/init_grade_options.sh-subr:
scripts/parse_grade_options.sh-subr:
	Add new option `--memory-profiling' and new grade `.memprof'.
	Add `--time-profiling' as a new synonym for `--profiling'.
	Also add `--profile-memory' for more fine-grained control:
	`--memory-profiling' implies both `--profile-memory' and
	`--profile-calls'.

scripts/mprof_merge_runs:
	Update to handle the new format of Prof.Counts and to
	also merge Prof.MemoryWords and Prof.MemoryCells.

profiler/options.m:
profiler/mercury_profile.m:
	Add new options `--profile memory-words' (`-m'),
	`--profile memory-cells' (`-M') and `--profile time' (`-t').
	Thes options make the profiler select a different count file,
	Prof.MemoryWords or Prof.MemoryCells instead of Prof.Counts.
	specific to time profiling.

profiler/read.m:
profiler/process_file.m:
profiler/prof_info.m:
profiler/generate_output.m:
	Update to handle the new format of the counts file.
	When reading the counts file, look at the first line of
	the file to determine what is being profiled.

profiler/globals.m:
	Add a new global variable `what_to_profile' that records
	what is being profiled.

profiler/output.m:
	Change the headings to reflect what is being profiled.

doc/user_guide.texi:
	Document memory profiling.
	Document new options.

doc/user_guide.texi:
compiler/options.m:
	Comment out the documentation for `.proftime'/`--profile-time',
	since doing time and call profiling seperately doesn't work,
	because the code addresses change when you recompile with a
	different grade.  Ditto for `.profmem'/`--profile-memory'.
	Also comment out the documentation for
	`.profcalls'/`--profile-calls', since it is redundant --
	`.memprof' produces the same information and more.

configure.in:
	Build a `.memprof' grade.  (Hmm, should we do this only
	if `--enable-all-grades' is specified?)
	Don't ever build a `.profcalls' grade.
This commit is contained in:
Fergus Henderson
1997-12-05 15:58:34 +00:00
parent 05267d2834
commit e6ac077bae
29 changed files with 1672 additions and 509 deletions

View File

@@ -0,0 +1,181 @@
/*
** Copyright (C) 1997 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** File: mercury_heap_profile.h
** Main authors: zs, fjh
**
** This module records information about the allocations of cells on the heap.
** The information recorded here is used by mercury_prof.c and
** by library/benchmarking.m.
*/
/*---------------------------------------------------------------------------*/
#ifndef MERCURY_HEAP_PROFILE_H
#define MERCURY_HEAP_PROFILE_H
/*---------------------------------------------------------------------------*/
/*
** Due to garbage collection, the total amount of memory allocated can
** exceed the amount of real or even virtual memory available. Hence
** the total amount of memory allocated by a long-running Mercury program
** might not fit into a single 32-bit `unsigned long'.
** Hence we record memory usage counts using either `unsigned long long',
** if available, or otherwise using a pair of unsigned longs (ugh).
*/
#ifdef MR_HAVE_LONG_LONG
/* nice and simple */
typedef unsigned long long MR_dword;
#define MR_convert_dword_to_double(dword_form, double_form) \
((double_form) = (double) (dword_form))
#define MR_zero_dword(dword) \
((dword) = 0)
#define MR_increment_dword(dword, inc) \
((dword) += (inc))
#define MR_add_two_dwords(src_dest_dword, src_dword) \
((src_dest_dword) += (src_dword))
#else /* not MR_HAVE_LONG_LONG */
/* oh well, guess we have to do it the hard way :-( */
typedef struct MR_dword
{
unsigned long low_word;
unsigned long high_word;
} MR_dword;
#include <limits.h>
#define MR_HIGHWORD_TO_DOUBLE (((double) ULONG_MAX) + 1.0)
#define MR_convert_dword_to_double(dword_form, double_form) \
do { \
double_form = (MR_HIGHWORD_TO_DOUBLE \
* (double) (dword_form).high_word) \
+ (double) (dword_form).low_word; \
} while (0)
#define MR_zero_dword(dword) \
do { \
(dword).low_word = 0; \
(dword).high_word = 0; \
} while (0)
#define MR_increment_dword(dword, inc) \
do { \
unsigned long old_low_word = (dword).low_word; \
(dword).low_word += (inc); \
if ((dword).low_word < old_low_word) { \
(dword).high_word += 1; \
} \
} while (0)
#define MR_add_two_dwords(src_dest_dword, src_dword) \
do { \
unsigned long old_low_word = (src_dest_dword).low_word; \
(src_dest_dword).low_word += (src_dword).low_word; \
if ((src_dest_dword).low_word < old_low_word) { \
(src_dest_dword).high_word += 1; \
} \
(src_dest_dword).high_word += (src_dword).high_word; \
} while (0)
#endif /* not MR_HAVE_LONG_LONG */
/*---------------------------------------------------------------------------*/
/* type declarations */
/*
** We count memory allocation in units of
** - cells (i.e. individual allocations), and
** - words
**
** We keep track of how much allocation occurs in each "period".
** A period ends (and a new period begins) at each call to
** report_stats or report_full_memory_stats in library/benchmarking.m.
** We also keep track of the total allocation over all periods.
**
** We keep track of how much memory was allocated
** - by each procedure,
** - for objects of each type,
** - and an overall total
**
** The tables of counters for each procedure is represented
** as a binary search tree. Similarly for the table of counters
** for each type.
*/
typedef struct MR_memprof_counter
{
MR_dword cells_at_period_start;
MR_dword words_at_period_start;
MR_dword cells_since_period_start;
MR_dword words_since_period_start;
} MR_memprof_counter;
/* type representing a binary tree node */
typedef struct MR_memprof_record
{
const char *name; /* of the type or procedure */
Code *addr; /* for procedures only */
MR_memprof_counter counter;
struct MR_memprof_record *left; /* left sub-tree */
struct MR_memprof_record *right; /* right sub-tree */
} MR_memprof_record;
/* type representing a binary tree */
typedef struct MR_memprof_table
{
MR_memprof_record *root;
int num_entries;
} MR_memprof_table;
/*---------------------------------------------------------------------------*/
/* global variables */
extern MR_memprof_counter MR_memprof_overall;
extern MR_memprof_table MR_memprof_procs;
extern MR_memprof_table MR_memprof_types;
/*---------------------------------------------------------------------------*/
/* function declarations */
/*
** MR_record_allocation(size, proc_addr, proc_name, type):
** Record heap profiling information for an allocation of one cell
** of `size' words by procedure `proc_name' with address `proc_addr'
** for an object of type `type'.
** The heap profiling information is recorded in the three global
** variables above.
*/
extern void MR_record_allocation(int size, Code *proc_addr,
const char *proc_name, const char *type);
/*
** MR_prof_output_mem_tables():
** Write out the information recorded by MR_record_allocation()
** to a pair of files `Prof.MemoryWords' and `Prof.MemoryCells'.
*/
extern void MR_prof_output_mem_tables(void);
/*---------------------------------------------------------------------------*/
#endif /* MERCURY_HEAP_PROFILE_H */
/*---------------------------------------------------------------------------*/