Files
mercury/runtime/mercury_memory.h
Peter Wang 7e26b55e74 Implement a new form of memory profiling, which tells the user what memory
Branches: main

Implement a new form of memory profiling, which tells the user what memory
is being retained during a program run.  This is done by allocating an extra
word before each cell, which is used to "attribute" the cell to an
allocation site.  The attribution, or "allocation id", is an address to an
MR_AllocSiteInfo structure generated by the Mercury compiler, giving the
procedure, filename and line number of the allocation, and the type
constructor and arity of the cell that it allocates.

The user must manually instrument the program with calls to
`benchmarking.report_memory_attribution', which forces a GC and summarises
the live objects on the heap using the attributions.  The mprof tool is
extended with a new mode to parse and present that data.

Objects which are unattributed (e.g. by hand-written C code which hasn't
been updated) are still accounted for, but show up in profiles as "unknown".

Currently this profiling mode only works in conjunction with the Boehm
garbage collector, though in principle it can work with any memory allocator
for which we can access a list of the live objects.  Since term size
profiling relies on the same technique of using an extra word per memory
cell, the two profiling modes are incompatible.

The output from `mprof -s' looks like this:

------ [1] some label ------
   cells            words         cumul  procedure / type (location)
   14150            38872                total

*   1949/ 13.8%      4872/ 12.5%  12.5%  <predicate `parser.parse_rest/7' mode 0>
     975/  6.9%      1950/  5.0%         list.list/1 (parser.m:502)
     487/  3.4%      1948/  5.0%         term.term/1 (parser.m:501)
     487/  3.4%       974/  2.5%         term.const/0 (parser.m:501)

*   1424/ 10.1%      4272/ 11.0%  23.5%  <predicate `parser.parse_simple_term_2/6' mode 0>
     708/  5.0%      2832/  7.3%         term.term/1 (parser.m:643)
     708/  5.0%      1416/  3.6%         term.const/0 (parser.m:643)
...


boehm_gc/alloc.c:
boehm_gc/include/gc.h:
boehm_gc/misc.c:
boehm_gc/reclaim.c:
	Add a callback function to be called for every live object after a GC.

	Add a function to write out the GC_size_map array.

compiler/layout.m:
	Define the alloc_site_info type which is equivalent to the
	MR_AllocSiteInfo C structure.

	Add alloc_site_array as a kind of "layout" array.

compiler/llds.m:
	Add allocation sites to `cfile' structure.

	Replace TypeMsg argument (which was also for profiling) on `incr_hp'
	instructions by an allocation site identifier.

	Add a new foreign_proc_component for allocation site ids.

compiler/code_info.m:
compiler/global_data.m:
compiler/proc_gen.m:
	Keep the set of allocation sites in the code_info and global_data
	structures.

compiler/unify_gen.m:
	Add allocation sites to LLDS allocation instructions.

compiler/layout_out.m:
compiler/llds_out_file.m:
compiler/llds_out_instr.m:
	Output MR_AllocSiteInfo arrays in generated C files.

	Output code to register the MR_AllocSiteInfo array with the Mercury
	runtime.

	Output allocation site ids for memory allocation instructions.

compiler/llds_out_util.m:
	Add allocation sites to llds_out_info.

compiler/pragma_c_gen.m:
compiler/ml_foreign_proc_gen.m:
	Generate a macro MR_ALLOC_ID which resolves to an allocation site
	structure, for every foreign_proc whose C code contains the string
	"MR_ALLOC_ID".  This is to be used by hand-written C code which
	allocates memory.

	MR_PROC_LABELs are retained for backwards compatibility.  Though
	they were introduced for profiling, they seem to have been co-opted
	for printf-debugging since then.

compiler/ml_global_data.m:
	Add allocation site structures to the MLDS global data.

compiler/mlds.m:
compiler/ml_unify_gen.m:
	Add allocation site id to `new_object' instruction.

compiler/mlds_to_c.m:
	Output allocation site arrays and allocation ids in high-level C code.

	Output a call to register the allocation site array with the Mercury
	runtime.

	Delete an unused predicate.

compiler/exprn_aux.m:
compiler/jumpopt.m:
compiler/livemap.m:
compiler/mercury_compile_llds_back_end.m:
compiler/middle_rec.m:
compiler/ml_accurate_gc.m:
compiler/ml_elim_nested.m:
compiler/ml_optimize.m:
compiler/ml_util.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_gcc.m:
compiler/mlds_to_il.m:
compiler/mlds_to_java.m:
compiler/mlds_to_managed.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/use_local_vars.m:
compiler/var_locn.m:
	Conform to changes.

compiler/pickle.m:
compiler/prog_event.m:
compiler/timestamp.m:
	Conform to changes in memory allocation macros.

library/benchmarking.m:
	Add the `report_memory_attribution' instrumentation predicates.

	Conform to changes to MR_memprof_record.

library/array.m:
library/bit_buffer.m:
library/bitmap.m:
library/construct.m:
library/deconstruct.m:
library/dir.m:
library/io.m:
library/mutvar.m:
library/store.m:
library/string.m:
library/thread.semaphore.m:
library/version_array.m:
	Use attributed memory allocation throughout the standard library so
	that objects don't show up in the memory profile as "unknown".

	Replace MR_PROC_LABEL by MR_ALLOC_ID.

mdbcomp/program_representation.m:
mdbcomp/rtti_access.m:
	Replace MR_PROC_LABEL by MR_ALLOC_ID.

profiler/Mercury.options:
profiler/globals.m:
profiler/mercury_profile.m:
profiler/options.m:
profiler/output.m:
profiler/snapshots.m:
	Add a new mode to `mprof' to parse and present the data from
	`Prof.Snapshots' files.

	Add options for the new profiling mode.

profiler/process_file.m:
	Fix a typo.

runtime/mercury_conf_param.h:
	#define MR_MPROF_PROFILE_MEMORY_ATTRIBUTION if memory profiling
	is enabled and we are using Boehm GC.

runtime/mercury.h:
	Make MR_new_object take an allocation id argument.

	Conform to changes in memory allocation macros.

runtime/mercury_memory.c:
runtime/mercury_memory.h:
runtime/mercury_types.h:
	Define MR_AllocSiteInfo.

	Add memory allocation functions and macros which take into the
	account the additional word necessary for the new profiling mode.
	These should be used in preferences to the raw memory allocation
	functions wherever possible so that objects do not show up in the
	profile as "unknown".

	Add analogues of realloc/free which take into account the offset
	introduced by the attribution word.

	Add function versions of the MR_new_object macros, which can't be
	written in standard C.  They are only used when necessary.

	Add built-in allocation site ids, to be used in the runtime and
	other hand-written code when context-specific ids are unavailable.

runtime/mercury_heap.h:
	Make MR_tag_offset_incr_hp_msg and MR_tag_offset_incr_hp_atomic_msg
	allocate an extra word when memory attribution is desired, and store
	the allocation id there.

	Similarly for MR_create{1,2,3}_msg.

	Replace proclabel arguments in allocation macros by alloc_id
	arguments.

	Replace MR_hp_alloc_atomic by MR_hp_alloc_atomic_msg.  It was only
	used for boxing floats.

	Conform to change to MR_new_object macro.

runtime/mercury_bootstrap.h:
	Delete obsolete macro hp_alloc_atomic.

runtime/mercury_heap_profile.c:
runtime/mercury_heap_profile.h:
	Add the code to summarise the live objects on the Boehm GC heap and
	writes out the data to `Prof.Snapshots', for display by mprof.

	Don't store the procedure name in MR_memprof_record: the procedure
	address is enough and faster to compare.

runtime/mercury_prof.c:
	Finish and close the `Prof.Snapshots' file when the program
	terminates.

	Conform to changes in MR_memprof_record.

runtime/mercury_misc.h:
	Add a macro to expand to the name of the allocation sites array
	in LLDS grades.

runtime/mercury_bitmap.c:
runtime/mercury_bitmap.h:
	Pass allocation id through bitmap allocation functions.

	Delete unused function MR_string_to_bitmap.

runtime/mercury_string.h:
	Add MR_make_aligned_string_copy_msg.

	Make string allocation macros take allocation id arguments.

runtime/mercury.c:
runtime/mercury_array_macros.h:
runtime/mercury_context.c:
runtime/mercury_deconstruct.c:
runtime/mercury_deconstruct_macros.h:
runtime/mercury_dlist.c:
runtime/mercury_engine.c:
runtime/mercury_float.h:
runtime/mercury_hash_table.c:
runtime/mercury_ho_call.c:
runtime/mercury_label.c:
runtime/mercury_prof_mem.c:
runtime/mercury_stacks.c:
runtime/mercury_stm.c:
runtime/mercury_string.c:
runtime/mercury_thread.c:
runtime/mercury_trace_base.c:
runtime/mercury_trail.c:
runtime/mercury_type_desc.c:
runtime/mercury_type_info.c:
runtime/mercury_wsdeque.c:
	Use attributed memory allocation throughout the runtime so that
	objects don't show up in the profile as "unknown".

runtime/mercury_memory_zones.c:
	Attribute memory zones to the Mercury runtime.

runtime/mercury_tabling.c:
runtime/mercury_tabling.h:
	Use attributed memory allocation macros for tabling structures.

	Delete unused MR_table_realloc_* and MR_table_copy_bytes macros.

runtime/mercury_deep_copy_body.h:
	Try to retain the original attribution word when copying values.

runtime/mercury_ml_expand_body.h:
	Conform to changes in memory allocation macros.

runtime/mercury_tags.h:
	Replace proclabel arguments by alloc_id arguments in allocation macros.

runtime/mercury_wrapper.c:
	If memory attribution is enabled, tell Boehm GC that pointers may be
	displaced by an extra word.

trace/mercury_trace.c:
trace/mercury_trace_tables.c:
	Conform to changes in memory allocation macros.

extras/net/tcp.m:
extras/solver_types/library/any_array.m:
extras/trailed_update/tr_array.m:
	Conform to changes in memory allocation macros.

doc/user_guide.texi:
	Document the new profiling mode.

doc/reference_manual.texi:
	Update a commented out example.
2011-05-20 04:16:58 +00:00

324 lines
11 KiB
C

/*
** Copyright (C) 1994-2000,2002, 2004, 2006, 2008 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.
*/
/*
** mercury_memory.h:
** general memory-allocation related stuff for the Mercury runtime.
**
** This defines the different memory areas used by the Mercury runtime,
** including the det & nondet stacks, the heap (and solutions heap),
** and the fake_reg array for holding Mercury virtual registers.
** It also provides interfaces for constructing new memory zones,
** and for allocating (possibly shared) memory.
*/
#ifndef MERCURY_MEMORY_H
#define MERCURY_MEMORY_H
#include "mercury_memory_zones.h"
#include <stddef.h> /* for size_t */
#include "mercury_types.h" /* for MR_Word */
#include "mercury_std.h" /* for MR_bool */
#include "mercury_conf.h" /* for MR_CONSERVATIVE_GC, etc. */
#if defined(MR_CONSERVATIVE_GC)
#if defined(MR_MPS_GC)
#include "mercury_mps.h" /* for GC_FREE */
#endif
#if defined(MR_BOEHM_GC)
#define GC_I_HIDE_POINTERS
#include "gc.h" /* for GC_FREE */
#endif
#endif
/*
** MR_round_up(amount, align) returns `amount' rounded up to the nearest
** alignment boundary. `align' must be a power of 2.
*/
#define MR_round_up(amount, align) ((((amount) - 1) | ((align) - 1)) + 1)
/*
** MR_kilobytes_to_bytes_and_round_up(var) takes an original value in var
** which represents an memory size measured in kilobytes, and converts it to
** a memory size measured in bytes, and then rounds it up to be the next
** multiple of MR_unit.
*/
#define MR_kilobytes_to_bytes_and_round_up(var) \
do { \
var = MR_round_up(var * 1024, MR_unit); \
} while (0)
/*
** For these functions, see the comments in mercury_memory.c and
** mercury_engine.c
*/
extern void MR_init_memory(void);
extern void MR_init_heap(void);
#ifdef MR_CONSERVATIVE_GC
extern void MR_init_conservative_GC(void);
#endif
/*---------------------------------------------------------------------------*/
/*
** MR_malloc() and MR_realloc() are like the standard C malloc() and realloc()
** functions, except that the return values are checked.
**
** Structures allocated with MR_malloc() and MR_realloc() must NOT contain
** pointers into GC'ed memory, because those pointers will never be traced
** by the conservative GC. Use MR_GC_malloc() or MR_GC_malloc_uncollectable()
** for that.
**
** MR_NEW(type):
** Allocates space for an object of the specified type.
**
** MR_NEW_ARRAY(type, num):
** Allocates space for an array of objects of the specified type.
**
** MR_RESIZE_ARRAY(ptr, type, num):
** Resizes the array, as with realloc().
**
** MR_malloc(bytes):
** Allocates the given number of bytes.
**
** MR_realloc(old, bytes):
** Allocates the given number of bytes, copies over the old contents of
** the previously allocated block pointed to by old, and then frees that
** old block.
**
** MR_ensure_big_enough_buffer(buffer_ptr, buffer_size_ptr, needed_size):
** Given a character buffer pointed to by buffer_ptr whose is given by
** *buffer_size_ptr, ensure that the buffer is big enough to hold
** needed_size characters. If it needs to make the block bigger,
** this function will update both *buffer_ptr and *buffer_size_ptr.
**
** MR_free(ptr):
** Deallocates the memory.
*/
extern void *MR_malloc(size_t n);
extern void *MR_realloc(void *old, size_t n);
extern void MR_ensure_big_enough_buffer(char **buffer_ptr,
int *buffer_size_ptr, int needed_size);
#define MR_free(ptr) free(ptr)
#define MR_free_func free
#define MR_NEW(type) \
((type *) MR_malloc(sizeof(type)))
#define MR_NEW_ARRAY(type, num) \
((type *) MR_malloc((num) * sizeof(type)))
#define MR_RESIZE_ARRAY(ptr, type, num) \
((type *) MR_realloc((ptr), (num) * sizeof(type)))
/*
** These routines all allocate memory that will be traced by the
** conservative garbage collector, if conservative GC is enabled.
** (For the native GC, you need to call MR_add_root() to register roots.)
** These routines all check for a null return value themselves,
** so the caller need not check.
**
** MR_GC_NEW(type):
** Allocates space for an object of the specified type.
** If conservative GC is enabled, the object will be garbage collected
** when it is no longer referenced from GC-traced memory.
** Memory allocated with malloc() (or MR_malloc() or MR_NEW())
** is not GC-traced. Nor is thread-local storage.
**
** MR_GC_NEW_UNCOLLECTABLE(type):
** Allocates space for an object of the specified type.
** The object will not be garbage collected even if it is not referenced,
** or only referenced from thread-local storage or storage allocated
** with malloc(). It should be explicitly deallocated with MR_GC_free().
**
** MR_GC_NEW_ARRAY(type, num):
** Allocates space for an array of objects of the specified type.
**
** MR_GC_RESIZE_ARRAY(ptr, type, num):
** Resizes the array, as with realloc().
**
** MR_GC_malloc(bytes):
** Allocates the given number of bytes.
** If conservative GC is enabled, the memory will be garbage collected
** when it is no longer referenced from GC-traced memory (see above).
**
** MR_GC_malloc_uncollectable(bytes):
** Allocates the given number of bytes.
** The memory will not be garbage collected, and so
** it should be explicitly deallocated using MR_GC_free().
**
** MR_GC_realloc(ptr, bytes):
** Reallocates the memory block pointed to by ptr.
**
** MR_GC_free(ptr):
** Deallocates the memory.
**
** MR_GC_register_finalizer(ptr, finalize_func, data):
** When ptr is garbage collected invoke (*finalize_func)(ptr, data).
** ptr must have be a pointer to space allocated by the garbage collector.
** data is a pointer to some user-defined data.
** XXX currently this only works with the Boehm collector, i.e. in .gc
** grades, it is a no-op in non .gc grades.
**
** XXX this interface is subject to change.
**
** Note: consider using the _attrib variants below.
*/
extern void *MR_GC_malloc(size_t num_bytes);
extern void *MR_GC_malloc_uncollectable(size_t num_bytes);
extern void *MR_GC_realloc(void *ptr, size_t num_bytes);
typedef void (*MR_GC_finalizer)(void *ptr, void *data);
#define MR_GC_NEW(type) \
((type *) MR_GC_malloc(sizeof(type)))
#define MR_GC_NEW_UNCOLLECTABLE(type) \
((type *) MR_GC_malloc_uncollectable(sizeof(type)))
#define MR_GC_NEW_ARRAY(type, num) \
((type *) MR_GC_malloc((num) * sizeof(type)))
#define MR_GC_RESIZE_ARRAY(ptr, type, num) \
((type *) MR_GC_realloc((ptr), (num) * sizeof(type)))
#ifdef MR_CONSERVATIVE_GC
#define MR_GC_free(ptr) GC_FREE(ptr)
#else
#define MR_GC_free(ptr) free(ptr)
#endif
#if defined(MR_CONSERVATIVE_GC) && defined(MR_BOEHM_GC)
#define MR_GC_register_finalizer(ptr, finalizer, data) \
GC_REGISTER_FINALIZER((ptr), (finalizer), (data), 0, 0)
#else
#define MR_GC_register_finalizer(ptr, finalizer, data)
#endif
/*
** MR_GC_NEW_ATTRIB(type, attrib):
** MR_GC_NEW_UNCOLLECTABLE_ATTRIB(type, attrib):
** MR_GC_NEW_ARRAY_ATTRIB(type, attrib):
** MR_GC_malloc_attrib(bytes, attrib):
** MR_GC_malloc_uncollectable_attrib(bytes, attrib):
** MR_GC_realloc_attrib(ptr, num_bytes):
** In grades with memory attribution support, these variants will allocate
** an extra word before the object. The value stored `attrib' is stored
** in that extra word.
**
** MR_GC_RESIZE_ARRAY_ATTRIB(ptr, type, num):
** MR_GC_free_attrib(ptr):
** These variants take into account the extra word before ptr.
** You must NOT pass pointers which were returned by non-"attrib"
** functions/macros to these "attrib" variants, and vice versa.
*/
#define MR_GC_NEW_ATTRIB(type, attrib) \
((type *) MR_GC_malloc_attrib(sizeof(type), (attrib)))
#define MR_GC_NEW_UNCOLLECTABLE_ATTRIB(type, attrib) \
((type *) MR_GC_malloc_uncollectable_attrib(sizeof(type), (attrib)))
#define MR_GC_NEW_ARRAY_ATTRIB(type, num, attrib) \
((type *) MR_GC_malloc_attrib((num) * sizeof(type), (attrib)))
#define MR_GC_RESIZE_ARRAY_ATTRIB(ptr, type, num) \
((type *) MR_GC_realloc_attrib((ptr), (num) * sizeof(type)))
extern void *MR_GC_malloc_attrib(size_t num_bytes, void *attrib);
extern void *MR_GC_malloc_uncollectable_attrib(size_t num_bytes,
void *attrib);
extern void *MR_GC_realloc_attrib(void *ptr, size_t num_bytes);
extern void MR_GC_free_attrib(void *ptr);
struct MR_AllocSiteInfo_Struct {
MR_Code *MR_asi_proc;
const char *MR_asi_file_name;
const int MR_asi_line_number;
const char *MR_asi_type;
const int MR_asi_words;
};
/*
** Built-in allocation site ids for use in the runtime and other
** hand-written code when context-specific ids are unavailable.
** MR_ALLOC_SITE_RUNTIME is a catch-all for internal runtime structures;
** these are hidden by default in `mprof -s' output.
*/
#define MR_ALLOC_SITE_NONE ((void *) 0)
#ifdef MR_MPROF_PROFILE_MEMORY_ATTRIBUTION
/* These must match the entries in mercury_heap_profile.c. */
extern MR_AllocSiteInfo MR_builtin_alloc_sites[7];
#define MR_ALLOC_SITE_RUNTIME ((void *) &MR_builtin_alloc_sites[0])
#define MR_ALLOC_SITE_FLOAT ((void *) &MR_builtin_alloc_sites[1])
#define MR_ALLOC_SITE_STRING ((void *) &MR_builtin_alloc_sites[2])
#define MR_ALLOC_SITE_TYPE_INFO ((void *) &MR_builtin_alloc_sites[3])
#define MR_ALLOC_SITE_FOREIGN ((void *) &MR_builtin_alloc_sites[4])
#define MR_ALLOC_SITE_TABLING ((void *) &MR_builtin_alloc_sites[5])
#define MR_ALLOC_SITE_STM ((void *) &MR_builtin_alloc_sites[6])
#else
#define MR_ALLOC_ID MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_RUNTIME MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_FLOAT MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_STRING MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_TYPE_INFO MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_FOREIGN MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_TABLING MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_STM MR_ALLOC_SITE_NONE
#endif
extern void *MR_new_object_func(size_t num_bytes,
MR_AllocSiteInfoPtr alloc_id, const char *name);
extern void *MR_new_object_atomic_func(size_t num_bytes,
MR_AllocSiteInfoPtr alloc_id, const char *name);
/*---------------------------------------------------------------------------*/
/*
** MR_copy_string makes a copy of the given string,
** using memory allocated with MR_malloc().
*/
extern char *MR_copy_string(const char *s);
/*---------------------------------------------------------------------------*/
/*
** `MR_unit' is the size of the minimum unit of memory we allocate (in bytes).
** `MR_page_size' is the size of a single page of memory.
*/
extern size_t MR_unit;
extern size_t MR_page_size;
/*---------------------------------------------------------------------------*/
/*
** Users need to call MR_add_root() for any global variable which contains
** pointers to the Mercury heap. This information is only used for agc grades.
*/
#ifdef MR_NATIVE_GC
#define MR_add_root(root_ptr, type_info) \
MR_agc_add_root((root_ptr), (type_info))
#else
#define MR_add_root(root_ptr, type_info) /* nothing */
#endif
/*---------------------------------------------------------------------------*/
#endif /* not MERCURY_MEMORY_H */