mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 14:25:56 +00:00
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:
181
runtime/mercury_heap_profile.h
Normal file
181
runtime/mercury_heap_profile.h
Normal 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 */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
Reference in New Issue
Block a user