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