mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-11 20:03:28 +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.
678 lines
25 KiB
C
678 lines
25 KiB
C
/*
|
|
** Copyright (C) 1997-2000,2002-2007 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_tabling.h - definitions of some basic stuff used for tabling.
|
|
** For tabling code, the Mercury compiler (compiler/table_gen.m) generates
|
|
** references to special procedures defined in library/table_builtin.m.
|
|
** The types and macros defined here are used by the procedures defined in
|
|
** library/table_builtin.m.
|
|
*/
|
|
|
|
#ifndef MERCURY_TABLING_H
|
|
#define MERCURY_TABLING_H
|
|
|
|
#include "mercury_types.h"
|
|
#include "mercury_bitmap.h"
|
|
#include "mercury_type_info.h"
|
|
#include "mercury_float.h"
|
|
#include "mercury_reg_workarounds.h"
|
|
#include "mercury_dlist.h"
|
|
#include "mercury_goto.h" /* for MR_declare_entry */
|
|
#include "mercury_tags.h" /* for `MR_DEFINE_BUILTIN_ENUM_CONST' */
|
|
|
|
#ifndef MR_CONSERVATIVE_GC
|
|
#include "mercury_deep_copy.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#ifdef MR_TABLE_DEBUG
|
|
#define MR_TABLE_DEBUG_BOOL MR_TRUE
|
|
#else
|
|
#define MR_TABLE_DEBUG_BOOL MR_FALSE
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
** Tabling builds up two kinds of tables, both conceptually tries. For call
|
|
** tables, there is one layer in the trie for each input argument; for answer
|
|
** tables, there is one layer in the trie for each output argument. However,
|
|
** the way each trie node is implemented depends on the type of the relevant
|
|
** argument. In addition, what is stored at the tips of the call and answer
|
|
** tables also depends on what kind of tabling (e.g. loopcheck, memo, minimal
|
|
** model) is being performed on the current predicate, and (in some cases)
|
|
** on what stage the execution of the current predicate has reached.
|
|
**
|
|
** We declare trie nodes to have type MR_TrieNode, which is a pointer to
|
|
** MR_TableNode. MR_TableNode is a union of all the types that we may need
|
|
** to be able to store in trie nodes: various kinds of trie implementations,
|
|
** status indications, and answer blocks. Since in several places we write
|
|
** to the union through one member and read from it through another, it is
|
|
** important that all members be the same size; this is why the simple table
|
|
** status field is an (unsigned) integer, not an enum.
|
|
**
|
|
** The integer field is for generic code that does not know what kind of node
|
|
** the node will be; this means initialization. A value of zero means the node
|
|
** is uninitialized; this must be true for all members. (Also, see below on
|
|
** duplicate detection.)
|
|
**
|
|
** The hash table field is used when the "trie" node is implemented with a
|
|
** hash table, whether of ints, floats, strings or another type that can be
|
|
** coerced to one of these types.
|
|
**
|
|
** The fix table field implements a true trie node of fixed size, simply
|
|
** indexed by an integer.
|
|
**
|
|
** The start table field implements a dynamically expandable trie node,
|
|
** simply indexed by the difference between an integer value and a start value.
|
|
**
|
|
** The MR_loop_status member of the union gives the status of a loopcheck
|
|
** subgoal, it should be interpreted using the MR_LOOP_* macros below.
|
|
**
|
|
** The MR_memo_status member of the union gives the status of a memo subgoal,
|
|
** it should be interpreted using the MR_MEMO_* macros below. Note that this
|
|
** word, which is at the end of the chain of trie nodes given by the input
|
|
** arguments of the tabled subgoal, will be overwritten by a pointer to the
|
|
** answer block containing the output arguments when the goal succeeds;
|
|
** the MR_MEMO_SUCCEEDED status code is used only when the goal has no
|
|
** outputs, and thus no answer block. This is why code looking at
|
|
** MR_memo_status must consider "table->MR_memo_status >= MR_MEMO_BLOCK"
|
|
** to be the same as MR_MEMO_SUCCEEDED. The value MR_MEMO_FAILED is last,
|
|
** because the types memo_det_status and memo_semi_status Mercury types
|
|
** are implemented by the first three and four MR_MEMO_* macros respectively.
|
|
**
|
|
** The subgoal field contains the state of a model_non subgoal.
|
|
**
|
|
** The answer block field contains a pointer to an array of words, with
|
|
** one word per output argument.
|
|
**
|
|
** The hash table, fix table and start table members may appear at any interior
|
|
** node in the trie. The simple table status and subgoal members only appear
|
|
** at the tips of call tables. The answer block member appears only at the tips
|
|
** of call tables, either directly (for model_det and model_semi procedures),
|
|
** or indirectly inside answer lists (for model_non procedures). There are no
|
|
** answer tables for model_det and model_semi procedures, since they can only
|
|
** ever have at most one answer. You can of course have answer tables for
|
|
** model_non procedures, at whose tips you find only a duplicate indication.
|
|
** When the tip nodes of answer tables are created, they are initialized to
|
|
** zero as usual. Duplicate checking checks that the tip node is zero and
|
|
** then sets the tip to a nonzero value; this way if the answer is generated
|
|
** again, duplicate checking will fail.
|
|
**
|
|
** Note that once a tabled predicate has inserted its input arguments into
|
|
** its table and got back a pointer to the MR_TableNode representing the
|
|
** selected tip of its call table, it may in general call other tabled
|
|
** predicates and cause insertions into many tables, including its own,
|
|
** before it updates the call table tip node. This means that the tip node
|
|
** must not change address; once a tabling operation has returned an
|
|
** MR_TrieNode to its caller, that address must be valid and have the same
|
|
** meaning until the end of the computation.
|
|
**
|
|
** The implementation of start tables currently does not obey this requirement.
|
|
** This is okay, because start tables are used only by I/O tabling, which
|
|
** guarantees that there will be no insertions into the same (or any other)
|
|
** table between getting back a tip node on the one hand and updating it and
|
|
** releasing the pointer to it on the other hand.
|
|
**
|
|
** NOTE: the mercury_type_tables module uses the expandable hash table routines
|
|
** defined in this module to implement its tables. This is the only use of the
|
|
** MR_type_table field.
|
|
*/
|
|
|
|
/* these macros are used to interpret the MR_loop_status field */
|
|
#define MR_LOOP_INACTIVE 0
|
|
#define MR_LOOP_ACTIVE 1
|
|
|
|
/* these macros are used to interpret the MR_memo_status field */
|
|
#define MR_MEMO_INACTIVE 0
|
|
#define MR_MEMO_ACTIVE 1
|
|
#define MR_MEMO_SUCCEEDED 2
|
|
#define MR_MEMO_FAILED 3
|
|
#define MR_MEMO_BLOCK 4
|
|
|
|
typedef enum {
|
|
MR_MEMO_NON_INACTIVE,
|
|
MR_MEMO_NON_ACTIVE,
|
|
MR_MEMO_NON_INCOMPLETE,
|
|
MR_MEMO_NON_COMPLETE
|
|
} MR_MemoNonStatus;
|
|
|
|
typedef enum {
|
|
MR_SUBGOAL_INACTIVE,
|
|
MR_SUBGOAL_ACTIVE,
|
|
MR_SUBGOAL_COMPLETE
|
|
} MR_SubgoalStatus;
|
|
|
|
struct MR_AnswerListNode_Struct {
|
|
MR_Word *MR_aln_answer_block;
|
|
MR_AnswerList MR_aln_next_answer;
|
|
};
|
|
|
|
union MR_TableNode_Union {
|
|
MR_Integer MR_integer;
|
|
MR_HashTable *MR_hash_table;
|
|
MR_TableNode *MR_fix_table;
|
|
MR_TableNode *MR_start_table;
|
|
MR_Unsigned MR_loop_status;
|
|
MR_Unsigned MR_memo_status;
|
|
MR_Subgoal *MR_subgoal;
|
|
MR_MemoNonRecordPtr MR_memo_non_record;
|
|
MR_GeneratorPtr MR_generator;
|
|
MR_AnswerBlock MR_answerblock;
|
|
MR_Dlist *MR_type_table;
|
|
};
|
|
|
|
#define MR_trie_node_seen_before(t) ((t)->MR_integer != 0)
|
|
|
|
struct MR_MemoNonRecord_Struct {
|
|
MR_TrieNode MR_mn_back_ptr;
|
|
MR_MemoNonStatus MR_mn_status;
|
|
int MR_mn_num_answers;
|
|
MR_TableNode MR_mn_answer_table;
|
|
MR_AnswerList MR_mn_answer_list;
|
|
MR_AnswerList *MR_mn_answer_list_tail;
|
|
};
|
|
|
|
/*
|
|
** The MR_ProcTableInfo structure.
|
|
**
|
|
** To enable debugging (especially performance debugging) of tabled predicates,
|
|
** the compiler generates one of these structures for each tabled predicate
|
|
** (except I/O primitives, for which it generates an MR_TableIoDecl
|
|
** structure).
|
|
**
|
|
** Each argument of a tabled predicate is an input or an output. Inputs are put
|
|
** into the call trie (stored in the tablenode field), which has one level
|
|
** per input argument. The structure of each level depends on what kind of type
|
|
** the corresponding input argument is; this is recorded in the input_steps
|
|
** field, which points to an array of size num_inputs. If the type is an enum,
|
|
** we cannot interpret the data structures on that level without also knowing
|
|
** how many alternatives the type has; this is recorded in the corresponding
|
|
** element of the enum_params array, which is likewise of size num_inputs.
|
|
** (Elements of the enum_params array that correspond to arguments whose types
|
|
** are not enums are not meaningful.)
|
|
**
|
|
** The ptis field points to an array of pseudotypeinfos of size num_inputs +
|
|
** num_outputs. The first num_inputs elements give the types of the input
|
|
** arguments, while the remaining num_outputs elements give the types of the
|
|
** output arguments. The type_params field describes where any typeinfos
|
|
** among the input arguments are at call, since without this information
|
|
** the debugger cannot turn the pseudotypeinfos pointed to by ptis field info
|
|
** typeinfos.
|
|
**
|
|
** If the collection of statistics was not enabled for this table, then the
|
|
** stats field will point to an array num_inputs MR_TableStepStats structures,
|
|
** one for each input argument. Each element of this array contains statistics
|
|
** about the corresponding level of the trie.
|
|
**
|
|
** Users can use the stats field to retrieve statistics derived from the
|
|
** entire lifetime of the table so far. To enable users to derive information
|
|
** derived only since the last such lookup, we record the information retrieved
|
|
** on each lookup in the prev_stats field (which will be NULL until the first
|
|
** such lookup).
|
|
**
|
|
** If there is no size limit on the table, then the size_limit field will be
|
|
** zero and the call_table_tips, num_call_table_tips and next_to_evict fields
|
|
** are not meaningful. If there is a size limit on the table, then the
|
|
** size_limit field says how many call table tips are allowed to exist at
|
|
** any one time, the num_call_table_tips field says how many exist at this time
|
|
** (this number will be between zero and size_limit, both inclusive),
|
|
** the call_table_tips field will point to an array of size_limit call table
|
|
** tips, of which the first num_call_table_tips will be meaningful. The
|
|
** next_to_evict field says which one of these entries is scheduled to be
|
|
** evicted next under the FIFO replacement strategy.
|
|
**
|
|
** XXX We need other fields (e.g. in hash tables and tries) to allow us
|
|
** to delete internal nodes of the trie that become empty after evictions.
|
|
*/
|
|
|
|
typedef enum {
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_TYPE_LOOPCHECK),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_TYPE_MEMO),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_TYPE_MINIMAL_MODEL_STACK_COPY),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_TYPE_MINIMAL_MODEL_OWN_STACKS)
|
|
} MR_TableType;
|
|
|
|
/*
|
|
** The definition of this type should correspond to the type table_step_kind
|
|
** in library/table_statistics.m.
|
|
*/
|
|
|
|
typedef enum {
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_DUMMY),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_INT),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_CHAR),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_STRING),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_FLOAT),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_ENUM),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_FOREIGN_ENUM),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_GEN),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_GEN_ADDR),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_GEN_POLY),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_GEN_POLY_ADDR),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_TYPEINFO),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_TYPECLASSINFO),
|
|
MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_PROMISE_IMPLIED)
|
|
} MR_TableTrieStep;
|
|
|
|
typedef MR_Unsigned MR_Counter;
|
|
|
|
typedef enum {
|
|
MR_TABLE_STATS_DETAIL_HASH,
|
|
MR_TABLE_STATS_DETAIL_ENUM,
|
|
MR_TABLE_STATS_DETAIL_START,
|
|
MR_TABLE_STATS_DETAIL_DU,
|
|
MR_TABLE_STATS_DETAIL_POLY,
|
|
MR_TABLE_STATS_DETAIL_NONE
|
|
} MR_TableStepStatsKind;
|
|
|
|
struct MR_TableStepStats_Struct {
|
|
MR_Counter MR_tss_num_lookups;
|
|
MR_Counter MR_tss_num_lookups_is_dupl;
|
|
MR_TableStepStatsKind MR_tss_detail_kind;
|
|
|
|
MR_Counter MR_tss_hash_num_table_allocs;
|
|
MR_Counter MR_tss_hash_num_table_alloc_bytes;
|
|
MR_Counter MR_tss_hash_num_link_chunk_allocs;
|
|
MR_Counter MR_tss_hash_num_link_chunk_alloc_bytes;
|
|
MR_Counter MR_tss_hash_num_key_compares_not_dupl;
|
|
MR_Counter MR_tss_hash_num_key_compares_dupl;
|
|
MR_Counter MR_tss_hash_num_resizes;
|
|
MR_Counter MR_tss_hash_resize_old_entries;
|
|
MR_Counter MR_tss_hash_resize_new_entries;
|
|
|
|
MR_Counter MR_tss_enum_num_node_allocs;
|
|
MR_Counter MR_tss_enum_num_node_alloc_bytes;
|
|
|
|
MR_Counter MR_tss_du_num_node_allocs;
|
|
MR_Counter MR_tss_du_num_node_alloc_bytes;
|
|
MR_Counter MR_tss_du_num_arg_lookups;
|
|
MR_Counter MR_tss_du_num_exist_lookups;
|
|
|
|
MR_Counter MR_tss_start_num_allocs;
|
|
MR_Counter MR_tss_start_num_alloc_bytes;
|
|
};
|
|
|
|
struct MR_TableStats_Struct {
|
|
MR_Counter MR_ts_num_lookups;
|
|
MR_Counter MR_ts_num_lookups_is_dupl;
|
|
/*
|
|
** The number of steps is given by MR_pt_num_inputs for the call table
|
|
** and MR_pt_num_outputs for the answer table.
|
|
*/
|
|
MR_TableStepStats *MR_ts_steps;
|
|
};
|
|
|
|
#define MR_TABLE_CALL_TABLE 0
|
|
#define MR_TABLE_ANSWER_TABLE 1
|
|
|
|
#define MR_TABLE_STATS_CURR 0
|
|
#define MR_TABLE_STATS_PREV 1
|
|
|
|
struct MR_TableStepDesc_Struct {
|
|
MR_ConstString MR_tsd_var_name;
|
|
MR_TableTrieStep MR_tsd_trie_step;
|
|
MR_Integer MR_tsd_trie_enum_param;
|
|
};
|
|
|
|
struct MR_ProcTableInfo_Struct {
|
|
MR_TableType MR_pt_table_type;
|
|
int MR_pt_num_inputs;
|
|
int MR_pt_num_outputs;
|
|
int MR_pt_has_answer_table;
|
|
const MR_PseudoTypeInfo *MR_pt_ptis;
|
|
const MR_TypeParamLocns *MR_pt_type_params;
|
|
|
|
MR_TableNode MR_pt_tablenode;
|
|
|
|
/*
|
|
** The index should be either MR_TABLE_CALL_TABLE or
|
|
** MR_TABLE_ANSWER_TABLE. The size of the pointed-to array is
|
|
** MR_pt_num_inputs for MR_TABLE_CALL_TABLE and MR_pt_num_outputs
|
|
** for MR_TABLE_ANSWER_TABLE.
|
|
*/
|
|
const MR_TableStepDesc *MR_pt_steps_desc[2];
|
|
|
|
/*
|
|
** The first index should be either MR_TABLE_CALL_TABLE or
|
|
** MR_TABLE_ANSWER_TABLE, while the second index should be either
|
|
** MR_TABLE_STATS_CURR or MR_TABLE_STATS_PREV.
|
|
*/
|
|
MR_TableStats MR_pt_stats[2][2];
|
|
|
|
MR_Unsigned MR_pt_size_limit;
|
|
MR_TrieNode *MR_pt_call_table_tips;
|
|
MR_Unsigned MR_pt_num_call_table_tips;
|
|
MR_Unsigned MR_pt_next_to_evict;
|
|
};
|
|
|
|
/* This type is only for backward compatibility */
|
|
typedef struct MR_Table_Gen_Struct {
|
|
int MR_table_gen_num_inputs;
|
|
int MR_table_gen_num_outputs;
|
|
const MR_TableTrieStep *MR_table_gen_input_steps;
|
|
const MR_Integer *MR_table_gen_enum_params;
|
|
const MR_PseudoTypeInfo *MR_table_gen_ptis;
|
|
const MR_TypeParamLocns *MR_table_gen_type_params;
|
|
} MR_Table_Gen;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
** The functions defined here should be used only via the macros defined
|
|
** in mercury_tabling_macros.h.
|
|
**
|
|
** These functions look to see if the given key is in the given table.
|
|
** If it is, they return the address of the data pointer associated with
|
|
** the key. If it is not, they create a new element for the key in the table
|
|
** and return the address of its data pointer.
|
|
*/
|
|
|
|
/*
|
|
** These functions assume that the table is a dynamically resizable hash table.
|
|
*/
|
|
|
|
extern MR_TrieNode MR_int_hash_lookup_or_add(MR_TrieNode table,
|
|
MR_Integer key);
|
|
extern MR_TrieNode MR_int_hash_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_Integer key);
|
|
extern MR_TrieNode MR_float_hash_lookup_or_add(MR_TrieNode table,
|
|
MR_Float key);
|
|
extern MR_TrieNode MR_float_hash_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_Float key);
|
|
extern MR_TrieNode MR_string_hash_lookup_or_add(MR_TrieNode table,
|
|
MR_ConstString key);
|
|
extern MR_TrieNode MR_string_hash_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_ConstString key);
|
|
extern MR_TrieNode MR_bitmap_hash_lookup_or_add(MR_TrieNode table,
|
|
MR_ConstBitmapPtr key);
|
|
extern MR_TrieNode MR_bitmap_hash_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_ConstBitmapPtr key);
|
|
extern MR_TrieNode MR_word_hash_lookup_or_add(MR_TrieNode table,
|
|
MR_Word key);
|
|
extern MR_TrieNode MR_word_hash_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_Word key);
|
|
|
|
/*
|
|
** These functions assume that the table is a statically sized array,
|
|
** with the index ranging from 0 to range - 1.
|
|
*/
|
|
|
|
extern MR_TrieNode MR_int_fix_index_enum_lookup_or_add(MR_TrieNode table,
|
|
MR_Integer range, MR_Integer key);
|
|
extern MR_TrieNode MR_int_fix_index_enum_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_Integer range, MR_Integer key);
|
|
|
|
extern MR_TrieNode MR_int_fix_index_du_lookup_or_add(MR_TrieNode table,
|
|
MR_Integer range, MR_Integer key);
|
|
extern MR_TrieNode MR_int_fix_index_du_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_Integer range, MR_Integer key);
|
|
|
|
/*
|
|
** These functions assume that the table is an expandable array,
|
|
** with the smallest valid index value being start.
|
|
*/
|
|
|
|
extern MR_TrieNode MR_int_start_index_lookup_or_add(MR_TrieNode table,
|
|
MR_Integer start, MR_Integer key);
|
|
extern MR_TrieNode MR_int_start_index_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_Integer start, MR_Integer key);
|
|
|
|
/*
|
|
** These functions table type_infos in a hash table.
|
|
*/
|
|
|
|
extern MR_TrieNode MR_type_info_lookup_or_add(MR_TrieNode table,
|
|
MR_TypeInfo type_info);
|
|
extern MR_TrieNode MR_type_info_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_TypeInfo type_info);
|
|
|
|
/*
|
|
** These functions table typeclass_infos in a hash table.
|
|
*/
|
|
|
|
extern MR_TrieNode MR_type_class_info_lookup_or_add(MR_TrieNode table,
|
|
MR_Word *type_class_info);
|
|
extern MR_TrieNode MR_type_class_info_lookup_or_add_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_Word *type_class_info);
|
|
|
|
/*
|
|
** These functions table values of arbitrary types; the form of the data
|
|
** structure depends on the actual type of the value. The tabling is done
|
|
** by tabling all the function symbols of the value; unlike
|
|
** MR_word_hash_lookup, this function *does* guarantee that all duplicates
|
|
** will be detected.
|
|
*/
|
|
|
|
extern MR_TrieNode MR_table_type(MR_TrieNode table,
|
|
MR_TypeInfo type_info, MR_Word data_value);
|
|
extern MR_TrieNode MR_table_type_debug(MR_TrieNode table,
|
|
MR_TypeInfo type_info, MR_Word data_value);
|
|
extern MR_TrieNode MR_table_type_stats(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_TypeInfo type_info, MR_Word data_value);
|
|
extern MR_TrieNode MR_table_type_stats_debug(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_TypeInfo type_info, MR_Word data_value);
|
|
extern MR_TrieNode MR_table_type_back(MR_TrieNode table,
|
|
MR_TypeInfo type_info, MR_Word data_value);
|
|
extern MR_TrieNode MR_table_type_debug_back(MR_TrieNode table,
|
|
MR_TypeInfo type_info, MR_Word data_value);
|
|
extern MR_TrieNode MR_table_type_stats_back(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_TypeInfo type_info, MR_Word data_value);
|
|
extern MR_TrieNode MR_table_type_stats_debug_back(
|
|
MR_TableStepStats *stats, MR_TrieNode table,
|
|
MR_TypeInfo type_info, MR_Word data_value);
|
|
|
|
/*
|
|
** These functions look to see if the given key is in the given table.
|
|
** If it is, they return the address of the data pointer associated with
|
|
** the key. If it is not, they return NULL.
|
|
**
|
|
** These functions assume that the table is a dynamically resizable hash table.
|
|
*/
|
|
|
|
extern MR_TrieNode MR_int_hash_lookup(MR_TrieNode table,
|
|
MR_Integer key);
|
|
extern MR_TrieNode MR_float_hash_lookup(MR_TrieNode table,
|
|
MR_Float key);
|
|
extern MR_TrieNode MR_string_hash_lookup(MR_TrieNode table,
|
|
MR_ConstString key);
|
|
extern MR_TrieNode MR_bitmap_hash_lookup(MR_TrieNode table,
|
|
MR_ConstBitmapPtr key);
|
|
extern MR_TrieNode MR_word_hash_lookup(MR_TrieNode table,
|
|
MR_Word data_value);
|
|
|
|
/*
|
|
** These functions return a dynamically resizable array (using the primitives
|
|
** in mercury_array_macros.h) containing all the elements in the given
|
|
** dynamically resizable hash table.
|
|
*/
|
|
|
|
extern MR_bool MR_get_int_hash_table_contents(MR_TrieNode t,
|
|
MR_Integer **values_ptr, int *value_next_ptr);
|
|
extern MR_bool MR_get_float_hash_table_contents(MR_TrieNode t,
|
|
MR_Float **values_ptr, int *value_next_ptr);
|
|
extern MR_bool MR_get_string_hash_table_contents(MR_TrieNode t,
|
|
MR_ConstString **values_ptr,
|
|
int *value_next_ptr);
|
|
extern MR_bool MR_get_bitmap_hash_table_contents(MR_TrieNode t,
|
|
MR_ConstBitmapPtr **values_ptr,
|
|
int *value_next_ptr);
|
|
|
|
/*
|
|
** This function prints statistics about the operation of tabling, if the
|
|
** collection of such statistics is enabled, on the given stream.
|
|
*/
|
|
|
|
extern void MR_table_report_statistics(FILE *fp);
|
|
|
|
/*
|
|
** These functions return printable representations of the MR_loop_status
|
|
** MR_memo_status and MR_mn_status fields.
|
|
*/
|
|
|
|
extern const char *MR_loopcheck_status(MR_Unsigned);
|
|
extern const char *MR_memo_status(MR_Unsigned);
|
|
extern const char *MR_memo_non_status(MR_MemoNonStatus);
|
|
|
|
/*
|
|
** These functions print the tips of the call tables for loopcheck and memo
|
|
** tabled predicates to fp.
|
|
*/
|
|
|
|
extern void MR_print_loopcheck_tip(FILE *fp,
|
|
const MR_ProcLayout *proc, MR_TrieNode table);
|
|
extern void MR_print_memo_tip(FILE *fp,
|
|
const MR_ProcLayout *proc, MR_TrieNode table);
|
|
extern void MR_print_memo_non_record(FILE *fp,
|
|
const MR_ProcLayout *proc,
|
|
MR_MemoNonRecordPtr record);
|
|
|
|
/*
|
|
** Prints the given answer_block of the given procedure to fp.
|
|
*/
|
|
|
|
extern void MR_print_answerblock(FILE *fp,
|
|
const MR_ProcLayout *proc,
|
|
MR_Word *answer_block);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#ifndef MR_NATIVE_GC
|
|
|
|
#define MR_TABLE_NEW(type) \
|
|
MR_GC_NEW_ATTRIB(type, MR_ALLOC_SITE_TABLING)
|
|
|
|
#define MR_TABLE_NEW_ARRAY(type, count) \
|
|
MR_GC_NEW_ARRAY_ATTRIB(type, (count), MR_ALLOC_SITE_TABLING)
|
|
|
|
#define MR_TABLE_RESIZE_ARRAY(ptr, type, count) \
|
|
MR_GC_RESIZE_ARRAY_ATTRIB((ptr), type, (count))
|
|
|
|
#define MR_table_allocate_words(size) \
|
|
((MR_Word *) MR_GC_malloc_attrib(sizeof(MR_Word) * (size), \
|
|
MR_ALLOC_SITE_TABLING))
|
|
|
|
#define MR_table_allocate_struct(type) \
|
|
((type *) MR_GC_malloc_attrib(sizeof(type), \
|
|
MR_ALLOC_SITE_TABLING))
|
|
|
|
#define MR_table_allocate_structs(num, type) \
|
|
((type *) MR_GC_malloc_attrib(sizeof(type) * (num), \
|
|
MR_ALLOC_SITE_TABLING))
|
|
|
|
#define MR_table_free(pointer) \
|
|
MR_GC_free_attrib((pointer))
|
|
|
|
#else /* MR_NATIVE_GC */
|
|
|
|
#define MR_TABLE_NATIVE_GC_MSG \
|
|
"Sorry, not implemented: tabling in native gc grades"
|
|
|
|
#define MR_TABLE_NEW(type) \
|
|
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
|
|
(void *) NULL)
|
|
#define MR_TABLE_NEW_ARRAY(type, count) \
|
|
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
|
|
(void *) NULL)
|
|
#define MR_TABLE_RESIZE_ARRAY(pointer, type, count) \
|
|
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
|
|
(void *) NULL)
|
|
#if 0
|
|
#define MR_table_allocate_bytes(size) \
|
|
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
|
|
(void *) NULL)
|
|
#endif
|
|
#define MR_table_allocate_words(size) \
|
|
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
|
|
(void *) NULL)
|
|
#define MR_table_allocate_struct(type) \
|
|
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
|
|
(void *) NULL)
|
|
#define MR_table_allocate_structs(num, type) \
|
|
(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), \
|
|
(void *) NULL)
|
|
#define MR_table_free(pointer) \
|
|
MR_fatal_error(MR_TABLE_NATIVE_GC_MSG)
|
|
|
|
#endif /* MR_NATIVE_GC */
|
|
|
|
/*
|
|
** XXX The extra memory attribution word is not yet copied.
|
|
*/
|
|
#define MR_table_copy_words(dest, source, size) \
|
|
(MR_CHECK_EXPR_TYPE((dest), MR_Word *), \
|
|
(MR_CHECK_EXPR_TYPE((source), MR_Word *), \
|
|
MR_memcpy((char *) (dest), (char *) (source), \
|
|
sizeof(MR_Word) * (size))))
|
|
|
|
#define MR_table_copy_structs(dest, source, num, type) \
|
|
(MR_CHECK_EXPR_TYPE((dest), type *), \
|
|
(MR_CHECK_EXPR_TYPE((source), type *), \
|
|
MR_memcpy((char *) (dest), (char *) (source), \
|
|
sizeof(type) * (num))))
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
#ifdef MR_USE_GCC_NESTED_FUNCTIONS
|
|
extern void MR_CALL
|
|
mercury__table_builtin__table_memo_return_all_answers_multi_2_p_0(
|
|
MR_Box record, MR_Box *answer_block_ptr,
|
|
MR_NestedCont cont);
|
|
|
|
extern void MR_CALL
|
|
mercury__table_builtin__table_memo_return_all_answers_nondet_2_p_0(
|
|
MR_Box record, MR_Box *answer_block_ptr,
|
|
MR_NestedCont cont);
|
|
#else /* ! MR_USE_GCC_NESTED_FUNCTIONS */
|
|
extern void MR_CALL
|
|
mercury__table_builtin__table_memo_return_all_answers_multi_2_p_0(
|
|
MR_Box record, MR_Box *answer_block_ptr,
|
|
MR_Cont cont, void *cont_env_ptr);
|
|
|
|
extern void MR_CALL
|
|
mercury__table_builtin__table_memo_return_all_answers_nondet_2_p_0(
|
|
MR_Box record, MR_Box *answer_block_ptr,
|
|
MR_Cont cont, void *cont_env_ptr);
|
|
#endif /* MR_USE_GCC_NESTED_FUNCTIONS */
|
|
|
|
#else /* ! MR_HIGHLEVEL_CODE */
|
|
#define MR_MEMO_NON_RET_ALL_NONDET_ENTRY \
|
|
MR_proc_entry_user_name(table_builtin, \
|
|
table_memo_return_all_answers_nondet, 2, 0)
|
|
#define MR_MEMO_NON_RET_ALL_MULTI_ENTRY \
|
|
MR_proc_entry_user_name(table_builtin, \
|
|
table_memo_return_all_answers_multi, 2, 0)
|
|
|
|
MR_declare_entry(MR_MEMO_NON_RET_ALL_NONDET_ENTRY);
|
|
MR_declare_entry(MR_MEMO_NON_RET_ALL_MULTI_ENTRY);
|
|
#endif /* MR_HIGHLEVEL_CODE */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#include "mercury_tabling_macros.h"
|
|
#include "mercury_tabling_preds.h"
|
|
|
|
#include "mercury_stack_layout.h" /* for MR_ProcLayout and */
|
|
/* MR_TypeParamLocns */
|
|
|
|
#endif /* not MERCURY_TABLING_H */
|