mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-08 18:34:00 +00:00
Most sane systems use 64-bit offsets with those functions; Windows does not.
runtime/mercury_file.h:
Define macros MR_fseek and MR_ftell that expand to the name of the
fseek or ftell function that uses 64-bit offsets.
runtime/mercury_deep_profiling.c:
library/io.m:
Use the new macros and always use 64-bit offsets.
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_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_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_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_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_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
|