mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-10 03:13:46 +00:00
library/set.m:
library/set_bbbtree.m:
library/set_ctree234.m:
library/set_ordlist.m:
library/set_tree234.m:
library/set_unordlist.m:
Mark empty/1 and non_empty/1 as obsolete with is_empty and is_non_empty
as suggested replacements, and mark set/1 as obsolete with list_to_set/1
as suggested replacement.
NEWS:
Mention the above changes.
configure.ac:
Require the installed compiler to handle suggested replacements
in obsolete pragmas.
compiler/analysis.m:
Avoid calling the newly obsolete predicates.
Remove a workaround that probably hasn't been needed in a long time.
compiler/error_util.m:
compiler/hlds_args.m:
compiler/intermod.m:
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/mercury_compile_main.m:
compiler/module_cmds.m:
compiler/old_type_constraints.m:
compiler/options.m:
compiler/ordering_mode_constraints.m:
compiler/par_conj_gen.m:
compiler/parse_pragma.m:
compiler/prog_ctgc.m:
compiler/rbmm.add_rbmm_goal_infos.m:
compiler/rbmm.live_region_analysis.m:
compiler/structure_reuse.domain.m:
compiler/structure_reuse.versions.m:
compiler/structure_sharing.domain.m:
compiler/switch_detection.m:
compiler/term_constr_fixpoint.m:
compiler/term_constr_util.m:
compiler/tupling.m:
deep_profiler/analysis_utils.m:
deep_profiler/autopar_annotate.m:
deep_profiler/autopar_calc_overlap.m:
deep_profiler/recursion_patterns.m:
deep_profiler/var_use_analysis.m:
Avoid calling the newly obsolete predicates.
423 lines
16 KiB
Mathematica
423 lines
16 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: analysis_utils.m.
|
|
% Author: pbone.
|
|
%
|
|
% This module contains utility code that is useful for writing profile
|
|
% analyses.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module analysis_utils.
|
|
:- interface.
|
|
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.goal_path.
|
|
:- import_module mdbcomp.program_representation.
|
|
:- import_module measurements.
|
|
:- import_module profile.
|
|
:- import_module report.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module pair.
|
|
:- import_module set.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Instead of using the clique report above to find proc dynamics for a
|
|
% clique, use this as it is much faster.
|
|
%
|
|
:- pred find_clique_first_and_other_procs(deep::in, clique_ptr::in,
|
|
maybe(proc_dynamic_ptr)::out, list(proc_dynamic_ptr)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Lookup a procedure representation from the deep structure.
|
|
%
|
|
% (Perhaps this should be a new report).
|
|
%
|
|
:- pred deep_get_maybe_procrep(deep::in, proc_static_ptr::in,
|
|
maybe_error(proc_rep)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type cost_and_callees == cost_and_callees(callee).
|
|
|
|
:- type cost_and_callees(Callee)
|
|
---> cost_and_callees(
|
|
cac_cost :: cs_cost_csq,
|
|
cac_exits :: int,
|
|
cac_callees :: set(Callee),
|
|
cac_call_site_is_ho :: higher_order
|
|
).
|
|
|
|
:- type callee
|
|
---> callee(
|
|
c_clique :: clique_ptr,
|
|
c_csd :: call_site_dynamic_ptr
|
|
).
|
|
|
|
:- type higher_order
|
|
---> first_order_call
|
|
; higher_order_call.
|
|
|
|
:- pred build_static_call_site_cost_and_callee_map(deep::in,
|
|
call_site_static_ptr::in,
|
|
map(reverse_goal_path, cost_and_callees(proc_static_ptr))::in,
|
|
map(reverse_goal_path, cost_and_callees(proc_static_ptr))::out) is det.
|
|
|
|
:- pred build_dynamic_call_site_cost_and_callee_map(deep::in,
|
|
pair(call_site_static_ptr, call_site_array_slot)::in,
|
|
map(reverse_goal_path, cost_and_callees)::in,
|
|
map(reverse_goal_path, cost_and_callees)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Estimate the cost of the recursive calls under the assumption that
|
|
% current call to this procedure had a particular cost.
|
|
%
|
|
:- pred build_recursive_call_site_cost_map(deep, clique_ptr,
|
|
proc_dynamic_ptr, recursion_type, maybe(recursion_depth),
|
|
maybe_error(map(reverse_goal_path, cs_cost_csq))).
|
|
:- mode build_recursive_call_site_cost_map(in, in, in,
|
|
in(recursion_type_known_costs), in(maybe_yes(ground)),
|
|
out(maybe_error_ok(ground))) is det.
|
|
:- mode build_recursive_call_site_cost_map(in, in, in, in, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred proc_dynamic_paired_call_site_slots(deep::in, proc_dynamic_ptr::in,
|
|
assoc_list(call_site_static_ptr, call_site_array_slot)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred cost_and_callees_is_recursive(clique_ptr::in, cost_and_callees::in)
|
|
is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module program_representation_utils.
|
|
|
|
:- import_module array.
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module float.
|
|
:- import_module int.
|
|
:- import_module io.
|
|
:- import_module message.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
find_clique_first_and_other_procs(Deep, CliquePtr, MaybeFirstPDPtr,
|
|
OtherPDPtrs) :-
|
|
deep_lookup_clique_members(Deep, CliquePtr, PDPtrs),
|
|
deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
|
|
( if valid_call_site_dynamic_ptr(Deep, EntryCSDPtr) then
|
|
deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
|
|
FirstPDPtr = EntryCSD ^ csd_callee,
|
|
MaybeFirstPDPtr = yes(FirstPDPtr),
|
|
list.negated_filter(unify(FirstPDPtr), PDPtrs, OtherPDPtrs)
|
|
else
|
|
MaybeFirstPDPtr = no,
|
|
OtherPDPtrs = PDPtrs
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
deep_get_maybe_procrep(Deep, PSPtr, MaybeProcRep) :-
|
|
deep_get_maybe_progrep(Deep, MaybeProgRep),
|
|
(
|
|
MaybeProgRep = ok(ProgRep),
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
ProcLabel = PS ^ ps_id,
|
|
( if progrep_search_proc(ProgRep, ProcLabel, ProcRep) then
|
|
MaybeProcRep = ok(ProcRep)
|
|
else
|
|
MaybeProcRep = error("Cannot find procedure representation")
|
|
)
|
|
;
|
|
MaybeProgRep = error(Error),
|
|
MaybeProcRep = error(Error)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
build_static_call_site_cost_and_callee_map(Deep, CSSPtr, !CallSitesMap) :-
|
|
deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
|
|
deep_lookup_css_own(Deep, CSSPtr, Own),
|
|
deep_lookup_css_desc(Deep, CSSPtr, Inherit),
|
|
CostCsq = build_cs_cost_csq(calls(Own),
|
|
float(callseqs(Own) + inherit_callseqs(Inherit))),
|
|
Exits = exits(Own),
|
|
KindAndCallee = CSS ^ css_kind,
|
|
call_site_kind_to_higher_order(KindAndCallee, HigherOrder),
|
|
call_site_kind_to_maybe_callee(KindAndCallee, MaybeCallee),
|
|
(
|
|
MaybeCallee = yes(Callee),
|
|
Callees = set.make_singleton_set(Callee)
|
|
;
|
|
MaybeCallee = no,
|
|
Callees = set.init
|
|
),
|
|
CostAndCallees = cost_and_callees(CostCsq, Exits, Callees, HigherOrder),
|
|
RevGoalPath = CSS ^ css_goal_path,
|
|
map.det_insert(RevGoalPath, CostAndCallees, !CallSitesMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
build_dynamic_call_site_cost_and_callee_map(Deep, CSSPtr - Slot,
|
|
!CallSitesMap) :-
|
|
(
|
|
Slot = slot_normal(CSDPtr),
|
|
( if valid_call_site_dynamic_ptr(Deep, CSDPtr) then
|
|
call_site_dynamic_get_callee_and_costs(Deep, CSDPtr, Callee,
|
|
Own, Inherit),
|
|
CostCsq = build_cs_cost_csq(calls(Own),
|
|
float(callseqs(Own) + inherit_callseqs(Inherit))),
|
|
Callees = [Callee],
|
|
Exits = exits(Own)
|
|
else
|
|
CostCsq = build_cs_cost_csq(0, 0.0),
|
|
Callees = [],
|
|
Exits = 0
|
|
)
|
|
;
|
|
Slot = slot_multi(_, CSDPtrsArray),
|
|
to_list(CSDPtrsArray, CSDPtrs),
|
|
map3(call_site_dynamic_get_callee_and_costs(Deep), CSDPtrs,
|
|
Callees, Owns, Inherits),
|
|
Own = sum_own_infos(Owns),
|
|
Inherit = sum_inherit_infos(Inherits),
|
|
CostCsq = build_cs_cost_csq(calls(Own),
|
|
float(callseqs(Own) + inherit_callseqs(Inherit))),
|
|
Exits = exits(Own)
|
|
),
|
|
CostAndCallees = cost_and_callees(CostCsq, Exits,
|
|
set.list_to_set(Callees), HigherOrder),
|
|
lookup_call_site_statics(Deep ^ call_site_statics, CSSPtr, CSS),
|
|
call_site_kind_to_higher_order(CSS ^ css_kind, HigherOrder),
|
|
RevGoalPath = CSS ^ css_goal_path,
|
|
map.det_insert(RevGoalPath, CostAndCallees, !CallSitesMap).
|
|
|
|
:- pred call_site_dynamic_get_callee_and_costs(deep::in,
|
|
call_site_dynamic_ptr::in, callee::out, own_prof_info::out,
|
|
inherit_prof_info::out) is det.
|
|
|
|
call_site_dynamic_get_callee_and_costs(Deep, CSDPtr,
|
|
callee(CalleeCliquePtr, CSDPtr), Own, Inherit) :-
|
|
lookup_call_site_dynamics(Deep ^ call_site_dynamics, CSDPtr, CSD),
|
|
lookup_csd_desc(Deep ^ csd_desc, CSDPtr, Inherit),
|
|
PDPtr = CSD ^ csd_callee,
|
|
lookup_clique_index(Deep ^ clique_index, PDPtr, CalleeCliquePtr),
|
|
Own = CSD ^ csd_own_prof.
|
|
|
|
:- pred call_site_kind_to_higher_order(call_site_kind_and_callee::in,
|
|
higher_order::out) is det.
|
|
|
|
call_site_kind_to_higher_order(CallSiteKind, HigherOrder) :-
|
|
(
|
|
( CallSiteKind = normal_call_and_callee(_, _)
|
|
; CallSiteKind = callback_and_no_callee
|
|
),
|
|
HigherOrder = first_order_call
|
|
;
|
|
( CallSiteKind = special_call_and_no_callee
|
|
; CallSiteKind = higher_order_call_and_no_callee
|
|
; CallSiteKind = method_call_and_no_callee
|
|
),
|
|
HigherOrder = higher_order_call
|
|
).
|
|
|
|
:- pred call_site_kind_to_maybe_callee(call_site_kind_and_callee::in,
|
|
maybe(proc_static_ptr)::out) is det.
|
|
|
|
call_site_kind_to_maybe_callee(normal_call_and_callee(Callee, _), yes(Callee)).
|
|
call_site_kind_to_maybe_callee(special_call_and_no_callee, no).
|
|
call_site_kind_to_maybe_callee(higher_order_call_and_no_callee, no).
|
|
call_site_kind_to_maybe_callee(method_call_and_no_callee, no).
|
|
call_site_kind_to_maybe_callee(callback_and_no_callee, no).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
build_recursive_call_site_cost_map(Deep, CliquePtr, PDPtr, RecursionType,
|
|
MaybeDepth, MaybeRecursiveCallSiteCostMap) :-
|
|
(
|
|
RecursionType = rt_not_recursive,
|
|
MaybeRecursiveCallSiteCostMap = ok(map.init)
|
|
;
|
|
RecursionType = rt_single(_, _, MaxDepth, _AvgRecCost, CostFn),
|
|
(
|
|
MaybeDepth = yes(Depth0),
|
|
( if recursion_depth_is_base_case(Depth0) then
|
|
MaybeRecursiveCallSiteCostMap = ok(map.init)
|
|
else
|
|
% Descend once to move to the depth of the recursive callees.
|
|
get_recursive_calls_and_counts(Deep, CliquePtr, PDPtr,
|
|
CallCountsMap),
|
|
RecursiveCallSiteCostMap = map_values_only(
|
|
(func(Count) =
|
|
build_cs_cost_csq_percall(float(Count),
|
|
CostFn(DepthI)) :-
|
|
DepthI = round_to_int(MaxDepth / float(Count))
|
|
),
|
|
CallCountsMap),
|
|
MaybeRecursiveCallSiteCostMap = ok(RecursiveCallSiteCostMap),
|
|
|
|
trace [compile_time(flag("debug_recursive_call_costs")),
|
|
io(!IO)] (
|
|
format_recursive_call_site_cost_map(
|
|
RecursiveCallSiteCostMap, PrettyCostMapCord),
|
|
PrettyCostMap = append_list(cord.list(PrettyCostMapCord)),
|
|
io.format(
|
|
"D: In clique %s recursive call site cost map is:" ++
|
|
"\n%s\n",
|
|
[s(string(CliquePtr)), s(PrettyCostMap)], !IO),
|
|
io.flush_output(!IO)
|
|
)
|
|
)
|
|
;
|
|
MaybeDepth = no,
|
|
unexpected($pred, "Expected valid depth for known recursion type")
|
|
)
|
|
;
|
|
( RecursionType = rt_divide_and_conquer(_, _)
|
|
; RecursionType = rt_mutual_recursion(_)
|
|
; RecursionType = rt_other(_)
|
|
; RecursionType = rt_errors(_)
|
|
),
|
|
(
|
|
( RecursionType = rt_divide_and_conquer(_, _)
|
|
; RecursionType = rt_mutual_recursion(_)
|
|
),
|
|
Error = "No average recursion depth for this recursion type"
|
|
;
|
|
RecursionType = rt_other(_),
|
|
Error = "Could not detect recursion type"
|
|
;
|
|
RecursionType = rt_errors(Errors),
|
|
Error = join_list("; and ", Errors)
|
|
),
|
|
MaybeRecursiveCallSiteCostMap = error(Error)
|
|
).
|
|
|
|
:- pred get_recursive_calls_and_counts(deep::in, clique_ptr::in,
|
|
proc_dynamic_ptr::in, map(reverse_goal_path, int)::out) is det.
|
|
|
|
get_recursive_calls_and_counts(Deep, CliquePtr, PDPtr, CallCountsMap) :-
|
|
proc_dynamic_paired_call_site_slots(Deep, PDPtr, SiteSlots),
|
|
foldl(build_recursive_call_site_counts_map(Deep, CliquePtr), SiteSlots,
|
|
map.init, CallCountsMap).
|
|
|
|
:- pred build_recursive_call_site_counts_map(deep::in, clique_ptr::in,
|
|
pair(call_site_static_ptr, call_site_array_slot)::in,
|
|
map(reverse_goal_path, int)::in, map(reverse_goal_path, int)::out) is det.
|
|
|
|
build_recursive_call_site_counts_map(Deep, CliquePtr, CSSPtr - CSDSlot,
|
|
!Map) :-
|
|
(
|
|
CSDSlot = slot_normal(CSDPtr),
|
|
( if valid_call_site_dynamic_ptr(Deep, CSDPtr) then
|
|
call_site_dynamic_get_count_and_callee(Deep, CSDPtr, Count,
|
|
MaybeCallee),
|
|
( if maybe_equals_or_is_no(CliquePtr, MaybeCallee) then
|
|
Recursive = yes
|
|
else
|
|
Recursive = no
|
|
)
|
|
else
|
|
Recursive = no,
|
|
Count = 0
|
|
)
|
|
;
|
|
CSDSlot = slot_multi(_, CSDPtrs),
|
|
map2(call_site_dynamic_get_count_and_callee(Deep), to_list(CSDPtrs),
|
|
Counts, MaybeCallees),
|
|
Count = foldl(plus, Counts, 0),
|
|
( if
|
|
member(MaybeCallee, MaybeCallees),
|
|
maybe_equals_or_is_no(CliquePtr, MaybeCallee)
|
|
then
|
|
Recursive = yes
|
|
else
|
|
Recursive = no
|
|
)
|
|
),
|
|
(
|
|
Recursive = yes,
|
|
deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
|
|
RevGoalPath = CSS ^ css_goal_path,
|
|
map.det_insert(RevGoalPath, Count, !Map)
|
|
;
|
|
Recursive = no
|
|
).
|
|
|
|
:- pred maybe_equals_or_is_no(T::in, maybe(T)::in) is semidet.
|
|
|
|
maybe_equals_or_is_no(_, no).
|
|
maybe_equals_or_is_no(X, yes(X)).
|
|
|
|
:- pred call_site_dynamic_get_count_and_callee(deep::in,
|
|
call_site_dynamic_ptr::in, int::out, maybe(clique_ptr)::out) is det.
|
|
|
|
call_site_dynamic_get_count_and_callee(Deep, CSDPtr, Count, MaybeCallee) :-
|
|
( if valid_call_site_dynamic_ptr(Deep, CSDPtr) then
|
|
deep_lookup_csd_own(Deep, CSDPtr, Own),
|
|
Count = calls(Own),
|
|
deep_lookup_clique_maybe_child(Deep, CSDPtr, MaybeCallee)
|
|
else
|
|
Count = 0,
|
|
MaybeCallee = no
|
|
).
|
|
|
|
:- pred format_recursive_call_site_cost_map(
|
|
map(reverse_goal_path, cs_cost_csq)::in, cord(string)::out) is det.
|
|
|
|
format_recursive_call_site_cost_map(Map, Result) :-
|
|
map.foldl(format_recursive_call_site_cost, Map, cord.empty, Result).
|
|
|
|
:- pred format_recursive_call_site_cost(reverse_goal_path::in, cs_cost_csq::in,
|
|
cord(string)::in, cord(string)::out) is det.
|
|
|
|
format_recursive_call_site_cost(RevGoalPath, Cost, !Result) :-
|
|
!:Result = cord.snoc(!.Result ++ indent(1), String),
|
|
String = format("%s -> Percall cost: %f Calls: %f\n",
|
|
[s(GoalPathString), f(PerCallCost), f(Calls)]),
|
|
GoalPathString = rev_goal_path_to_string(RevGoalPath),
|
|
PerCallCost = cs_cost_get_percall(Cost),
|
|
Calls = cs_cost_get_calls(Cost).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
proc_dynamic_paired_call_site_slots(Deep, PDPtr, PairedSlots) :-
|
|
deep_lookup_proc_dynamics(Deep, PDPtr, PD),
|
|
PSPtr = PD ^ pd_proc_static,
|
|
CSDArray = PD ^ pd_sites,
|
|
deep_lookup_proc_statics(Deep, PSPtr, PS),
|
|
CSSArray = PS ^ ps_sites,
|
|
array.to_list(CSDArray, CSDSlots),
|
|
array.to_list(CSSArray, CSSSlots),
|
|
assoc_list.from_corresponding_lists(CSSSlots, CSDSlots, PairedSlots).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
cost_and_callees_is_recursive(ParentCliquePtr, CostAndCallees) :-
|
|
Callees = CostAndCallees ^ cac_callees,
|
|
member(Callee, Callees),
|
|
ParentCliquePtr = Callee ^ c_clique.
|
|
|
|
%---------------------------------------------------------------------------%
|