mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 06:47:17 +00:00
Estimated hours taken: 0.1 Branches: main Avoid a C compiler warning on x86_64. runtime/mercury_deep_profiling.c: In the MR_hash_ptr macro, cast `void * ' to `MR_Unsigned' rather than `unsigned int'.
1578 lines
47 KiB
C
1578 lines
47 KiB
C
/*
|
|
** vim:sw=4 ts=4 expandtab
|
|
*/
|
|
/*
|
|
** Copyright (C) 2001-2005 The University of Melbourne.
|
|
** This file may only be copied under the terms of the GNU Library General
|
|
** Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
*/
|
|
|
|
/*
|
|
** 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" /* for strerror() on some systems */
|
|
#include "mercury_deep_profiling.h"
|
|
#include "mercury_deep_profiling_hand.h"
|
|
|
|
#ifdef MR_DEEP_PROFILING
|
|
|
|
#include <stdio.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_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_Proc_Layout_User MR_main_parent_proc_layout =
|
|
{
|
|
{ MR_do_not_reached, MR_DETISM_DET, -1, MR_LONG_LVAL_TYPE_UNKNOWN },
|
|
{ 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_Proc_Layout *) &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_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 */
|
|
|
|
void
|
|
MR_deep_assert_failed(const MR_CallSiteDynamic *csd, const MR_Proc_Layout *pl,
|
|
const MR_ProcStatic *ps, const char *cond,
|
|
const char *filename, int linenumber)
|
|
{
|
|
char buf[1024];
|
|
char bufcsd[1024];
|
|
char bufps[1024];
|
|
|
|
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, "");
|
|
}
|
|
|
|
sprintf(buf, "Deep profiling assertion failed, %s:%d\n%s%s%s\n",
|
|
filename, linenumber, cond, bufcsd, bufps);
|
|
MR_fatal_error(buf);
|
|
}
|
|
|
|
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_MALLOC(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);
|
|
static void MR_write_out_profiling_tree_check_unwritten(FILE *check_fp);
|
|
|
|
static void MR_write_out_id_string(FILE *fp);
|
|
|
|
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 4
|
|
|
|
static void MR_write_csd_ptr(FILE *fp, const MR_CallSiteDynamic *csd);
|
|
static void MR_write_ptr(FILE *fp, MR_NodeKind kind, const int node_id);
|
|
static void MR_write_kind(FILE *fp, MR_CallSite_Kind 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, unsigned long 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_Proc_Layout *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_Proc_Layout *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_DATAFILENAME "Deep.data"
|
|
|
|
void
|
|
MR_write_out_profiling_tree(void)
|
|
{
|
|
int i;
|
|
MR_ProfilingHashNode *n;
|
|
MR_Proc_Id *pid;
|
|
int root_pd_id;
|
|
FILE *fp;
|
|
int ticks_per_sec;
|
|
FILE *check_fp;
|
|
|
|
fp = fopen(MR_MDPROF_DATAFILENAME, "wb+");
|
|
if (fp == NULL) {
|
|
MR_fatal_error("cannot open `%s' for writing: %s",
|
|
MR_MDPROF_DATAFILENAME, strerror(errno));
|
|
}
|
|
|
|
#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_id_string(fp);
|
|
MR_write_fixed_size_int(fp, 0);
|
|
MR_write_fixed_size_int(fp, 0);
|
|
MR_write_fixed_size_int(fp, 0);
|
|
MR_write_fixed_size_int(fp, 0);
|
|
|
|
#ifdef MR_CLOCK_TICKS_PER_SECOND
|
|
ticks_per_sec = MR_CLOCK_TICKS_PER_SECOND;
|
|
#else
|
|
ticks_per_sec = 0;
|
|
#endif
|
|
|
|
MR_write_num(fp, ticks_per_sec);
|
|
MR_write_num(fp, MR_quanta_inside_deep_profiling_code);
|
|
MR_write_num(fp, MR_quanta_outside_deep_profiling_code);
|
|
MR_write_byte(fp, sizeof(MR_Word));
|
|
MR_write_byte(fp, 0); /* the canonical flag is MR_FALSE = 0 */
|
|
|
|
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(fp, kind_pd, root_pd_id);
|
|
|
|
MR_write_out_proc_dynamic(fp, &MR_main_parent_proc_dynamic);
|
|
|
|
MR_write_out_user_proc_static(fp, &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)(fp);
|
|
|
|
if (fseek(fp, 0L, SEEK_SET) != 0) {
|
|
MR_deep_data_output_error("cannot seek to start of");
|
|
}
|
|
|
|
MR_write_out_id_string(fp);
|
|
MR_write_fixed_size_int(fp, MR_call_site_dynamic_table->last_id);
|
|
MR_write_fixed_size_int(fp, MR_call_site_static_table->last_id);
|
|
MR_write_fixed_size_int(fp, MR_proc_dynamic_table->last_id);
|
|
MR_write_fixed_size_int(fp, MR_proc_layout_table->last_id);
|
|
|
|
if (fclose(fp) != 0) {
|
|
MR_deep_data_output_error("cannot close");
|
|
}
|
|
|
|
#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
|
|
|
|
#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)
|
|
{
|
|
MR_warning("%s %s: %s", op, MR_MDPROF_DATAFILENAME, strerror(errno));
|
|
|
|
/*
|
|
** 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_DATAFILENAME) != 0) {
|
|
MR_warning("cannot remove %s: %s",
|
|
MR_MDPROF_DATAFILENAME, strerror(errno));
|
|
}
|
|
|
|
exit(1);
|
|
}
|
|
|
|
static void
|
|
MR_write_out_id_string(FILE *fp)
|
|
{
|
|
/* Must be the same as id_string in deep_profiler/read_profile.m */
|
|
const char *id_string = "Mercury deep profiler data version 1\n";
|
|
|
|
fputs(id_string, fp);
|
|
}
|
|
|
|
void
|
|
MR_write_out_user_proc_static(FILE *fp, const MR_Proc_Layout_User *proc_layout)
|
|
{
|
|
MR_write_out_proc_static(fp, (const MR_Proc_Layout *) proc_layout);
|
|
}
|
|
|
|
void
|
|
MR_write_out_uci_proc_static(FILE *fp, const MR_Proc_Layout_UCI *proc_layout)
|
|
{
|
|
MR_write_out_proc_static(fp, (const MR_Proc_Layout *) proc_layout);
|
|
}
|
|
|
|
void
|
|
MR_write_out_proc_static(FILE *fp, const MR_Proc_Layout *proc_layout)
|
|
{
|
|
const MR_ProcStatic *ps;
|
|
const MR_Proc_Id *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;
|
|
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(fp, MR_deep_token_proc_static);
|
|
MR_write_ptr(fp, kind_ps, ps_id);
|
|
|
|
procid = &proc_layout->MR_sle_proc_id;
|
|
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(fp, MR_deep_token_isa_uci_pred);
|
|
MR_write_string(fp, procid->MR_proc_uci.MR_uci_type_name);
|
|
MR_write_string(fp, procid->MR_proc_uci.MR_uci_type_module);
|
|
MR_write_string(fp, procid->MR_proc_uci.MR_uci_def_module);
|
|
MR_write_string(fp, procid->MR_proc_uci.MR_uci_pred_name);
|
|
MR_write_num(fp, procid->MR_proc_uci.MR_uci_type_arity);
|
|
MR_write_num(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(fp, MR_deep_token_isa_predicate);
|
|
} else {
|
|
MR_write_byte(fp, MR_deep_token_isa_function);
|
|
}
|
|
|
|
MR_write_string(fp, procid->MR_proc_user.MR_user_decl_module);
|
|
MR_write_string(fp, procid->MR_proc_user.MR_user_def_module);
|
|
MR_write_string(fp, procid->MR_proc_user.MR_user_name);
|
|
MR_write_num(fp, procid->MR_proc_user.MR_user_arity);
|
|
MR_write_num(fp, procid->MR_proc_user.MR_user_mode);
|
|
}
|
|
|
|
MR_write_string(fp, ps->MR_ps_file_name);
|
|
MR_write_num(fp, ps->MR_ps_line_number);
|
|
MR_write_byte(fp, ps->MR_ps_is_in_interface);
|
|
MR_write_num(fp, ps->MR_ps_num_call_sites);
|
|
|
|
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(fp, kind_css, css_id);
|
|
}
|
|
|
|
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(fp, &ps->MR_ps_call_sites[i]);
|
|
}
|
|
}
|
|
|
|
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_token_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_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_token_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 |= 0x0008;
|
|
}
|
|
if (csd->MR_csd_own.MR_own_excps != 0) {
|
|
bitmask |= 0x0010;
|
|
}
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_TIMING
|
|
if (csd->MR_csd_own.MR_own_quanta != 0) {
|
|
bitmask |= 0x0020;
|
|
}
|
|
#endif
|
|
#ifdef MR_DEEP_PROFILING_MEMORY
|
|
if (csd->MR_csd_own.MR_own_allocs != 0) {
|
|
bitmask |= 0x0040;
|
|
}
|
|
if (csd->MR_csd_own.MR_own_words != 0) {
|
|
bitmask |= 0x0080;
|
|
}
|
|
#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_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_Proc_Layout *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_token_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
|
|
|
|
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_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_special_call:
|
|
case MR_higher_order_call:
|
|
case MR_method_call:
|
|
case MR_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_normal_call:
|
|
MR_write_out_call_site_dynamic(fp,
|
|
pd->MR_pd_call_site_ptr_ptrs[i]);
|
|
break;
|
|
|
|
case MR_special_call:
|
|
case MR_higher_order_call:
|
|
case MR_method_call:
|
|
case MR_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_token_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);
|
|
}
|
|
|
|
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_CallSite_Kind kind)
|
|
{
|
|
int byte;
|
|
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "call_site_kind: %d\n", (int) kind);
|
|
}
|
|
#endif
|
|
|
|
/* convert from a MR_CallSite_Kind to an MR_Profiling_Encoding_Token */
|
|
byte = (int) kind +
|
|
((int) MR_deep_token_normal_call - (int) MR_normal_call);
|
|
if (byte < MR_deep_token_normal_call || byte > MR_deep_token_callback) {
|
|
MR_fatal_error("MR_write_kind: bad kind %d %d\n", (int) kind, byte);
|
|
}
|
|
|
|
MR_write_byte(fp, byte);
|
|
}
|
|
|
|
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, (int) 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, unsigned long num)
|
|
{
|
|
int i;
|
|
|
|
#ifdef MR_DEEP_PROFILING_DETAIL_DEBUG
|
|
if (debug_fp != NULL) {
|
|
fprintf(debug_fp, "fixed_size_int: %ld\n", num);
|
|
}
|
|
#endif
|
|
|
|
MR_deep_assert(NULL, NULL, NULL, (int) num >= 0);
|
|
|
|
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_Proc_Layout *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_Proc_Layout *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;
|
|
int iteration;
|
|
|
|
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_Proc_Layout *proc_layout;
|
|
const MR_Proc_Id *procid;
|
|
|
|
proc_layout = (const MR_Proc_Layout *) pl;
|
|
|
|
if (! MR_PROC_LAYOUT_HAS_PROC_ID(proc_layout)) {
|
|
MR_fatal_error("MR_write_out_proc_layout_from_void: no proc_id\n");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
fprintf(stderr, "UNWRITTEN proc layout %p\n", pl);
|
|
}
|
|
|
|
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 */
|