mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
deep_profiler/*.m:
Fix inconsistencies between (a) the order in which functions and predicates
are declared, and (b) the order in which they are defined.
In most modules, either the order of the declarations or the order
of the definitions made sense, and I changed the other to match.
In some modules, neither made sense, so I changed *both* to an order
that *does* make sense (i.e. it has related predicates together).
In query.m, put the various commands in the same sensible order
as the code processing them.
In html_format.m, merge two exported functions together, since
they can't be used separately.
In some places, put dividers between groups of related
functions/predicates, to make the groups themselves more visible.
In some places, fix comments or programming style.
deep_profiler/DEEP_FLAGS.in:
Since all the modules in this directory are now free from any warnings
generated by --warn-inconsistent-pred-order-clauses, specify that option
by default in this directory to keep it that way.
1752 lines
68 KiB
Mathematica
1752 lines
68 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: create_report.m.
|
|
% Author: pbone.
|
|
%
|
|
% This module creates a report from a deep data structure and a query.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module create_report.
|
|
:- interface.
|
|
|
|
:- import_module measurements.
|
|
:- import_module profile.
|
|
:- import_module query.
|
|
:- import_module report.
|
|
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred create_report(cmd::in, deep::in, deep_report::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Create a clique report for the specified clique.
|
|
%
|
|
:- pred create_clique_report(deep::in, clique_ptr::in,
|
|
maybe_error(clique_report)::out) is det.
|
|
|
|
% Create a proc report for the specified procedure.
|
|
%
|
|
:- pred create_proc_report(deep::in, proc_static_ptr::in,
|
|
maybe_error(proc_report)::out) is det.
|
|
|
|
% Create a static procrep coverage report.
|
|
%
|
|
:- pred create_static_procrep_coverage_report(deep::in,
|
|
proc_static_ptr::in, maybe_error(procrep_coverage_info)::out) is det.
|
|
|
|
% Create a dynamic procrep coverage report.
|
|
%
|
|
% This will fail if dynamic coverage information is not present in the
|
|
% profile.
|
|
%
|
|
:- pred create_dynamic_procrep_coverage_report(deep::in,
|
|
proc_dynamic_ptr::in, maybe_error(procrep_coverage_info)::out) is det.
|
|
|
|
% Create a CSD var use report.
|
|
%
|
|
:- pred create_call_site_dynamic_var_use_report(deep::in,
|
|
call_site_dynamic_ptr::in,
|
|
maybe_error(call_site_dynamic_var_use_info)::out) is det.
|
|
|
|
% Create a top procs report, from the given data with the specified
|
|
% parameters.
|
|
%
|
|
:- pred create_top_procs_report(deep::in, display_limit::in, cost_kind::in,
|
|
include_descendants::in, measurement_scope::in,
|
|
maybe_error(top_procs_report)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Create a proc_desc structure for a given proc static pointer.
|
|
%
|
|
:- func describe_proc(deep, proc_static_ptr) = proc_desc.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Convert own and inherit perf information to row data used for reports.
|
|
%
|
|
:- pred own_and_inherit_to_perf_row_data(deep::in, T::in,
|
|
own_prof_info::in, inherit_prof_info::in, perf_row_data(T)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module analysis_utils.
|
|
:- import_module apply_exclusion.
|
|
:- import_module coverage.
|
|
:- import_module exclude.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.goal_path.
|
|
:- import_module mdbcomp.program_representation.
|
|
:- import_module measurement_units.
|
|
:- import_module program_representation_utils.
|
|
:- import_module recursion_patterns.
|
|
:- import_module top_procs.
|
|
:- import_module var_use_analysis.
|
|
|
|
:- import_module array.
|
|
:- import_module char.
|
|
:- import_module cord.
|
|
:- import_module float.
|
|
:- import_module int.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module unit.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
create_report(Cmd, Deep, Report) :-
|
|
(
|
|
Cmd = deep_cmd_quit,
|
|
Msg = string.format("Shutting down deep profile server for %s.",
|
|
[s(Deep ^ data_file_name)]),
|
|
MessageReport = message_report(Msg),
|
|
Report = report_message(MessageReport)
|
|
;
|
|
Cmd = deep_cmd_restart,
|
|
unexpected($pred, "restart command")
|
|
;
|
|
Cmd = deep_cmd_timeout(Timeout),
|
|
Msg = string.format("Timeout set to %d minutes.", [i(Timeout)]),
|
|
MessageReport = message_report(Msg),
|
|
Report = report_message(MessageReport)
|
|
;
|
|
Cmd = deep_cmd_menu,
|
|
Deep ^ profile_stats = profile_stats(ProgramName,
|
|
NumCSD, NumCSS, NumPD, NumPS,
|
|
QuantaPerSec, InstrumentationQuanta, UserQuanta, NumCallseqs, _),
|
|
NumCliques = array.max(Deep ^ clique_members),
|
|
MenuReport = menu_report(ProgramName, QuantaPerSec,
|
|
UserQuanta, InstrumentationQuanta,
|
|
NumCallseqs, NumCSD, NumCSS, NumPD, NumPS, NumCliques),
|
|
Report = report_menu(ok(MenuReport))
|
|
;
|
|
Cmd = deep_cmd_root(MaybePercent),
|
|
create_root_report(Deep, MaybePercent, MaybeCliqueReport),
|
|
Report = report_clique(MaybeCliqueReport)
|
|
;
|
|
Cmd = deep_cmd_clique(CliquePtr),
|
|
create_clique_report(Deep, CliquePtr, MaybeCliqueReport),
|
|
Report = report_clique(MaybeCliqueReport)
|
|
;
|
|
Cmd = deep_cmd_clique_recursive_costs(CliquePtr),
|
|
create_clique_recursion_costs_report(Deep, CliquePtr,
|
|
MaybeCliqueRecursionReport),
|
|
Report = report_clique_recursion_costs(MaybeCliqueRecursionReport)
|
|
;
|
|
Cmd = deep_cmd_proc(PSPtr),
|
|
create_proc_report(Deep, PSPtr, MaybeProcReport),
|
|
Report = report_proc(MaybeProcReport)
|
|
;
|
|
Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum,
|
|
CallersPerBunch, Contour),
|
|
create_proc_callers_report(Deep, PSPtr, CallerGroups, BunchNum,
|
|
CallersPerBunch, Contour, MaybeProcCallersReport),
|
|
Report = report_proc_callers(MaybeProcCallersReport)
|
|
;
|
|
(
|
|
Cmd = deep_cmd_static_procrep_coverage(PSPtr),
|
|
create_static_procrep_coverage_report(Deep, PSPtr,
|
|
MaybeProcrepCoverageReport)
|
|
;
|
|
Cmd = deep_cmd_dynamic_procrep_coverage(PDPtr),
|
|
create_dynamic_procrep_coverage_report(Deep, PDPtr,
|
|
MaybeProcrepCoverageReport)
|
|
),
|
|
Report = report_procrep_coverage(MaybeProcrepCoverageReport)
|
|
;
|
|
Cmd = deep_cmd_call_site_dynamic_var_use(CSDPtr),
|
|
create_call_site_dynamic_var_use_report(Deep, CSDPtr, MaybeVarUse),
|
|
Report = report_call_site_dynamic_var_use(MaybeVarUse)
|
|
;
|
|
Cmd = deep_cmd_recursion_types_frequency,
|
|
create_recursion_types_frequency_report(Deep, MaybeRecTypesFreqReport),
|
|
Report = report_recursion_types_frequency(MaybeRecTypesFreqReport)
|
|
;
|
|
Cmd = deep_cmd_program_modules,
|
|
create_program_modules_report(Deep, MaybeProgramModulesReport),
|
|
Report = report_program_modules(MaybeProgramModulesReport)
|
|
;
|
|
Cmd = deep_cmd_module(ModuleName),
|
|
create_module_report(Deep, ModuleName, MaybeModuleReport),
|
|
Report = report_module(MaybeModuleReport)
|
|
;
|
|
Cmd = deep_cmd_module_getter_setters(ModuleName),
|
|
create_module_getter_setter_report(Deep, ModuleName,
|
|
MaybeModuleGetterSettersReport),
|
|
Report = report_module_getter_setters(MaybeModuleGetterSettersReport)
|
|
;
|
|
Cmd = deep_cmd_module_rep(ModuleName),
|
|
create_module_rep_report(Deep, ModuleName, MaybeModuleRepReport),
|
|
Report = report_module_rep(MaybeModuleRepReport)
|
|
;
|
|
Cmd = deep_cmd_top_procs(Limit, CostKind, InclDesc, Scope),
|
|
create_top_procs_report(Deep, Limit, CostKind, InclDesc, Scope,
|
|
MaybeTopProcsReport),
|
|
Report = report_top_procs(MaybeTopProcsReport)
|
|
;
|
|
Cmd = deep_cmd_dump_clique(CliquePtr),
|
|
create_clique_dump_report(Deep, CliquePtr, MaybeCliqueDump),
|
|
Report = report_clique_dump(MaybeCliqueDump)
|
|
;
|
|
Cmd = deep_cmd_dump_proc_static(PSPtr),
|
|
create_proc_static_dump_report(Deep, PSPtr, MaybeProcStaticDump),
|
|
Report = report_proc_static_dump(MaybeProcStaticDump)
|
|
;
|
|
Cmd = deep_cmd_dump_proc_dynamic(PDPtr),
|
|
create_proc_dynamic_dump_report(Deep, PDPtr, MaybeProcDynamicDump),
|
|
Report = report_proc_dynamic_dump(MaybeProcDynamicDump)
|
|
;
|
|
Cmd = deep_cmd_dump_call_site_static(CSSPtr),
|
|
create_call_site_static_dump_report(Deep, CSSPtr,
|
|
MaybeCallSiteStaticDump),
|
|
Report = report_call_site_static_dump(MaybeCallSiteStaticDump)
|
|
;
|
|
Cmd = deep_cmd_dump_call_site_dynamic(CSDPtr),
|
|
create_call_site_dynamic_dump_report(Deep, CSDPtr,
|
|
MaybeCallSiteStaticDump),
|
|
Report = report_call_site_dynamic_dump(MaybeCallSiteStaticDump)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a clique report for the root clique, or the clique where
|
|
% the action begins.
|
|
%
|
|
|
|
:- pred create_root_report(deep::in, maybe(int)::in,
|
|
maybe_error(clique_report)::out) is det.
|
|
|
|
create_root_report(Deep, MaybePercent, MaybeReport) :-
|
|
deep_lookup_clique_index(Deep, Deep ^ root, RootCliquePtr),
|
|
create_clique_report(Deep, RootCliquePtr, MaybeRootCliqueReport),
|
|
(
|
|
MaybeRootCliqueReport = error(_),
|
|
MaybeReport = MaybeRootCliqueReport
|
|
;
|
|
MaybeRootCliqueReport = ok(RootCliqueReport),
|
|
(
|
|
MaybePercent = no,
|
|
MaybeReport = ok(RootCliqueReport)
|
|
;
|
|
MaybePercent = yes(Percent),
|
|
find_start_of_action(Deep, Percent, RootCliqueReport, Report),
|
|
MaybeReport = ok(Report)
|
|
)
|
|
).
|
|
|
|
:- pred find_start_of_action(deep::in, int::in,
|
|
clique_report::in, clique_report::out) is det.
|
|
|
|
find_start_of_action(Deep, Percent, CurrentReport, SelectedReport) :-
|
|
CurrentReport = clique_report(_, _, CliqueProcs),
|
|
list.foldl(find_start_of_action_clique_proc(Percent), CliqueProcs,
|
|
[], ActionCliquePtrs),
|
|
( if
|
|
ActionCliquePtrs = [ActionCliquePtr],
|
|
create_clique_report(Deep, ActionCliquePtr, MaybeActionCliqueReport),
|
|
MaybeActionCliqueReport = ok(ActionCliqueReport)
|
|
then
|
|
find_start_of_action(Deep, Percent, ActionCliqueReport, SelectedReport)
|
|
else
|
|
SelectedReport = CurrentReport
|
|
).
|
|
|
|
:- pred find_start_of_action_clique_proc(int::in, clique_proc_report::in,
|
|
list(clique_ptr)::in, list(clique_ptr)::out) is det.
|
|
|
|
find_start_of_action_clique_proc(Percent, CliqueProcReport,
|
|
!ActionCliquePtrs) :-
|
|
CliqueProcReport = clique_proc_report(_, FirstPDReport, LaterPDReports),
|
|
find_start_of_action_clique_proc_dynamic(Percent,
|
|
FirstPDReport, !ActionCliquePtrs),
|
|
list.foldl(find_start_of_action_clique_proc_dynamic(Percent),
|
|
LaterPDReports, !ActionCliquePtrs).
|
|
|
|
:- pred find_start_of_action_clique_proc_dynamic(int::in,
|
|
clique_proc_dynamic_report::in,
|
|
list(clique_ptr)::in, list(clique_ptr)::out) is det.
|
|
|
|
find_start_of_action_clique_proc_dynamic(Percent, CliquePDReport,
|
|
!ActionCliquePtrs) :-
|
|
CliquePDReport = clique_proc_dynamic_report(_, CallSites),
|
|
list.foldl(find_start_of_action_call_site(Percent), CallSites,
|
|
!ActionCliquePtrs).
|
|
|
|
:- pred find_start_of_action_call_site(int::in, clique_call_site_report::in,
|
|
list(clique_ptr)::in, list(clique_ptr)::out) is det.
|
|
|
|
find_start_of_action_call_site(Percent, CallSiteReport, !ActionCliquePtrs) :-
|
|
CallSiteReport = clique_call_site_report(_, _, CalleeRowDatas),
|
|
list.foldl(find_start_of_action_callee(Percent), CalleeRowDatas,
|
|
!ActionCliquePtrs).
|
|
|
|
:- pred find_start_of_action_callee(int::in, perf_row_data(clique_desc)::in,
|
|
list(clique_ptr)::in, list(clique_ptr)::out) is det.
|
|
|
|
find_start_of_action_callee(Percent, RowData, !ActionCliquePtrs) :-
|
|
MaybeTotalPerf = RowData ^ perf_row_maybe_total,
|
|
(
|
|
MaybeTotalPerf = no,
|
|
unexpected($pred, "no total perf")
|
|
;
|
|
MaybeTotalPerf = yes(TotalPerf),
|
|
CallSeqsPercent = TotalPerf ^ perf_row_callseqs_percent,
|
|
( if percent_at_or_above_threshold(Percent, CallSeqsPercent) then
|
|
CliqueDesc = RowData ^ perf_row_subject,
|
|
CliquePtr = CliqueDesc ^ cdesc_clique_ptr,
|
|
!:ActionCliquePtrs = [CliquePtr | !.ActionCliquePtrs]
|
|
else
|
|
true
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a clique report.
|
|
%
|
|
|
|
create_clique_report(Deep, CliquePtr, MaybeCliqueReport) :-
|
|
AncestorRowDatas = find_clique_ancestors(Deep, CliquePtr),
|
|
|
|
deep_lookup_clique_members(Deep, CliquePtr, PDPtrs),
|
|
list.foldl(group_proc_dynamics_by_proc_static(Deep), PDPtrs,
|
|
map.init, PStoPDsMap),
|
|
map.to_assoc_list(PStoPDsMap, PStoPDsList0),
|
|
deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
|
|
( if valid_call_site_dynamic_ptr(Deep, EntryCSDPtr) then
|
|
deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
|
|
EntryPDPtr = EntryCSD ^ csd_callee,
|
|
list.filter(proc_group_contains(EntryPDPtr), PStoPDsList0,
|
|
EntryGroup, RestGroup),
|
|
PStoPDsList = EntryGroup ++ RestGroup
|
|
else
|
|
PStoPDsList = PStoPDsList0
|
|
),
|
|
list.map(create_clique_proc_report(Deep, CliquePtr),
|
|
PStoPDsList, CliqueProcs),
|
|
|
|
CliqueReport = clique_report(CliquePtr, AncestorRowDatas, CliqueProcs),
|
|
MaybeCliqueReport = ok(CliqueReport).
|
|
|
|
:- func find_clique_ancestors(deep, clique_ptr) =
|
|
list(perf_row_data(ancestor_desc)).
|
|
|
|
find_clique_ancestors(Deep, CliquePtr) = Ancestors :-
|
|
deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
|
|
( if valid_call_site_dynamic_ptr(Deep, EntryCSDPtr) then
|
|
deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
|
|
EntryPDPtr = EntryCSD ^ csd_caller,
|
|
( if EntryPDPtr = Deep ^ root then
|
|
% We could return the true root node, which is the Mercury runtime
|
|
% system, but that is of no interest to either users or programs.
|
|
Ancestors = []
|
|
else
|
|
deep_lookup_clique_index(Deep, EntryPDPtr, EntryCliquePtr),
|
|
CalleePDPtr = EntryCSD ^ csd_callee,
|
|
deep_lookup_proc_dynamics(Deep, CalleePDPtr, CalleePD),
|
|
CalleePSPtr = CalleePD ^ pd_proc_static,
|
|
CalleeDesc = describe_proc(Deep, CalleePSPtr),
|
|
deep_lookup_call_site_static_map(Deep, EntryCSDPtr, EntryCSSPtr),
|
|
EntryCallSiteDesc = describe_call_site(Deep, EntryCSSPtr),
|
|
AncestorDesc = ancestor_desc(EntryCliquePtr, CliquePtr,
|
|
CalleeDesc, EntryCallSiteDesc),
|
|
Own = EntryCSD ^ csd_own_prof,
|
|
deep_lookup_csd_desc(Deep, EntryCSDPtr, Desc),
|
|
own_and_inherit_to_perf_row_data(Deep, AncestorDesc, Own, Desc,
|
|
Parent),
|
|
MoreAncestors = find_clique_ancestors(Deep, EntryCliquePtr),
|
|
Ancestors = [Parent | MoreAncestors]
|
|
)
|
|
else
|
|
Ancestors = []
|
|
).
|
|
|
|
:- pred group_proc_dynamics_by_proc_static(deep::in, proc_dynamic_ptr::in,
|
|
map(proc_static_ptr, list(proc_dynamic_ptr))::in,
|
|
map(proc_static_ptr, list(proc_dynamic_ptr))::out) is det.
|
|
|
|
group_proc_dynamics_by_proc_static(Deep, PDPtr, !PStoPDsMap) :-
|
|
require(valid_proc_dynamic_ptr(Deep, PDPtr),
|
|
"group_proc_dynamics_by_proc_static: invalid PDPtr"),
|
|
deep_lookup_proc_dynamics(Deep, PDPtr, PD),
|
|
PSPtr = PD ^ pd_proc_static,
|
|
( if map.search(!.PStoPDsMap, PSPtr, PSPDs0) then
|
|
PSPDs = [PDPtr | PSPDs0],
|
|
map.det_update(PSPtr, PSPDs, !PStoPDsMap)
|
|
else
|
|
map.det_insert(PSPtr, [PDPtr], !PStoPDsMap)
|
|
).
|
|
|
|
:- pred proc_group_contains(proc_dynamic_ptr::in,
|
|
pair(proc_static_ptr, list(proc_dynamic_ptr))::in) is semidet.
|
|
|
|
proc_group_contains(EntryPDPtr, _ - PDPtrs) :-
|
|
list.member(EntryPDPtr, PDPtrs).
|
|
|
|
:- pred create_clique_proc_report(deep::in, clique_ptr::in,
|
|
pair(proc_static_ptr, list(proc_dynamic_ptr))::in,
|
|
clique_proc_report::out) is det.
|
|
|
|
create_clique_proc_report(Deep, CliquePtr, PSPtr - PDPtrs, CliqueProcReport) :-
|
|
(
|
|
PDPtrs = [],
|
|
unexpected($pred, "PDPtrs = []")
|
|
;
|
|
PDPtrs = [FirstPDPtr | LaterPDPtrs],
|
|
ProcDesc = describe_proc(Deep, PSPtr),
|
|
create_clique_proc_dynamic_report(Deep, CliquePtr, ProcDesc,
|
|
FirstPDPtr, FirstPDOwn, FirstPDDesc, FirstPDReport),
|
|
list.map3(create_clique_proc_dynamic_report(Deep, CliquePtr, ProcDesc),
|
|
LaterPDPtrs, LaterPDOwns, LaterPDDescs, LaterPDReports),
|
|
SummaryOwn = sum_own_infos([FirstPDOwn | LaterPDOwns]),
|
|
SummaryDesc = sum_inherit_infos([FirstPDDesc | LaterPDDescs]),
|
|
own_and_inherit_to_perf_row_data(Deep, ProcDesc,
|
|
SummaryOwn, SummaryDesc, ProcSummaryRowData),
|
|
CliqueProcReport = clique_proc_report(ProcSummaryRowData,
|
|
FirstPDReport, LaterPDReports)
|
|
).
|
|
|
|
:- pred create_clique_proc_dynamic_report(deep::in, clique_ptr::in,
|
|
proc_desc::in, proc_dynamic_ptr::in,
|
|
own_prof_info::out, inherit_prof_info::out,
|
|
clique_proc_dynamic_report::out) is det.
|
|
|
|
create_clique_proc_dynamic_report(Deep, _CliquePtr, ProcDesc, PDPtr,
|
|
Own, Desc, CliquePDReport) :-
|
|
( if valid_proc_dynamic_ptr(Deep, PDPtr) then
|
|
deep_lookup_pd_own(Deep, PDPtr, Own),
|
|
deep_lookup_pd_desc(Deep, PDPtr, Desc),
|
|
own_and_inherit_to_perf_row_data(Deep, ProcDesc, Own, Desc,
|
|
PDRowData),
|
|
deep_lookup_proc_dynamics(Deep, PDPtr, PD),
|
|
PSPtr = PD ^ pd_proc_static,
|
|
require(unify(PSPtr, ProcDesc ^ pdesc_ps_ptr),
|
|
"create_clique_proc_dynamic_report: psptr mismatch"),
|
|
create_child_call_site_reports(Deep, PDPtr, CliqueCallSiteReports),
|
|
CliquePDReport = clique_proc_dynamic_report(PDRowData,
|
|
CliqueCallSiteReports)
|
|
else
|
|
unexpected($pred, "invalid proc_dynamic index")
|
|
).
|
|
|
|
:- pred create_child_call_site_reports(deep::in, proc_dynamic_ptr::in,
|
|
list(clique_call_site_report)::out) is det.
|
|
|
|
create_child_call_site_reports(Deep, PDPtr, CliqueCallSiteReports) :-
|
|
proc_dynamic_paired_call_site_slots(Deep, PDPtr, PairedSlots),
|
|
list.map(create_child_call_site_report(Deep), PairedSlots,
|
|
CliqueCallSiteReports).
|
|
|
|
:- pred create_child_call_site_report(deep::in,
|
|
pair(call_site_static_ptr, call_site_array_slot)::in,
|
|
clique_call_site_report::out) is det.
|
|
|
|
create_child_call_site_report(Deep, Pair, CliqueCallSiteReport) :-
|
|
Pair = CSSPtr - CallSiteArraySlot,
|
|
deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
|
|
CallSiteDesc = describe_call_site(Deep, CSSPtr),
|
|
Kind = CSS ^ css_kind,
|
|
(
|
|
Kind = normal_call_and_callee(CalleePSPtr, TypeSubst),
|
|
KnownCalleeDesc = describe_proc(Deep, CalleePSPtr),
|
|
ProcDescKind = normal_call_and_callee(KnownCalleeDesc, TypeSubst),
|
|
(
|
|
CallSiteArraySlot = slot_normal(CSDPtr)
|
|
;
|
|
CallSiteArraySlot = slot_multi(_, _),
|
|
unexpected($pred, "normal_call is multi")
|
|
),
|
|
( if valid_call_site_dynamic_ptr(Deep, CSDPtr) then
|
|
create_callee_clique_perf_row_data(Deep, CSDPtr, Own, Desc,
|
|
CalleeCliqueRowData),
|
|
CalleeCliqueRowDatas = [CalleeCliqueRowData]
|
|
else
|
|
Own = zero_own_prof_info,
|
|
Desc = zero_inherit_prof_info,
|
|
CalleeCliqueRowDatas = []
|
|
)
|
|
;
|
|
(
|
|
Kind = special_call_and_no_callee,
|
|
ProcDescKind = special_call_and_no_callee
|
|
;
|
|
Kind = higher_order_call_and_no_callee,
|
|
ProcDescKind = higher_order_call_and_no_callee
|
|
;
|
|
Kind = method_call_and_no_callee,
|
|
ProcDescKind = method_call_and_no_callee
|
|
;
|
|
Kind = callback_and_no_callee,
|
|
ProcDescKind = callback_and_no_callee
|
|
),
|
|
(
|
|
CallSiteArraySlot = slot_normal(_),
|
|
unexpected($pred, "non-normal_call is normal")
|
|
;
|
|
CallSiteArraySlot = slot_multi(_IsZeroed, CSDPtrsArray),
|
|
array.to_list(CSDPtrsArray, CSDPtrs)
|
|
),
|
|
list.map3(create_callee_clique_perf_row_data(Deep), CSDPtrs,
|
|
Owns, Descs, CalleeCliqueRowDatas),
|
|
Own = sum_own_infos(Owns),
|
|
Desc = sum_inherit_infos(Descs)
|
|
),
|
|
own_and_inherit_to_perf_row_data(Deep, CallSiteDesc, Own, Desc,
|
|
SummaryRowData),
|
|
CliqueCallSiteReport = clique_call_site_report(SummaryRowData,
|
|
ProcDescKind, CalleeCliqueRowDatas).
|
|
|
|
:- pred create_callee_clique_perf_row_data(deep::in, call_site_dynamic_ptr::in,
|
|
own_prof_info::out, inherit_prof_info::out,
|
|
perf_row_data(clique_desc)::out) is det.
|
|
|
|
create_callee_clique_perf_row_data(Deep, CSDPtr, Own, Desc,
|
|
CalleeCliqueRowData) :-
|
|
require(valid_call_site_dynamic_ptr(Deep, CSDPtr),
|
|
"create_callee_clique_perf_row_data: invalid call_site_dynamic_ptr"),
|
|
deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
|
|
CalleePDPtr = CSD ^ csd_callee,
|
|
Own = CSD ^ csd_own_prof,
|
|
deep_lookup_csd_desc(Deep, CSDPtr, Desc),
|
|
deep_lookup_clique_index(Deep, CalleePDPtr, CalleeCliquePtr),
|
|
CliqueDesc = describe_clique(Deep, CalleeCliquePtr, yes(CalleePDPtr)),
|
|
own_and_inherit_to_perf_row_data(Deep, CliqueDesc, Own, Desc,
|
|
CalleeCliqueRowData).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a proc report.
|
|
%
|
|
|
|
create_proc_report(Deep, PSPtr, MaybeProcReport) :-
|
|
( if valid_proc_static_ptr(Deep, PSPtr) then
|
|
ProcDesc = describe_proc(Deep, PSPtr),
|
|
deep_lookup_ps_own(Deep, PSPtr, Own),
|
|
deep_lookup_ps_desc(Deep, PSPtr, Desc),
|
|
own_and_inherit_to_perf_row_data(Deep, ProcDesc, Own, Desc,
|
|
ProcSummaryRowData),
|
|
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
CallSitesArray = PS ^ ps_sites,
|
|
array.to_list(CallSitesArray, CallSites),
|
|
ProcCallSiteSummaryRowDatas = list.map(create_call_site_summary(Deep),
|
|
CallSites),
|
|
|
|
deep_lookup_proc_callers(Deep, PSPtr, CallerCSDPtrs0),
|
|
summarize_callers(Deep, CallerCSDPtrs0, PSPtr, set.init, SeenProcs,
|
|
0, NumDynamic, zero_own_prof_info, CallersOwn,
|
|
zero_inherit_prof_info, CallersInherit),
|
|
NumStatic = set.count(SeenProcs),
|
|
own_and_inherit_to_perf_row_data(Deep,
|
|
callers_counts(NumStatic, NumDynamic), CallersOwn,
|
|
CallersInherit, CallersSummaryRowData),
|
|
|
|
ProcReport = proc_report(CallersSummaryRowData, ProcSummaryRowData,
|
|
ProcCallSiteSummaryRowDatas),
|
|
MaybeProcReport = ok(ProcReport)
|
|
else
|
|
MaybeProcReport = error("invalid proc_static index")
|
|
).
|
|
|
|
:- func create_call_site_summary(deep, call_site_static_ptr) = call_site_perf.
|
|
|
|
create_call_site_summary(Deep, CSSPtr) = CallSitePerf :-
|
|
CallSiteDesc = describe_call_site(Deep, CSSPtr),
|
|
|
|
deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
|
|
KindAndCallee = CSS ^ css_kind,
|
|
CallerPSPtr = CSS ^ css_container,
|
|
|
|
deep_lookup_call_site_calls(Deep, CSSPtr, CallSiteCallMap),
|
|
map.to_assoc_list(CallSiteCallMap, CallSiteCalls),
|
|
|
|
(
|
|
KindAndCallee = normal_call_and_callee(CalleePSPtr, TypeSubstStr),
|
|
CalleeDesc = describe_proc(Deep, CalleePSPtr),
|
|
NormalCallId = normal_callee_id(CalleeDesc, TypeSubstStr),
|
|
KindAndInfo = normal_call_and_info(NormalCallId),
|
|
(
|
|
CallSiteCalls = [],
|
|
Own = zero_own_prof_info,
|
|
Desc = zero_inherit_prof_info
|
|
;
|
|
CallSiteCalls = [CallSiteCall],
|
|
CallSiteCall = CalleePSPtrFromCall - _,
|
|
require(unify(CalleePSPtr, CalleePSPtrFromCall),
|
|
"create_call_site_summary: callee mismatch"),
|
|
CallSiteCalleePerf = generate_call_site_callee_perf(Deep,
|
|
CallerPSPtr, CallSiteCall),
|
|
CallSiteCalleePerf = call_site_callee_perf(_, Own, Desc)
|
|
;
|
|
CallSiteCalls = [_, _ | _],
|
|
unexpected($pred, ">1 proc called at normal site")
|
|
),
|
|
own_and_inherit_to_perf_row_data(Deep, CallSiteDesc, Own, Desc,
|
|
SummaryRowData),
|
|
SubRowDatas = []
|
|
;
|
|
(
|
|
KindAndCallee = special_call_and_no_callee,
|
|
KindAndInfo = special_call_and_no_info
|
|
;
|
|
KindAndCallee = higher_order_call_and_no_callee,
|
|
KindAndInfo = higher_order_call_and_no_info
|
|
;
|
|
KindAndCallee = method_call_and_no_callee,
|
|
KindAndInfo = method_call_and_no_info
|
|
;
|
|
KindAndCallee = callback_and_no_callee,
|
|
KindAndInfo = callback_and_no_info
|
|
),
|
|
CallSiteCalleePerfs =
|
|
list.map(generate_call_site_callee_perf(Deep, CallerPSPtr),
|
|
CallSiteCalls),
|
|
list.map_foldl2(accumulate_call_site_callees(Deep),
|
|
CallSiteCalleePerfs, SubRowDatas,
|
|
zero_own_prof_info, SumOwn, zero_inherit_prof_info, SumDesc),
|
|
own_and_inherit_to_perf_row_data(Deep, CallSiteDesc, SumOwn, SumDesc,
|
|
SummaryRowData)
|
|
),
|
|
CallSitePerf = call_site_perf(KindAndInfo, SummaryRowData, SubRowDatas).
|
|
|
|
:- type call_site_callee_perf
|
|
---> call_site_callee_perf(
|
|
cscpi_callee :: proc_static_ptr,
|
|
cscpi_own_prof_info :: own_prof_info,
|
|
cscpi_inherit_prof_info :: inherit_prof_info
|
|
).
|
|
|
|
:- func generate_call_site_callee_perf(deep, proc_static_ptr,
|
|
pair(proc_static_ptr, list(call_site_dynamic_ptr)))
|
|
= call_site_callee_perf.
|
|
|
|
generate_call_site_callee_perf(Deep, CallerPSPtr, PSPtr - CSDPtrs)
|
|
= CalleeProf :-
|
|
list.foldl2(accumulate_csd_prof_info(Deep, CallerPSPtr), CSDPtrs,
|
|
zero_own_prof_info, Own, zero_inherit_prof_info, Desc),
|
|
CalleeProf = call_site_callee_perf(PSPtr, Own, Desc).
|
|
|
|
:- pred summarize_callers(deep::in, list(call_site_dynamic_ptr)::in,
|
|
proc_static_ptr::in, set(proc_static_ptr)::in, set(proc_static_ptr)::out,
|
|
int::in, int::out, own_prof_info::in, own_prof_info::out,
|
|
inherit_prof_info::in, inherit_prof_info::out) is det.
|
|
|
|
summarize_callers(Deep, CallerCSDPtrs0, CalleePSPtr, !PSSeen, !NumDynamic,
|
|
!Own, !Desc) :-
|
|
(
|
|
CallerCSDPtrs0 = []
|
|
;
|
|
CallerCSDPtrs0 = [CSDPtr | CallerCSDPtrs],
|
|
|
|
deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
|
|
CallerPDPtr = CSD ^ csd_caller,
|
|
deep_lookup_proc_dynamics(Deep, CallerPDPtr, CallerPD),
|
|
CallerPSPtr = CallerPD ^ pd_proc_static,
|
|
( if CallerPSPtr = CalleePSPtr then
|
|
% Exclude recursive calls.
|
|
true
|
|
else
|
|
!:NumDynamic = !.NumDynamic + 1,
|
|
set.insert(CallerPSPtr, !PSSeen),
|
|
CSDOwn = CSD ^ csd_own_prof,
|
|
!:Own = add_own_to_own(!.Own, CSDOwn),
|
|
deep_lookup_csd_desc(Deep, CSDPtr, CSDInherit),
|
|
!:Desc = add_inherit_to_inherit(!.Desc, CSDInherit)
|
|
),
|
|
|
|
summarize_callers(Deep, CallerCSDPtrs, CalleePSPtr, !PSSeen,
|
|
!NumDynamic, !Own, !Desc)
|
|
).
|
|
|
|
:- pred accumulate_csd_prof_info(deep::in, proc_static_ptr::in,
|
|
call_site_dynamic_ptr::in,
|
|
own_prof_info::in, own_prof_info::out,
|
|
inherit_prof_info::in, inherit_prof_info::out) is det.
|
|
|
|
accumulate_csd_prof_info(Deep, CallerPSPtr, CSDPtr, !Own, !Desc) :-
|
|
deep_lookup_csd_own(Deep, CSDPtr, CSDOwn),
|
|
deep_lookup_csd_desc(Deep, CSDPtr, CSDDesc),
|
|
!:Own = add_own_to_own(!.Own, CSDOwn),
|
|
!:Desc = add_inherit_to_inherit(!.Desc, CSDDesc),
|
|
deep_lookup_csd_comp_table(Deep, CSDPtr, CompTableArray),
|
|
( if map.search(CompTableArray, CallerPSPtr, InnerTotal) then
|
|
!:Desc = subtract_inherit_from_inherit(InnerTotal, !.Desc)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred accumulate_call_site_callees(deep::in,
|
|
call_site_callee_perf::in, perf_row_data(proc_desc)::out,
|
|
own_prof_info::in, own_prof_info::out,
|
|
inherit_prof_info::in, inherit_prof_info::out) is det.
|
|
|
|
accumulate_call_site_callees(Deep, CalleePerf, RowData, !Own, !Desc) :-
|
|
CalleePerf = call_site_callee_perf(CalleePSPtr, CalleeOwn, CalleeDesc),
|
|
CalleeProcDesc = describe_proc(Deep, CalleePSPtr),
|
|
own_and_inherit_to_perf_row_data(Deep, CalleeProcDesc,
|
|
CalleeOwn, CalleeDesc, RowData),
|
|
!:Own = add_own_to_own(!.Own, CalleeOwn),
|
|
!:Desc = add_inherit_to_inherit(!.Desc, CalleeDesc).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a proc_callers report.
|
|
%
|
|
|
|
:- pred create_proc_callers_report(deep::in, proc_static_ptr::in,
|
|
caller_groups::in, int::in, int::in, contour_exclusion::in,
|
|
maybe_error(proc_callers_report)::out) is det.
|
|
|
|
create_proc_callers_report(Deep, PSPtr, CallerGroups, BunchNum,
|
|
CallersPerBunch, Contour, MaybeProcCallersReport) :-
|
|
( if valid_proc_static_ptr(Deep, PSPtr) then
|
|
ProcDesc = describe_proc(Deep, PSPtr),
|
|
|
|
deep_lookup_proc_callers(Deep, PSPtr, CallerCSDPtrs0),
|
|
(
|
|
Contour = do_not_apply_contour_exclusion,
|
|
CallerCSDPtrPairs0 = list.map(pair_self, CallerCSDPtrs0),
|
|
MaybeCallerCSDPtrPairs = ok(CallerCSDPtrPairs0),
|
|
MaybeWarnMessage = no
|
|
;
|
|
Contour = apply_contour_exclusion,
|
|
ExcludeFile = Deep ^ exclude_contour_file,
|
|
ExcludeFile = exclude_file(ExcludeFileName, ExcludeContents),
|
|
(
|
|
ExcludeContents = no_exclude_file,
|
|
% There is no contour exclusion file, so do the same as for
|
|
% do_not_apply_contour_exclusion, but add a message to the
|
|
% report.
|
|
string.format("Could not read contour exclusion file `%s'.",
|
|
[s(ExcludeFileName)], ErrorMessage0),
|
|
MaybeCallerCSDPtrPairs = error(ErrorMessage0),
|
|
MaybeWarnMessage = no
|
|
;
|
|
ExcludeContents = unreadable_exclude_file(ErrorMsg),
|
|
string.format(
|
|
"The contour exclusion file `%s' has an error: %s.",
|
|
[s(ExcludeFileName), s(ErrorMsg)], ErrorMessage0),
|
|
MaybeCallerCSDPtrPairs = error(ErrorMessage0),
|
|
MaybeWarnMessage = no
|
|
;
|
|
ExcludeContents = readable_exclude_file(ExcludeModules,
|
|
MaybeWarnMsg),
|
|
CallerCSDPtrPairs0 = list.map(
|
|
pair_contour(Deep, ExcludeModules), CallerCSDPtrs0),
|
|
MaybeCallerCSDPtrPairs = ok(CallerCSDPtrPairs0),
|
|
(
|
|
MaybeWarnMsg = no,
|
|
MaybeWarnMessage = no
|
|
;
|
|
MaybeWarnMsg = yes(WarnMessage),
|
|
MaybeWarnMessage = yes(WarnMessage)
|
|
)
|
|
)
|
|
),
|
|
(
|
|
MaybeCallerCSDPtrPairs = error(ErrorMessage),
|
|
MaybeProcCallersReport = error(ErrorMessage)
|
|
;
|
|
MaybeCallerCSDPtrPairs = ok(CallerCSDPtrPairs),
|
|
(
|
|
CallerGroups = group_by_call_site,
|
|
CallSiteCallerGroups = group_csds_by_call_site(Deep,
|
|
CallerCSDPtrPairs),
|
|
ProcCallerCallSites = list.map(
|
|
create_proc_caller_call_sites(Deep, PSPtr),
|
|
CallSiteCallerGroups),
|
|
Callers = proc_caller_call_sites(ProcCallerCallSites)
|
|
;
|
|
CallerGroups = group_by_proc,
|
|
ProcCallerGroups = group_csds_by_procedure(Deep,
|
|
CallerCSDPtrPairs),
|
|
ProcCallerProcs = list.map(
|
|
create_proc_caller_procedures(Deep, PSPtr),
|
|
ProcCallerGroups),
|
|
Callers = proc_caller_procedures(ProcCallerProcs)
|
|
;
|
|
CallerGroups = group_by_module,
|
|
ModuleCallerGroups = group_csds_by_module(Deep,
|
|
CallerCSDPtrPairs),
|
|
ProcCallerModules = list.map(
|
|
create_proc_caller_modules(Deep, PSPtr),
|
|
ModuleCallerGroups),
|
|
Callers = proc_caller_modules(ProcCallerModules)
|
|
;
|
|
CallerGroups = group_by_clique,
|
|
CliqueCallerGroups = group_csds_by_clique(Deep,
|
|
CallerCSDPtrPairs),
|
|
ProcCallerCliques = list.map(
|
|
create_proc_caller_cliques(Deep, PSPtr),
|
|
CliqueCallerGroups),
|
|
Callers = proc_caller_cliques(ProcCallerCliques)
|
|
),
|
|
ProcCallersReport = proc_callers_report(ProcDesc, Callers,
|
|
BunchNum, CallersPerBunch, Contour, MaybeWarnMessage),
|
|
MaybeProcCallersReport = ok(ProcCallersReport)
|
|
)
|
|
else
|
|
MaybeProcCallersReport = error("invalid proc_static index")
|
|
).
|
|
|
|
:- func create_proc_caller_call_sites(deep, proc_static_ptr,
|
|
pair(call_site_static_ptr, list(call_site_dynamic_ptr)))
|
|
= perf_row_data(call_site_desc).
|
|
|
|
create_proc_caller_call_sites(Deep, CalleePSPtr, CSSPtr - CSDPtrs) =
|
|
PerfRowData :-
|
|
CallSiteDesc = describe_call_site(Deep, CSSPtr),
|
|
compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
|
|
own_and_inherit_to_perf_row_data(Deep, CallSiteDesc, Own, Desc,
|
|
PerfRowData).
|
|
|
|
:- func create_proc_caller_procedures(deep, proc_static_ptr,
|
|
pair(proc_static_ptr, list(call_site_dynamic_ptr)))
|
|
= perf_row_data(proc_desc).
|
|
|
|
create_proc_caller_procedures(Deep, CalleePSPtr, PSSPtr - CSDPtrs) =
|
|
PerfRowData :-
|
|
ProcDesc = describe_proc(Deep, PSSPtr),
|
|
compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
|
|
own_and_inherit_to_perf_row_data(Deep, ProcDesc, Own, Desc,
|
|
PerfRowData).
|
|
|
|
:- func create_proc_caller_modules(deep, proc_static_ptr,
|
|
pair(string, list(call_site_dynamic_ptr)))
|
|
= perf_row_data(string).
|
|
|
|
create_proc_caller_modules(Deep, CalleePSPtr, ModuleName - CSDPtrs) =
|
|
PerfRowData :-
|
|
compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
|
|
own_and_inherit_to_perf_row_data(Deep, ModuleName, Own, Desc,
|
|
PerfRowData).
|
|
|
|
:- func create_proc_caller_cliques(deep, proc_static_ptr,
|
|
pair(clique_ptr, list(call_site_dynamic_ptr)))
|
|
= perf_row_data(clique_desc).
|
|
|
|
create_proc_caller_cliques(Deep, CalleePSPtr, CliquePtr - CSDPtrs) =
|
|
PerfRowData :-
|
|
CliqueDesc = describe_clique(Deep, CliquePtr, no),
|
|
compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
|
|
own_and_inherit_to_perf_row_data(Deep, CliqueDesc, Own, Desc,
|
|
PerfRowData).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to create the coverage annotated procedure representation report.
|
|
%
|
|
|
|
create_static_procrep_coverage_report(Deep, PSPtr, MaybeReport) :-
|
|
( if valid_proc_static_ptr(Deep, PSPtr) then
|
|
deep_lookup_ps_coverage(Deep, PSPtr, StaticCoverage),
|
|
MaybeCoveragePoints =
|
|
static_coverage_maybe_get_coverage_points(StaticCoverage),
|
|
|
|
% Gather call site information.
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
CallSitesArray = PS ^ ps_sites,
|
|
array.foldl(build_static_call_site_cost_and_callee_map(Deep),
|
|
CallSitesArray, map.init, CallSitesMap),
|
|
|
|
% Gather information about the procedure.
|
|
deep_lookup_ps_own(Deep, PSPtr, Own),
|
|
|
|
maybe_create_procrep_coverage_report(Deep, PSPtr, Own,
|
|
MaybeCoveragePoints, CallSitesMap, MaybeReport)
|
|
else
|
|
PSPtr = proc_static_ptr(PSId),
|
|
MaybeReport = error(
|
|
string.format("Proc static pointer is invalid %d", [i(PSId)]))
|
|
).
|
|
|
|
create_dynamic_procrep_coverage_report(Deep, PDPtr, MaybeReport) :-
|
|
( if valid_proc_dynamic_ptr(Deep, PDPtr) then
|
|
deep_lookup_proc_dynamics(Deep, PDPtr, PD),
|
|
PSPtr = PD ^ pd_proc_static,
|
|
MaybeCoveragePoints = PD ^ pd_maybe_coverage_points,
|
|
|
|
% Gather call site information.
|
|
proc_dynamic_paired_call_site_slots(Deep, PDPtr, Slots),
|
|
foldl(build_dynamic_call_site_cost_and_callee_map(Deep), Slots,
|
|
map.init, CallSitesMap),
|
|
|
|
% Gather information about the procedure.
|
|
deep_lookup_pd_own(Deep, PDPtr, Own),
|
|
|
|
maybe_create_procrep_coverage_report(Deep, PSPtr, Own,
|
|
MaybeCoveragePoints, CallSitesMap, MaybeReport)
|
|
else
|
|
PDPtr = proc_dynamic_ptr(PDId),
|
|
MaybeReport = error(
|
|
string.format("Proc dynamic pointer is invalid %d", [i(PDId)]))
|
|
).
|
|
|
|
:- pred maybe_create_procrep_coverage_report(deep::in, proc_static_ptr::in,
|
|
own_prof_info::in, maybe(array(int))::in,
|
|
map(reverse_goal_path, cost_and_callees(Callee))::in,
|
|
maybe_error(procrep_coverage_info)::out) is det.
|
|
|
|
maybe_create_procrep_coverage_report(_, _, _, no, _, error(Error)) :-
|
|
Error = "No coverage information available".
|
|
maybe_create_procrep_coverage_report(Deep, PSPtr, Own,
|
|
yes(CoveragePointsArray), CallSitesMap, MaybeReport) :-
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
coverage_point_arrays_to_list(PS ^ ps_coverage_point_infos,
|
|
CoveragePointsArray, CoveragePoints),
|
|
deep_get_maybe_procrep(Deep, PSPtr, MaybeProcRep0),
|
|
(
|
|
MaybeProcRep0 = error(Error),
|
|
MaybeReport = error(Error)
|
|
;
|
|
MaybeProcRep0 = ok(ProcRep0),
|
|
|
|
foldl2(add_coverage_point_to_map,
|
|
CoveragePoints, map.init, SolnsCoveragePointMap,
|
|
map.init, BranchCoveragePointMap),
|
|
Goal0 = ProcRep0 ^ pr_defn ^ pdr_goal,
|
|
label_goals(LastGoalId, ContainingGoalMap, Goal0, Goal),
|
|
ProcRep = ProcRep0 ^ pr_defn ^ pdr_goal := Goal,
|
|
procrep_annotate_with_coverage(ProcRep, Own, CallSitesMap,
|
|
SolnsCoveragePointMap, BranchCoveragePointMap,
|
|
ContainingGoalMap, LastGoalId, CoverageArray),
|
|
MaybeReport = ok(procrep_coverage_info(PSPtr, ProcRep, CoverageArray))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a var use report for a call site.
|
|
%
|
|
|
|
create_call_site_dynamic_var_use_report(Deep, CSDPtr, MaybeVarUseInfo) :-
|
|
( if valid_call_site_dynamic_ptr(Deep, CSDPtr) then
|
|
deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
|
|
CalleePDPtr = CSD ^ csd_callee,
|
|
CallerPDPtr = CSD ^ csd_caller,
|
|
deep_lookup_proc_dynamics(Deep, CalleePDPtr, CalleePD),
|
|
CalleePSPtr = CalleePD ^ pd_proc_static,
|
|
deep_get_maybe_procrep(Deep, CalleePSPtr, MaybeProcrep),
|
|
(
|
|
MaybeProcrep = ok(Procrep),
|
|
HeadVars = Procrep ^ pr_defn ^ pdr_head_vars,
|
|
VarNameTable = Procrep ^ pr_defn ^ pdr_var_name_table,
|
|
deep_lookup_clique_index(Deep, CallerPDPtr, ParentCliquePtr),
|
|
deep_lookup_clique_index(Deep, CalleePDPtr, CalleeCliquePtr),
|
|
create_clique_recursion_costs_report(Deep, ParentCliquePtr,
|
|
MaybeRecursiveCostsReport),
|
|
(
|
|
MaybeRecursiveCostsReport = ok(RecursiveCostsReport),
|
|
RecursionType = RecursiveCostsReport ^ crr_recursion_type,
|
|
( if ParentCliquePtr = CalleeCliquePtr then
|
|
get_recursive_csd_cost(Deep, CSDPtr, RecursionType,
|
|
MaybeCost)
|
|
else
|
|
deep_lookup_csd_desc(Deep, CSDPtr, Desc),
|
|
deep_lookup_csd_own(Deep, CSDPtr, Own),
|
|
Cost0 = callseqs(Own) + inherit_callseqs(Desc),
|
|
MaybeCost = ok(float(Cost0))
|
|
),
|
|
(
|
|
MaybeCost = ok(Cost),
|
|
map_foldl(call_site_dynamic_var_use_arg(Deep, CSDPtr,
|
|
RecursionType, Cost, VarNameTable),
|
|
HeadVars, Uses0, 0, _),
|
|
list_maybe_error_to_maybe_error_list(Uses0, MaybeUses),
|
|
(
|
|
MaybeUses = ok(Uses),
|
|
VarUseInfo =
|
|
call_site_dynamic_var_use_info(Cost, Uses),
|
|
MaybeVarUseInfo = ok(VarUseInfo)
|
|
;
|
|
MaybeUses = error(Error),
|
|
MaybeVarUseInfo = error(Error)
|
|
)
|
|
;
|
|
MaybeCost = error(Error),
|
|
MaybeVarUseInfo = error(Error)
|
|
)
|
|
;
|
|
MaybeRecursiveCostsReport = error(Error),
|
|
MaybeVarUseInfo = error(Error)
|
|
)
|
|
;
|
|
MaybeProcrep = error(Error),
|
|
MaybeVarUseInfo = error(Error)
|
|
)
|
|
else
|
|
CSDPtr = call_site_dynamic_ptr(CSDNum),
|
|
MaybeVarUseInfo = error(
|
|
string.format("Invalid call site dynamic %d", [i(CSDNum)]))
|
|
).
|
|
|
|
:- pred call_site_dynamic_var_use_arg(deep::in, call_site_dynamic_ptr::in,
|
|
recursion_type::in, float::in, var_name_table::in, head_var_rep::in,
|
|
maybe_error(var_use_and_name)::out, int::in, int::out) is det.
|
|
|
|
call_site_dynamic_var_use_arg(Deep, CSDPtr, RecursionType, Cost, VarNameTable,
|
|
HeadVar, MaybeUseAndName, !ArgNum) :-
|
|
HeadVar = head_var_rep(Var, Mode),
|
|
var_mode_to_var_use_type(Mode, UseType),
|
|
% XXX: Allow user to configure var use options.
|
|
UseOptions = var_use_options(Deep, follow_any_call, UseType),
|
|
get_call_site_dynamic_var_use_info(CSDPtr, !.ArgNum, RecursionType,
|
|
Cost, UseOptions, MaybeUse),
|
|
(
|
|
MaybeUse = ok(Use),
|
|
lookup_var_name(VarNameTable, Var, Name),
|
|
MaybeUseAndName = ok(var_use_and_name(Name, Use))
|
|
;
|
|
MaybeUse = error(Error),
|
|
MaybeUseAndName = error(Error)
|
|
),
|
|
!:ArgNum = !.ArgNum + 1.
|
|
|
|
:- pred list_maybe_error_to_maybe_error_list(list(maybe_error(T))::in,
|
|
maybe_error(list(T))::out) is det.
|
|
|
|
list_maybe_error_to_maybe_error_list([], ok([])).
|
|
list_maybe_error_to_maybe_error_list([error(E) | _], error(E)).
|
|
list_maybe_error_to_maybe_error_list([ok(X) | MaybeXs0], MaybeXs) :-
|
|
list_maybe_error_to_maybe_error_list(MaybeXs0, MaybeXs1),
|
|
(
|
|
MaybeXs1 = ok(Xs1),
|
|
MaybeXs = ok([X | Xs1])
|
|
;
|
|
MaybeXs1 = error(E),
|
|
MaybeXs = error(E)
|
|
).
|
|
|
|
:- pred get_recursive_csd_cost(deep::in, call_site_dynamic_ptr::in,
|
|
recursion_type::in, maybe_error(float)::out) is det.
|
|
|
|
get_recursive_csd_cost(Deep, CSDPtr, RecursionType, MaybeCost) :-
|
|
(
|
|
RecursionType = rt_not_recursive,
|
|
MaybeCost =
|
|
error("get_recursive_csd_cost called for non-recursive clique")
|
|
;
|
|
RecursionType = rt_single(_, _, AvgMaxDepth, _, CostFn),
|
|
deep_lookup_csd_own(Deep, CSDPtr, Own),
|
|
Calls = float(calls(Own)),
|
|
MaybeCost = ok(CostFn(round_to_int(AvgMaxDepth) - 1) * Calls)
|
|
;
|
|
( RecursionType = rt_divide_and_conquer(_, _)
|
|
; RecursionType = rt_mutual_recursion(_)
|
|
; RecursionType = rt_other(_)
|
|
),
|
|
MaybeCost = error("get_recursive_csd_cost: unhandled recursion type")
|
|
;
|
|
RecursionType = rt_errors(Errors),
|
|
MaybeCost = error(join_list("\n", Errors))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a program_modules report.
|
|
%
|
|
|
|
% Create a program_modules report, from the given data with the specified
|
|
% parameters.
|
|
%
|
|
:- pred create_program_modules_report(deep::in,
|
|
maybe_error(program_modules_report)::out) is det.
|
|
|
|
create_program_modules_report(Deep, MaybeProgramModulesReport) :-
|
|
map.to_assoc_list(Deep ^ module_data, ModulePairs0),
|
|
list.filter(not_mercury_runtime, ModulePairs0, ModulePairs),
|
|
ModuleRowDatas = list.map(module_pair_to_row_data(Deep), ModulePairs),
|
|
ProgramModulesReport = program_modules_report(ModuleRowDatas),
|
|
MaybeProgramModulesReport = ok(ProgramModulesReport).
|
|
|
|
:- pred not_mercury_runtime(pair(string, module_data)::in) is semidet.
|
|
|
|
not_mercury_runtime(ModuleName - _) :-
|
|
ModuleName \= "Mercury runtime".
|
|
|
|
:- func module_pair_to_row_data(deep, pair(string, module_data))
|
|
= perf_row_data(module_active).
|
|
|
|
module_pair_to_row_data(Deep, ModuleName - ModuleData) = ModuleRowData :-
|
|
Own = ModuleData ^ module_own,
|
|
IsActive = compute_is_active(Own),
|
|
(
|
|
IsActive = is_active,
|
|
ModuleIsActive = module_is_active
|
|
;
|
|
IsActive = is_not_active,
|
|
ModuleIsActive = module_is_not_active
|
|
),
|
|
ModuleActive = module_active(ModuleName, ModuleIsActive),
|
|
own_and_maybe_inherit_to_perf_row_data(Deep, ModuleActive, Own, no,
|
|
ModuleRowData).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a module report.
|
|
%
|
|
|
|
% Create a module report, from the given data with the specified
|
|
% parameters.
|
|
%
|
|
:- pred create_module_report(deep::in, string::in,
|
|
maybe_error(module_report)::out) is det.
|
|
|
|
create_module_report(Deep, ModuleName, MaybeModuleReport) :-
|
|
( if map.search(Deep ^ module_data, ModuleName, ModuleData) then
|
|
deep_get_maybe_progrep(Deep, MaybeProgRep),
|
|
( if
|
|
MaybeProgRep = ok(ProgRep),
|
|
ProgRep = prog_rep(ModuleMap),
|
|
map.search(ModuleMap, ModuleName, _)
|
|
then
|
|
HaveModuleRep = have_module_rep
|
|
else
|
|
HaveModuleRep = do_not_have_module_rep
|
|
),
|
|
PSPtrs = ModuleData ^ module_procs,
|
|
ProcRowDatas = list.map(proc_to_active_row_data(Deep), PSPtrs),
|
|
ModuleReport = module_report(ModuleName, HaveModuleRep, ProcRowDatas),
|
|
MaybeModuleReport = ok(ModuleReport)
|
|
else
|
|
Msg = string.format("There is no module named `%s'.\n",
|
|
[s(ModuleName)]),
|
|
MaybeModuleReport = error(Msg)
|
|
).
|
|
|
|
:- func proc_to_active_row_data(deep, proc_static_ptr)
|
|
= perf_row_data(proc_active).
|
|
|
|
proc_to_active_row_data(Deep, PSPtr) = ProcRowData :-
|
|
deep_lookup_ps_own(Deep, PSPtr, Own),
|
|
deep_lookup_ps_desc(Deep, PSPtr, Desc),
|
|
IsActive = compute_is_active(Own),
|
|
(
|
|
IsActive = is_active,
|
|
ProcIsActive = proc_is_active
|
|
;
|
|
IsActive = is_not_active,
|
|
ProcIsActive = proc_is_not_active
|
|
),
|
|
ProcDesc = describe_proc(Deep, PSPtr),
|
|
ProcActive = proc_active(ProcDesc, ProcIsActive),
|
|
own_and_inherit_to_perf_row_data(Deep, ProcActive, Own, Desc, ProcRowData).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a module_getter_setters report.
|
|
%
|
|
|
|
:- type gs_field_raw_data
|
|
---> gs_field_raw_data(
|
|
gs_raw_proc :: proc_desc,
|
|
gs_raw_own :: own_prof_info,
|
|
gs_raw_desc :: inherit_prof_info
|
|
).
|
|
|
|
:- type raw_gs_field_info == gs_field_info(gs_field_raw_data, unit).
|
|
:- type raw_gs_field_map == gs_field_map(raw_gs_field_info).
|
|
:- type raw_gs_ds_map == gs_ds_map(raw_gs_field_info).
|
|
|
|
% Create a module_getter_setters report, from the given data
|
|
% with the specified parameters.
|
|
%
|
|
:- pred create_module_getter_setter_report(deep::in, string::in,
|
|
maybe_error(module_getter_setters_report)::out) is det.
|
|
|
|
create_module_getter_setter_report(Deep, ModuleName,
|
|
MaybeModuleGetterSettersReport) :-
|
|
( if map.search(Deep ^ module_data, ModuleName, ModuleData) then
|
|
PSPtrs = ModuleData ^ module_procs,
|
|
list.foldl(gather_getters_setters(Deep), PSPtrs,
|
|
map.init, GetterSetterDataMap),
|
|
map.map_values(getter_setter_raw_map_to_info_map(Deep),
|
|
GetterSetterDataMap, GetterSetterInfoMap),
|
|
ModuleGetterSettersReport = module_getter_setters_report(ModuleName,
|
|
GetterSetterInfoMap),
|
|
MaybeModuleGetterSettersReport = ok(ModuleGetterSettersReport)
|
|
else
|
|
Msg = string.format("There is no module named `%s'.\n",
|
|
[s(ModuleName)]),
|
|
MaybeModuleGetterSettersReport = error(Msg)
|
|
).
|
|
|
|
:- pred getter_setter_raw_map_to_info_map(deep::in, data_struct_name::in,
|
|
raw_gs_field_map::in, gs_field_map::out) is det.
|
|
|
|
getter_setter_raw_map_to_info_map(Deep, _DataStructName, RawMap, Map) :-
|
|
map.map_values(getter_setter_raw_data_to_info(Deep), RawMap, Map).
|
|
|
|
:- pred getter_setter_raw_data_to_info(deep::in, field_name::in,
|
|
raw_gs_field_info::in, gs_field_info::out) is det.
|
|
|
|
getter_setter_raw_data_to_info(Deep, _FieldName, RawData, Data) :-
|
|
(
|
|
RawData = gs_field_both(RawGetter, RawSetter, _),
|
|
RawGetter = gs_field_raw_data(GetterProcDesc, GetterOwn, GetterDesc),
|
|
RawSetter = gs_field_raw_data(SetterProcDesc, SetterOwn, SetterDesc),
|
|
own_and_inherit_to_perf_row_data(Deep, GetterProcDesc,
|
|
GetterOwn, GetterDesc, GetterRowData),
|
|
own_and_inherit_to_perf_row_data(Deep, SetterProcDesc,
|
|
SetterOwn, SetterDesc, SetterRowData),
|
|
SumOwn = add_own_to_own(GetterOwn, SetterOwn),
|
|
SumDesc = add_inherit_to_inherit(GetterDesc, SetterDesc),
|
|
own_and_inherit_to_perf_row_data(Deep, unit, SumOwn, SumDesc,
|
|
SumRowData),
|
|
Data = gs_field_both(GetterRowData, SetterRowData, SumRowData)
|
|
;
|
|
RawData = gs_field_getter(RawGetter),
|
|
RawGetter = gs_field_raw_data(GetterProcDesc, GetterOwn, GetterDesc),
|
|
own_and_inherit_to_perf_row_data(Deep, GetterProcDesc, GetterOwn,
|
|
GetterDesc, GetterRowData),
|
|
Data = gs_field_getter(GetterRowData)
|
|
;
|
|
RawData = gs_field_setter(RawSetter),
|
|
RawSetter = gs_field_raw_data(SetterProcDesc, SetterOwn, SetterDesc),
|
|
own_and_inherit_to_perf_row_data(Deep, SetterProcDesc, SetterOwn,
|
|
SetterDesc, SetterRowData),
|
|
Data = gs_field_setter(SetterRowData)
|
|
).
|
|
|
|
:- pred gather_getters_setters(deep::in, proc_static_ptr::in,
|
|
raw_gs_ds_map::in, raw_gs_ds_map::out) is det.
|
|
|
|
gather_getters_setters(Deep, PSPtr, !GSDSRawMap) :-
|
|
( if valid_proc_static_ptr(Deep, PSPtr) then
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
Id = PS ^ ps_id,
|
|
( if
|
|
is_getter_or_setter(Id, GetterSetter, DataStructName, FieldName)
|
|
then
|
|
deep_lookup_ps_own(Deep, PSPtr, Own),
|
|
deep_lookup_ps_desc(Deep, PSPtr, Desc),
|
|
ProcDesc = describe_proc(Deep, PSPtr),
|
|
RawData = gs_field_raw_data(ProcDesc, Own, Desc),
|
|
( if map.search(!.GSDSRawMap, DataStructName, FieldMap0Prime) then
|
|
FieldMap0 = FieldMap0Prime
|
|
else
|
|
map.init(FieldMap0)
|
|
),
|
|
( if map.search(FieldMap0, FieldName, FieldData0) then
|
|
(
|
|
GetterSetter = getter,
|
|
(
|
|
( FieldData0 = gs_field_both(_, _, _)
|
|
; FieldData0 = gs_field_getter(_)
|
|
),
|
|
unexpected($pred, "redundant getter")
|
|
;
|
|
FieldData0 = gs_field_setter(SetterRawData),
|
|
FieldData = gs_field_both(RawData, SetterRawData, unit)
|
|
)
|
|
;
|
|
GetterSetter = setter,
|
|
(
|
|
( FieldData0 = gs_field_both(_, _, _)
|
|
; FieldData0 = gs_field_setter(_)
|
|
),
|
|
unexpected($pred, "redundant setter")
|
|
;
|
|
FieldData0 = gs_field_getter(GetterRawData),
|
|
FieldData = gs_field_both(GetterRawData, RawData, unit)
|
|
)
|
|
),
|
|
map.det_update(FieldName, FieldData, FieldMap0, FieldMap)
|
|
else
|
|
(
|
|
GetterSetter = getter,
|
|
FieldData = gs_field_getter(RawData)
|
|
;
|
|
GetterSetter = setter,
|
|
FieldData = gs_field_setter(RawData)
|
|
),
|
|
map.det_insert(FieldName, FieldData, FieldMap0, FieldMap)
|
|
),
|
|
map.set(DataStructName, FieldMap, !GSDSRawMap)
|
|
else
|
|
true
|
|
)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred is_getter_or_setter(string_proc_label::in, getter_or_setter::out,
|
|
data_struct_name::out, field_name::out) is semidet.
|
|
|
|
is_getter_or_setter(StringProcLabel, GetterSetter, DataStructName,
|
|
FieldName) :-
|
|
StringProcLabel = str_ordinary_proc_label(_PorF, DeclModule, DefModule,
|
|
Name, Arity, _Mode),
|
|
DeclModule = DefModule,
|
|
string.to_char_list(Name, NameChars),
|
|
is_getter_or_setter_2(NameChars, GetterSetter, DataStructNameChars,
|
|
FieldNameChars),
|
|
(
|
|
GetterSetter = getter,
|
|
Arity = 2
|
|
;
|
|
GetterSetter = setter,
|
|
Arity = 3
|
|
),
|
|
string.from_char_list(DataStructNameChars, DataStructNameStr),
|
|
string.from_char_list(FieldNameChars, FieldNameStr),
|
|
DataStructName = data_struct_name(DataStructNameStr),
|
|
FieldName = field_name(FieldNameStr).
|
|
|
|
:- pred is_getter_or_setter_2(list(char)::in, getter_or_setter::out,
|
|
list(char)::out, list(char)::out) is semidet.
|
|
|
|
is_getter_or_setter_2(NameChars, GetterSetter, DataStructNameChars,
|
|
FieldNameChars) :-
|
|
( if NameChars = ['_', 'g', 'e', 't', '_' | FieldNameCharsPrime] then
|
|
GetterSetter = getter,
|
|
DataStructNameChars = [],
|
|
FieldNameChars = FieldNameCharsPrime
|
|
else if NameChars = ['_', 's', 'e', 't', '_' | FieldNameCharsPrime] then
|
|
GetterSetter = setter,
|
|
DataStructNameChars = [],
|
|
FieldNameChars = FieldNameCharsPrime
|
|
else
|
|
NameChars = [FirstNameChar | LaterNameChars],
|
|
is_getter_or_setter_2(LaterNameChars, GetterSetter,
|
|
LaterDataStructNameChars, FieldNameChars),
|
|
DataStructNameChars = [FirstNameChar | LaterDataStructNameChars]
|
|
).
|
|
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a module_rep report.
|
|
%
|
|
|
|
:- pred create_module_rep_report(deep::in, string::in,
|
|
maybe_error(module_rep_report)::out) is det.
|
|
|
|
create_module_rep_report(Deep, ModuleName, MaybeModuleRepReport) :-
|
|
MaybeProgRep = Deep ^ procrep_file,
|
|
(
|
|
MaybeProgRep = yes(MaybeErrorProgRep),
|
|
(
|
|
MaybeErrorProgRep = ok(ProgRep),
|
|
ProgRep = prog_rep(ModuleRepMap),
|
|
( if map.search(ModuleRepMap, ModuleName, ModuleRep) then
|
|
print_module_to_strings(ModuleRep, CordStrs),
|
|
Str = string.append_list(cord.list(CordStrs)),
|
|
ModuleRepReport = module_rep_report(ModuleName, Str),
|
|
MaybeModuleRepReport = ok(ModuleRepReport)
|
|
else
|
|
Msg = string.format("There is no module named %s.\n",
|
|
[s(ModuleName)]),
|
|
MaybeModuleRepReport = error(Msg)
|
|
)
|
|
;
|
|
MaybeErrorProgRep = error(Msg),
|
|
MaybeModuleRepReport = error(Msg)
|
|
)
|
|
;
|
|
MaybeProgRep = no,
|
|
Msg = "Information about module representations is not available.\n",
|
|
MaybeModuleRepReport = error(Msg)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build a top_procs report.
|
|
%
|
|
|
|
create_top_procs_report(Deep, Limit, CostKind, InclDesc0, Scope0,
|
|
MaybeTopProcsReport) :-
|
|
(
|
|
CostKind = cost_calls,
|
|
% Counting calls is incompatible both with self_and_desc
|
|
% and per_call.
|
|
InclDesc = self,
|
|
Scope = overall
|
|
;
|
|
( CostKind = cost_redos
|
|
; CostKind = cost_time
|
|
; CostKind = cost_callseqs
|
|
; CostKind = cost_allocs
|
|
; CostKind = cost_words
|
|
),
|
|
InclDesc = InclDesc0,
|
|
Scope = Scope0
|
|
),
|
|
MaybeTopPSIs = find_top_procs(CostKind, InclDesc, Scope, Limit, Deep),
|
|
(
|
|
MaybeTopPSIs = error(ErrorMessage),
|
|
MaybeTopProcsReport = error("Internal error: " ++ ErrorMessage)
|
|
;
|
|
MaybeTopPSIs = ok(TopPSIs),
|
|
Ordering = report_ordering(Limit, CostKind, InclDesc, Scope),
|
|
list.map(psi_to_perf_row_data(Deep), TopPSIs, ProcRowDatas),
|
|
TopProcsReport = top_procs_report(Ordering, ProcRowDatas),
|
|
MaybeTopProcsReport = ok(TopProcsReport)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to build the reports that just dump the contents of the main
|
|
% data structures.
|
|
%
|
|
|
|
:- pred create_clique_dump_report(deep::in, clique_ptr::in,
|
|
maybe_error(clique_dump_info)::out) is det.
|
|
|
|
create_clique_dump_report(Deep, CliquePtr, MaybeCliqueDumpInfo) :-
|
|
( if valid_clique_ptr(Deep, CliquePtr) then
|
|
CliqueDesc = describe_clique(Deep, CliquePtr, no),
|
|
deep_lookup_clique_parents(Deep, CliquePtr, ParentCSDPtr),
|
|
deep_lookup_clique_members(Deep, CliquePtr, MemberPDPtrs),
|
|
CliqueDumpInfo = clique_dump_info(CliqueDesc, ParentCSDPtr,
|
|
MemberPDPtrs),
|
|
MaybeCliqueDumpInfo = ok(CliqueDumpInfo)
|
|
else
|
|
MaybeCliqueDumpInfo = error("invalid clique_ptr")
|
|
).
|
|
|
|
:- pred create_proc_static_dump_report(deep::in, proc_static_ptr::in,
|
|
maybe_error(proc_static_dump_info)::out) is det.
|
|
|
|
create_proc_static_dump_report(Deep, PSPtr, MaybeProcStaticDumpInfo) :-
|
|
( if valid_proc_static_ptr(Deep, PSPtr) then
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
% Should we dump some other fields?
|
|
PS = proc_static(_ProcId, _DeclModule,
|
|
UnQualRefinedName, QualRefinedName, RawName, FileName, LineNumber,
|
|
_InInterface, CallSites, CoveragePointInfos, _MaybeCoveragePoints,
|
|
_IsZeroed),
|
|
array.max(CallSites, MaxCallSiteIdx),
|
|
NumCallSites = MaxCallSiteIdx + 1,
|
|
array.max(CoveragePointInfos, MaxCoveragePointIdx),
|
|
NumCoveragePoints = MaxCoveragePointIdx + 1,
|
|
ProcStaticDumpInfo = proc_static_dump_info(PSPtr, RawName,
|
|
UnQualRefinedName, QualRefinedName,
|
|
FileName, LineNumber, NumCallSites, NumCoveragePoints),
|
|
MaybeProcStaticDumpInfo = ok(ProcStaticDumpInfo)
|
|
else
|
|
MaybeProcStaticDumpInfo = error("invalid proc_static index")
|
|
).
|
|
|
|
:- pred create_proc_dynamic_dump_report(deep::in, proc_dynamic_ptr::in,
|
|
maybe_error(proc_dynamic_dump_info)::out) is det.
|
|
|
|
create_proc_dynamic_dump_report(Deep, PDPtr, MaybeProcDynamicDumpInfo) :-
|
|
( if valid_proc_dynamic_ptr(Deep, PDPtr) then
|
|
deep_lookup_proc_dynamics(Deep, PDPtr, PD),
|
|
PD = proc_dynamic(PSPtr, CallSiteArray, MaybeCPCounts),
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
RawName = PS ^ ps_raw_id,
|
|
ModuleName = PS ^ ps_decl_module,
|
|
UnQualRefinedName = PS ^ ps_uq_refined_id,
|
|
QualRefinedName = PS ^ ps_q_refined_id,
|
|
array.to_list(CallSiteArray, CallSites),
|
|
(
|
|
MaybeCPCounts = yes(CPCounts),
|
|
CPInfos = PS ^ ps_coverage_point_infos,
|
|
coverage_point_arrays_to_list(CPInfos, CPCounts, CPs),
|
|
MaybeCPs = yes(CPs)
|
|
;
|
|
MaybeCPCounts = no,
|
|
MaybeCPs = no
|
|
),
|
|
ProcDynamicDumpInfo = proc_dynamic_dump_info(PDPtr, PSPtr,
|
|
RawName, ModuleName, UnQualRefinedName, QualRefinedName,
|
|
CallSites, MaybeCPs),
|
|
MaybeProcDynamicDumpInfo = ok(ProcDynamicDumpInfo)
|
|
else
|
|
MaybeProcDynamicDumpInfo = error("invalid proc_dynamic index")
|
|
).
|
|
|
|
:- pred create_call_site_static_dump_report(deep::in, call_site_static_ptr::in,
|
|
maybe_error(call_site_static_dump_info)::out) is det.
|
|
|
|
create_call_site_static_dump_report(Deep, CSSPtr,
|
|
MaybeCallSiteStaticDumpInfo) :-
|
|
( if valid_call_site_static_ptr(Deep, CSSPtr) then
|
|
deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
|
|
CSS = call_site_static(ContainingPSPtr, SlotNumber, CallSiteKind,
|
|
LineNumber, GoalPath),
|
|
CallSiteStaticDumpInfo = call_site_static_dump_info(CSSPtr,
|
|
ContainingPSPtr, SlotNumber, LineNumber, GoalPath, CallSiteKind),
|
|
MaybeCallSiteStaticDumpInfo = ok(CallSiteStaticDumpInfo)
|
|
else
|
|
MaybeCallSiteStaticDumpInfo = error("invalid call_site_static index")
|
|
).
|
|
|
|
:- pred create_call_site_dynamic_dump_report(deep::in,
|
|
call_site_dynamic_ptr::in,
|
|
maybe_error(call_site_dynamic_dump_info)::out) is det.
|
|
|
|
create_call_site_dynamic_dump_report(Deep, CSDPtr,
|
|
MaybeCallSiteDynamicDumpInfo) :-
|
|
( if valid_call_site_dynamic_ptr(Deep, CSDPtr) then
|
|
deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
|
|
CSD = call_site_dynamic(CallerPSPtr, CalleePSDPtr, Own),
|
|
Desc = zero_inherit_prof_info,
|
|
deep_lookup_call_site_static_map(Deep, CSDPtr, CSSPtr),
|
|
CallSiteDesc = describe_call_site(Deep, CSSPtr),
|
|
own_and_inherit_to_perf_row_data(Deep, CallSiteDesc, Own, Desc,
|
|
PerfRowData),
|
|
CallSiteDynamicDumpInfo = call_site_dynamic_dump_info(CSDPtr,
|
|
CallerPSPtr, CalleePSDPtr, PerfRowData),
|
|
MaybeCallSiteDynamicDumpInfo = ok(CallSiteDynamicDumpInfo)
|
|
else
|
|
MaybeCallSiteDynamicDumpInfo = error("invalid call_site_dynamic index")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
describe_proc(Deep, PSPtr) = ProcDesc :-
|
|
( if valid_proc_static_ptr(Deep, PSPtr) then
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
FileName = PS ^ ps_file_name,
|
|
LineNumber = PS ^ ps_line_number,
|
|
ModuleName = PS ^ ps_decl_module,
|
|
UnQualRefinedName = PS ^ ps_uq_refined_id,
|
|
QualRefinedName = PS ^ ps_q_refined_id
|
|
else
|
|
FileName = "",
|
|
LineNumber = 0,
|
|
ModuleName = "",
|
|
UnQualRefinedName = "mercury_runtime",
|
|
QualRefinedName = "mercury_runtime"
|
|
),
|
|
ProcDesc = proc_desc(PSPtr, FileName, LineNumber, ModuleName,
|
|
UnQualRefinedName, QualRefinedName).
|
|
|
|
% Create a call_site_desc structure for a given call site static pointer.
|
|
%
|
|
:- func describe_call_site(deep, call_site_static_ptr) = call_site_desc.
|
|
|
|
describe_call_site(Deep, CSSPtr) = CallSiteDesc :-
|
|
( if valid_call_site_static_ptr(Deep, CSSPtr) then
|
|
deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
|
|
CSS = call_site_static(ContainingPSPtr, SlotNumber, Kind, LineNumber,
|
|
RevGoalPath),
|
|
deep_lookup_proc_statics(Deep, ContainingPSPtr, ContainingPS),
|
|
FileName = ContainingPS ^ ps_file_name,
|
|
ModuleName = ContainingPS ^ ps_decl_module,
|
|
UnQualRefinedName = ContainingPS ^ ps_uq_refined_id,
|
|
QualRefinedName = ContainingPS ^ ps_q_refined_id,
|
|
(
|
|
Kind = normal_call_and_callee(CalleePSPtr, _TypeSubst),
|
|
CalleeDesc = describe_proc(Deep, CalleePSPtr),
|
|
MaybeCalleeDesc = yes(CalleeDesc)
|
|
;
|
|
( Kind = special_call_and_no_callee
|
|
; Kind = higher_order_call_and_no_callee
|
|
; Kind = method_call_and_no_callee
|
|
; Kind = callback_and_no_callee
|
|
),
|
|
MaybeCalleeDesc = no
|
|
)
|
|
else
|
|
ContainingPSPtr = dummy_proc_static_ptr,
|
|
FileName = "",
|
|
LineNumber = 0,
|
|
ModuleName = "",
|
|
UnQualRefinedName = "mercury_runtime",
|
|
QualRefinedName = "mercury_runtime",
|
|
SlotNumber = -1,
|
|
RevGoalPath = rgp_nil,
|
|
MaybeCalleeDesc = no
|
|
),
|
|
CallSiteDesc = call_site_desc(CSSPtr, ContainingPSPtr,
|
|
FileName, LineNumber, ModuleName, UnQualRefinedName, QualRefinedName,
|
|
SlotNumber, RevGoalPath, MaybeCalleeDesc).
|
|
|
|
% describe_clique(Deep, CliquePtr, MaybeEntryPDPtr) = CliqueDesc
|
|
%
|
|
% Create a clique_desc structure for a given clique. The calculation for
|
|
% the entry procedure into the clique can be overridden by supplying an
|
|
% EntryPDPtr in MaybeEntryPDPtr. This is useful when referring to a clique
|
|
% from itself.
|
|
%
|
|
:- func describe_clique(deep, clique_ptr, maybe(proc_dynamic_ptr)) =
|
|
clique_desc.
|
|
|
|
describe_clique(Deep, CliquePtr, MaybeEntryPDPtr) = CliqueDesc :-
|
|
( if valid_clique_ptr(Deep, CliquePtr) then
|
|
deep_lookup_clique_members(Deep, CliquePtr, MemberPDPtrs),
|
|
deep_lookup_clique_parents(Deep, CliquePtr, ParentCSDPtr),
|
|
deep_lookup_call_site_dynamics(Deep, ParentCSDPtr, ParentCSD),
|
|
(
|
|
MaybeEntryPDPtr = yes(EntryPDPtr)
|
|
;
|
|
MaybeEntryPDPtr = no,
|
|
EntryPDPtr = ParentCSD ^ csd_callee
|
|
),
|
|
( if list.delete_first(MemberPDPtrs, EntryPDPtr, OtherPDPtrs) then
|
|
EntryProcDesc = describe_clique_member(Deep, EntryPDPtr),
|
|
OtherProcDescs =
|
|
list.map(describe_clique_member(Deep), OtherPDPtrs),
|
|
CliqueDesc = clique_desc(CliquePtr, EntryProcDesc, OtherProcDescs)
|
|
else
|
|
unexpected($pred, "entry pdptr not a member")
|
|
)
|
|
else
|
|
unexpected($pred, "invalid clique_ptr")
|
|
).
|
|
|
|
:- func describe_clique_member(deep, proc_dynamic_ptr) = proc_desc.
|
|
|
|
describe_clique_member(Deep, PDPtr) = ProcDesc :-
|
|
deep_lookup_proc_dynamics(Deep, PDPtr, PD),
|
|
ProcDesc = describe_proc(Deep, PD ^ pd_proc_static).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Lookup the proc_static structure with the given PSI index number
|
|
% and return performance information about it.
|
|
%
|
|
:- pred psi_to_perf_row_data(deep::in, int::in, perf_row_data(proc_desc)::out)
|
|
is det.
|
|
|
|
psi_to_perf_row_data(Deep, PSI, RowData) :-
|
|
PSPtr = proc_static_ptr(PSI),
|
|
ProcDesc = describe_proc(Deep, PSPtr),
|
|
deep_lookup_ps_own(Deep, PSPtr, Own),
|
|
deep_lookup_ps_desc(Deep, PSPtr, Desc),
|
|
own_and_inherit_to_perf_row_data(Deep, ProcDesc, Own, Desc, RowData).
|
|
|
|
own_and_inherit_to_perf_row_data(Deep, Subject, Own, Desc, RowData) :-
|
|
own_and_maybe_inherit_to_perf_row_data(Deep, Subject, Own, yes(Desc),
|
|
RowData).
|
|
|
|
:- pred own_and_maybe_inherit_to_perf_row_data(deep::in, T::in,
|
|
own_prof_info::in, maybe(inherit_prof_info)::in, perf_row_data(T)::out)
|
|
is det.
|
|
|
|
own_and_maybe_inherit_to_perf_row_data(Deep, Subject, Own, MaybeDesc,
|
|
RowData) :-
|
|
% Look up global parameters and totals.
|
|
ProfileStats = Deep ^ profile_stats,
|
|
TicksPerSec = ProfileStats ^ prs_ticks_per_sec,
|
|
WordSize = ProfileStats ^ prs_deep_flags ^ df_bytes_per_int,
|
|
|
|
Root = root_total_info(Deep),
|
|
RootQuanta = inherit_quanta(Root),
|
|
RootCallseqs = inherit_callseqs(Root),
|
|
RootAllocs = inherit_allocs(Root),
|
|
RootWords = inherit_words(Root),
|
|
|
|
% Port counts.
|
|
Calls = calls(Own),
|
|
Exits = exits(Own),
|
|
Fails = fails(Own),
|
|
Redos = redos(Own),
|
|
Excps = excps(Own),
|
|
|
|
% Self times.
|
|
SelfTicks = quanta(Own),
|
|
SelfTime = ticks_to_time(SelfTicks, TicksPerSec),
|
|
SelfTimePercent = percent_from_ints(SelfTicks, RootQuanta),
|
|
SelfTimePerCall = time_percall(SelfTime, Calls),
|
|
|
|
% Self call sequence counts.
|
|
SelfCallseqs = callseqs(Own),
|
|
SelfCallseqsPercent = percent_from_ints(SelfCallseqs, RootCallseqs),
|
|
SelfCallseqsPerCall = int_per_call(SelfCallseqs, Calls),
|
|
|
|
% Self memory allocations.
|
|
SelfAllocs = allocs(Own),
|
|
SelfAllocsPercent = percent_from_ints(SelfAllocs, RootAllocs),
|
|
SelfAllocsPerCall = int_per_call(SelfAllocs, Calls),
|
|
|
|
% Self memory words.
|
|
SelfWords = words(Own),
|
|
SelfMemory = memory_words(SelfWords, WordSize),
|
|
SelfMemoryPercent = percent_from_ints(SelfWords, RootWords),
|
|
SelfMemoryPerCall = SelfMemory / Calls,
|
|
|
|
SelfPerf = inheritable_perf(
|
|
SelfTicks, SelfTime, SelfTimePercent, SelfTimePerCall,
|
|
SelfCallseqs, SelfCallseqsPercent, SelfCallseqsPerCall,
|
|
SelfAllocs, SelfAllocsPercent, SelfAllocsPerCall,
|
|
SelfMemory, SelfMemoryPercent, SelfMemoryPerCall),
|
|
|
|
(
|
|
MaybeDesc = no,
|
|
MaybeTotalPerf = no
|
|
;
|
|
MaybeDesc = yes(Desc),
|
|
|
|
% Self + descendants times.
|
|
TotalTicks = SelfTicks + inherit_quanta(Desc),
|
|
TotalTime = ticks_to_time(TotalTicks, TicksPerSec),
|
|
TotalTimePercent = percent_from_ints(TotalTicks, RootQuanta),
|
|
TotalTimePerCall = time_percall(TotalTime, Calls),
|
|
|
|
% Self + descendants call sequence counts.
|
|
TotalCallseqs = callseqs(Own) + inherit_callseqs(Desc),
|
|
TotalCallseqsPercent = percent_from_ints(TotalCallseqs, RootCallseqs),
|
|
TotalCallseqsPerCall = int_per_call(TotalCallseqs, Calls),
|
|
|
|
% Self + descendants memory allocations.
|
|
TotalAllocs = SelfAllocs + inherit_allocs(Desc),
|
|
TotalAllocsPercent = percent_from_ints(TotalAllocs, RootAllocs),
|
|
TotalAllocsPerCall = int_per_call(TotalAllocs, Calls),
|
|
|
|
% Self + descendants memory words.
|
|
TotalWords = SelfWords + inherit_words(Desc),
|
|
TotalMemory = memory_words(TotalWords, WordSize),
|
|
TotalMemoryPercent = percent_from_ints(TotalWords, RootWords),
|
|
TotalMemoryPerCall = TotalMemory / Calls,
|
|
|
|
TotalPerf = inheritable_perf(
|
|
TotalTicks, TotalTime, TotalTimePercent, TotalTimePerCall,
|
|
TotalCallseqs, TotalCallseqsPercent, TotalCallseqsPerCall,
|
|
TotalAllocs, TotalAllocsPercent, TotalAllocsPerCall,
|
|
TotalMemory, TotalMemoryPercent, TotalMemoryPerCall),
|
|
MaybeTotalPerf = yes(TotalPerf)
|
|
),
|
|
|
|
RowData = perf_row_data(Subject, Calls, Exits, Fails, Redos, Excps,
|
|
WordSize, SelfPerf, MaybeTotalPerf).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% int_per_call(Num, Calls) is the quotient of Nom and Calls, after they've
|
|
% both been cast to float.
|
|
%
|
|
:- func int_per_call(int, int) = float.
|
|
|
|
int_per_call(Num, Calls) =
|
|
( if Calls = 0 then
|
|
0.0
|
|
else
|
|
float(Num) / float(Calls)
|
|
).
|
|
|
|
% Give the percentage of two 'counts'.
|
|
%
|
|
:- func percent_from_ints(int, int) = percent.
|
|
|
|
percent_from_ints(Nom, Denom) = Percent :-
|
|
( if Denom = 0 then
|
|
Percent = percent(0.0)
|
|
else
|
|
Percent = percent(float(Nom) / float(Denom))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module create_report.
|
|
%---------------------------------------------------------------------------%
|