mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 18:33:58 +00:00
trace/mercury_trace_cmd_developer.c:
trace/mercury_trace_tables.[ch]:
Add two options to the mdb command "ambiguity".
Print ambiguities between function and predicate forms of the same
operation, such as list.length, only if the new option -b, or
--both-pred-and-func, is given.
Print ambiguities involving procedures that were created by type
specialization only if the new option -s, or --typespec is given.
(The -t option name was already taken.)
These changes remove from the ambiguity command's output
(some of) the parts that are not useful when one wants to eliminate
ambiguities by renaming.
Clarify a heading.
doc/user_guide.texi:
Document the above changes.
runtime/mercury_proc_id.h:
Fix a field name that has become misleading.
MR_UserProcId_Structs have a field named MR_user_arity.
In this name, the "MR_user_" part is a prefix shared by the other
fields in that structure, to indicate that they are part of the id
of a user-defined procedure, as opposed to a compiler-created
unify, compare or index procedure. However, the arity it contains
is what the compiler now calls a pred_form_arity: it does not count
type_info and typeclass_info arguments added by polymorphism, but
it *does* count function return values for functions. This is now
misleading, because in the compiler, a user_arity does *not* count
function return values for functions.
Replace this field name with MR_user_pred_form_arity, which tells
readers that this arity is a pred_form_arity. The presence of the
"user" part of the name may still cause some confusion, but at least
that confusion should motivate readers to look up the field name,
whose comment should clarify things.
mdbcomp/rtti_access.m:
runtime/mercury_debug.c:
runtime/mercury_deep_profiling.c:
runtime/mercury_ho_call.c:
runtime/mercury_layout_util.c:
runtime/mercury_ml_expand_body.h:
runtime/mercury_stack_layout.h:
runtime/mercury_trace_base.c:
trace/mercury_trace.c:
trace/mercury_trace_external.c:
trace/mercury_trace_util.c:
Conform to the change in mercury_proc_id.h.
tests/debugger/ambiguity.{m,inp,exp}:
tests/debugger/ambiguity_helper.m:
Expand this test case to test the new functionality.
The type specialized predicates are in a new helper module,
because this is the simplest way to avoid dead procedure elimination
deleting any of the predicates whose names we want to test for ambiguities.
1956 lines
60 KiB
C
1956 lines
60 KiB
C
// vim: ts=4 sw=4 expandtab ft=c
|
|
|
|
// Copyright (C) 2001-2008, 2010-2011 The University of Melbourne.
|
|
// Copyright (C) 2016, 2018 The Mercury team.
|
|
// This file is distributed under the terms specified in COPYING.LIB.
|
|
|
|
// Deep profiling module
|
|
//
|
|
// See ../deep_profiler/README for some pointers to documentation
|
|
// on deep profiling.
|
|
//
|
|
// Authors: conway, zs
|
|
|
|
// Turn on assertions, to protect the integrity of the generated data files.
|
|
#define MR_DEEP_CHECKS
|
|
|
|
#include "mercury_imp.h"
|
|
#include "mercury_ho_call.h"
|
|
#include "mercury_stack_layout.h"
|
|
#include "mercury_timing.h"
|
|
#include "mercury_prof_time.h"
|
|
#include "mercury_runtime_util.h"
|
|
#include "mercury_deep_profiling.h"
|
|
#include "mercury_deep_profiling_hand.h"
|
|
#include "mercury_file.h"
|
|
|
|
#ifdef MR_DEEP_PROFILING
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <errno.h>
|
|
|
|
#ifdef MR_EXEC_TRACE
|
|
MR_bool MR_disable_deep_profiling_in_debugger = MR_FALSE;
|
|
#endif
|
|
|
|
MR_CallSiteStatic MR_main_parent_call_site_statics[1] =
|
|
{
|
|
{ MR_callsite_callback, NULL, NULL, "Mercury runtime", 0, "" }
|
|
};
|
|
|
|
MR_ProcStatic MR_main_parent_proc_static =
|
|
{
|
|
"Mercury runtime",
|
|
0,
|
|
MR_TRUE,
|
|
1,
|
|
&MR_main_parent_call_site_statics[0],
|
|
#ifdef MR_USE_ACTIVATION_COUNTS
|
|
0,
|
|
#endif
|
|
NULL,
|
|
-1,
|
|
-1,
|
|
-1
|
|
};
|
|
|
|
MR_ProcLayoutUser MR_main_parent_proc_layout =
|
|
{
|
|
{ MR_do_not_reached, MR_LONG_LVAL_TYPE_UNKNOWN, -1, MR_DETISM_DET },
|
|
{ MR_PREDICATE, "Mercury runtime", "Mercury runtime",
|
|
"Mercury runtime", 0, 0 },
|
|
NULL,
|
|
&MR_main_parent_proc_static
|
|
};
|
|
|
|
MR_CallSiteDynamic *MR_main_parent_call_site_dynamics[1] =
|
|
{
|
|
NULL
|
|
};
|
|
|
|
MR_ProcDynamic MR_main_parent_proc_dynamic =
|
|
{
|
|
(MR_ProcLayout *) &MR_main_parent_proc_layout,
|
|
&MR_main_parent_call_site_dynamics[0]
|
|
};
|
|
|
|
MR_CallSiteDynamic MR_main_grandparent_call_site_dynamic =
|
|
{
|
|
&MR_main_parent_proc_dynamic,
|
|
{
|
|
#ifdef MR_DEEP_PROFILING_PORT_COUNTS
|
|
#ifdef MR_DEEP_PROFILING_EXPLICIT_CALL_COUNTS
|
|
1,
|
|
#else
|
|
// The call count is computed from the other counts.
|
|
#endif
|
|
1, 0, 0, 0,
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_TIMING
|
|
0,
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_MEMORY
|
|
0, 0
|
|
#endif
|
|
},
|
|
0
|
|
};
|
|
|
|
MR_CallSiteDynamic *MR_current_call_site_dynamic =
|
|
&MR_main_grandparent_call_site_dynamic;
|
|
MR_CallSiteDynamic *MR_next_call_site_dynamic = NULL;
|
|
MR_CallSiteDynList **MR_current_callback_site = (MR_CallSiteDynList **)
|
|
&MR_main_parent_call_site_dynamics[0];
|
|
|
|
volatile MR_bool MR_inside_deep_profiling_code = MR_FALSE;
|
|
volatile unsigned MR_quanta_inside_deep_profiling_code = 0;
|
|
volatile unsigned MR_quanta_outside_deep_profiling_code = 0;
|
|
|
|
#ifdef MR_DEEP_PROFILING_CALL_SEQ
|
|
unsigned MR_deep_prof_cur_call_seq = 0;
|
|
#endif
|
|
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
|
|
int MR_deep_num_csd_nodes = 0;
|
|
int MR_deep_num_pd_nodes = 0;
|
|
int MR_deep_num_pd_array_slots = 0;
|
|
int MR_deep_num_dynlist_nodes = 0;
|
|
|
|
int MR_dictionary_search_lengths[MR_MAX_CLOSURE_LIST_LENGTH];
|
|
int MR_closure_search_lengths[MR_MAX_CLOSURE_LIST_LENGTH];
|
|
int MR_method_search_lengths[MR_MAX_CLOSURE_LIST_LENGTH];
|
|
|
|
int MR_deep_prof_prep_normal_new = 0;
|
|
int MR_deep_prof_prep_normal_old = 0;
|
|
int MR_deep_prof_prep_special_new = 0;
|
|
int MR_deep_prof_prep_special_old = 0;
|
|
int MR_deep_prof_prep_ho_new = 0;
|
|
int MR_deep_prof_prep_ho_old = 0;
|
|
int MR_deep_prof_prep_method_new = 0;
|
|
int MR_deep_prof_prep_method_old = 0;
|
|
int MR_deep_prof_prep_callback_new = 0;
|
|
int MR_deep_prof_prep_callback_old = 0;
|
|
int MR_deep_prof_prep_tail_old = 0;
|
|
int MR_deep_prof_prep_tail_new = 0;
|
|
|
|
int MR_deep_prof_call_new = 0;
|
|
int MR_deep_prof_call_rec = 0;
|
|
int MR_deep_prof_call_old = 0;
|
|
int MR_deep_prof_call_builtin_new = 0;
|
|
int MR_deep_prof_call_builtin_old = 0;
|
|
|
|
#endif // MR_DEEP_PROFILING_STATISTICS
|
|
|
|
#ifdef MR_DEEP_PROFILING_LOG
|
|
FILE *MR_deep_prof_log_file = NULL;
|
|
#endif
|
|
|
|
void
|
|
MR_deep_assert_failed(const MR_CallSiteDynamic *csd, const MR_ProcLayout *pl,
|
|
const MR_ProcStatic *ps, const char *cond,
|
|
const char *filename, int linenumber)
|
|
{
|
|
char bufcsd[64];
|
|
char bufps[64];
|
|
|
|
if (csd != NULL) {
|
|
sprintf(bufcsd, ", csd %p\n", csd);
|
|
} else {
|
|
strcpy(bufcsd, "");
|
|
}
|
|
|
|
if (pl != NULL) {
|
|
sprintf(bufps, ", pl %p\n", pl);
|
|
} else {
|
|
strcpy(bufps, "");
|
|
}
|
|
|
|
if (ps != NULL) {
|
|
sprintf(bufps, ", ps %p\n", ps);
|
|
} else {
|
|
strcpy(bufps, "");
|
|
}
|
|
|
|
MR_fatal_error("Deep profiling assertion failed, %s:%d\n%s%s%s\n",
|
|
filename, linenumber, cond, bufcsd, bufps);
|
|
}
|
|
|
|
void
|
|
MR_setup_callback(void *entry)
|
|
{
|
|
MR_CallSiteDynList *csd_list;
|
|
MR_CallSiteDynamic *csd;
|
|
|
|
MR_enter_instrumentation();
|
|
csd_list = *MR_current_callback_site;
|
|
while (csd_list != NULL)
|
|
{
|
|
if (csd_list->MR_csdlist_key == entry) {
|
|
MR_next_call_site_dynamic = csd_list->MR_csdlist_call_site;
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
MR_deep_prof_prep_callback_old++;
|
|
#endif
|
|
MR_leave_instrumentation();
|
|
return;
|
|
}
|
|
|
|
csd_list = csd_list->MR_csdlist_next;
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
MR_deep_prof_prep_callback_new++;
|
|
#endif
|
|
|
|
MR_new_call_site_dynamic(csd);
|
|
|
|
csd_list = MR_PROFILING_NEW(MR_CallSiteDynList);
|
|
csd_list->MR_csdlist_key = entry;
|
|
csd_list->MR_csdlist_call_site = csd;
|
|
csd_list->MR_csdlist_next = *MR_current_callback_site;
|
|
*MR_current_callback_site = csd_list;
|
|
|
|
MR_next_call_site_dynamic = csd;
|
|
MR_leave_instrumentation();
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
|
|
int MR_deep_prof_search_len;
|
|
|
|
void
|
|
MR_deep_profile_update_special_history(void)
|
|
{
|
|
if (MR_deep_prof_search_len < MR_MAX_CLOSURE_LIST_LENGTH) {
|
|
MR_dictionary_search_lengths[MR_deep_prof_search_len]++;
|
|
}
|
|
}
|
|
|
|
void
|
|
MR_deep_profile_update_closure_history()
|
|
{
|
|
if (MR_deep_prof_search_len < MR_MAX_CLOSURE_LIST_LENGTH) {
|
|
MR_closure_search_lengths[MR_deep_prof_search_len]++;
|
|
}
|
|
}
|
|
|
|
void
|
|
MR_deep_profile_update_method_history()
|
|
{
|
|
if (MR_deep_prof_search_len < MR_MAX_CLOSURE_LIST_LENGTH) {
|
|
MR_method_search_lengths[MR_deep_prof_search_len]++;
|
|
}
|
|
}
|
|
|
|
#endif // MR_DEEP_PROFILING_STATISTICS
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Functions for writing out the data at the end of the execution.
|
|
|
|
static void MR_deep_data_output_error(const char *msg, const char *file);
|
|
static void MR_write_out_profiling_tree_check_unwritten(FILE *check_fp);
|
|
|
|
static void MR_write_out_deep_id_string(FILE *fp);
|
|
static void MR_write_out_procrep_id_string(FILE *fp);
|
|
static void MR_write_out_program_name(FILE *fp);
|
|
static void MR_write_out_deep_flags(FILE *fp, MR_bool compress);
|
|
|
|
static void MR_write_out_call_site_static(FILE *fp,
|
|
const MR_CallSiteStatic *css);
|
|
static void MR_write_out_call_site_dynamic(FILE *fp,
|
|
const MR_CallSiteDynamic *csd);
|
|
|
|
static void MR_write_out_proc_dynamic(FILE *fp, const MR_ProcDynamic *pd);
|
|
static void MR_write_out_ho_call_site_ptrs(FILE *fp,
|
|
const MR_ProcDynamic *pd,
|
|
const MR_CallSiteDynList *dynlist);
|
|
static void MR_write_out_ho_call_site_nodes(FILE *fp,
|
|
MR_CallSiteDynList *dynlist);
|
|
|
|
static void MR_unwritten_css_handler(FILE *fp, const void *css);
|
|
static void MR_unwritten_csd_handler(FILE *fp, const void *csd);
|
|
static void MR_unwritten_pl_handler(FILE *fp, const void *ps);
|
|
static void MR_unwritten_pd_handler(FILE *fp, const void *pd);
|
|
|
|
typedef enum node_kind {
|
|
kind_csd, kind_pd, kind_css, kind_ps
|
|
} MR_NodeKind;
|
|
|
|
// Must correspond to fixed_size_int_bytes in deep_profiler/read_profile.m.
|
|
#define MR_FIXED_SIZE_INT_BYTES 8
|
|
|
|
static void MR_write_csd_ptr(FILE *fp, const MR_CallSiteDynamic *csd);
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE
|
|
static void MR_write_out_coverage_points_static(FILE *fp,
|
|
const MR_ProcStatic *ps);
|
|
static void MR_write_out_coverage_points_dynamic(FILE *fp,
|
|
const MR_ProcDynamic *pd);
|
|
#endif
|
|
static void MR_write_ptr(FILE *fp, MR_NodeKind kind, int node_id);
|
|
static void MR_write_kind(FILE *fp, MR_CallSiteKind kind);
|
|
static void MR_write_byte(FILE *fp, const char byte);
|
|
static void MR_write_num(FILE *fp, unsigned long num);
|
|
static void MR_write_fixed_size_int(FILE *fp, MR_uint_least64_t num);
|
|
static void MR_write_string(FILE *fp, const char *ptr);
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// We need some hash tables, so here are the structures for handling them....
|
|
|
|
typedef struct MR_Profiling_Hash_Node_Struct {
|
|
const void *item;
|
|
int id;
|
|
MR_bool written;
|
|
struct MR_Profiling_Hash_Node_Struct *next;
|
|
} MR_ProfilingHashNode;
|
|
|
|
typedef struct {
|
|
int last_id;
|
|
int length;
|
|
MR_ProfilingHashNode **nodes;
|
|
} MR_ProfilingHashTable;
|
|
|
|
static MR_ProfilingHashTable *MR_create_hash_table(int size);
|
|
|
|
static MR_bool MR_insert_proc_layout(
|
|
const MR_ProcLayout *pl, int *id,
|
|
MR_bool *already_written,
|
|
MR_bool init_written);
|
|
static MR_bool MR_insert_proc_dynamic(
|
|
const MR_ProcDynamic *pd, int *id,
|
|
MR_bool *already_written,
|
|
MR_bool init_written);
|
|
static MR_bool MR_insert_call_site_static(
|
|
const MR_CallSiteStatic *css, int *id,
|
|
MR_bool *already_written,
|
|
MR_bool init_written);
|
|
static MR_bool MR_insert_call_site_dynamic(
|
|
const MR_CallSiteDynamic *csd, int *id,
|
|
MR_bool *already_written,
|
|
MR_bool init_written);
|
|
|
|
static void MR_flag_written_proc_layout(
|
|
const MR_ProcLayout *pl);
|
|
static void MR_flag_written_proc_dynamic(
|
|
const MR_ProcDynamic *pd);
|
|
static void MR_flag_written_call_site_static(
|
|
const MR_CallSiteStatic *css);
|
|
static void MR_flag_written_call_site_dynamic(
|
|
const MR_CallSiteDynamic *csd);
|
|
|
|
static MR_ProfilingHashTable *MR_call_site_dynamic_table;
|
|
static MR_ProfilingHashTable *MR_call_site_static_table;
|
|
static MR_ProfilingHashTable *MR_proc_dynamic_table;
|
|
static MR_ProfilingHashTable *MR_proc_layout_table;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// A convenient prime for the size of the node hash tables.
|
|
// The compiler contains nearly 10,000 preds, so a width of 10007
|
|
// (requiring about 40K of storage - not onerous compared to the
|
|
// size of the tree) will yield chain lengths of about 1 for the
|
|
// MR_needed_proc_statics table. For the MR_seen_nodes table, which
|
|
// stores all the MR_ProcDynamic nodes that have been seen, the average
|
|
// chain length will be longer - a typical run of the compiler can have
|
|
// as many as 50,000 nodes, so we don't want the table any narrower than this.
|
|
|
|
static const int MR_hash_table_size = 10007;
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
static FILE *debug_fp;
|
|
#endif
|
|
|
|
#define MR_MDPROF_DATA_FILENAME "Deep.data"
|
|
#define MR_MDPROF_PROCREP_FILENAME "Deep.procrep"
|
|
|
|
void
|
|
MR_write_out_profiling_tree(void)
|
|
{
|
|
int root_pd_id;
|
|
FILE *deep_fp;
|
|
FILE *procrep_fp;
|
|
FILE *check_fp;
|
|
int ticks_per_sec;
|
|
unsigned num_call_seqs;
|
|
int64_t table_sizes_offset;
|
|
char errbuf[MR_STRERROR_BUF_SIZE];
|
|
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
int i;
|
|
#endif
|
|
|
|
deep_fp = fopen(MR_MDPROF_DATA_FILENAME, "wb+");
|
|
if (deep_fp == NULL) {
|
|
MR_fatal_error("cannot open `%s' for writing: %s",
|
|
MR_MDPROF_DATA_FILENAME,
|
|
MR_strerror(errno, errbuf, sizeof(errbuf)));
|
|
}
|
|
|
|
procrep_fp = fopen(MR_MDPROF_PROCREP_FILENAME, "wb+");
|
|
if (procrep_fp == NULL) {
|
|
MR_fatal_error("cannot open `%s' for writing: %s",
|
|
MR_MDPROF_PROCREP_FILENAME,
|
|
MR_strerror(errno, errbuf, sizeof(errbuf)));
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (MR_deep_prof_debug_file_flag) {
|
|
debug_fp = fopen("Deep.debug", "w");
|
|
if (debug_fp == NULL) {
|
|
debug_fp = stderr;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
MR_write_out_deep_id_string(deep_fp);
|
|
MR_write_out_program_name(deep_fp);
|
|
|
|
MR_write_out_deep_flags(deep_fp, MR_FALSE);
|
|
|
|
// We overwrite these zeros after seeking back to table_sizes_offset.
|
|
table_sizes_offset = MR_ftell(deep_fp);
|
|
if (table_sizes_offset == -1) {
|
|
MR_deep_data_output_error("ftell failed for ",
|
|
MR_MDPROF_DATA_FILENAME);
|
|
}
|
|
MR_write_fixed_size_int(deep_fp, 0);
|
|
MR_write_fixed_size_int(deep_fp, 0);
|
|
MR_write_fixed_size_int(deep_fp, 0);
|
|
MR_write_fixed_size_int(deep_fp, 0);
|
|
|
|
MR_write_out_procrep_id_string(procrep_fp);
|
|
|
|
#ifdef MR_CLOCK_TICKS_PER_SECOND
|
|
ticks_per_sec = MR_CLOCK_TICKS_PER_SECOND;
|
|
#else
|
|
ticks_per_sec = 0;
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_CALL_SEQ
|
|
num_call_seqs = MR_deep_prof_cur_call_seq;
|
|
#else
|
|
num_call_seqs = 0;
|
|
#endif
|
|
|
|
MR_write_num(deep_fp, ticks_per_sec);
|
|
MR_write_num(deep_fp, MR_quanta_inside_deep_profiling_code);
|
|
MR_write_num(deep_fp, MR_quanta_outside_deep_profiling_code);
|
|
MR_write_num(deep_fp, num_call_seqs);
|
|
|
|
MR_call_site_dynamic_table = MR_create_hash_table(MR_hash_table_size);
|
|
MR_call_site_static_table = MR_create_hash_table(MR_hash_table_size);
|
|
MR_proc_dynamic_table = MR_create_hash_table(MR_hash_table_size);
|
|
MR_proc_layout_table = MR_create_hash_table(MR_hash_table_size);
|
|
|
|
if (MR_insert_proc_dynamic(&MR_main_parent_proc_dynamic, &root_pd_id,
|
|
NULL, MR_FALSE))
|
|
{
|
|
MR_fatal_error("MR_write_out_profiling_tree: root seen before");
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "root = %p, %d\n",
|
|
&MR_main_parent_proc_dynamic, root_pd_id);
|
|
}
|
|
#endif
|
|
|
|
MR_write_ptr(deep_fp, kind_pd, root_pd_id);
|
|
|
|
MR_write_out_proc_dynamic(deep_fp, &MR_main_parent_proc_dynamic);
|
|
|
|
MR_write_out_user_proc_static(deep_fp, NULL, &MR_main_parent_proc_layout);
|
|
MR_deep_assert(NULL, NULL, NULL,
|
|
MR_address_of_write_out_proc_statics != NULL);
|
|
(*MR_address_of_write_out_proc_statics)(deep_fp, procrep_fp);
|
|
|
|
if (MR_fseek(deep_fp, table_sizes_offset, SEEK_SET) != 0) {
|
|
MR_deep_data_output_error("cannot seek to header of",
|
|
MR_MDPROF_DATA_FILENAME);
|
|
}
|
|
|
|
MR_write_fixed_size_int(deep_fp, MR_call_site_dynamic_table->last_id);
|
|
MR_write_fixed_size_int(deep_fp, MR_call_site_static_table->last_id);
|
|
MR_write_fixed_size_int(deep_fp, MR_proc_dynamic_table->last_id);
|
|
MR_write_fixed_size_int(deep_fp, MR_proc_layout_table->last_id);
|
|
|
|
if (fclose(deep_fp) != 0) {
|
|
MR_deep_data_output_error("cannot close", MR_MDPROF_DATA_FILENAME);
|
|
}
|
|
|
|
putc(MR_no_more_modules, procrep_fp);
|
|
if (fclose(procrep_fp) != 0) {
|
|
MR_deep_data_output_error("cannot close",
|
|
MR_MDPROF_PROCREP_FILENAME);
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
if (! MR_print_deep_profiling_statistics) {
|
|
return;
|
|
}
|
|
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_normal_new:",
|
|
MR_deep_prof_prep_normal_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_normal_old:",
|
|
MR_deep_prof_prep_normal_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_normal all:",
|
|
MR_deep_prof_prep_normal_new +
|
|
MR_deep_prof_prep_normal_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_special_new:",
|
|
MR_deep_prof_prep_special_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_special_old:",
|
|
MR_deep_prof_prep_special_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_special all:",
|
|
MR_deep_prof_prep_special_new +
|
|
MR_deep_prof_prep_special_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_ho_new:",
|
|
MR_deep_prof_prep_ho_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_ho_old:",
|
|
MR_deep_prof_prep_ho_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_ho all:",
|
|
MR_deep_prof_prep_ho_new +
|
|
MR_deep_prof_prep_ho_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_method_new:",
|
|
MR_deep_prof_prep_method_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_method_old:",
|
|
MR_deep_prof_prep_method_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_method all:",
|
|
MR_deep_prof_prep_method_new +
|
|
MR_deep_prof_prep_method_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_callback_new:",
|
|
MR_deep_prof_prep_callback_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_callback_old:",
|
|
MR_deep_prof_prep_callback_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_callback all:",
|
|
MR_deep_prof_prep_callback_new +
|
|
MR_deep_prof_prep_callback_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_tail_new:",
|
|
MR_deep_prof_prep_tail_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_tail_old:",
|
|
MR_deep_prof_prep_tail_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_prep_tail all:",
|
|
MR_deep_prof_prep_tail_new +
|
|
MR_deep_prof_prep_tail_old);
|
|
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_call_new:",
|
|
MR_deep_prof_call_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_call_rec:",
|
|
MR_deep_prof_call_rec);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_call_old:",
|
|
MR_deep_prof_call_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_call all:",
|
|
MR_deep_prof_call_new +
|
|
MR_deep_prof_call_rec +
|
|
MR_deep_prof_call_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_call_builtin_new:",
|
|
MR_deep_prof_call_builtin_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_call_builtin_old:",
|
|
MR_deep_prof_call_builtin_old);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"MR_deep_prof_call_builtin all:",
|
|
MR_deep_prof_call_builtin_new +
|
|
MR_deep_prof_call_builtin_old);
|
|
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"call prepare:",
|
|
MR_deep_prof_prep_normal_new +
|
|
MR_deep_prof_prep_normal_old +
|
|
MR_deep_prof_prep_special_new +
|
|
MR_deep_prof_prep_special_old +
|
|
MR_deep_prof_prep_ho_new +
|
|
MR_deep_prof_prep_ho_old +
|
|
MR_deep_prof_prep_method_new +
|
|
MR_deep_prof_prep_method_old +
|
|
MR_deep_prof_prep_callback_new +
|
|
MR_deep_prof_prep_callback_old +
|
|
MR_deep_prof_prep_tail_old +
|
|
MR_deep_prof_prep_tail_new);
|
|
fprintf(stderr, "%-40s %10d\n",
|
|
"call arrival:",
|
|
MR_deep_prof_prep_tail_old +
|
|
MR_deep_prof_prep_tail_new +
|
|
MR_deep_prof_call_new +
|
|
MR_deep_prof_call_rec +
|
|
MR_deep_prof_call_old +
|
|
MR_deep_prof_call_builtin_new +
|
|
MR_deep_prof_call_builtin_old);
|
|
|
|
fprintf(stderr, "\ntotal size of profiling tree: %10d bytes\n",
|
|
MR_deep_num_csd_nodes * sizeof(MR_CallSiteDynamic) +
|
|
MR_deep_num_pd_nodes * sizeof(MR_ProcDynamic) +
|
|
MR_deep_num_pd_array_slots * sizeof(MR_CallSiteDynamic *) +
|
|
MR_deep_num_dynlist_nodes * sizeof(MR_CallSiteDynList));
|
|
fprintf(stderr, "%10d CSD nodes at %4d bytes per node: %10d bytes\n",
|
|
MR_deep_num_csd_nodes,
|
|
sizeof(MR_CallSiteDynamic),
|
|
MR_deep_num_csd_nodes * sizeof(MR_CallSiteDynamic));
|
|
fprintf(stderr, "%10d PD nodes at %4d bytes per node: %10d bytes\n",
|
|
MR_deep_num_pd_nodes,
|
|
sizeof(MR_ProcDynamic),
|
|
MR_deep_num_pd_nodes * sizeof(MR_ProcDynamic));
|
|
fprintf(stderr, "%10d array slots at %4d bytes per node: %10d bytes\n",
|
|
MR_deep_num_pd_array_slots,
|
|
sizeof(MR_CallSiteDynamic *),
|
|
MR_deep_num_pd_array_slots * sizeof(MR_CallSiteDynamic *));
|
|
fprintf(stderr, "%10d list nodes at %4d bytes per node: %10d bytes\n",
|
|
MR_deep_num_dynlist_nodes,
|
|
sizeof(MR_CallSiteDynList),
|
|
MR_deep_num_dynlist_nodes * sizeof(MR_CallSiteDynList));
|
|
|
|
fprintf(stderr, "\nTypeInfo search length histogram:\n");
|
|
for (i = 0; i < MR_MAX_CLOSURE_LIST_LENGTH; i++) {
|
|
if (MR_dictionary_search_lengths[i] > 0) {
|
|
fprintf(stderr, "\t%3d: %12d\n", i,
|
|
MR_dictionary_search_lengths[i]);
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "\nClosure search length histogram:\n");
|
|
for (i = 0; i < MR_MAX_CLOSURE_LIST_LENGTH; i++) {
|
|
if (MR_closure_search_lengths[i] > 0) {
|
|
fprintf(stderr, "\t%3d: %12d\n", i, MR_closure_search_lengths[i]);
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "\nMethod search length histogram:\n");
|
|
for (i = 0; i < MR_MAX_CLOSURE_LIST_LENGTH; i++) {
|
|
if (MR_method_search_lengths[i] > 0) {
|
|
fprintf(stderr, "\t%3d: %12d\n", i, MR_method_search_lengths[i]);
|
|
}
|
|
}
|
|
#endif // MR_DEEP_PROFILING_STATISTICS
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
check_fp = debug_fp;
|
|
#else
|
|
check_fp = NULL;
|
|
#endif
|
|
|
|
MR_write_out_profiling_tree_check_unwritten(check_fp);
|
|
}
|
|
|
|
static void
|
|
MR_deep_data_output_error(const char *op, const char *filename)
|
|
{
|
|
char errbuf[MR_STRERROR_BUF_SIZE];
|
|
|
|
MR_warning("%s %s: %s", op, filename,
|
|
MR_strerror(errno, errbuf, sizeof(errbuf)));
|
|
|
|
// An incomplete profiling data file is useless. Removing it prevents
|
|
// misunderstandings about that, and may also cure a disk-full condition,
|
|
// if the close failure was caused by that.
|
|
|
|
if (remove(MR_MDPROF_DATA_FILENAME) != 0) {
|
|
MR_warning("cannot remove %s: %s",
|
|
MR_MDPROF_DATA_FILENAME,
|
|
MR_strerror(errno, errbuf, sizeof(errbuf)));
|
|
}
|
|
|
|
if (remove(MR_MDPROF_PROCREP_FILENAME) != 0) {
|
|
MR_warning("cannot remove %s: %s",
|
|
MR_MDPROF_PROCREP_FILENAME,
|
|
MR_strerror(errno, errbuf, sizeof(errbuf)));
|
|
}
|
|
|
|
exit(1);
|
|
}
|
|
|
|
static void
|
|
MR_write_out_deep_id_string(FILE *fp)
|
|
{
|
|
// Must be the same as deep_id_string in deep_profiler/read_profile.m
|
|
const char *id_string = "Mercury deep profiler data version 8\n";
|
|
|
|
fputs(id_string, fp);
|
|
}
|
|
|
|
static void
|
|
MR_write_out_program_name(FILE *fp)
|
|
{
|
|
MR_write_string(fp, MR_progname);
|
|
}
|
|
|
|
// Flags in the deep profiler data file's header. Any bit without a meaning
|
|
// here must be set to zero as it it may be used in the future. The next line
|
|
// marks 16 bit boundaries in the 64 bit flags value:
|
|
//
|
|
// 48 32 16 0
|
|
|
|
#define MR_DEEP_FLAG_WORDSIZE_MASK \
|
|
(0x00000000000000FF)
|
|
#define MR_DEEP_FLAG_WORDSIZE_SHIFT \
|
|
(0)
|
|
#define MR_DEEP_FLAG_CANONICAL_MASK \
|
|
(0x0000000000000300)
|
|
#define MR_DEEP_FLAG_CANONICAL_SHIFT \
|
|
(8)
|
|
#define MR_DEEP_FLAG_COMPRESSION_MASK \
|
|
(0x0000000000000C00)
|
|
#define MR_DEEP_FLAG_COMPRESSION_SHIFT \
|
|
(10)
|
|
// This flag is two bits wide as it has three valid values.
|
|
#define MR_DEEP_FLAG_COVERAGE_DATA_TYPE_MASK \
|
|
(0x0000000000003000)
|
|
#define MR_DEEP_FLAG_COVERAGE_DATA_TYPE_SHIFT \
|
|
(12)
|
|
|
|
#if !defined(MR_DEEP_PROFILING_COVERAGE)
|
|
#define MR_DEEP_FLAG_COVERAGE_DATA_TYPE_VALUE 0
|
|
#elif defined(MR_DEEP_PROFILING_COVERAGE_STATIC)
|
|
#define MR_DEEP_FLAG_COVERAGE_DATA_TYPE_VALUE 1
|
|
#elif defined(MR_DEEP_PROFILING_COVERAGE_DYNAMIC)
|
|
#define MR_DEEP_FLAG_COVERAGE_DATA_TYPE_VALUE 2
|
|
#endif
|
|
|
|
static void
|
|
MR_write_out_deep_flags(FILE *fp, MR_bool compress)
|
|
{
|
|
MR_uint_least64_t flags = 0;
|
|
|
|
flags |= MR_DEEP_FLAG_WORDSIZE_MASK &
|
|
(sizeof(MR_Word) << MR_DEEP_FLAG_WORDSIZE_SHIFT);
|
|
|
|
flags |= MR_DEEP_FLAG_CANONICAL_MASK &
|
|
(1 << MR_DEEP_FLAG_CANONICAL_SHIFT);
|
|
|
|
// ignore compress for now
|
|
|
|
flags |= MR_DEEP_FLAG_COVERAGE_DATA_TYPE_MASK &
|
|
(MR_DEEP_FLAG_COVERAGE_DATA_TYPE_VALUE <<
|
|
MR_DEEP_FLAG_COVERAGE_DATA_TYPE_SHIFT);
|
|
|
|
MR_write_fixed_size_int(fp, flags);
|
|
}
|
|
|
|
static void
|
|
MR_write_out_procrep_id_string(FILE *fp)
|
|
{
|
|
// Must be the same as procrep_id_string (or new_procrep_id_string) in
|
|
// mdbcomp/program_representation.m.
|
|
|
|
const char *id_string = "Mercury deep profiler procrep version 6\n";
|
|
|
|
fputs(id_string, fp);
|
|
}
|
|
|
|
void
|
|
MR_write_out_user_proc_static(FILE *deep_fp, FILE *procrep_fp,
|
|
const MR_ProcLayoutUser *proc_layout)
|
|
{
|
|
MR_write_out_proc_static(deep_fp, procrep_fp,
|
|
(const MR_ProcLayout *) proc_layout);
|
|
}
|
|
|
|
void
|
|
MR_write_out_uci_proc_static(FILE *deep_fp, FILE *procrep_fp,
|
|
const MR_ProcLayoutUCI *proc_layout)
|
|
{
|
|
MR_write_out_proc_static(deep_fp, procrep_fp,
|
|
(const MR_ProcLayout *) proc_layout);
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_LOG
|
|
MR_bool MR_deep_prof_doing_logging = MR_FALSE;
|
|
|
|
void
|
|
MR_deep_log_proc_statics(FILE *fp)
|
|
{
|
|
MR_deep_prof_doing_logging = MR_TRUE;
|
|
(*MR_address_of_write_out_proc_statics)(fp);
|
|
MR_deep_prof_doing_logging = MR_FALSE;
|
|
}
|
|
#endif // MR_DEEP_PROFILING_LOG
|
|
|
|
void
|
|
MR_write_out_module_proc_reps_start(FILE *procrep_fp,
|
|
const MR_ModuleLayout *module_layout)
|
|
{
|
|
const MR_uint_least8_t *oisu_bytecode;
|
|
const MR_uint_least8_t *type_bytecode;
|
|
int size;
|
|
int bytenum;
|
|
|
|
putc(MR_next_module, procrep_fp);
|
|
MR_write_string(procrep_fp, module_layout->MR_ml_name);
|
|
|
|
MR_write_num(procrep_fp, module_layout->MR_ml_string_table_size);
|
|
size = module_layout->MR_ml_string_table_size;
|
|
for (bytenum = 0; bytenum < size; bytenum++) {
|
|
putc(module_layout->MR_ml_string_table[bytenum], procrep_fp);
|
|
}
|
|
|
|
MR_write_num(procrep_fp, module_layout->MR_ml_num_oisu_types);
|
|
oisu_bytecode = module_layout->MR_ml_oisu_bytes;
|
|
if (module_layout->MR_ml_num_oisu_types == 0) {
|
|
if (oisu_bytecode != NULL) {
|
|
MR_fatal_error("num_oisu_types == 0 but bytecode != NULL");
|
|
}
|
|
} else {
|
|
if (oisu_bytecode == NULL) {
|
|
MR_fatal_error("num_oisu_types != 0 but bytecode == NULL");
|
|
}
|
|
|
|
size = (oisu_bytecode[0] << 24) + (oisu_bytecode[1] << 16) +
|
|
(oisu_bytecode[2] << 8) + oisu_bytecode[3];
|
|
for (bytenum = 0; bytenum < size; bytenum++) {
|
|
putc(oisu_bytecode[bytenum], procrep_fp);
|
|
}
|
|
}
|
|
|
|
MR_write_num(procrep_fp, module_layout->MR_ml_num_table_types);
|
|
type_bytecode = module_layout->MR_ml_type_table_bytes;
|
|
if (module_layout->MR_ml_num_table_types == 0) {
|
|
if (type_bytecode != NULL) {
|
|
MR_fatal_error("num_types == 0 but bytecode != NULL");
|
|
}
|
|
} else {
|
|
if (type_bytecode == NULL) {
|
|
MR_fatal_error("num_types != 0 but bytecode == NULL");
|
|
}
|
|
|
|
size = (type_bytecode[0] << 24) + (type_bytecode[1] << 16) +
|
|
(type_bytecode[2] << 8) + type_bytecode[3];
|
|
for (bytenum = 0; bytenum < size; bytenum++) {
|
|
putc(type_bytecode[bytenum], procrep_fp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MR_write_out_module_proc_reps_end(FILE *procrep_fp)
|
|
{
|
|
putc(MR_no_more_procs, procrep_fp);
|
|
}
|
|
|
|
void
|
|
MR_write_out_proc_static(FILE *deep_fp, FILE *procrep_fp,
|
|
const MR_ProcLayout *proc_layout)
|
|
{
|
|
const MR_ProcStatic *ps;
|
|
const MR_ProcId *procid;
|
|
int ps_id;
|
|
int css_id;
|
|
MR_bool already_written;
|
|
int i;
|
|
|
|
if (proc_layout == NULL) {
|
|
MR_fatal_error("MR_write_out_proc_static: null proc_layout");
|
|
}
|
|
|
|
if (! MR_PROC_LAYOUT_HAS_PROC_ID(proc_layout)) {
|
|
MR_fatal_error("MR_write_out_proc_static: no proc_id\n");
|
|
}
|
|
|
|
ps = proc_layout->MR_sle_proc_static;
|
|
|
|
#ifdef MR_DEEP_PROFILING_LOG
|
|
if (MR_deep_prof_doing_logging) {
|
|
procid = &proc_layout->MR_sle_proc_id;
|
|
if (MR_PROC_ID_IS_UCI(*procid)) {
|
|
fprintf(deep_fp,
|
|
"proc_static_uci(%ld,\"%s\",\"%s\",\"%s\",\"%s\",%d,%d,[",
|
|
(long) proc_layout->MR_sle_proc_static,
|
|
procid->MR_proc_uci.MR_uci_type_name,
|
|
procid->MR_proc_uci.MR_uci_type_module,
|
|
procid->MR_proc_uci.MR_uci_def_module,
|
|
procid->MR_proc_uci.MR_uci_pred_name,
|
|
procid->MR_proc_uci.MR_uci_type_arity,
|
|
procid->MR_proc_uci.MR_uci_mode);
|
|
} else {
|
|
fprintf(deep_fp,
|
|
"proc_static_user(%ld,%s,\"%s\",\"%s\",\"%s\",%d,%d,[",
|
|
(long) proc_layout->MR_sle_proc_static,
|
|
procid->MR_proc_user.MR_user_pred_or_func == MR_PREDICATE ?
|
|
"p" : "f",
|
|
procid->MR_proc_user.MR_user_decl_module,
|
|
procid->MR_proc_user.MR_user_def_module,
|
|
procid->MR_proc_user.MR_user_name,
|
|
procid->MR_proc_user.MR_user_pred_form_arity,
|
|
procid->MR_proc_user.MR_user_mode);
|
|
}
|
|
|
|
for (i = 0; i < ps->MR_ps_num_call_sites; i++) {
|
|
if (i == 0) {
|
|
fputs("\n\t", deep_fp);
|
|
} else {
|
|
fputs(",\n\t", deep_fp);
|
|
}
|
|
|
|
switch (ps->MR_ps_call_sites[i].MR_css_kind) {
|
|
case MR_normal_call:
|
|
fprintf(deep_fp, "css_normal(%ld, %ld)",
|
|
(long) &ps->MR_ps_call_sites[i],
|
|
(long) &ps->MR_ps_call_sites[i].
|
|
MR_css_callee_ptr_if_known->MR_sle_proc_static);
|
|
break;
|
|
|
|
case MR_special_call:
|
|
fprintf(deep_fp, "css_special(%ld)",
|
|
(long) &ps->MR_ps_call_sites[i]);
|
|
break;
|
|
|
|
case MR_higher_order_call:
|
|
fprintf(deep_fp, "css_higher_order(%ld)",
|
|
(long) &ps->MR_ps_call_sites[i]);
|
|
break;
|
|
|
|
case MR_method_call:
|
|
fprintf(deep_fp, "css_method(%ld)",
|
|
(long) &ps->MR_ps_call_sites[i]);
|
|
break;
|
|
|
|
case MR_callback:
|
|
fprintf(deep_fp, "css_callback(%ld)",
|
|
(long) &ps->MR_ps_call_sites[i]);
|
|
break;
|
|
|
|
default:
|
|
fprintf(deep_fp, "css_unknown(%ld)",
|
|
(long) &ps->MR_ps_call_sites[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
fprintf(deep_fp, "]).\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (ps == NULL) {
|
|
procid = &proc_layout->MR_sle_proc_id;
|
|
if (MR_PROC_ID_IS_UCI(*procid)) {
|
|
fprintf(stderr, "uci %s/%s/%s/%s/%d/%d\n",
|
|
procid->MR_proc_uci.MR_uci_type_name,
|
|
procid->MR_proc_uci.MR_uci_type_module,
|
|
procid->MR_proc_uci.MR_uci_def_module,
|
|
procid->MR_proc_uci.MR_uci_pred_name,
|
|
procid->MR_proc_uci.MR_uci_type_arity,
|
|
procid->MR_proc_uci.MR_uci_mode);
|
|
} else {
|
|
fprintf(stderr, "user %d/%s/%s/%s/%d/%d\n",
|
|
procid->MR_proc_user.MR_user_pred_or_func,
|
|
procid->MR_proc_user.MR_user_decl_module,
|
|
procid->MR_proc_user.MR_user_def_module,
|
|
procid->MR_proc_user.MR_user_name,
|
|
procid->MR_proc_user.MR_user_pred_form_arity,
|
|
procid->MR_proc_user.MR_user_mode);
|
|
}
|
|
|
|
MR_fatal_error("MR_write_out_proc_static: null ps");
|
|
}
|
|
|
|
(void) MR_insert_proc_layout(proc_layout, &ps_id, &already_written,
|
|
MR_TRUE);
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "proc_static %p/%p/%d\n", proc_layout, ps, ps_id);
|
|
fprintf(debug_fp, " filename \"%s\", linenumber %d, "
|
|
"interface %d, %d call sites\n",
|
|
ps->MR_ps_file_name, ps->MR_ps_line_number,
|
|
ps->MR_ps_is_in_interface, ps->MR_ps_num_call_sites);
|
|
}
|
|
#endif
|
|
|
|
if (already_written) {
|
|
MR_fatal_error("MR_write_out_proc_static: seen ps");
|
|
}
|
|
|
|
MR_flag_written_proc_layout(proc_layout);
|
|
|
|
MR_write_byte(deep_fp, MR_deep_item_proc_static);
|
|
MR_write_ptr(deep_fp, kind_ps, ps_id);
|
|
|
|
procid = &proc_layout->MR_sle_proc_id;
|
|
MR_write_out_str_proc_label(deep_fp, procid);
|
|
|
|
MR_write_string(deep_fp, ps->MR_ps_file_name);
|
|
MR_write_num(deep_fp, ps->MR_ps_line_number);
|
|
MR_write_byte(deep_fp, ps->MR_ps_is_in_interface);
|
|
MR_write_num(deep_fp, ps->MR_ps_num_call_sites);
|
|
|
|
// Write out pointers to Call Site Statics. These are read in with the
|
|
// proc static.
|
|
|
|
for (i = 0; i < ps->MR_ps_num_call_sites; i++) {
|
|
(void) MR_insert_call_site_static(&ps->MR_ps_call_sites[i], &css_id,
|
|
NULL, MR_FALSE);
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp,
|
|
"call site id %d in proc_static %p/%p/%d -> %d\n",
|
|
i, proc_layout, ps, ps_id, css_id);
|
|
}
|
|
#endif
|
|
|
|
MR_write_ptr(deep_fp, kind_css, css_id);
|
|
}
|
|
|
|
// Write out coverage points. This is read in as part of the proc static.
|
|
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE
|
|
MR_write_out_coverage_points_static(deep_fp, ps);
|
|
#endif
|
|
|
|
// Write out the actual call site statics, These are read in after the
|
|
// proc static, not as part of it.
|
|
|
|
for (i = 0; i < ps->MR_ps_num_call_sites; i++) {
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "in proc_static %p/%p/%d, call site %d\n",
|
|
proc_layout, ps, ps_id, i);
|
|
}
|
|
#endif
|
|
|
|
MR_write_out_call_site_static(deep_fp, &ps->MR_ps_call_sites[i]);
|
|
}
|
|
|
|
const MR_uint_least8_t *bytecode;
|
|
|
|
// Some predicates in the Mercury standard library, such as
|
|
// exception.builtin_catch, have Mercury declarations but no Mercury
|
|
// implementation, even as foreign_proc code. We do still generate
|
|
// proc_static structures for them, since we *want* the hand-written
|
|
// C code to be able to collect deep profiling data (in this case,
|
|
// to count the number of executions of the EXCP port). This means that
|
|
// (a) they will have proc_layout structures, and (b) the bytecode
|
|
// pointer field in these structures will be NULL.
|
|
//
|
|
// We handle such procedures by simply not including them in the
|
|
// module representation. This is fine, as long as any code that reads
|
|
// and processes the program representation is aware that the bodies
|
|
// of procedures defined outside Mercury may be missing.
|
|
|
|
bytecode = proc_layout->MR_sle_body_bytes;
|
|
if (bytecode != NULL) {
|
|
int size;
|
|
int bytenum;
|
|
|
|
putc(MR_next_proc, procrep_fp);
|
|
MR_write_out_str_proc_label(procrep_fp, procid);
|
|
|
|
size = (bytecode[0] << 24) + (bytecode[1] << 16) +
|
|
(bytecode[2] << 8) + bytecode[3];
|
|
for (bytenum = 0; bytenum < size; bytenum++) {
|
|
putc(bytecode[bytenum], procrep_fp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MR_write_out_str_proc_label(FILE *deep_fp, const MR_ProcId *procid)
|
|
{
|
|
if (MR_PROC_ID_IS_UCI(*procid)) {
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, " uci %s/%s/%s/%s/%d/%d\n",
|
|
procid->MR_proc_uci.MR_uci_type_name,
|
|
procid->MR_proc_uci.MR_uci_type_module,
|
|
procid->MR_proc_uci.MR_uci_def_module,
|
|
procid->MR_proc_uci.MR_uci_pred_name,
|
|
procid->MR_proc_uci.MR_uci_type_arity,
|
|
procid->MR_proc_uci.MR_uci_mode);
|
|
}
|
|
#endif
|
|
|
|
MR_write_byte(deep_fp, MR_proclabel_special);
|
|
MR_write_string(deep_fp, procid->MR_proc_uci.MR_uci_type_name);
|
|
MR_write_string(deep_fp, procid->MR_proc_uci.MR_uci_type_module);
|
|
MR_write_string(deep_fp, procid->MR_proc_uci.MR_uci_def_module);
|
|
MR_write_string(deep_fp, procid->MR_proc_uci.MR_uci_pred_name);
|
|
MR_write_num(deep_fp, procid->MR_proc_uci.MR_uci_type_arity);
|
|
MR_write_num(deep_fp, procid->MR_proc_uci.MR_uci_mode);
|
|
} else {
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, " user %d/%s/%s/%s/%d/%d\n",
|
|
procid->MR_proc_user.MR_user_pred_or_func,
|
|
procid->MR_proc_user.MR_user_decl_module,
|
|
procid->MR_proc_user.MR_user_def_module,
|
|
procid->MR_proc_user.MR_user_name,
|
|
procid->MR_proc_user.MR_user_pred_form_arity,
|
|
procid->MR_proc_user.MR_user_mode);
|
|
}
|
|
#endif
|
|
|
|
if (procid->MR_proc_user.MR_user_pred_or_func == MR_PREDICATE) {
|
|
MR_write_byte(deep_fp, MR_proclabel_user_predicate);
|
|
} else {
|
|
MR_write_byte(deep_fp, MR_proclabel_user_function);
|
|
}
|
|
|
|
MR_write_string(deep_fp, procid->MR_proc_user.MR_user_decl_module);
|
|
MR_write_string(deep_fp, procid->MR_proc_user.MR_user_def_module);
|
|
MR_write_string(deep_fp, procid->MR_proc_user.MR_user_name);
|
|
MR_write_num(deep_fp, procid->MR_proc_user.MR_user_pred_form_arity);
|
|
MR_write_num(deep_fp, procid->MR_proc_user.MR_user_mode);
|
|
}
|
|
}
|
|
|
|
static void
|
|
MR_write_out_call_site_static(FILE *fp, const MR_CallSiteStatic *css)
|
|
{
|
|
int css_id;
|
|
int ps_id;
|
|
MR_bool already_written;
|
|
|
|
if (css == NULL) {
|
|
MR_fatal_error("MR_write_out_call_site_static: null css");
|
|
}
|
|
|
|
(void) MR_insert_call_site_static(css, &css_id, &already_written, MR_TRUE);
|
|
|
|
if (already_written) {
|
|
MR_fatal_error("MR_write_out_call_site_static: seen css");
|
|
fflush(fp);
|
|
}
|
|
|
|
MR_flag_written_call_site_static(css);
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "call_site_static %p/%d\n", css, css_id);
|
|
fprintf(debug_fp,
|
|
" filename \"%s\", linenum %d, goal path %s, kind %d\n",
|
|
css->MR_css_file_name, css->MR_css_line_number,
|
|
css->MR_css_goal_path, css->MR_css_kind);
|
|
}
|
|
#endif
|
|
|
|
MR_write_byte(fp, MR_deep_item_call_site_static);
|
|
MR_write_ptr(fp, kind_css, css_id);
|
|
MR_write_kind(fp, css->MR_css_kind);
|
|
if (css->MR_css_kind == MR_callsite_normal_call) {
|
|
(void) MR_insert_proc_layout(css->MR_css_callee_ptr_if_known, &ps_id,
|
|
NULL, MR_FALSE);
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, " callee %p/%d\n",
|
|
css->MR_css_callee_ptr_if_known, ps_id);
|
|
}
|
|
#endif
|
|
MR_write_num(fp, ps_id);
|
|
if (css->MR_css_type_subst_if_known != NULL) {
|
|
MR_write_string(fp, css->MR_css_type_subst_if_known);
|
|
} else {
|
|
MR_write_string(fp, "");
|
|
}
|
|
}
|
|
// XXX MR_css_file_name
|
|
MR_write_num(fp, css->MR_css_line_number);
|
|
MR_write_string(fp, css->MR_css_goal_path);
|
|
}
|
|
|
|
static void
|
|
MR_write_out_call_site_dynamic(FILE *fp, const MR_CallSiteDynamic *csd)
|
|
{
|
|
int bitmask = 0;
|
|
int csd_id;
|
|
int pd_id;
|
|
|
|
if (csd == NULL) {
|
|
return;
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
MR_deep_num_csd_nodes++;
|
|
#endif
|
|
|
|
MR_deep_assert(csd, NULL, NULL, csd->MR_csd_callee_ptr != NULL);
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "call_site_dynamic %p: callee proc_dynamic %p\n",
|
|
csd, csd->MR_csd_callee_ptr);
|
|
}
|
|
#endif
|
|
|
|
MR_write_byte(fp, MR_deep_item_call_site_dynamic);
|
|
if (! MR_insert_call_site_dynamic(csd, &csd_id, NULL, MR_FALSE)) {
|
|
MR_fatal_error("MR_write_out_call_site_dynamic: insert succeeded");
|
|
}
|
|
|
|
MR_flag_written_call_site_dynamic(csd);
|
|
|
|
MR_write_ptr(fp, kind_csd, csd_id);
|
|
if (csd->MR_csd_callee_ptr == NULL) {
|
|
pd_id = 0;
|
|
} else {
|
|
(void) MR_insert_proc_dynamic(csd->MR_csd_callee_ptr, &pd_id, NULL,
|
|
MR_FALSE);
|
|
}
|
|
|
|
MR_write_ptr(fp, kind_pd, pd_id);
|
|
|
|
// The masks here must exactly correspond with the masks in
|
|
// predicate read_profile in deep_profiler/read_profile.m.
|
|
|
|
#ifdef MR_DEEP_PROFILING_PORT_COUNTS
|
|
#ifdef MR_DEEP_PROFILING_EXPLICIT_CALL_COUNTS
|
|
if (csd->MR_csd_own.MR_own_calls != 0) {
|
|
bitmask |= 0x0001;
|
|
}
|
|
#endif
|
|
if (csd->MR_csd_own.MR_own_exits != 0) {
|
|
bitmask |= 0x0002;
|
|
}
|
|
if (csd->MR_csd_own.MR_own_fails != 0) {
|
|
bitmask |= 0x0004;
|
|
}
|
|
if (csd->MR_csd_own.MR_own_redos != 0) {
|
|
bitmask |= 0x0040;
|
|
}
|
|
if (csd->MR_csd_own.MR_own_excps != 0) {
|
|
bitmask |= 0x0080;
|
|
}
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_TIMING
|
|
if (csd->MR_csd_own.MR_own_quanta != 0) {
|
|
bitmask |= 0x0100;
|
|
}
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_CALL_SEQ
|
|
if (csd->MR_csd_own.MR_own_call_seqs != 0) {
|
|
bitmask |= 0x0008;
|
|
}
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_MEMORY
|
|
if (csd->MR_csd_own.MR_own_allocs != 0) {
|
|
bitmask |= 0x0010;
|
|
}
|
|
if (csd->MR_csd_own.MR_own_words != 0) {
|
|
bitmask |= 0x0020;
|
|
}
|
|
#endif
|
|
|
|
MR_write_num(fp, bitmask);
|
|
|
|
#ifdef MR_DEEP_PROFILING_PORT_COUNTS
|
|
#ifdef MR_DEEP_PROFILING_EXPLICIT_CALL_COUNTS
|
|
if (csd->MR_csd_own.MR_own_calls != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_calls);
|
|
}
|
|
#endif
|
|
if (csd->MR_csd_own.MR_own_exits != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_exits);
|
|
}
|
|
if (csd->MR_csd_own.MR_own_fails != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_fails);
|
|
}
|
|
if (csd->MR_csd_own.MR_own_redos != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_redos);
|
|
}
|
|
if (csd->MR_csd_own.MR_own_excps != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_excps);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MR_DEEP_PROFILING_TIMING
|
|
if (csd->MR_csd_own.MR_own_quanta != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_quanta);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MR_DEEP_PROFILING_CALL_SEQ
|
|
if (csd->MR_csd_own.MR_own_call_seqs != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_call_seqs);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MR_DEEP_PROFILING_MEMORY
|
|
if (csd->MR_csd_own.MR_own_allocs != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_allocs);
|
|
}
|
|
if (csd->MR_csd_own.MR_own_words != 0) {
|
|
MR_write_num(fp, csd->MR_csd_own.MR_own_words);
|
|
}
|
|
#endif
|
|
|
|
MR_write_out_proc_dynamic(fp, csd->MR_csd_callee_ptr);
|
|
}
|
|
|
|
static void
|
|
MR_write_out_proc_dynamic(FILE *fp, const MR_ProcDynamic *pd)
|
|
{
|
|
const MR_ProcStatic *ps;
|
|
const MR_ProcLayout *pl;
|
|
int pd_id;
|
|
int ps_id;
|
|
MR_bool already_written;
|
|
int i;
|
|
|
|
if (pd == NULL) {
|
|
// This shouldn't really happen except that we don't have
|
|
// correct handling of nondet pragma_foreign_code yet.
|
|
|
|
return;
|
|
}
|
|
|
|
if (! MR_insert_proc_dynamic(pd, &pd_id, &already_written, MR_TRUE)) {
|
|
MR_fatal_error("MR_write_out_proc_dynamic: unseen pd");
|
|
}
|
|
|
|
if (already_written) {
|
|
return;
|
|
}
|
|
|
|
pl = pd->MR_pd_proc_layout;
|
|
ps = pl->MR_sle_proc_static;
|
|
|
|
MR_flag_written_proc_dynamic(pd);
|
|
(void) MR_insert_proc_layout(pl, &ps_id, NULL, MR_FALSE);
|
|
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
MR_deep_num_pd_nodes++;
|
|
MR_deep_num_pd_array_slots += ps->MR_ps_num_call_sites;
|
|
#endif
|
|
|
|
MR_write_byte(fp, MR_deep_item_proc_dynamic);
|
|
MR_write_ptr(fp, kind_pd, pd_id);
|
|
MR_write_ptr(fp, kind_ps, ps_id);
|
|
MR_write_num(fp, ps->MR_ps_num_call_sites);
|
|
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "proc_dynamic %p/%d, proc_static %p/%p/%d\n",
|
|
pd, pd_id, pd->MR_pd_proc_layout, ps, ps_id);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE
|
|
MR_write_out_coverage_points_dynamic(fp, pd);
|
|
#endif
|
|
|
|
for (i = 0; i < ps->MR_ps_num_call_sites; i++) {
|
|
MR_write_kind(fp, ps->MR_ps_call_sites[i].MR_css_kind);
|
|
switch (ps->MR_ps_call_sites[i].MR_css_kind)
|
|
{
|
|
case MR_callsite_normal_call:
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp,
|
|
" normal call from pd %p to pd %p\n",
|
|
pd, pd->MR_pd_call_site_ptr_ptrs[i]);
|
|
}
|
|
#endif
|
|
MR_write_csd_ptr(fp, pd->MR_pd_call_site_ptr_ptrs[i]);
|
|
break;
|
|
|
|
case MR_callsite_special_call:
|
|
case MR_callsite_higher_order_call:
|
|
case MR_callsite_method_call:
|
|
case MR_callsite_callback:
|
|
MR_write_out_ho_call_site_ptrs(fp, pd,
|
|
(MR_CallSiteDynList *) pd->MR_pd_call_site_ptr_ptrs[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ps->MR_ps_num_call_sites; i++) {
|
|
switch (ps->MR_ps_call_sites[i].MR_css_kind)
|
|
{
|
|
case MR_callsite_normal_call:
|
|
MR_write_out_call_site_dynamic(fp,
|
|
pd->MR_pd_call_site_ptr_ptrs[i]);
|
|
break;
|
|
|
|
case MR_callsite_special_call:
|
|
case MR_callsite_higher_order_call:
|
|
case MR_callsite_method_call:
|
|
case MR_callsite_callback:
|
|
MR_write_out_ho_call_site_nodes(fp,
|
|
(MR_CallSiteDynList *) pd->MR_pd_call_site_ptr_ptrs[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
MR_write_out_ho_call_site_ptrs(FILE *fp, const MR_ProcDynamic *pd,
|
|
const MR_CallSiteDynList *dynlist)
|
|
{
|
|
while (dynlist != NULL) {
|
|
#ifdef MR_DEEP_PROFILING_STATISTICS
|
|
MR_deep_num_dynlist_nodes++;
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, " multi call from pd %p to pd %p\n",
|
|
pd, dynlist->MR_csdlist_call_site);
|
|
}
|
|
#endif
|
|
MR_write_csd_ptr(fp, dynlist->MR_csdlist_call_site);
|
|
dynlist = dynlist->MR_csdlist_next;
|
|
}
|
|
MR_write_byte(fp, MR_deep_item_end);
|
|
}
|
|
|
|
static void
|
|
MR_write_out_ho_call_site_nodes(FILE *fp, MR_CallSiteDynList *dynlist)
|
|
{
|
|
while (dynlist != NULL) {
|
|
MR_write_out_call_site_dynamic(fp, dynlist->MR_csdlist_call_site);
|
|
dynlist = dynlist->MR_csdlist_next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
MR_write_csd_ptr(FILE *fp, const MR_CallSiteDynamic *csd)
|
|
{
|
|
int csd_id;
|
|
|
|
if (csd == NULL) {
|
|
csd_id = 0;
|
|
} else {
|
|
(void) MR_insert_call_site_dynamic(csd, &csd_id, NULL, MR_FALSE);
|
|
}
|
|
|
|
MR_write_ptr(fp, kind_csd, csd_id);
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE
|
|
static void
|
|
MR_write_out_coverage_points_static(FILE *fp, const MR_ProcStatic *ps)
|
|
{
|
|
const MR_CoveragePointStatic *cps_static;
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE_STATIC
|
|
const MR_Unsigned *cps;
|
|
#endif
|
|
unsigned int i;
|
|
|
|
cps_static = ps->MR_ps_coverage_points_static;
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE_STATIC
|
|
cps = ps->MR_ps_coverage_points;
|
|
#endif
|
|
|
|
MR_write_num(fp, ps->MR_ps_num_coverage_points);
|
|
for (i = 0; i < ps->MR_ps_num_coverage_points; i++) {
|
|
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "coverage point: %s,%d",
|
|
cps_static[i].MR_cp_goal_path, cps_static[i].MR_cp_type);
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE_STATIC
|
|
fprintf(debug_fp, ": %d\n", cps[i]);
|
|
#else
|
|
fprintf(debug_fp, "\n");
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
MR_write_string(fp, cps_static[i].MR_cp_goal_path);
|
|
MR_write_num(fp, cps_static[i].MR_cp_type);
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE_STATIC
|
|
MR_write_num(fp, cps[i]);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void
|
|
MR_write_out_coverage_points_dynamic(FILE *fp, const MR_ProcDynamic *pd)
|
|
{
|
|
#ifdef MR_DEEP_PROFILING_COVERAGE_DYNAMIC
|
|
const MR_Unsigned *cps;
|
|
unsigned int i;
|
|
unsigned int ncps;
|
|
|
|
cps = pd->MR_pd_coverage_points;
|
|
ncps = pd->MR_pd_proc_layout->MR_sle_proc_static->
|
|
MR_ps_num_coverage_points;
|
|
|
|
MR_write_num(fp, ncps);
|
|
for (i = 0; i < ncps; i++) {
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "coverage point: %d",
|
|
cps[i]);
|
|
}
|
|
#endif
|
|
MR_write_num(fp, cps[i]);
|
|
}
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
static void
|
|
MR_write_ptr(FILE *fp, MR_NodeKind kind, int node_id)
|
|
{
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "ptr: %d\n", node_id);
|
|
}
|
|
#endif
|
|
|
|
// MR_write_byte(fp, (int) kind);
|
|
MR_write_num(fp, node_id);
|
|
}
|
|
|
|
static void
|
|
MR_write_kind(FILE *fp, MR_CallSiteKind kind)
|
|
{
|
|
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "call_site_kind: %d\n", (int) kind);
|
|
}
|
|
#endif
|
|
|
|
MR_write_byte(fp, (const char) kind);
|
|
}
|
|
|
|
static void
|
|
MR_write_byte(FILE *fp, const char byte)
|
|
{
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "byte: %d\n", (int) byte);
|
|
}
|
|
#endif
|
|
putc(byte, fp);
|
|
}
|
|
|
|
// Write out a (non-negative) integer. The format we use is a multibyte format
|
|
// which uses the least significant 7 bits as data bits and the most
|
|
// significant bit to indicate whether there are more bytes following.
|
|
// Numbers are written most significant byte first.
|
|
|
|
static void
|
|
MR_write_num(FILE *fp, unsigned long num)
|
|
{
|
|
unsigned char pieces[sizeof(unsigned long) * 8 / 7 + 1];
|
|
int i;
|
|
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "num: %ld\n", num);
|
|
}
|
|
#endif
|
|
|
|
MR_deep_assert(NULL, NULL, NULL, (MR_Integer) num >= 0);
|
|
|
|
i = 0;
|
|
do {
|
|
pieces[i] = num & 0x7f;
|
|
num = num >> 7;
|
|
i++;
|
|
} while (num != 0);
|
|
|
|
i--;
|
|
|
|
while (i > 0) {
|
|
putc(pieces[i--] | 0x80, fp);
|
|
}
|
|
putc(pieces[0], fp);
|
|
}
|
|
|
|
static void
|
|
MR_write_fixed_size_int(FILE *fp, MR_uint_least64_t num)
|
|
{
|
|
int i;
|
|
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "fixed_size_int: %ld\n", num);
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < MR_FIXED_SIZE_INT_BYTES; i++) {
|
|
putc(num & ((1 << 8) - 1), fp);
|
|
num = num >> 8;
|
|
}
|
|
}
|
|
|
|
static void
|
|
MR_write_string(FILE *fp, const char *ptr)
|
|
{
|
|
int i;
|
|
int len;
|
|
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "string: <%s>\n", ptr);
|
|
}
|
|
#endif
|
|
|
|
len = strlen(ptr);
|
|
MR_write_num(fp, len);
|
|
for (i = 0; i < len; i++) {
|
|
putc(ptr[i], fp);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// This section of the file implements the hash tables that turn the addresses
|
|
// of ProcDynamic, ProcDynamic, and CallSiteDynamic nodes into node ids.
|
|
// We use our own routines instead of reusing the hash table routines in
|
|
// mercury_hash_table.c for efficiency. By writing our own code, we avoid
|
|
// several sources of overhead: higher order calls, separate calls to lookup
|
|
// a pointer and insert it if it isn't there, and the use of doubly-linked
|
|
// lists. Efficiency is reasonably important, since the tables can have
|
|
// millions of entries. Eventually, they should be implemented using
|
|
// dynamically sized hash tables (extendible hashing or linear hashing).
|
|
|
|
static MR_ProfilingHashTable *
|
|
MR_create_hash_table(int size)
|
|
{
|
|
MR_ProfilingHashTable *ptr;
|
|
int i;
|
|
|
|
ptr = MR_NEW(MR_ProfilingHashTable);
|
|
ptr->length = size;
|
|
ptr->last_id = 0;
|
|
ptr->nodes = MR_NEW_ARRAY(MR_ProfilingHashNode *, size);
|
|
|
|
for (i = 0; i < size; i++) {
|
|
ptr->nodes[i] = NULL;
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Type safe interfaces to the generic hash table routines.
|
|
//
|
|
// We declare those generic routines here to ensure that any calls to them
|
|
// from above this point get error messages from mgnuc.
|
|
|
|
static MR_bool MR_hash_table_insert_INTERNAL(
|
|
MR_ProfilingHashTable *table,
|
|
const void *ptr, int *id,
|
|
MR_bool *already_written,
|
|
MR_bool init_written);
|
|
static void MR_hash_table_flag_written_INTERNAL(
|
|
MR_ProfilingHashTable *table,
|
|
const void *ptr);
|
|
static int MR_hash_table_check_all_written_INTERNAL(
|
|
FILE *fp, const char *type,
|
|
MR_ProfilingHashTable *table,
|
|
void write_func(FILE *fp, const void *));
|
|
|
|
static MR_bool
|
|
MR_insert_proc_layout(const MR_ProcLayout *pl, int *id,
|
|
MR_bool *already_written, MR_bool init_written)
|
|
{
|
|
return MR_hash_table_insert_INTERNAL(MR_proc_layout_table,
|
|
(const void *) pl, id, already_written, init_written);
|
|
}
|
|
|
|
static MR_bool
|
|
MR_insert_proc_dynamic(const MR_ProcDynamic *pd, int *id,
|
|
MR_bool *already_written, MR_bool init_written)
|
|
{
|
|
return MR_hash_table_insert_INTERNAL(MR_proc_dynamic_table,
|
|
(const void *) pd, id, already_written, init_written);
|
|
}
|
|
|
|
static MR_bool
|
|
MR_insert_call_site_static(const MR_CallSiteStatic *css, int *id,
|
|
MR_bool *already_written, MR_bool init_written)
|
|
{
|
|
return MR_hash_table_insert_INTERNAL(MR_call_site_static_table,
|
|
(const void *) css, id, already_written, init_written);
|
|
}
|
|
|
|
static MR_bool
|
|
MR_insert_call_site_dynamic(const MR_CallSiteDynamic *csd, int *id,
|
|
MR_bool *already_written, MR_bool init_written)
|
|
{
|
|
return MR_hash_table_insert_INTERNAL(MR_call_site_dynamic_table,
|
|
(const void *) csd, id, already_written, init_written);
|
|
}
|
|
|
|
static void
|
|
MR_flag_written_proc_layout(const MR_ProcLayout *pl)
|
|
{
|
|
MR_hash_table_flag_written_INTERNAL(MR_proc_layout_table,
|
|
(const void *) pl);
|
|
}
|
|
|
|
static void
|
|
MR_flag_written_proc_dynamic(const MR_ProcDynamic *pd)
|
|
{
|
|
MR_hash_table_flag_written_INTERNAL(MR_proc_dynamic_table,
|
|
(const void *) pd);
|
|
}
|
|
|
|
static void
|
|
MR_flag_written_call_site_static(const MR_CallSiteStatic *css)
|
|
{
|
|
MR_hash_table_flag_written_INTERNAL(MR_call_site_static_table,
|
|
(const void *) css);
|
|
}
|
|
|
|
static void
|
|
MR_flag_written_call_site_dynamic(const MR_CallSiteDynamic *csd)
|
|
{
|
|
MR_hash_table_flag_written_INTERNAL(MR_call_site_dynamic_table,
|
|
(const void *) csd);
|
|
}
|
|
|
|
#define MR_hash_ptr(ptr, table) (((MR_Unsigned) (ptr) >> 2) % (table)->length)
|
|
|
|
static MR_bool
|
|
MR_hash_table_insert_INTERNAL(MR_ProfilingHashTable *table, const void *ptr,
|
|
int *id, MR_bool *already_written, MR_bool init_written)
|
|
{
|
|
int hash;
|
|
MR_ProfilingHashNode *node;
|
|
|
|
if (ptr == NULL) {
|
|
MR_fatal_error("NULL ptr in MR_hash_table_insert");
|
|
}
|
|
|
|
hash = MR_hash_ptr(ptr, table);
|
|
node = table->nodes[hash];
|
|
while (node != NULL) {
|
|
if (node->item == ptr) {
|
|
*id = node->id;
|
|
if (already_written != NULL) {
|
|
*already_written = node->written;
|
|
}
|
|
return MR_TRUE;
|
|
}
|
|
node = node->next;
|
|
}
|
|
|
|
node = MR_NEW(MR_ProfilingHashNode);
|
|
node->item = ptr;
|
|
node->id = ++table->last_id;
|
|
node->written = init_written;
|
|
node->next = table->nodes[hash];
|
|
table->nodes[hash] = node;
|
|
|
|
*id = node->id;
|
|
if (already_written != NULL) {
|
|
*already_written = MR_FALSE;
|
|
}
|
|
|
|
return MR_FALSE;
|
|
}
|
|
|
|
static void
|
|
MR_hash_table_flag_written_INTERNAL(MR_ProfilingHashTable *table,
|
|
const void *ptr)
|
|
{
|
|
int hash;
|
|
MR_ProfilingHashNode *node;
|
|
|
|
if (ptr == NULL) {
|
|
MR_fatal_error("NULL ptr in MR_hash_table_flag_written");
|
|
}
|
|
|
|
hash = MR_hash_ptr(ptr, table);
|
|
node = table->nodes[hash];
|
|
while (node != NULL) {
|
|
if (node->item == ptr) {
|
|
node->written = MR_TRUE;
|
|
return;
|
|
}
|
|
node = node->next;
|
|
}
|
|
|
|
MR_fatal_error("MR_hash_table_flag_written: did not find node");
|
|
}
|
|
|
|
static void
|
|
MR_write_out_profiling_tree_check_unwritten(FILE *check_fp)
|
|
{
|
|
int unwritten_csd;
|
|
int unwritten_css;
|
|
int unwritten_pd;
|
|
int unwritten_ps;
|
|
int any_unwritten;
|
|
|
|
unwritten_ps = MR_hash_table_check_all_written_INTERNAL(check_fp,
|
|
"ProcLayout", MR_proc_layout_table,
|
|
MR_unwritten_pl_handler);
|
|
unwritten_pd = MR_hash_table_check_all_written_INTERNAL(check_fp,
|
|
"ProcDynamic", MR_proc_dynamic_table,
|
|
MR_unwritten_pd_handler);
|
|
unwritten_css = MR_hash_table_check_all_written_INTERNAL(check_fp,
|
|
"CallSiteStatic", MR_call_site_static_table,
|
|
MR_unwritten_css_handler);
|
|
unwritten_csd = MR_hash_table_check_all_written_INTERNAL(check_fp,
|
|
"CallSiteDynamic", MR_call_site_dynamic_table,
|
|
MR_unwritten_csd_handler);
|
|
any_unwritten = unwritten_ps + unwritten_pd +
|
|
unwritten_css + unwritten_csd;
|
|
|
|
if (unwritten_ps > 0 && check_fp != NULL) {
|
|
fprintf(check_fp, "%d unwritten proc statics\n",
|
|
unwritten_ps);
|
|
}
|
|
|
|
if (unwritten_pd > 0 && check_fp != NULL) {
|
|
fprintf(check_fp, "%d unwritten proc dynamics\n",
|
|
unwritten_pd);
|
|
}
|
|
|
|
if (unwritten_css > 0 && check_fp != NULL) {
|
|
fprintf(check_fp, "%d unwritten call site statics\n",
|
|
unwritten_css);
|
|
}
|
|
|
|
if (unwritten_csd > 0 && check_fp != NULL) {
|
|
fprintf(check_fp, "%d unwritten call site dynamics\n",
|
|
unwritten_csd);
|
|
}
|
|
|
|
if (any_unwritten > 0) {
|
|
MR_fatal_error("UNWRITTEN nodes: Deep.data file corrupted\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
MR_unwritten_css_handler(FILE *fp, const void *css)
|
|
{
|
|
fprintf(stderr, "UNWRITTEN call site static %p\n", css);
|
|
}
|
|
|
|
static void
|
|
MR_unwritten_csd_handler(FILE *fp, const void *csd)
|
|
{
|
|
fprintf(stderr, "UNWRITTEN call site dynamic %p\n", csd);
|
|
}
|
|
|
|
static void
|
|
MR_unwritten_pl_handler(FILE *fp, const void *pl)
|
|
{
|
|
const MR_ProcLayout *proc_layout;
|
|
const MR_ProcId *procid;
|
|
|
|
proc_layout = (const MR_ProcLayout *) pl;
|
|
|
|
if (! MR_PROC_LAYOUT_HAS_PROC_ID(proc_layout)) {
|
|
MR_fatal_error("MR_write_out_proc_layout_from_void: no proc_id\n");
|
|
}
|
|
|
|
fprintf(stderr, "UNWRITTEN proc layout %p:\n", pl);
|
|
|
|
procid = &proc_layout->MR_sle_proc_id;
|
|
if (MR_PROC_ID_IS_UCI(*procid)) {
|
|
fprintf(stderr, "uci %s/%s/%s/%s/%d/%d\n",
|
|
procid->MR_proc_uci.MR_uci_type_name,
|
|
procid->MR_proc_uci.MR_uci_type_module,
|
|
procid->MR_proc_uci.MR_uci_def_module,
|
|
procid->MR_proc_uci.MR_uci_pred_name,
|
|
procid->MR_proc_uci.MR_uci_type_arity,
|
|
procid->MR_proc_uci.MR_uci_mode);
|
|
} else {
|
|
fprintf(stderr, "user %d/%s/%s/%s/%d/%d\n",
|
|
procid->MR_proc_user.MR_user_pred_or_func,
|
|
procid->MR_proc_user.MR_user_decl_module,
|
|
procid->MR_proc_user.MR_user_def_module,
|
|
procid->MR_proc_user.MR_user_name,
|
|
procid->MR_proc_user.MR_user_pred_form_arity,
|
|
procid->MR_proc_user.MR_user_mode);
|
|
}
|
|
}
|
|
|
|
static void
|
|
MR_unwritten_pd_handler(FILE *fp, const void *pd)
|
|
{
|
|
fprintf(stderr, "UNWRITTEN proc dynamic %p\n", pd);
|
|
}
|
|
|
|
static int
|
|
MR_hash_table_check_all_written_INTERNAL(FILE *fp, const char *type,
|
|
MR_ProfilingHashTable *table, void write_func(FILE *, const void *))
|
|
{
|
|
int i;
|
|
int errors;
|
|
MR_ProfilingHashNode *node;
|
|
|
|
errors = 0;
|
|
for (i = 0; i < table->length ; i++) {
|
|
for (node = table->nodes[i]; node != NULL; node = node->next) {
|
|
if (! node->written) {
|
|
errors++;
|
|
if (fp != NULL) {
|
|
fprintf(fp, "unwritten %s %d at %p\n",
|
|
type, node->id, node->item);
|
|
fflush(fp);
|
|
(*write_func)(fp, node->item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
MR_deep_prof_init(void)
|
|
{
|
|
#ifdef MR_DEEP_PROFILING_TIMING
|
|
MR_init_time_profile_method();
|
|
#endif
|
|
}
|
|
|
|
static void MR_deep_tick_handler(int signum);
|
|
|
|
void
|
|
MR_deep_prof_turn_on_time_profiling(void)
|
|
{
|
|
#ifdef MR_DEEP_PROFILING_TIMING
|
|
MR_turn_on_time_profiling(MR_deep_tick_handler);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MR_deep_prof_turn_off_time_profiling(void)
|
|
{
|
|
#ifdef MR_DEEP_PROFILING_TIMING
|
|
MR_turn_off_time_profiling();
|
|
#endif
|
|
}
|
|
|
|
#ifdef MR_DEEP_PROFILING_TIMING
|
|
|
|
static void
|
|
MR_deep_tick_handler(/*unused */ int signum)
|
|
{
|
|
if (MR_inside_deep_profiling_code) {
|
|
MR_quanta_inside_deep_profiling_code++;
|
|
} else {
|
|
MR_quanta_outside_deep_profiling_code++;
|
|
MR_current_call_site_dynamic->MR_csd_own.MR_own_quanta++;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif // MR_DEEP_PROFILING
|