Files
mercury/runtime/mercury_deep_profiling.c
Zoltan Somogyi e35a09542e Print two kinds of ambiguities only if asked for.
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.
2022-07-05 08:00:12 +10:00

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