mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-12 04:14:06 +00:00
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.
293 lines
8.9 KiB
C
293 lines
8.9 KiB
C
/*
|
|
** vim:ts=4 sw=4 expandtab
|
|
*/
|
|
/*
|
|
** Copyright (C) 2007-2009 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_stm.h - runtime support for software transactional memory.
|
|
*/
|
|
|
|
#ifndef MERCURY_STM_H
|
|
#define MERCURY_STM_H
|
|
|
|
#include "mercury_types.h"
|
|
#include "mercury_thread.h"
|
|
#include "mercury_conf.h"
|
|
#include "mercury_conf_param.h"
|
|
#include "mercury_context.h"
|
|
#include "mercury_engine.h"
|
|
#include <stdio.h>
|
|
|
|
typedef struct MR_STM_Waiter_Struct MR_STM_Waiter;
|
|
typedef struct MR_STM_Var_Struct MR_STM_Var;
|
|
typedef struct MR_STM_TransRecord_Struct MR_STM_TransRecord;
|
|
typedef struct MR_STM_TransLog_Struct MR_STM_TransLog;
|
|
|
|
|
|
/*
|
|
** The type MR_ThreadId provides an abstract means of identifying a Mercury
|
|
** thread. Depending upon the grade we use one of three notions of thread
|
|
** identity.
|
|
**
|
|
** For high-level code with parallelism it is the value returned by a call
|
|
** to pthread_self().
|
|
**
|
|
** For high-level code without parallelism it is an MR_Integer - in this case
|
|
** concurrency is not supported so there is only ever one thread.
|
|
**
|
|
** For low-level code with use the context address as the thread id.
|
|
**
|
|
** The macro MR_THIS_THREAD_ID expands to a value of type MR_ThreadId.
|
|
** This value is the identity of the current thread.
|
|
*/
|
|
#if defined(MR_HIGHLEVEL_CODE)
|
|
|
|
#if defined(MR_THREAD_SAFE)
|
|
typedef pthread_t MR_ThreadId;
|
|
|
|
#define MR_THIS_THREAD_ID pthread_self()
|
|
#else
|
|
typedef MR_Integer MR_ThreadId;
|
|
/*
|
|
** Since these grades don't support concurrency there is only one
|
|
** thread which we always give the id 0.
|
|
*/
|
|
#define MR_THIS_THREAD_ID 0
|
|
#endif
|
|
|
|
#else /* !MR_HIGHLEVEL_CODE */
|
|
|
|
typedef MR_Context *MR_ThreadId;
|
|
#define MR_THIS_THREAD_ID (MR_ENGINE(MR_eng_this_context))
|
|
|
|
#endif /* !MR_HIGHLEVEL_CODE */
|
|
|
|
|
|
/*
|
|
** The type MR_STM_ConditionVar provides an abstract method of blocking and
|
|
** signalling threads based on conditions.
|
|
*/
|
|
#if defined(MR_HIGHLEVEL_CODE)
|
|
|
|
#if defined(MR_THREAD_SAFE)
|
|
typedef MercuryCond MR_STM_ConditionVar;
|
|
|
|
#define MR_STM_condvar_init(x) pthread_cond_init(x, MR_COND_ATTR)
|
|
#define MR_STM_condvar_wait(x, y) MR_cond_wait(x, y, "STM_condvar_wait")
|
|
#define MR_STM_condvar_signal(x) MR_cond_signal(x, "STM_condvar_signal")
|
|
#else
|
|
typedef MR_Integer MR_STM_ConditionVar;
|
|
/*
|
|
** Since these grades don't support concurrency, there is no
|
|
** need to block the thread.
|
|
*/
|
|
#define MR_STM_condvar_init(x)
|
|
#define MR_STM_condvar_wait(x, y)
|
|
#define MR_STM_condvar_signal(x)
|
|
#endif
|
|
|
|
#else /* !MR_HIGHLEVEL_CODE */
|
|
|
|
typedef MR_STM_TransLog MR_STM_ConditionVar;
|
|
|
|
/*
|
|
** NOTE: The global STM lock (MR_STM_lock) must be held when calling this
|
|
** function, as it manipulates the STM variable waiter lists.
|
|
*/
|
|
void MR_STM_condvar_signal(MR_STM_ConditionVar *cvar);
|
|
|
|
#define MR_STM_context_from_condvar(x) ((x)->MR_STM_tl_thread)
|
|
|
|
#endif /* !MR_HIGHLEVEL_CODE */
|
|
|
|
/*
|
|
** A waiter is the identity of a thread that is blocking until the value
|
|
** of this transaction variable changes.
|
|
*/
|
|
|
|
struct MR_STM_Waiter_Struct {
|
|
MR_STM_ConditionVar *MR_STM_cond_var;
|
|
MR_STM_Waiter *MR_STM_waiter_next;
|
|
MR_STM_Waiter *MR_STM_waiter_prev;
|
|
};
|
|
|
|
/*
|
|
** XXX This should also contain the type_info for the value, so we can
|
|
** print them out in the debugger.
|
|
*/
|
|
|
|
struct MR_STM_Var_Struct {
|
|
MR_Word MR_STM_var_value;
|
|
MR_STM_Waiter *MR_STM_var_waiters;
|
|
};
|
|
|
|
struct MR_STM_TransRecord_Struct {
|
|
MR_STM_Var *MR_STM_tr_var;
|
|
MR_Word MR_STM_tr_old_value;
|
|
MR_Word MR_STM_tr_new_value;
|
|
MR_STM_TransRecord *MR_STM_tr_next;
|
|
};
|
|
|
|
struct MR_STM_TransLog_Struct {
|
|
MR_STM_TransRecord *MR_STM_tl_records;
|
|
MR_ThreadId MR_STM_tl_thread;
|
|
MR_STM_TransLog *MR_STM_tl_parent;
|
|
};
|
|
|
|
/*
|
|
** The global STM lock. This lock must be acquired before validating or
|
|
** committing a transaction log.
|
|
*/
|
|
|
|
#if defined(MR_THREAD_SAFE)
|
|
extern MercuryLock MR_STM_lock;
|
|
#endif
|
|
|
|
/*
|
|
** Allocate a new transaction variable.
|
|
*/
|
|
#define MR_STM_new_stm_var(value, var) \
|
|
do { \
|
|
(var) = MR_GC_NEW_ATTRIB(MR_STM_Var, MR_ALLOC_SITE_STM); \
|
|
(var)->MR_STM_var_value = (value); \
|
|
(var)->MR_STM_var_waiters = NULL; \
|
|
} while (0)
|
|
|
|
/*
|
|
** Create a new transaction log.
|
|
** If the log is for a nested transaction then the `parent' field points
|
|
** to the log of the enclosing transaction. It is NULL otherwise.
|
|
*/
|
|
#define MR_STM_create_log(tlog, parent) \
|
|
do { \
|
|
(tlog) = MR_GC_NEW_ATTRIB(MR_STM_TransLog, MR_ALLOC_SITE_STM); \
|
|
(tlog)->MR_STM_tl_records = NULL; \
|
|
(tlog)->MR_STM_tl_thread = MR_THIS_THREAD_ID; \
|
|
(tlog)->MR_STM_tl_parent = (parent); \
|
|
} while (0)
|
|
|
|
/*
|
|
** Discard a transaction log.
|
|
** XXX we should free the memory in nogc grades.
|
|
*/
|
|
#define MR_STM_discard_log(tlog) \
|
|
do { \
|
|
(tlog) = NULL; \
|
|
} while (0)
|
|
|
|
/*
|
|
** Record a change of state for transaction variable `var' in the
|
|
** given transaction log. `old_value' and `new_value' give the value
|
|
** of the transaction variable before and after the change of state.
|
|
*/
|
|
|
|
extern void MR_STM_record_transaction(MR_STM_TransLog *tlog,
|
|
MR_STM_Var *var,
|
|
MR_Word old_value, MR_Word new_value);
|
|
|
|
/*
|
|
** Add a waiter for the current thread to all of the transaction variables
|
|
** listed in the log.
|
|
*/
|
|
|
|
extern void MR_STM_wait(MR_STM_TransLog *tlog,
|
|
MR_STM_ConditionVar *cvar);
|
|
|
|
/*
|
|
** Detach waiters for the current thread from all of the transaction variables
|
|
** referenced by the given transaction log.
|
|
*/
|
|
|
|
extern void MR_STM_unwait(MR_STM_TransLog *tlog,
|
|
MR_STM_ConditionVar *cvar);
|
|
|
|
/*
|
|
** Attach a waiter for thread tid to the transaction variable. The condition
|
|
** variable should be a condition variable properly initialised and associated
|
|
** with the thread.
|
|
*/
|
|
extern void MR_STM_attach_waiter(MR_STM_Var *var, MR_ThreadId tid,
|
|
MR_STM_ConditionVar *cvar);
|
|
|
|
/*
|
|
** Detach any waiters for thread tid from the transaction variable.
|
|
** This will cause execution to abort if no waiter for thread tid can
|
|
** be found since it can only correctly be called in a situation where
|
|
** such a waiter exists.
|
|
*/
|
|
|
|
extern void MR_STM_detach_waiter(MR_STM_Var *var,
|
|
MR_STM_ConditionVar *cvar);
|
|
|
|
extern MR_Integer MR_STM_validate(MR_STM_TransLog *tlog);
|
|
|
|
/*
|
|
** Irrevocably write the changes stored in a transaction log to memory.
|
|
*/
|
|
|
|
extern void MR_STM_commit(MR_STM_TransLog *tlog);
|
|
|
|
/*
|
|
** Changes the value of transaction variable var in a transaction log.
|
|
*/
|
|
|
|
extern void MR_STM_write_var(MR_STM_Var *var, MR_Word value,
|
|
MR_STM_TransLog *tlog);
|
|
|
|
/*
|
|
** Returns the value of transaction variable var in a transaction log.
|
|
** If no entry for var exists, the actual value of the transaction variable
|
|
** var is returned (and added to the transaction log).
|
|
*/
|
|
|
|
extern MR_Word MR_STM_read_var(MR_STM_Var *var, MR_STM_TransLog *tlog);
|
|
|
|
/*
|
|
** Changes the value of the transaction variable var without going through
|
|
** the log.
|
|
**
|
|
** NOTE: This functions must only be used for debugging purposes and will
|
|
** eventually be removed. Please, DO NOT use it for normal operations.
|
|
*/
|
|
|
|
extern void MR_STM_unsafe_write_var(MR_STM_Var *var, MR_Word value);
|
|
|
|
/*
|
|
** Blocks a thread from execution. This method is called by the thread
|
|
** which is to be blocked. The STM lock MUST be aquired by the thread
|
|
** before this method is called and acquires the lock when the thread
|
|
** is signalled.
|
|
*/
|
|
|
|
extern void MR_STM_block_thread(MR_STM_TransLog *tlog);
|
|
|
|
/*
|
|
** Merges a transaction log with its parent. Do not merge it with any
|
|
** other ancestors. Aborts if the given transaction log does not have a
|
|
** parent.
|
|
*/
|
|
|
|
extern void MR_STM_merge_transactions(MR_STM_TransLog *tlog);
|
|
|
|
/*
|
|
** Reschedules all threads currently waiting on the given transaction
|
|
** variables.
|
|
*/
|
|
|
|
extern void MR_STM_signal_vars(MR_STM_Var *tvar);
|
|
|
|
/*
|
|
** These definitions need to be kept in sync with the definition of the type
|
|
** stm_validation_result/0 in library/stm_builtin.m. Changes here may need
|
|
** be reflected there.
|
|
*/
|
|
|
|
#define MR_STM_TRANSACTION_VALID 0
|
|
#define MR_STM_TRANSACTION_INVALID 1
|
|
|
|
#endif /* not MERCURY_STM_H */
|