mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-06 07:49:02 +00:00
Fix a problem that arises in the deep profiler if the program being profiled
was using both intermodule optimization and inlining. The issue was that
even though runtime/mercury_deep_profiling.c had access, for every call site
to the full context of that call site, containing both the file name and
the line number, it wrote out *only* the line number. The deep profiler
then got the file name from the file name stored in the proc_static structure
of the procedure containing the call site.
This works very close to 100% of the time, because
- user-written programs just about never use ":- pragma source_file", and
- in the absence of such pragmas, all the goals in a procedure will be
from the same file as the procedure's context.
However, if
- a call site calls a procedure in another module,
- the compiler has access to the code of that procedure from a .opt file, and
- the compiler decides to inline that call,
then the call, whose context is in the original source file, will be replaced
by the code of the procedure from the .opt file, whose context will NOT have
the same file name. Any description of this call site will list
- the code from the .opt file (such as the callee's callee),
- the file name from the original source file, and
- the line number from the .opt file.
This mismatch is very confusing, which is why this diff fixes it.
runtime/mercury_deep_profiling.c:
Fix this by writing out the file name part, as well as the line number
part, of each call site. The space impact is not as big as one might
expect, because compiler/deep_profiling.m already had an optimization
that set the filename part of each call site context to the empty string
if it was identical to the context of the procedure. Therefore for all
call sites that do NOT exhibit the bug that this diff fixes, the space
cost is only a single NULL character in the profiling data file.
Since this IS a change in the file format, bump the format version number
from 8 to 9.
deep_profiler/profile.m:
deep_profiler/read_profile.m:
Handle reading in both version 8 and version 9 profiling data files.
deep_profiler/create_report.m:
When creating descriptions of call sites, use the call site's filename
if it is not the empty string; if it is the empty string, then use
the containing procedure's file name, as we have done all along.
deep_profiler/display_report.m:
deep_profiler/dump.m:
deep_profiler/report.m:
Dump the new field in commands intended only for implementors.
deep_profiler/startup.m:
Conform to the changes above.
738 lines
29 KiB
Mathematica
738 lines
29 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2008-2011 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: report.m.
|
|
% Author: pbone.
|
|
%
|
|
% This module defines deep profiling reports. Each report is the result of
|
|
% querying a Deep.data file. Different queries result in different types
|
|
% of reports. Reports can be converted into HTML by display_report.m and
|
|
% html_format.m, but some tools may use the data structures constructed here
|
|
% directly.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module report.
|
|
:- interface.
|
|
|
|
:- import_module coverage.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.goal_path.
|
|
:- import_module mdbcomp.program_representation.
|
|
:- import_module measurement_units.
|
|
:- import_module profile.
|
|
% TODO: The data structures in query should be moved into a different module,
|
|
% then this module may depend on those data structures but not the rest of
|
|
% query.
|
|
:- import_module query.
|
|
:- import_module var_use_analysis.
|
|
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module set.
|
|
:- import_module unit.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type deep_report
|
|
---> report_message(
|
|
message_report
|
|
)
|
|
; report_menu(
|
|
maybe_error(menu_report)
|
|
)
|
|
; report_clique(
|
|
maybe_error(clique_report)
|
|
)
|
|
; report_clique_recursion_costs(
|
|
maybe_error(clique_recursion_report)
|
|
)
|
|
; report_recursion_types_frequency(
|
|
maybe_error(recursion_types_frequency_report)
|
|
)
|
|
; report_program_modules(
|
|
maybe_error(program_modules_report)
|
|
)
|
|
; report_module(
|
|
maybe_error(module_report)
|
|
)
|
|
; report_module_getter_setters(
|
|
maybe_error(module_getter_setters_report)
|
|
)
|
|
; report_module_rep(
|
|
maybe_error(module_rep_report)
|
|
)
|
|
; report_top_procs(
|
|
maybe_error(top_procs_report)
|
|
)
|
|
; report_proc(
|
|
maybe_error(proc_report)
|
|
)
|
|
; report_procrep_coverage(
|
|
maybe_error(procrep_coverage_info)
|
|
)
|
|
; report_proc_callers(
|
|
maybe_error(proc_callers_report)
|
|
)
|
|
; report_proc_static_dump(
|
|
maybe_error(proc_static_dump_info)
|
|
)
|
|
; report_proc_dynamic_dump(
|
|
maybe_error(proc_dynamic_dump_info)
|
|
)
|
|
; report_call_site_static_dump(
|
|
maybe_error(call_site_static_dump_info)
|
|
)
|
|
; report_call_site_dynamic_dump(
|
|
maybe_error(call_site_dynamic_dump_info)
|
|
)
|
|
; report_clique_dump(
|
|
maybe_error(clique_dump_info)
|
|
)
|
|
; report_call_site_dynamic_var_use(
|
|
maybe_error(call_site_dynamic_var_use_info)
|
|
).
|
|
|
|
:- type message_report
|
|
---> message_report(
|
|
% A simple message, this may be used in response to the
|
|
% 'shutdown' and similar queries.
|
|
|
|
string
|
|
).
|
|
|
|
:- type menu_report
|
|
---> menu_report(
|
|
% Statistics about the deep profiling data. Gives simple
|
|
% information about the size of the program and its runtime.
|
|
% These statistics are displayed on the menu of the mdprof_cgi
|
|
% program.
|
|
|
|
menu_program_name :: string,
|
|
menu_quanta_per_sec :: int,
|
|
menu_user_quanta :: int,
|
|
menu_inst_quanta :: int,
|
|
menu_num_callseqs :: int,
|
|
menu_num_csd :: int,
|
|
menu_num_css :: int,
|
|
menu_num_pd :: int,
|
|
menu_num_ps :: int,
|
|
menu_num_clique :: int
|
|
).
|
|
|
|
:- type clique_report
|
|
---> clique_report(
|
|
% The clique the report is for.
|
|
cr_clique_ptr :: clique_ptr,
|
|
|
|
% The ancestor call sites of the clique,
|
|
% - from the innermost ancestor call site (in the parent)
|
|
% - to the outermost ancestor call site (in main/2).
|
|
cr_ancestor_call_sites :: list(
|
|
perf_row_data(ancestor_desc)),
|
|
|
|
% Reports for every procedure in the clique. The first
|
|
% procedure in the list is the entry procedure (if the parent
|
|
% clique had a valid CSD.) and that CSD was found in the
|
|
% clique. TODO: we might want to express this within this
|
|
% type.
|
|
cr_clique_procs :: list(clique_proc_report)
|
|
).
|
|
|
|
:- type clique_proc_report
|
|
---> clique_proc_report(
|
|
% Summary information for the cost of this procedure in this
|
|
% clique.
|
|
cpr_proc_summary :: perf_row_data(proc_desc),
|
|
|
|
% A clique may contain more than one proc_dynamic for the same
|
|
% procedure in one rare circumstance. Consider a clique of
|
|
% two procedures, let's call them p and q. The entry procedure
|
|
% is p. When p calls q and q then calls p, the runtime
|
|
% discovers they are in the same clique. However, after all
|
|
% those mutually recursive calls unwind and we get back to the
|
|
% original call to p, p can call q again. If it does so through
|
|
% a call site through which it has not called q before, then
|
|
% the call port code in q will allocate a new proc_dynamic,
|
|
% since it will not find an existing one it can reuse;
|
|
% q's proc_static won't point to an active proc_dynamic, and
|
|
% the call site will not supply one either.
|
|
%
|
|
% We could modify the code we invoke at call ports to keep a
|
|
% list of the proc_dynamics of the procedures known to be in
|
|
% the current clique, and to reuse the proc_dynamic of the
|
|
% callee in these cases, but that would significantly increase
|
|
% the call port overhead. Instead, we let the callee allocate a
|
|
% second (and maybe third etc) proc_dynamic for a procedure,
|
|
% and let the deep profiler sort it out.
|
|
%
|
|
% Note that the entry procedure of a clique will always have
|
|
% exactly one proc_dynamic.
|
|
cpr_first_proc_dynamic :: clique_proc_dynamic_report,
|
|
cpr_other_proc_dynamics :: list(clique_proc_dynamic_report)
|
|
).
|
|
|
|
:- type clique_proc_dynamic_report
|
|
---> clique_proc_dynamic_report(
|
|
% Summary information for the cost of this proc _dynamic
|
|
% in this clique.
|
|
cpdr_proc_summary :: perf_row_data(proc_desc),
|
|
|
|
% Information about the costs of the call sites in this
|
|
% procedure in this clique.
|
|
cpdr_call_sites :: list(clique_call_site_report)
|
|
).
|
|
|
|
:- type clique_call_site_report
|
|
---> clique_call_site_report(
|
|
% The id of the call site, and the summary performance for
|
|
% that call site.
|
|
ccsr_call_site_summary :: perf_row_data(call_site_desc),
|
|
|
|
ccsr_kind_and_callee :: call_site_kind_and_callee(
|
|
proc_desc),
|
|
|
|
% All the callees and their associated performance information.
|
|
% If ccsr_kind_and_callee indicates a normal call, the list
|
|
% will have either zero entries (no calls through this site)
|
|
% or one entry (some calls through this site). If this is
|
|
% some other kind of call site, the list may have any number
|
|
% of entries.
|
|
ccsr_callee_perfs :: list(perf_row_data(clique_desc))
|
|
).
|
|
|
|
:- type clique_recursion_report
|
|
---> clique_recursion_report(
|
|
% The clique the report is for.
|
|
crr_clique_ptr :: clique_ptr,
|
|
|
|
% The type of recursion in this clique.
|
|
crr_recursion_type :: recursion_type,
|
|
|
|
% The number of procedures in the clique.
|
|
crr_num_procs :: int
|
|
).
|
|
|
|
:- type recursion_type
|
|
---> rt_not_recursive
|
|
; rt_single(
|
|
rts_base :: recursion_level_report,
|
|
rts_recursive :: recursion_level_report,
|
|
rts_avg_max_depth :: float,
|
|
|
|
% These costs are per-call.
|
|
rts_avg_rec_cost :: float,
|
|
|
|
% The cost at any level is Cost = func(Level).
|
|
rts_any_rec_cost :: (func(int) = float)
|
|
)
|
|
; rt_divide_and_conquer(
|
|
rtdsc_base :: recursion_level_report,
|
|
rtdsc_recursive :: recursion_level_report
|
|
)
|
|
; rt_mutual_recursion(
|
|
rtml_num_procs :: int
|
|
)
|
|
; rt_other(
|
|
rto_all_levels :: list(recursion_level_report)
|
|
)
|
|
; rt_errors(
|
|
rte_errors :: list(string)
|
|
).
|
|
|
|
% Recursion types for which call costs at any level can be calculated.
|
|
%
|
|
:- inst recursion_type_known_costs for recursion_type/0
|
|
---> rt_not_recursive
|
|
; rt_single(ground, ground, ground, ground, ground).
|
|
|
|
% Recursion types for which call costs at any level can not be calculated.
|
|
%
|
|
:- inst recursion_type_unknown_costs for recursion_type/0
|
|
---> rt_divide_and_conquer(ground, ground)
|
|
; rt_mutual_recursion(ground)
|
|
; rt_other(ground)
|
|
; rt_errors(ground).
|
|
|
|
:- type recursion_level_report
|
|
---> recursion_level_report(
|
|
rlr_level :: int,
|
|
rlr_calls :: int,
|
|
rlr_prob :: probability,
|
|
rlr_non_rec_calls_cost :: float,
|
|
rlr_rec_calls_ex_chld_cost :: float
|
|
).
|
|
|
|
:- type recursion_types_frequency_report
|
|
---> recursion_types_frequency_report(
|
|
rtfr_histogram :: recursion_type_histogram
|
|
).
|
|
|
|
:- type recursion_type_histogram ==
|
|
map(recursion_type_simple, recursion_type_freq_data).
|
|
|
|
:- type recursion_type_simple
|
|
---> rts_not_recursive
|
|
; rts_single
|
|
; rts_divide_and_conquer
|
|
; rts_mutual_recursion(
|
|
rtsmr_num_procs :: int
|
|
)
|
|
; rts_other(
|
|
rtso_levels :: set(int)
|
|
)
|
|
; rts_error(
|
|
rtse_error :: string
|
|
)
|
|
; rts_total_error_instances.
|
|
|
|
:- type recursion_type_freq_data
|
|
---> recursion_type_freq_data(
|
|
rtfd_freq :: int,
|
|
rtfd_percent :: percent,
|
|
rtfd_maybe_summary :: maybe(perf_row_data(unit)),
|
|
rtfd_entry_procs :: recursion_type_proc_map
|
|
).
|
|
|
|
:- type recursion_type_proc_map ==
|
|
map(proc_static_ptr, recursion_type_proc_freq_data).
|
|
|
|
:- type recursion_type_proc_freq_data
|
|
---> recursion_type_proc_freq_data(
|
|
rtpfd_freq :: int,
|
|
rtpfd_percent :: percent,
|
|
rtpfd_summary :: perf_row_data(proc_desc)
|
|
).
|
|
|
|
:- type program_modules_report
|
|
---> program_modules_report(
|
|
% Summary information about all the modules of the program.
|
|
program_modules :: list(
|
|
perf_row_data(module_active))
|
|
).
|
|
|
|
:- type module_report
|
|
---> module_report(
|
|
% Summary information about all the procedures in one module
|
|
% of the program.
|
|
mr_module_name :: string,
|
|
mr_have_module_rep :: maybe_have_module_rep,
|
|
mr_procs :: list(perf_row_data(proc_active))
|
|
).
|
|
|
|
:- type maybe_have_module_rep
|
|
---> do_not_have_module_rep
|
|
; have_module_rep.
|
|
|
|
:- type data_struct_name
|
|
---> data_struct_name(string).
|
|
|
|
:- type field_name
|
|
---> field_name(string).
|
|
|
|
:- type getter_or_setter
|
|
---> getter
|
|
; setter.
|
|
|
|
:- type gs_field_info(I, S)
|
|
---> gs_field_both(
|
|
gsf_both_getter :: I,
|
|
gsf_both_setter :: I,
|
|
gsf_both_summary :: S
|
|
)
|
|
; gs_field_getter(
|
|
gsf_getter :: I
|
|
)
|
|
; gs_field_setter(
|
|
gsf_setter :: I
|
|
).
|
|
|
|
:- type gs_field_map(T) == map(field_name, T).
|
|
:- type gs_ds_map(T) == map(data_struct_name, gs_field_map(T)).
|
|
|
|
:- type gs_field_info == gs_field_info(
|
|
perf_row_data(proc_desc),
|
|
perf_row_data(unit)
|
|
).
|
|
:- type gs_field_map == gs_field_map(gs_field_info).
|
|
:- type gs_ds_map == gs_ds_map(gs_field_info).
|
|
|
|
:- type module_getter_setters_report
|
|
---> module_getter_setters_report(
|
|
% Summary information about all the getter/setter procedures
|
|
% in one module of the program.
|
|
mgsr_module_name :: string,
|
|
mgsr_procs :: gs_ds_map
|
|
).
|
|
|
|
:- type module_rep_report
|
|
---> module_rep_report(
|
|
% A representation of one module of the program.
|
|
mrr_module_name :: string,
|
|
mrr_report :: string
|
|
).
|
|
|
|
:- type top_procs_report
|
|
---> top_procs_report(
|
|
% Information about the most expensive procedures. The ordering
|
|
% field defines what measurements are used to select and order
|
|
% the procedures in this report.
|
|
|
|
tp_ordering :: report_ordering,
|
|
tp_top_procs :: list(perf_row_data(proc_desc))
|
|
).
|
|
|
|
:- type proc_report
|
|
---> proc_report(
|
|
% The integer is a count of the number of cliques this
|
|
% procedure appears in.
|
|
proc_callers_summary :: perf_row_data(callers_counts),
|
|
|
|
% The proc description is inside the proc_summary field.
|
|
proc_summary :: perf_row_data(proc_desc),
|
|
proc_call_site_summaries :: list(call_site_perf)
|
|
).
|
|
|
|
% A count of the number of callers.
|
|
%
|
|
:- type callers_counts
|
|
---> callers_counts(
|
|
cc_static :: int,
|
|
cc_dynamic :: int
|
|
).
|
|
|
|
:- type call_site_perf
|
|
---> call_site_perf(
|
|
% The csf_summary_perf field contains the description of this
|
|
% call site and the summary of its performance.
|
|
%
|
|
% If the call site can call only one procedure, the csf_kind
|
|
% field tell you the id and the name of that procedure, and
|
|
% the type substitution made in the call to it, if there is one
|
|
% and it is known.
|
|
%
|
|
% Otherwise, if the call site can call more than one procedure,
|
|
% the csf_sub_callees field will have one performance row
|
|
% giving the contribution of each of the called procedures.
|
|
%
|
|
% If csf_kind = normal_call_and_info(_), then csf_sub_callees
|
|
% should be the empty list.
|
|
%
|
|
% The call site description is inside the csf_summary field.
|
|
|
|
csf_kind :: call_site_kind_and_info(
|
|
normal_callee_id),
|
|
csf_summary_perf :: perf_row_data(call_site_desc),
|
|
csf_sub_callees :: list(perf_row_data(proc_desc))
|
|
).
|
|
|
|
:- type normal_callee_id
|
|
---> normal_callee_id(
|
|
nci_callee_desc :: proc_desc,
|
|
nci_type_subst :: string
|
|
).
|
|
|
|
:- type procrep_coverage_info
|
|
---> procrep_coverage_info(
|
|
prci_proc :: proc_static_ptr,
|
|
prci_proc_rep :: proc_rep(goal_id),
|
|
prci_coverage_array :: goal_attr_array(coverage_info)
|
|
).
|
|
|
|
:- type proc_callers_report
|
|
---> proc_callers_report(
|
|
% The id of the procedure.
|
|
pc_proc_desc :: proc_desc,
|
|
|
|
% The call sites that call this procedure.
|
|
pc_callers :: proc_callers,
|
|
|
|
% Which batch of rows to show; transmitted without processing
|
|
% from the request.
|
|
pc_batch_number :: int,
|
|
|
|
% How many callers per batch, also transmitted without
|
|
% processing from the request.
|
|
pc_callers_per_batch :: int,
|
|
|
|
% Whether contour exclusion was applied in computing the
|
|
% pc_callers field.
|
|
pc_contour_exclusion :: contour_exclusion,
|
|
|
|
% If contour exclusion was asked for, this field may contain
|
|
% a warning message about nonfatal problems with the exclusion
|
|
% specification file.
|
|
pc_contour_warn_message :: maybe(string)
|
|
).
|
|
|
|
:- type proc_callers
|
|
---> proc_caller_call_sites(
|
|
pc_caller_call_sites :: list(
|
|
perf_row_data(call_site_desc))
|
|
)
|
|
; proc_caller_procedures(
|
|
pc_caller_procedures :: list(
|
|
perf_row_data(proc_desc))
|
|
)
|
|
; proc_caller_modules(
|
|
pc_caller_modules :: list(
|
|
perf_row_data(string))
|
|
)
|
|
; proc_caller_cliques(
|
|
pc_caller_cliques :: list(
|
|
perf_row_data(clique_desc))
|
|
).
|
|
|
|
:- type proc_static_dump_info
|
|
---> proc_static_dump_info(
|
|
psdi_psptr :: proc_static_ptr,
|
|
psdi_raw_name :: string,
|
|
psdi_uq_refined_name :: string,
|
|
psdi_q_refined_name :: string,
|
|
psdi_filename :: string,
|
|
psdi_linenumber :: int,
|
|
% Should we list the call_site_statics and coverage points
|
|
% themselves?
|
|
psdi_num_call_sites :: int,
|
|
psdi_num_coverage_points :: int
|
|
).
|
|
|
|
:- type proc_dynamic_dump_info
|
|
---> proc_dynamic_dump_info(
|
|
pddi_pdptr :: proc_dynamic_ptr,
|
|
pddi_psptr :: proc_static_ptr,
|
|
pddi_ps_raw_name :: string,
|
|
pddi_ps_module_name :: string,
|
|
pddi_ps_uq_refined_name :: string,
|
|
pddi_ps_q_refined_name :: string,
|
|
pddi_call_sites :: list(call_site_array_slot),
|
|
pddi_coverage_points :: maybe(list(coverage_point))
|
|
).
|
|
|
|
:- type call_site_static_dump_info
|
|
---> call_site_static_dump_info(
|
|
cssdi_cssptr :: call_site_static_ptr,
|
|
cssdi_containing_psptr :: proc_static_ptr,
|
|
cssdi_slot_number :: int,
|
|
cssdi_file_name :: string,
|
|
cssdi_line_number :: int,
|
|
cssdi_goal_path :: reverse_goal_path,
|
|
cssdi_callee :: call_site_kind_and_callee
|
|
).
|
|
|
|
:- type call_site_dynamic_dump_info
|
|
---> call_site_dynamic_dump_info(
|
|
csddi_csdptr :: call_site_dynamic_ptr,
|
|
csddi_caller_pdptr :: proc_dynamic_ptr,
|
|
csddi_callee_pdptr :: proc_dynamic_ptr,
|
|
csddi_own_perf :: perf_row_data(call_site_desc)
|
|
).
|
|
|
|
:- type clique_dump_info
|
|
---> clique_dump_info(
|
|
cdi_clique_desc :: clique_desc,
|
|
cdi_caller_csd_ptr :: call_site_dynamic_ptr,
|
|
cdi_member_pdptrs :: list(proc_dynamic_ptr)
|
|
).
|
|
|
|
:- type call_site_dynamic_var_use_info
|
|
---> call_site_dynamic_var_use_info(
|
|
csdvui_total_cost :: float,
|
|
csdvui_var_uses :: list(var_use_and_name)
|
|
).
|
|
|
|
:- type var_use_and_name
|
|
---> var_use_and_name(
|
|
vun_var_name :: string,
|
|
vun_use :: var_use_info
|
|
).
|
|
|
|
% This type represents information about the performance of the subject.
|
|
% It is intended to be displayed on a browser page or used by a tool as is.
|
|
% It is NOT intended to be subject to further processing, such as adding
|
|
% two perf_row_datas together. Any such arithmetic is much better done
|
|
% on the data structures from which perf_row_datas are derived
|
|
% (own_prof_info and inherit_prof_info in the measurements module).
|
|
%
|
|
:- type perf_row_data(T)
|
|
---> perf_row_data(
|
|
% The item represented by this data row.
|
|
perf_row_subject :: T,
|
|
|
|
% Port counts.
|
|
perf_row_calls :: int,
|
|
perf_row_exits :: int,
|
|
perf_row_fails :: int,
|
|
perf_row_redos :: int,
|
|
perf_row_excps :: int,
|
|
|
|
perf_row_bytes_per_word :: int,
|
|
perf_row_self :: inheritable_perf,
|
|
perf_row_maybe_total :: maybe(inheritable_perf)
|
|
).
|
|
|
|
:- type inheritable_perf
|
|
---> inheritable_perf(
|
|
% Clock ticks and times. We always use simple integers to
|
|
% represent clock ticks, whereas for time, we use more
|
|
% user-friendly units. When the total time for the program
|
|
% is close to zero, i.e. the number of ticks or quanta is zero
|
|
% for the whole program, then the percentage may be zero
|
|
% for everything (it used to be a NaN for 0/0, but we now
|
|
% check explicitly for division by zero).
|
|
perf_row_ticks :: int,
|
|
perf_row_time :: time,
|
|
perf_row_time_percent :: percent,
|
|
perf_row_time_percall :: time,
|
|
|
|
% Call sequence counts.
|
|
perf_row_callseqs :: int,
|
|
perf_row_callseqs_percent :: percent,
|
|
perf_row_callseqs_percall :: float,
|
|
|
|
% Memory allocations.
|
|
perf_row_allocs :: int,
|
|
perf_row_allocs_percent :: percent,
|
|
perf_row_allocs_percall :: float,
|
|
|
|
% Memory used. We try to use the most appropriate units
|
|
% for representing each given amount of memory.
|
|
% XXX Memory per call might not be an integer, so we should
|
|
% make sure that the memory type can represent fractions.
|
|
perf_row_mem :: memory,
|
|
perf_row_mem_percent :: percent,
|
|
perf_row_mem_percall :: memory
|
|
).
|
|
|
|
% This type is used to define 'most expensive procedures'. It contains all
|
|
% the parameters that the query is given to select and order the procedures
|
|
% shown in the report. See also the function symbol deep_cmd_top_procs of
|
|
% the cmd type.
|
|
%
|
|
:- type report_ordering
|
|
---> report_ordering(
|
|
display_limit :: display_limit,
|
|
cost_kind :: cost_kind,
|
|
incl_desc :: include_descendants,
|
|
scope :: measurement_scope
|
|
).
|
|
|
|
% The representation of a module in a report structure.
|
|
%
|
|
:- type module_active
|
|
---> module_active(
|
|
ma_module_name :: string,
|
|
ma_is_active :: module_is_active
|
|
).
|
|
|
|
:- type module_is_active
|
|
---> module_is_active
|
|
; module_is_not_active.
|
|
|
|
:- type proc_active
|
|
---> proc_active(
|
|
pa_proc_desc :: proc_desc,
|
|
pa_is_active :: proc_is_active
|
|
).
|
|
|
|
:- type proc_is_active
|
|
---> proc_is_active
|
|
; proc_is_not_active.
|
|
|
|
% The representation of a procedure in a report structure, including
|
|
% information about its location in Mercury source code.
|
|
%
|
|
:- type proc_desc
|
|
---> proc_desc(
|
|
pdesc_ps_ptr :: proc_static_ptr,
|
|
pdesc_file_name :: string,
|
|
pdesc_line_number :: int,
|
|
pdesc_module_name :: string,
|
|
pdesc_uq_refined_name :: string,
|
|
pdesc_q_refined_name :: string
|
|
).
|
|
|
|
% The representation of a call site in a report structure, including
|
|
% information about its location in Mercury source code.
|
|
%
|
|
:- type call_site_desc
|
|
---> call_site_desc(
|
|
csdesc_css_ptr :: call_site_static_ptr,
|
|
csdesc_container :: proc_static_ptr,
|
|
csdesc_file_name :: string,
|
|
csdesc_line_number :: int,
|
|
csdesc_caller_module_name :: string,
|
|
csdesc_caller_uq_refined_name :: string,
|
|
csdesc_caller_q_refined_name :: string,
|
|
csdesc_slot_number :: int,
|
|
csdesc_goal_path :: reverse_goal_path,
|
|
csdesc_maybe_callee :: maybe(proc_desc)
|
|
).
|
|
|
|
:- type ancestor_desc
|
|
---> ancestor_desc(
|
|
% The caller and callee cliques.
|
|
ad_caller_clique_ptr :: clique_ptr,
|
|
ad_callee_clique_ptr :: clique_ptr,
|
|
|
|
% The callee procedure.
|
|
ad_callee_pdesc :: proc_desc,
|
|
|
|
% The description of the call site. This includes a description
|
|
% of the caller procedure.
|
|
ad_call_site_desc :: call_site_desc
|
|
).
|
|
|
|
% The description of a clique in a report structure.
|
|
%
|
|
:- type clique_desc
|
|
---> clique_desc(
|
|
cdesc_clique_ptr :: clique_ptr,
|
|
cdesc_entry_member :: proc_desc,
|
|
cdesc_other_members :: list(proc_desc)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Predicates to make common actions on these types easier.
|
|
%
|
|
|
|
:- pred proc_label_from_proc_desc(deep::in, proc_desc::in,
|
|
string_proc_label::out) is det.
|
|
|
|
% foldl(add_call_site_report_to_map(CallSiteReports, map.init,
|
|
% CallSitesMap).
|
|
%
|
|
% Build a map from goal paths to call site reports.
|
|
%
|
|
:- pred add_call_site_report_to_map(clique_call_site_report::in,
|
|
map(reverse_goal_path, clique_call_site_report)::in,
|
|
map(reverse_goal_path, clique_call_site_report)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
proc_label_from_proc_desc(Deep, ProcDesc, ProcLabel) :-
|
|
PSPtr = ProcDesc ^ pdesc_ps_ptr,
|
|
deep_lookup_proc_statics(Deep, PSPtr, ProcStatic),
|
|
ProcLabel = ProcStatic ^ ps_id.
|
|
|
|
add_call_site_report_to_map(CallSite, !Map) :-
|
|
GoalPath = CallSite ^ ccsr_call_site_summary ^ perf_row_subject
|
|
^ csdesc_goal_path,
|
|
map.det_insert(GoalPath, CallSite, !Map).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module report.
|
|
%---------------------------------------------------------------------------%
|