[m-rev.] for post-commit review: Coverage Profiling completed.
Paul Bone
pbone at csse.unimelb.edu.au
Thu Sep 25 23:33:59 AEST 2008
For post-commit review by Zoltan.
Estimated hours taken: 10
Branches: main
Re-write coverage profiling transformation and propagation algorithm. The code
in the profiler and in the compiler both now traverse a procedure in the same
way. This way the coverage profiling transformation knows if the coverage
propagation algorithm will be able to infer the coverage at a given point in
the program or if it needs a coverage point inserted.
compiler/deep_profiling.m:
As above.
Print out status messages before performing deep profiling on each
procedure when the verbose option is enabled..
compiler/options.m:
The first pass of the coverage profiling transformation has been disabled
since it's not currently used by the second pass.
compiler/mercury_compile.m:
Conform to changes in compiler/deep_profiling.m
compiler/Mercury.options:
Disable the work around for bug 85 since it is no longer triggered by
deep_profiling.m.
deep_profiler/program_representation_utils.m:
As above.
Fix a bug when printing out a scope goal in the procedure representation.
Index: compiler/Mercury.options
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/Mercury.options,v
retrieving revision 1.38
diff -u -p -b -r1.38 Mercury.options
--- compiler/Mercury.options 23 Sep 2008 01:26:10 -0000 1.38
+++ compiler/Mercury.options 25 Sep 2008 12:42:05 -0000
@@ -60,9 +60,6 @@ MCFLAGS-analysis = --no-common-struct
# mmc -r analysis.file.c -s asm_fast.gc -O4 --intermodule-optimisation
MCFLAGS-analysis.file = --no-optimise-higher-order
-# Workaround for bug 85 in Mantis.
-MCFLAGS-ll_backend.deep_profiling = -O2
-
# This works around bug 32 in Mantis.
MCFLAGS-check_hlds.check_typeclass = --no-loop-invariants
Index: compiler/deep_profiling.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/deep_profiling.m,v
retrieving revision 1.86
diff -u -p -b -r1.86 deep_profiling.m
--- compiler/deep_profiling.m 20 Sep 2008 11:38:03 -0000 1.86
+++ compiler/deep_profiling.m 25 Sep 2008 13:31:02 -0000
@@ -20,10 +20,12 @@
:- import_module hlds.hlds_module.
+:- import_module io.
+
%-----------------------------------------------------------------------------%
-:- pred apply_deep_profiling_transformation(module_info::in, module_info::out)
- is det.
+:- pred apply_deep_profiling_transformation(module_info::in, module_info::out,
+ io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -36,11 +38,13 @@
:- import_module hlds.code_model.
:- import_module hlds.goal_util.
:- import_module hlds.hlds_goal.
+:- import_module hlds.hlds_out.
:- import_module hlds.hlds_pred.
:- import_module hlds.hlds_rtti.
:- import_module hlds.instmap.
:- import_module hlds.pred_table.
:- import_module libs.compiler_util.
+:- import_module libs.file_util.
:- import_module libs.globals.
:- import_module libs.options.
:- import_module mdbcomp.prim_data.
@@ -69,7 +73,7 @@
%-----------------------------------------------------------------------------%
-apply_deep_profiling_transformation(!ModuleInfo) :-
+apply_deep_profiling_transformation(!ModuleInfo, !IO) :-
module_info_get_globals(!.ModuleInfo, Globals),
globals.lookup_bool_option(Globals, deep_profile_tail_recursion,
TailRecursion),
@@ -82,7 +86,8 @@ apply_deep_profiling_transformation(!Mod
module_info_predids(PredIds, !ModuleInfo),
module_info_get_predicate_table(!.ModuleInfo, PredTable0),
predicate_table_get_preds(PredTable0, PredMap0),
- list.foldl(transform_predicate(!.ModuleInfo), PredIds, PredMap0, PredMap),
+ list.foldl2(transform_predicate(!.ModuleInfo), PredIds, PredMap0, PredMap,
+ !IO),
predicate_table_set_preds(PredMap, PredTable0, PredTable),
module_info_set_predicate_table(PredTable, !ModuleInfo).
@@ -444,21 +449,21 @@ figure_out_rec_call_numbers_in_case_list
%-----------------------------------------------------------------------------%
:- pred transform_predicate(module_info::in, pred_id::in,
- pred_table::in, pred_table::out) is det.
+ pred_table::in, pred_table::out, io::di, io::uo) is det.
-transform_predicate(ModuleInfo, PredId, PredMap0, PredMap) :-
+transform_predicate(ModuleInfo, PredId, PredMap0, PredMap, !IO) :-
map.lookup(PredMap0, PredId, PredInfo0),
ProcIds = pred_info_non_imported_procids(PredInfo0),
pred_info_get_procedures(PredInfo0, ProcTable0),
- list.foldl(maybe_transform_procedure(ModuleInfo, PredId),
- ProcIds, ProcTable0, ProcTable),
+ list.foldl2(maybe_transform_procedure(ModuleInfo, PredId),
+ ProcIds, ProcTable0, ProcTable, !IO),
pred_info_set_procedures(ProcTable, PredInfo0, PredInfo),
map.det_update(PredMap0, PredId, PredInfo, PredMap).
:- pred maybe_transform_procedure(module_info::in, pred_id::in, proc_id::in,
- proc_table::in, proc_table::out) is det.
+ proc_table::in, proc_table::out, io::di, io::uo) is det.
-maybe_transform_procedure(ModuleInfo, PredId, ProcId, !ProcTable) :-
+maybe_transform_procedure(ModuleInfo, PredId, ProcId, !ProcTable, !IO) :-
map.lookup(!.ProcTable, ProcId, ProcInfo0),
proc_info_get_goal(ProcInfo0, Goal0),
PredModuleName = predicate_module(ModuleInfo, PredId),
@@ -476,6 +481,12 @@ maybe_transform_procedure(ModuleInfo, Pr
->
true
;
+ module_info_get_globals(ModuleInfo, Globals),
+ globals.lookup_bool_option(Globals, verbose, Verbose),
+ ProcName = pred_proc_id_pair_to_string(ModuleInfo, PredId, ProcId),
+ maybe_write_string(Verbose,
+ string.format("Deep profiling: %s\n", [s(ProcName)]),
+ !IO),
deep_prof_transform_proc(ModuleInfo, proc(PredId, ProcId),
ProcInfo0, ProcInfo),
map.det_update(!.ProcTable, ProcId, ProcInfo, !:ProcTable)
@@ -2008,7 +2019,7 @@ coverage_prof_transform_goal(ModuleInfo,
;
CoverageProfilingOptions ^ cpo_use_2pass = no
),
- coverage_prof_second_pass_goal(!Goal, coverage_after_known, _,
+ coverage_prof_second_pass_goal(!Goal, coverage_before_known, _,
CoverageInfo0, CoverageInfo, _),
CoverageInfo ^ ci_coverage_points = CoveragePointsMap,
CoverageInfo ^ ci_var_info = !:VarInfo,
@@ -2017,140 +2028,42 @@ coverage_prof_transform_goal(ModuleInfo,
% Transform a goal for coverage profiling. This is the second pass of
% the coverage profiling transformation, and it consists of several steps.
%
- % If the first pass has been performed then we collect the relevant
- % information from the goal_info structure.
+ % Step 1: Apply transformation recursively.
%
- % Step 1: Make a decision whether to insert a coverage point after this
- % goal or not.
+ % Step 2: Consider inserting a coverage point after this goal to measure
+ % how many times it succeeds.
%
- % Step 2: Determine if coverage information is known for goals that
- % execute before this goal completes. This includes goals before this
- % goal (such as within a conjunction) or goals within this goal.
- % Information collected in the first pass is used here.
- %
- % Step 3: Transform inner goals if this goal is non-atomic.
- %
- % Step 4: Insert a coverage point after this goal if we decided to do so
- % at step 1. This is done here after any inner goals have been
- % transformed.
+ % Step 3: Insert the coverage point if we decided to earlier.
%
:- pred coverage_prof_second_pass_goal(hlds_goal::in, hlds_goal::out,
- coverage_after_known::in, coverage_after_known::out,
+ coverage_before_known::in, coverage_before_known::out,
proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
coverage_prof_second_pass_goal(Goal0, Goal,
- CoverageAfterKnown0, NextCoverageAfterKnown, !Info, AddedImpurity) :-
+ CoverageBeforeKnown, NextCoverageBeforeKnown, !Info, AddedImpurity) :-
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
Detism = GoalInfo0 ^ goal_info_get_determinism,
CPOptions = !.Info ^ ci_coverage_profiling_opts,
+ GoalPath = goal_info_get_goal_path(GoalInfo0),
- % Depending on command line arguments first pass information may or may not
- % be available, if it is not available, we assume semi-sensible defaults.
- DPInfo = goal_info_get_dp_info(GoalInfo0),
- DPInfo = dp_goal_info(IsMDProfInst, MaybeDPCoverageInfo),
- (
- MaybeDPCoverageInfo =
- yes(dp_coverage_goal_info(GoalTrivial, GoalPortCountsCoverageAfter))
- ;
- MaybeDPCoverageInfo = no,
-
- % XXX: Zoltan says;
- % Is this the best default you can get? You should be able to do
- % better for goals like unifications.
- %
- % pbone: I agree. Idealy we should get more accurate information for
- % atomic goals and fall back to these defaults for any other goal.
-
- GoalTrivial = goal_is_nontrivial,
- GoalPortCountsCoverageAfter = no_port_counts_give_coverage_after
- ),
-
- (
- GoalPortCountsCoverageAfter = port_counts_give_coverage_after,
- CoverageAfterKnown1 = coverage_after_known
- ;
- GoalPortCountsCoverageAfter = no_port_counts_give_coverage_after,
- CoverageAfterKnown1 = CoverageAfterKnown0
- ),
-
- % Step 1.
- %
- % Consider inserting a coverage point after this goal to measure how
- % many solutions it may have.
- (
(
- % Never insert coverage points on goals that are part of the deep
- % profiling instrumentation.
- IsMDProfInst = goal_is_mdprof_inst
- ;
- % We already have execution counts for the program point after this
- % goal; adding a counter would be redundant.
- CoverageAfterKnown1 = coverage_after_known
- ;
- % We don't need to know the execution count of this goal, since
- % it is too cheap to matter.
- GoalTrivial = goal_is_trivial
- ;
- % Never insert coverage points after conjunctions; wait until
- % the algorithm recurses to inside the conjunction and make a
- % better decision about the last conjunct. This can reduce the
- % number of coverage points inserted in some cases.
- GoalExpr0 = conj(plain_conj, _)
-
- % We haven't yet thought about whether or not we should treat
- % parallel conjunctions the same way.
- )
+ IsMDProfInst = goal_is_not_mdprof_inst,
+ CoverageBeforeKnown = coverage_before_unknown
->
- MaybeCPType = no
+ unexpected(this_file, string.format(
+ "coverage_prof_second_pass_goal: Coverage information is unknown\n"
+ ++ "\tGoalPath: %s",
+ [s(goal_path_to_string(GoalPath))]))
;
- CoverageAfterGoals = CPOptions ^ cpo_coverage_after_goal,
- (
- CoverageAfterGoals = yes,
- MaybeCPType = yes(cp_type_coverage_after)
- ;
- CoverageAfterGoals = no,
- MaybeCPType = no
- )
+ true
),
- % Step 2.
- %
- % Update coverage known information.
- (
- MaybeCPType = yes(_),
- CoverageAfterKnown2 = coverage_after_known
- ;
- MaybeCPType = no,
- CoverageAfterKnown2 = CoverageAfterKnown1
- ),
- % If the goal has a port count, then coverage is known at the point directy
- % before this goal.
- (
- GoalPortCountsCoverageAfter = port_counts_give_coverage_after,
- CoverageAfterKnown = coverage_after_known
- ;
- GoalPortCountsCoverageAfter = no_port_counts_give_coverage_after,
- (
- % If there is not exactly one solution then the coverage is
- % not known.
- ( Detism = detism_semi
- ; Detism = detism_multi
- ; Detism = detism_non
- ; Detism = detism_cc_non
- ; Detism = detism_erroneous
- ; Detism = detism_failure
- ),
- CoverageAfterKnown = coverage_after_unknown
- ;
- % Otherwise the coverage remains the same.
- ( Detism = detism_det
- ; Detism = detism_cc_multi
- ),
- CoverageAfterKnown = CoverageAfterKnown2
- )
- ),
+ % Currently the first pass is unsupported, we don't make use of the
+ % information it provides.
+ DPInfo = goal_info_get_dp_info(GoalInfo0),
+ DPInfo = dp_goal_info(IsMDProfInst, _MaybeDPCoverageInfo),
- % Step 3.
+ % Step 1.
%
% Apply transformation recursively.
(
@@ -2159,93 +2072,112 @@ coverage_prof_second_pass_goal(Goal0, Go
; GoalExpr0 = generic_call(_, _, _, _)
; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
),
+ ( goal_expr_has_call_site(GoalExpr0) ->
+ NextCoverageBeforeKnown0 = coverage_before_known
+ ;
+ coverage_known_after_goal_with_detism(Detism,
+ CoverageBeforeKnown, NextCoverageBeforeKnown0)
+ ),
AddedImpurityInner = no,
- GoalExpr1 = GoalExpr0,
- NextCoverageAfterKnown = CoverageAfterKnown
+ GoalExpr1 = GoalExpr0
;
GoalExpr0 = conj(ConjType, Goals0),
coverage_prof_second_pass_conj(ConjType, Goals0, Goals,
- CoverageAfterKnown, NextCoverageAfterKnown, !Info,
+ CoverageBeforeKnown, NextCoverageBeforeKnown0, !Info,
AddedImpurityInner),
GoalExpr1 = conj(ConjType, Goals)
;
- % There may be optimizations that can allow us to avoid inserting
- % superfluous coverage points, however they are most likely to be
- % non-trivial.
-
GoalExpr0 = disj(Goals0),
- coverage_prof_second_pass_disj(DPInfo, Goals0, Goals, !Info,
- AddedImpurityInner),
- (
- ( Detism = detism_det
- ; Detism = detism_cc_multi
- ),
- NextCoverageAfterKnown = CoverageAfterKnown
- ;
- ( Detism = detism_semi
- ; Detism = detism_multi
- ; Detism = detism_non
- ; Detism = detism_cc_non
- ; Detism = detism_erroneous
- ; Detism = detism_failure
- ),
- NextCoverageAfterKnown = coverage_after_unknown
- ),
+ coverage_prof_second_pass_disj(DPInfo,
+ CoverageBeforeKnown, NextCoverageBeforeKnown0,
+ Goals0, Goals, !Info, AddedImpurityInner),
GoalExpr1 = disj(Goals)
;
GoalExpr0 = switch(Var, SwitchCanFail, Cases0),
coverage_prof_second_pass_switchcase(DPInfo, SwitchCanFail,
- Cases0, Cases, CoverageAfterKnown, NextCoverageAfterKnown0, !Info,
- AddedImpurityInner),
- (
- SwitchCanFail = cannot_fail,
- NextCoverageAfterKnown = NextCoverageAfterKnown0
- ;
- SwitchCanFail = can_fail,
- NextCoverageAfterKnown = coverage_after_unknown
- ),
+ Cases0, Cases, CoverageBeforeKnown, NextCoverageBeforeKnown0,
+ !Info, AddedImpurityInner),
GoalExpr1 = switch(Var, SwitchCanFail, Cases)
;
GoalExpr0 = negation(NegGoal0),
- % The coverage after a negated goal is always unknown.
coverage_prof_second_pass_goal(NegGoal0, NegGoal,
- coverage_after_unknown, NextCoverageAfterKnown, !Info,
+ CoverageBeforeKnown, _, !Info,
AddedImpurityInner),
+ % The coverage after a negated goal cannot be inferred from it's inner
+ % goals.
+ coverage_known_after_goal_with_detism(Detism,
+ CoverageBeforeKnown, NextCoverageBeforeKnown0),
GoalExpr1 = negation(NegGoal)
;
GoalExpr0 = scope(Reason, ScopeGoal0),
+ coverage_prof_second_pass_goal(ScopeGoal0, ScopeGoal,
+ CoverageBeforeKnown, CoverageAfterScopedGoalKnown, !Info,
+ AddedImpurityInner),
% A scope may cut away solutions, if it does we don't know the number
% of solutions of the scoped goal.
ScopedGoalDetism =
ScopeGoal0 ^ hlds_goal_info ^ goal_info_get_determinism,
( ScopedGoalDetism = Detism ->
- CoverageAfterScopedGoalKnown = CoverageAfterKnown
+ NextCoverageBeforeKnown0 = CoverageAfterScopedGoalKnown
;
- CoverageAfterScopedGoalKnown = coverage_after_unknown
+ coverage_known_after_goal_with_detism(Detism,
+ CoverageBeforeKnown, NextCoverageBeforeKnown0)
),
- coverage_prof_second_pass_goal(ScopeGoal0, ScopeGoal,
- CoverageAfterScopedGoalKnown, NextCoverageAfterKnown, !Info,
- AddedImpurityInner),
GoalExpr1 = scope(Reason, ScopeGoal)
;
GoalExpr0 = if_then_else(ITEExistVars, Cond, Then, Else),
coverage_prof_second_pass_ite(DPInfo, ITEExistVars, Cond, Then, Else,
- GoalExpr1, CoverageAfterKnown, NextCoverageAfterKnown, !Info,
+ GoalExpr1, CoverageBeforeKnown, NextCoverageBeforeKnown0, !Info,
AddedImpurityInner)
;
GoalExpr0 = shorthand(_),
unexpected(this_file, "coverage_prof_second_pass_goal: shorthand")
),
- add_impurity_if_needed(AddedImpurityInner, GoalInfo0, GoalInfo1),
- Goal1 = hlds_goal(GoalExpr1, GoalInfo1),
+
+ % Step 3.
+ %
+ % Consider inserting a coverage point after this goal to measure how many
+ % times it succeeds.
+ (
+ (
+ % Never insert coverage points on goals that are part of the deep
+ % profiling instrumentation.
+ IsMDProfInst = goal_is_mdprof_inst
+ ;
+ % We already have execution counts for the program point after this
+ % goal; adding a counter would be redundant.
+ NextCoverageBeforeKnown0 = coverage_before_known
+ ;
+ % Never insert coverage points after conjunctions; wait until
+ % the algorithm recurses to inside the conjunction and make a
+ % better decision about the last conjunct. This can reduce the
+ % number of coverage points inserted in some cases.
+ GoalExpr0 = conj(_, _)
+ )
+ ->
+ MaybeCPType = no,
+ NextCoverageBeforeKnown = NextCoverageBeforeKnown0
+ ;
+ CoverageAfterGoals = CPOptions ^ cpo_coverage_after_goal,
+ (
+ CoverageAfterGoals = yes,
+ MaybeCPType = yes(cp_type_coverage_after),
+ NextCoverageBeforeKnown = coverage_before_known
+ ;
+ CoverageAfterGoals = no,
+ MaybeCPType = no,
+ NextCoverageBeforeKnown = NextCoverageBeforeKnown0
+ )
+ ),
% Step 4.
%
% Insert the coverage point if we decided to earlier.
+ add_impurity_if_needed(AddedImpurityInner, GoalInfo0, GoalInfo1),
+ Goal1 = hlds_goal(GoalExpr1, GoalInfo1),
(
MaybeCPType = yes(CPType),
- Path = goal_info_get_goal_path(GoalInfo1),
- CPInfo = coverage_point_info(Path, CPType),
+ CPInfo = coverage_point_info(GoalPath, CPType),
make_coverage_point(CPInfo, CPGoals, !Info),
create_conj_from_list([Goal1 | CPGoals], plain_conj, Goal),
@@ -2257,26 +2189,67 @@ coverage_prof_second_pass_goal(Goal0, Go
AddedImpurity = AddedImpurityInner
).
- % Perform the coverage profiling transformation for conjuncts starting
- % at the tail of the goal list and moving back towards the head. The
- % goal list represents the list of goals within a conjunction minus
- % 'Pos' goals removed from the head.
+ % True if the deep profiler will instrument this call site and the port
+ % counts from it are useful for coverage profiling.
%
- % This is done tail first as to take advantage of knowledge of goals after
- % the current goal within the conjunction.
+:- pred goal_expr_has_call_site(hlds_goal_expr::in) is semidet.
+
+goal_expr_has_call_site(GoalExpr) :-
+ (
+ GoalExpr = plain_call(_, _, _, BuiltinState, _, _),
+ ( BuiltinState = out_of_line_builtin
+ ; BuiltinState = not_builtin
+ )
+ ;
+ GoalExpr = generic_call(GenericCall, _, _, _),
+ ( GenericCall = higher_order(_, _, _, _)
+ ; GenericCall = class_method(_, _, _, _)
+ )
+ ;
+ % Even though the deep profiler creates a call site when these may
+ % call mercury the coverage propagation code cannot make use of the
+ % port counts, since they measure how often Mercury is re-entered,
+ % not how often this call is made.
+ GoalExpr = call_foreign_proc(_, _, _, _, _, _, _),
+ fail
+ ).
+
+:- pred coverage_known_after_goal_with_detism(determinism::in,
+ coverage_before_known::in, coverage_before_known::out) is det.
+
+coverage_known_after_goal_with_detism(Detism, !CoverageKnown) :-
+ (
+ ( Detism = detism_semi
+ ; Detism = detism_multi
+ ; Detism = detism_non
+ ; Detism = detism_cc_non
+ ; Detism = detism_erroneous
+ ; Detism = detism_failure
+ ),
+ !:CoverageKnown = coverage_before_unknown
+ ;
+ ( Detism = detism_det
+ ; Detism = detism_cc_multi
+ )
+ ).
+
+ % Perform the coverage profiling transformation for conjuncts. The goal
+ % list represents the list of goals within a conjunction minus 'Pos' goals
+ % removed from the head.
%
:- pred coverage_prof_second_pass_conj(conj_type::in,
list(hlds_goal)::in, list(hlds_goal)::out,
- coverage_after_known::in, coverage_after_known::out,
+ coverage_before_known::in, coverage_before_known::out,
proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
-coverage_prof_second_pass_conj(_, [], [], !CoverageAfterKnown, !Info, no).
+coverage_prof_second_pass_conj(_, [], [], !CoverageBeforeKnown, !Info, no).
coverage_prof_second_pass_conj(ConjType, [Goal0 | Goals0], Goals,
- CoverageAfterKnown0, NextCoverageAfterKnown, !Info, AddedImpurity) :-
- coverage_prof_second_pass_conj(ConjType, Goals0, Goals1,
- CoverageAfterKnown0, CoverageAfterKnown, !Info, AddedImpurityTail),
+ CoverageBeforeKnown, NextCoverageBeforeKnown, !Info, AddedImpurity) :-
coverage_prof_second_pass_goal(Goal0, Goal1,
- CoverageAfterKnown, NextCoverageAfterKnown, !Info, AddedImpurityHead),
+ CoverageBeforeKnown, CoverageBeforeTailKnown, !Info, AddedImpurityHead),
+
+ % Flatten the conjunction, this is necessary when coverage points are
+ % inserted into conjuncts.
(
Goal1 = hlds_goal(conj(plain_conj, ConjGoals), _),
ConjType = plain_conj
@@ -2285,198 +2258,215 @@ coverage_prof_second_pass_conj(ConjType,
;
Goals = [Goal1 | Goals1]
),
+
+ coverage_prof_second_pass_conj(ConjType, Goals0, Goals1,
+ CoverageBeforeTailKnown, NextCoverageBeforeKnown, !Info,
+ AddedImpurityTail),
bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
% Perform the coverage profiling transformation over goals within a
% disjunction. The list of goals represents the tail of the disjunction
% currently being transformed.
%
- % Disjuncts are also transformed in reverse order, as knowledge from
- % later disjuncts can be used to reduce the number of coverage points
- % placed in earlier disjuncts.
- %
-:- pred coverage_prof_second_pass_disj(
- dp_goal_info::in, list(hlds_goal)::in, list(hlds_goal)::out,
+:- pred coverage_prof_second_pass_disj(dp_goal_info::in,
+ coverage_before_known::in, coverage_before_known::out,
+ list(hlds_goal)::in, list(hlds_goal)::out,
proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
-coverage_prof_second_pass_disj(_, [], [], !Info, no).
-coverage_prof_second_pass_disj(DPInfo, [Goal0 | Goals0], [Goal | Goals], !Info,
- AddedImpurity) :-
- % Transform the tail of the disjunction.
- coverage_prof_second_pass_disj(DPInfo, Goals0, Goals, !Info,
- AddedImpurityTail),
+coverage_prof_second_pass_disj(DPInfo, CoverageBeforeKnown,
+ NextCoverageBeforeKnown, Disjs0, Disjs, !Info, AddedImpurity) :-
+ % If the disjunction was introduced by the deep profiling pass, it has two
+ % disjuncts and it's second disjunct has 'failure' determinism, then
+ % perform the coverage profiling pass on the first disjunct as if this
+ % is the only goal.
+ (
+ DPInfo = dp_goal_info(goal_is_mdprof_inst, _),
+ Disjs0 = [FirstDisj0, SecondDisj],
+ SecondDisj ^ hlds_goal_info ^ goal_info_get_determinism = detism_failure
+ ->
+ coverage_prof_second_pass_goal(FirstDisj0, FirstDisj,
+ CoverageBeforeKnown, NextCoverageBeforeKnown, !Info,
+ AddedImpurity),
+ Disjs = [FirstDisj, SecondDisj]
+ ;
+ coverage_prof_second_pass_disj_2(DPInfo, CoverageBeforeKnown,
+ Disjs0, Disjs, !Info, AddedImpurity),
+ NextCoverageBeforeKnown = coverage_before_unknown
+ ).
- % Transform this goal and optionally add a coverage point before it.
- coverage_prof_second_pass_goal(Goal0, Goal1,
- coverage_after_unknown, NextCoverageAfterKnown, !Info,
- AddedImpurityHead0),
+:- pred coverage_prof_second_pass_disj_2(dp_goal_info::in,
+ coverage_before_known::in,
+ list(hlds_goal)::in, list(hlds_goal)::out,
+ proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
+
+coverage_prof_second_pass_disj_2(_, _, [], [], !Info, no).
+coverage_prof_second_pass_disj_2(DPInfo, CoverageBeforeKnown0,
+ [Goal0 | Goals0], [Goal | Goals], !Info, AddedImpurity) :-
+ % If coverage is unknown before the disjunct, then decide to insert a
+ % branch coverage point at the beginning of the disjunct.
CPOBranchDisj = !.Info ^ ci_coverage_profiling_opts ^ cpo_branch_disj,
DPInfo = dp_goal_info(IsMDProfInst, _),
(
CPOBranchDisj = yes,
- NextCoverageAfterKnown = coverage_after_unknown,
+ CoverageBeforeKnown0 = coverage_before_unknown,
IsMDProfInst = goal_is_not_mdprof_inst
->
+ InsertCP = yes,
+ CoverageBeforeKnown = coverage_before_known
+ ;
+ InsertCP = no,
+ CoverageBeforeKnown = CoverageBeforeKnown0
+ ),
+
+ % Transform the disjunct its self.
+ coverage_prof_second_pass_goal(Goal0, Goal1,
+ CoverageBeforeKnown, _CoverageAfterHeadKnown, !Info,
+ AddedImpurityHead),
+
+ % Transform the tail of the disjunction.
+ coverage_prof_second_pass_disj_2(DPInfo,
+ coverage_before_unknown, Goals0, Goals, !Info,
+ AddedImpurityTail),
+
+ % Insert the coverage point if we decided to above.
+ (
+ InsertCP = yes
+ ->
DisjPath = goal_info_get_goal_path(Goal0 ^ hlds_goal_info),
insert_coverage_point_before(coverage_point_info(DisjPath,
cp_type_branch_arm), Goal1, Goal, !Info),
- AddedImpurityHead = yes
+ AddedImpurity = yes
;
Goal = Goal1,
- AddedImpurityHead = AddedImpurityHead0
- ),
-
- bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
+ AddedImpurity = bool.or(AddedImpurityHead, AddedImpurityTail)
+ ).
+ % coverage_prof_second_pass_switchcase(DPInfo, SwitchCanFial, !Cases,
+ % CoverageBeforeSwitch, !Info, AddedImpurity).
+ %
+ % Preform coverage profiling transformation on switch cases.
+ %
:- pred coverage_prof_second_pass_switchcase(dp_goal_info::in, can_fail::in,
list(case)::in, list(case)::out,
- coverage_after_known::in, coverage_after_known::out,
+ coverage_before_known::in, coverage_before_known::out,
+ proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
+
+coverage_prof_second_pass_switchcase(DPInfo, CanFail, Cases0, Cases,
+ CoverageBeforeSwitchKnown, CoverageAfterSwitchKnown, !Info, AddedImpurity) :-
+ % If the switch can fail then the coverage after it will be unknown.
+ (
+ CanFail = can_fail,
+ CoverageAfterSwitchKnown0 = coverage_before_unknown
+ ;
+ CanFail = cannot_fail,
+ CoverageAfterSwitchKnown0 = coverage_before_known
+ ),
+ coverage_prof_second_pass_switchcase_2(DPInfo, CanFail, Cases0, Cases,
+ CoverageBeforeSwitchKnown, coverage_before_known,
+ CoverageAfterSwitchKnown0, CoverageAfterSwitchKnown, !Info,
+ AddedImpurity).
+
+:- pred coverage_prof_second_pass_switchcase_2(dp_goal_info::in, can_fail::in,
+ list(case)::in, list(case)::out, coverage_before_known::in,
+ coverage_before_known::in,
+ coverage_before_known::in, coverage_before_known::out,
proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
-coverage_prof_second_pass_switchcase(_, _, [], [], _, coverage_after_known,
- !Info, no).
-coverage_prof_second_pass_switchcase(DPInfo, SwitchCanFail,
- [Case0 | Cases0], [Case | Cases], CoverageAfterSwitchKnown,
- NextCoverageAfterKnown, !Info, AddedImpurity) :-
+coverage_prof_second_pass_switchcase_2(_, _, [], [], _, _,
+ !CoverageAfterSwitchKnown, !Info, no).
+
+coverage_prof_second_pass_switchcase_2(DPInfo, SwitchCanFail,
+ [Case0 | Cases0], [Case | Cases], CoverageBeforeSwitchKnown,
+ CoverageBeforeEveryCaseKnown, !CoverageAfterSwitchKnown, !Info,
+ AddedImpurity) :-
Goal0 = Case0 ^ case_goal,
% If the switch cannot fail and this is the last case then the coverage
- % at the end of this case can be computed from the coverage after the
- % entire switch and coverage information for the tail of the switch
- % such as branch coverage points.
-
+ % at the beginning of this case can be computed from the coverage before the
+ % entire switch and coverage information for the tail of the switch such as
+ % branch coverage points.
(
Cases0 = [],
(
SwitchCanFail = cannot_fail,
- CoverageAfterHeadKnown = CoverageAfterSwitchKnown
+ CoverageBeforeHeadKnown0 = coverage_before_known_and(
+ CoverageBeforeSwitchKnown, CoverageBeforeEveryCaseKnown)
;
SwitchCanFail = can_fail,
- CoverageAfterHeadKnown = coverage_after_unknown
+ CoverageBeforeHeadKnown0 = coverage_before_unknown
)
;
Cases0 = [_ | _],
- CoverageAfterHeadKnown = coverage_after_unknown
+ CoverageBeforeHeadKnown0 = coverage_before_unknown
),
- coverage_prof_second_pass_goal(Goal0, Goal1, CoverageAfterHeadKnown,
- NextCoverageAfterKnown0, !Info, AddedImpurityHead0),
-
- % Possibly insert coverage point.
+ % Decide whether to insert a coverage point here.
CPOBranchSwitch = !.Info ^ ci_coverage_profiling_opts ^
cpo_branch_switch,
DPInfo = dp_goal_info(IsMDProfInst, _),
(
CPOBranchSwitch = yes,
- NextCoverageAfterKnown0 = coverage_after_unknown,
+ CoverageBeforeHeadKnown0 = coverage_before_unknown,
IsMDProfInst = goal_is_not_mdprof_inst
->
+ InsertCP = yes,
+ CoverageBeforeHeadKnown = coverage_before_known
+ ;
+ InsertCP = no,
+ CoverageBeforeHeadKnown = CoverageBeforeHeadKnown0
+ ),
+
+ coverage_prof_second_pass_goal(Goal0, Goal1, CoverageBeforeHeadKnown,
+ CoverageAfterCaseKnown, !Info, AddedImpurityHead0),
+ !:CoverageAfterSwitchKnown = coverage_before_known_and(
+ CoverageAfterCaseKnown, !.CoverageAfterSwitchKnown),
+
+ % Possibly insert coverage point.
+ (
+ InsertCP = yes,
CasePath = goal_info_get_goal_path(Goal0 ^ hlds_goal_info),
insert_coverage_point_before(coverage_point_info(CasePath,
cp_type_branch_arm), Goal1, Goal, !Info),
- AddedImpurityHead = yes,
- NextCoverageAfterKnownHead = coverage_after_known
+ AddedImpurityHead = yes
;
+ InsertCP = no,
Goal = Goal1,
- AddedImpurityHead = AddedImpurityHead0,
- NextCoverageAfterKnownHead = NextCoverageAfterKnown0
+ AddedImpurityHead = AddedImpurityHead0
),
% Handle recursive case and prepare output variables.
- coverage_prof_second_pass_switchcase(DPInfo, SwitchCanFail, Cases0, Cases,
- CoverageAfterSwitchKnown, NextCoverageAfterKnownTail, !Info,
- AddedImpurityTail),
+ NextCoverageBeforeEveryCaseKnown = coverage_before_known_and(
+ CoverageBeforeEveryCaseKnown, CoverageBeforeHeadKnown),
+ coverage_prof_second_pass_switchcase_2(DPInfo, SwitchCanFail, Cases0, Cases,
+ CoverageBeforeSwitchKnown, NextCoverageBeforeEveryCaseKnown,
+ !CoverageAfterSwitchKnown, !Info, AddedImpurityTail),
Case = Case0 ^ case_goal := Goal,
- coverage_after_known_branch(NextCoverageAfterKnownHead,
- NextCoverageAfterKnownTail, NextCoverageAfterKnown),
bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
% Determine if branch coverage points should be inserted in either or
% both of the then and else branches, insert them and transform the
% sub-goals.
%
- % This is performed by first transforming the Else and Then branches,
- % then making decisions about cooverage points and inserting them, then
- % transforming the condition and constructing the new ITE goal_expr.
+ % This is performed by first transforming the condition goal,
+ % then making decisions about coverage points and inserting them, then
+ % transforming the then and else branches and constructing the new ITE
+ % goal_expr.
%
:- pred coverage_prof_second_pass_ite(dp_goal_info::in, list(prog_var)::in,
hlds_goal::in, hlds_goal::in, hlds_goal::in, hlds_goal_expr::out,
- coverage_after_known::in, coverage_after_known::out,
+ coverage_before_known::in, coverage_before_known::out,
proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
coverage_prof_second_pass_ite(DPInfo, ITEExistVars, Cond0, Then0, Else0,
- GoalExpr, CoverageAfterITEKnown, NextCoverageAfterKnown,
+ GoalExpr, CoverageBeforeITEKnown, NextCoverageBeforeKnown,
!Info, AddedImpurity) :-
- % If the then and else goals have exactly one solution and coverage is
- % known after the ite, then the coverage at the end of one branch can
- % be computed from the other branch and the coverage known after the ite.
- % This helps later to insert fewer coverage points in the beginning of
- % the branches, and may also help reduce coverage points within the
- % branches.
-
- ThenPortCountsCoverageAfter = goal_get_maybe_dp_port_counts_coverage(Then0),
- ElsePortCountsCoverageAfter = goal_get_maybe_dp_port_counts_coverage(Else0),
- (
- CoverageAfterITEKnown = coverage_after_known,
- ThenDetism = Then0 ^ hlds_goal_info ^ goal_info_get_determinism,
- ElseDetism = Else0 ^ hlds_goal_info ^ goal_info_get_determinism,
- (
- ( ThenDetism = detism_det
- ; ThenDetism = detism_cc_multi
- ),
- ( ElseDetism = detism_det
- ; ElseDetism = detism_cc_multi
- )
- ->
- (
- ThenPortCountsCoverageAfter =
- no_port_counts_give_coverage_after,
- ElsePortCountsCoverageAfter =
- no_port_counts_give_coverage_after,
-
- % The coverage at the end of the else goal can be calculated
- % from the coverage at the end of the then goal.
- CoverageAfterThenKnown = coverage_after_unknown,
- CoverageAfterElseKnown = coverage_after_known
- ;
- ThenPortCountsCoverageAfter =
- no_port_counts_give_coverage_after,
- ElsePortCountsCoverageAfter = port_counts_give_coverage_after,
-
- % The coverage at the end of the then goal can be calculated
- % from the coverage at the end of the else goal.
- CoverageAfterThenKnown = coverage_after_known,
- CoverageAfterElseKnown = coverage_after_known
- ;
- ThenPortCountsCoverageAfter = port_counts_give_coverage_after,
-
- % The coverage at the end of the else goal (if it doesn't have
- % port counts), can be calculated from the coverage of the then
- % goal. Or it's already known because the port counts from
- % within the goal give the coverage information.
- CoverageAfterThenKnown = coverage_after_known,
- CoverageAfterElseKnown = coverage_after_known
- )
- ;
- % The branches of the ITE are not deterministic.
- CoverageAfterThenKnown = coverage_after_unknown,
- CoverageAfterElseKnown = coverage_after_unknown
- )
- ;
- CoverageAfterITEKnown = coverage_after_unknown,
- CoverageAfterElseKnown = coverage_after_unknown,
- CoverageAfterThenKnown = coverage_after_unknown
- ),
-
- % Transform Else branch,
- coverage_prof_second_pass_goal(Else0, Else1,
- CoverageAfterElseKnown, CoverageBeforeElseKnown1, !Info,
- AddedImpurityElseGoal),
+ % Transform Cond branch.
+ coverage_prof_second_pass_goal(Cond0, Cond,
+ CoverageBeforeITEKnown, CoverageKnownAfterCond, !Info,
+ AddedImpurityCond),
- % Transform Then branch.
- coverage_prof_second_pass_goal(Then0, Then1,
- CoverageAfterThenKnown, CoverageBeforeThenKnown1, !Info,
- AddedImpurityThenGoal),
+ CoverageKnownBeforeThen0 = CoverageKnownAfterCond,
+ CoverageKnownBeforeElse0 = coverage_before_unknown,
% Gather information and decide what coverage points to insert.
%
@@ -2486,59 +2476,69 @@ coverage_prof_second_pass_ite(DPInfo, IT
%
% Whatever we do we will ensure that the coverage will be known at the
% beginning of each branch,
-
CPOBranchIf = !.Info ^ ci_coverage_profiling_opts ^ cpo_branch_ite,
- CondPortCountsCoverageAfter = goal_get_maybe_dp_port_counts_coverage(Cond0),
DPInfo = dp_goal_info(IsMDProfInst, _),
(
CPOBranchIf = yes,
- CondPortCountsCoverageAfter = no_port_counts_give_coverage_after,
IsMDProfInst = goal_is_not_mdprof_inst
->
(
- CoverageBeforeThenKnown1 = coverage_after_unknown,
+ CoverageKnownBeforeThen0 = coverage_before_unknown,
ThenPath = goal_info_get_goal_path(Then0 ^ hlds_goal_info),
InsertCPThen = yes(coverage_point_info(ThenPath,
cp_type_branch_arm))
;
- CoverageBeforeThenKnown1 = coverage_after_known,
- InsertCPThen = no
- )
- ;
- % Don't insert any coverage points,
+ CoverageKnownBeforeThen0 = coverage_before_known,
InsertCPThen = no
),
- (
- CoverageBeforeElseKnown1 = coverage_after_unknown,
+ % Always insert a coverage point for the else branch.
ElsePath = goal_info_get_goal_path(Else0 ^ hlds_goal_info),
InsertCPElse = yes(coverage_point_info(ElsePath,
- cp_type_branch_arm))
+ cp_type_branch_arm)),
+ CoverageKnownBeforeThen = coverage_before_known,
+ CoverageKnownBeforeElse = coverage_before_known
;
- CoverageBeforeElseKnown1 = coverage_after_known,
- InsertCPElse = no
+ % Don't insert any coverage points,
+ InsertCPThen = no,
+ InsertCPElse = no,
+ CoverageKnownBeforeThen = CoverageKnownBeforeThen0,
+ CoverageKnownBeforeElse = CoverageKnownBeforeElse0
),
- % Insert any coverage points.
- maybe_insert_coverage_point_before(InsertCPElse, Else1, Else,
- CoverageBeforeElseKnown1, _CoverageBeforeElseKnown, !Info,
- AddedImpurityElseCP),
- bool.or(AddedImpurityElseGoal, AddedImpurityElseCP, AddedImpurityElse),
-
- maybe_insert_coverage_point_before(InsertCPThen, Then1, Then,
- CoverageBeforeThenKnown1, CoverageBeforeThenKnown, !Info,
- AddedImpurityThenCP),
- bool.or(AddedImpurityThenGoal, AddedImpurityThenCP, AddedImpurityThen),
+ % Transform Then and Else branches,
+ coverage_prof_second_pass_goal(Then0, Then1,
+ CoverageKnownBeforeThen, NextCoverageKnownThen, !Info,
+ AddedImpurityThenGoal),
+ coverage_prof_second_pass_goal(Else0, Else1,
+ CoverageKnownBeforeElse, NextCoverageKnownElse, !Info,
+ AddedImpurityElseGoal),
- % Transform Cond branch.
- CoverageKnownAfterCond = CoverageBeforeThenKnown,
- coverage_prof_second_pass_goal(Cond0, Cond,
- CoverageKnownAfterCond, NextCoverageAfterKnown, !Info,
- AddedImpurityCond),
+ % Insert any coverage points.
+ (
+ InsertCPThen = yes(CPInfoThen),
+ insert_coverage_point_before(CPInfoThen, Then1, Then, !Info),
+ AddedImpurityThen = yes
+ ;
+ InsertCPThen = no,
+ Then = Then1,
+ AddedImpurityThen = AddedImpurityThenGoal
+ ),
+ (
+ InsertCPElse = yes(CPInfoElse),
+ insert_coverage_point_before(CPInfoElse, Else1, Else, !Info),
+ AddedImpurityElse = yes
+ ;
+ InsertCPElse = no,
+ Else = Else1,
+ AddedImpurityElse = AddedImpurityElseGoal
+ ),
% Build goal experession and tidy up.
AddedImpurity = bool.or(AddedImpurityCond,
bool.or(AddedImpurityThen, AddedImpurityElse)),
- GoalExpr = if_then_else(ITEExistVars, Cond, Then, Else).
+ GoalExpr = if_then_else(ITEExistVars, Cond, Then, Else),
+ NextCoverageBeforeKnown = coverage_before_known_and(
+ NextCoverageKnownThen, NextCoverageKnownElse).
:- func goal_info_get_dp_info(hlds_goal_info) = dp_goal_info.
@@ -2600,12 +2600,12 @@ goal_info_set_mdprof_inst(IsMDProfInst,
%
:- pred maybe_insert_coverage_point_before(maybe(coverage_point_info)::in,
hlds_goal::in, hlds_goal::out,
- coverage_after_known::in, coverage_after_known::out,
+ coverage_before_known::in, coverage_before_known::out,
proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
-maybe_insert_coverage_point_before(no, !Goal, !CoverageAfterKnown, !Info, no).
+maybe_insert_coverage_point_before(no, !Goal, !CoverageBeforeKnown, !Info, no).
maybe_insert_coverage_point_before(yes(CPInfo), !Goal,
- _, coverage_after_known, !Info, yes) :-
+ _, coverage_before_known, !Info, yes) :-
insert_coverage_point_before(CPInfo, !Goal, !Info).
% Insert a coverage point before the given goal. This returns a flat
@@ -2627,30 +2627,20 @@ insert_coverage_point_before(CPInfo, !Go
% Used to describe if coverage information is known at a partiular point
% within a procedure.
%
-:- type coverage_after_known
- ---> coverage_after_known
- ; coverage_after_unknown.
-
- % Merge two coverage_after_known values at the beginning of a branch.
- %
- % The coverage profiling algorithm moves right to left through conjunctions
- % and disjunctions, and from inner goals to outer goals on all non-atomic
- % goals. It may reach a branch of execution knowing the coverage known
- % information entering both branches, this predicate computes the coverage
- % known information for the branch as a whole. For example. In an
- % if-then-else this can compute weather the coverage is known after the
- % condition based in weather the coverage is known before both the then and
- % else branches.
- %
-:- pred coverage_after_known_branch(coverage_after_known::in,
- coverage_after_known::in, coverage_after_known::out) is det.
-
-coverage_after_known_branch(coverage_after_known, coverage_after_known,
- coverage_after_known).
-coverage_after_known_branch(coverage_after_known, coverage_after_unknown,
- coverage_after_unknown).
-coverage_after_known_branch(coverage_after_unknown, _,
- coverage_after_unknown).
+:- type coverage_before_known
+ ---> coverage_before_known
+ ; coverage_before_unknown.
+
+ % The logical 'and' of coverage_before_known values.
+:- func coverage_before_known_and(coverage_before_known, coverage_before_known)
+ = coverage_before_known.
+
+coverage_before_known_and(coverage_before_known, coverage_before_known) =
+ coverage_before_known.
+coverage_before_known_and(coverage_before_known, coverage_before_unknown) =
+ coverage_before_unknown.
+coverage_before_known_and(coverage_before_unknown, _) =
+ coverage_before_unknown.
% Create a coverage info struture, initializing some values to sensible
% defaults.
@@ -2722,7 +2712,7 @@ has_port_counts_after(Goal, PCDirect, PC
has_port_counts_if_det(Detism, PCBefore, PC)
).
- % Given the current goal's determinism and wheather the next earliest goal
+ % Given the current goal's determinism and whether the next earliest goal
% has port counts does this goal have port counts
%
:- pred has_port_counts_if_det(determinism::in,
@@ -2745,10 +2735,13 @@ has_port_counts_if_det(Detism, PortCount
% transformation.
%
% This pass gathers the information in the dp_coverage_goal_info structure,
- % namely weather the goal is trivial (if it and none of it's subgoals are
- % calls), And weather a port count is available from the deep profiler
+ % namely whether the goal is trivial (if it and none of it's subgoals are
+ % calls), And whether a port count is available from the deep profiler
% from which the coverage _after_ this goal can be computed.
%
+ % XXX: Currently the first pass is unsupported. The second pass does not
+ % use the information it generates.
+ %
:- pred coverage_prof_first_pass(coverage_profiling_options::in, hlds_goal::in,
hlds_goal::out, port_counts_give_coverage_after::in,
dp_coverage_goal_info::out) is det.
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.478
diff -u -p -b -r1.478 mercury_compile.m
--- compiler/mercury_compile.m 5 Sep 2008 03:57:36 -0000 1.478
+++ compiler/mercury_compile.m 24 Sep 2008 04:33:39 -0000
@@ -4409,7 +4409,7 @@ maybe_deep_profiling(Verbose, Stats, !HL
maybe_write_string(Verbose,
"% Applying deep profiling transformation...\n", !IO),
maybe_flush_output(Verbose, !IO),
- apply_deep_profiling_transformation(!HLDS),
+ apply_deep_profiling_transformation(!HLDS, !IO),
maybe_write_string(Verbose, "% done.\n", !IO),
maybe_report_stats(Stats, !IO)
;
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.631
diff -u -p -b -r1.631 options.m
--- compiler/options.m 24 Sep 2008 06:47:14 -0000 1.631
+++ compiler/options.m 25 Sep 2008 12:52:58 -0000
@@ -304,6 +304,7 @@
; profile_deep_coverage_branch_disj
% Tunables for the coverage profiling pass.
+ % XXX: Currently both these options are unsupported.
; profile_deep_coverage_use_portcounts
; profile_deep_coverage_use_trivial
@@ -1167,8 +1168,8 @@ option_defaults_2(compilation_model_opti
profile_deep_coverage_branch_ite - bool(yes),
profile_deep_coverage_branch_switch - bool(yes),
profile_deep_coverage_branch_disj - bool(yes),
- profile_deep_coverage_use_portcounts - bool(yes),
- profile_deep_coverage_use_trivial - bool(yes),
+ profile_deep_coverage_use_portcounts - bool(no),
+ profile_deep_coverage_use_trivial - bool(no),
profile_for_implicit_parallelism - bool(no),
use_zeroing_for_ho_cycles - bool(yes),
use_lots_of_ho_specialization - bool(no),
Index: deep_profiler/program_representation_utils.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/program_representation_utils.m,v
retrieving revision 1.4
diff -u -p -b -r1.4 program_representation_utils.m
--- deep_profiler/program_representation_utils.m 21 Sep 2008 12:05:06 -0000 1.4
+++ deep_profiler/program_representation_utils.m 25 Sep 2008 12:56:13 -0000
@@ -185,10 +185,10 @@ print_goal_to_strings(VarTable, Indent,
GoalExprRep = scope_rep(SubGoalRep, MaybeCut),
(
MaybeCut = scope_is_cut,
- CutString = cord.empty
+ CutString = cord.singleton(" cut")
;
MaybeCut = scope_is_no_cut,
- CutString = cord.singleton(" cut")
+ CutString = cord.empty
),
print_goal_to_strings(VarTable, Indent + 1, SubGoalRep, SubGoalString),
Strings = indent(Indent) ++ DetismString ++ GoalAnnotationString ++
@@ -507,6 +507,19 @@ modulerep_search_proc(ModuleRep, ProcLab
%----------------------------------------------------------------------------%
+ % Annotate a procedure representation structure with coverage information.
+ %
+ % The following trace flags control debugging for this predicate.
+ %
+ % debug_coverage_propagation:
+ % Print out diagnostic messages to aid in the debugging of the
+ % propagation coverage algorithm.
+ %
+ % no_coverage_propagation_assertions:
+ % Disable assertions used to test this algorithm, This allows the
+ % algorithm to proceed past the problem and allow the programmer to
+ % view erroneous output.
+ %
procrep_annotate_with_coverage(OwnProf, CallSites, SolnsCoveragePoints,
BranchCoveragePoints, !ProcRep) :-
some [!ProcDefn, !GoalRep] (
@@ -542,6 +555,81 @@ procrep_annotate_with_coverage(OwnProf,
cri_branch_coverage_points :: map(goal_path, coverage_point)
).
+ % Try to get coverage information from:
+ % + Port counts if this is an atomic goal.
+ % + A solution count from a coverage point after the goal
+ % + If the goal is in a conjunction and it is not the first conjunct, try
+ % to get the solution count of the previous goal.
+ %
+ % This does not check for branch entry counts.
+ %
+:- pred get_coverage_information(coverage_reference_info::in,
+ goal_expr_rep(T)::in, goal_path::in, detism_rep::in,
+ coverage_info::in, coverage_info::out) is det.
+
+get_coverage_information(Info, GoalExpr, GoalPath, Detism, !Coverage) :-
+ % Try to get coverage information from goal port counts.
+ (
+ ( !.Coverage = coverage_unknown
+ ; !.Coverage = coverage_known_before(_)
+ ; !.Coverage = coverage_known_after(_)
+ ),
+ GoalExpr = atomic_goal_rep(_, _, _, AtomicGoal),
+ ( AtomicGoal = higher_order_call_rep(_, _)
+ ; AtomicGoal = method_call_rep(_, _, _)
+ ; AtomicGoal = plain_call_rep(_, _, _)
+ ; AtomicGoal = builtin_call_rep(_, _, _)
+ ; AtomicGoal = pragma_foreign_code_rep(_)
+ )
+ ->
+ (
+ map.search(Info ^ cri_call_sites, GoalPath, CallSite),
+ % Callback call sites measure the port counts when mercury is
+ % re-entered, not the number of calls made from this call site.
+ CallSite ^ csf_kind \= callback_and_no_info
+ ->
+ Summary = CallSite ^ csf_summary_perf,
+ % Entry due to redo is not counted at the point before the
+ % goal, it's represented when the number of exists is greater
+ % than the number of calls, This won't work with nondet code
+ % which should be fixed in the future.
+ Calls = Summary ^ perf_row_calls,
+ Exits = Summary ^ perf_row_exits,
+ !:Coverage = coverage_known(Calls, Exits)
+ ;
+ (
+ % These goal call types must have call sites, whereas some
+ % builtins and foreign code pragmas may not.
+ ( AtomicGoal = higher_order_call_rep(_, _)
+ ; AtomicGoal = method_call_rep(_, _, _)
+ ; AtomicGoal = plain_call_rep(_, _, _)
+ )
+ ->
+ error("Couldn't look up call site for port counts GP: " ++
+ goal_path_to_string(GoalPath))
+ ;
+ true
+ )
+ )
+ ;
+ true
+ ),
+
+ % Search for a coverage point after this goal.
+ (
+ ( !.Coverage = coverage_unknown
+ ; !.Coverage = coverage_known_before(_)
+ ),
+ map.search(Info ^ cri_solns_coverage_points, GoalPath, CoveragePoint1)
+ ->
+ CoveragePoint1 = coverage_point(Count1, _, _),
+ !:Coverage = merge_coverage(!.Coverage, coverage_known_after(Count1))
+ ;
+ true
+ ),
+
+ propagate_coverage(Detism, GoalPath, !Coverage).
+
% Annotate a goal and it's children with coverage information.
%
:- pred goal_annotate_coverage(coverage_reference_info::in, goal_path::in,
@@ -552,26 +640,12 @@ goal_annotate_coverage(Info, GoalPath, !
Goal0 = goal_rep(GoalExpr0, Detism, _),
% Gather any coverage information about this goal and apply it.
- (
- get_coverage_after(!.Coverage) = coverage_unknown,
- map.search(Info ^ cri_solns_coverage_points, GoalPath, CoveragePoint)
- ->
- CoveragePoint = coverage_point(Coverage, _, _),
- !:Coverage = merge_coverage(get_coverage_before(!.Coverage),
- coverage_known_after(Coverage))
- ;
- true
- ),
- % TODO: Infer that if a goal has a coverage of exactly 0 before it, then it
- % must have a coverage of exactly 0 after it. And that a goal that cannot
- % fail that has a coverage of 0 after it, must have a coverage of 0 before
- % it.
- maybe_propagate_det_coverage(Detism, GoalPath, !Coverage),
+ get_coverage_information(Info, GoalExpr0, GoalPath, Detism, !Coverage),
% Calculate coverage of any inner goals.
(
GoalExpr0 = conj_rep(Conjuncts0),
- conj_annotate_coverage(Info, GoalPath, 1, !Coverage,
+ conj_annotate_coverage(Info, GoalPath, !Coverage,
Conjuncts0, Conjuncts),
GoalExpr = conj_rep(Conjuncts)
;
@@ -581,7 +655,7 @@ goal_annotate_coverage(Info, GoalPath, !
GoalExpr = disj_rep(Disjuncts)
;
GoalExpr0 = switch_rep(Var, CanFail, Cases0),
- switch_annotate_coverage(Info, Detism, GoalPath, !Coverage,
+ switch_annotate_coverage(Info, CanFail, GoalPath, !Coverage,
Cases0, Cases),
GoalExpr = switch_rep(Var, CanFail, Cases)
;
@@ -601,51 +675,9 @@ goal_annotate_coverage(Info, GoalPath, !
GoalExpr = scope_rep(ScopedGoal, MaybeCut)
;
GoalExpr0 = atomic_goal_rep(Filename, Line, Vars, AtomicGoal),
- (
- ( AtomicGoal = unify_construct_rep(_, _, _)
- ; AtomicGoal = unify_deconstruct_rep(_, _, _)
- ; AtomicGoal = partial_deconstruct_rep(_, _, _)
- ; AtomicGoal = partial_construct_rep(_, _, _)
- ; AtomicGoal = unify_assign_rep(_, _)
- ; AtomicGoal = cast_rep(_, _)
- ; AtomicGoal = unify_simple_test_rep(_, _)
- ; AtomicGoal = event_call_rep(_, _)
- )
- ;
- ( AtomicGoal = higher_order_call_rep(_, _)
- ; AtomicGoal = method_call_rep(_, _, _)
- ; AtomicGoal = plain_call_rep(_, _, _)
- ; AtomicGoal = builtin_call_rep(_, _, _)
- ; AtomicGoal = pragma_foreign_code_rep(_)
- ),
- ( map.search(Info ^ cri_call_sites, GoalPath, CallSite) ->
- Summary = CallSite ^ csf_summary_perf,
- % Entry due to redo is not counted at the point before the
- % goal, it's represented when the number of exists is greater
- % than the number of calls, This won't work with nondet code
- % which should be fixed in the future.
- Calls = Summary ^ perf_row_calls,
- Exits = Summary ^ perf_row_exits,
- !:Coverage = coverage_known(Calls, Exits)
- ;
- (
- % These goal call types must have call sites, whereas some
- % builtins and foreign code pragmas may not.
- ( AtomicGoal = higher_order_call_rep(_, _)
- ; AtomicGoal = method_call_rep(_, _, _)
- ; AtomicGoal = plain_call_rep(_, _, _)
- )
- ->
- error("Couldn't look up call site for port counts GP: " ++
- goal_path_to_string(GoalPath))
- ;
- true
- )
- )
- ),
GoalExpr = atomic_goal_rep(Filename, Line, Vars, AtomicGoal)
),
- maybe_propagate_det_coverage(Detism, GoalPath, !Coverage),
+ propagate_coverage(Detism, GoalPath, !Coverage),
Goal = goal_rep(GoalExpr, Detism, !.Coverage),
trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
io.write_string("goal_annotate_coverage: done\n", !IO),
@@ -654,57 +686,56 @@ goal_annotate_coverage(Info, GoalPath, !
s(string(Detism)),
s(string(!.Coverage))], !IO)
),
+ trace [ compile_time(not flag("no_coverage_propagation_assertions")) ]
+ (
+ require(check_coverage_complete(!.Coverage, GoalExpr),
+ string.format("check_coverage_complete failed\n" ++
+ "\tCoverage: %s\n\tGoalPath: %s\n",
+ [s(string(!.Coverage)), s(goal_path_to_string(GoalPath))])),
require(check_coverage_regarding_detism(!.Coverage, Detism),
string.format("check_coverage_regarding_detism failed: %s %s",
- [s(string(!.Coverage)), s(string(Detism))])).
+ [s(string(!.Coverage)), s(string(Detism))]))
+ ).
+
+ % Annotate a conjunction with coverage information.
+ %
+:- pred conj_annotate_coverage(coverage_reference_info::in, goal_path::in,
+ coverage_info::in, coverage_info::out,
+ list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
- % Annotate a conjunction with coverage information. This folds from the
- % right over the list of conjuncts (backwards).
+conj_annotate_coverage(Info, GoalPath, !Coverage, Conjs0, Conjs) :-
+ conj_annotate_coverage_2(Info, GoalPath, 1, !Coverage, Conjs0, Conjs).
+
+ % Annotate a conjunction with coverage information.
%
% The list of goals is the tail of a conjunction, the coverage argument
% describes the coverage of this list of goals if it where the entire
- % conjunction. However each goal has it's own coverage.
+ % conjunction. Each goal also has it's own coverage.
%
-:- pred conj_annotate_coverage(coverage_reference_info::in, goal_path::in,
+:- pred conj_annotate_coverage_2(coverage_reference_info::in, goal_path::in,
int::in, coverage_info::in, coverage_info::out,
list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
-conj_annotate_coverage(_, GoalPath, ConjunctNum, !Coverage, [], []) :-
+conj_annotate_coverage_2(_, GoalPath, ConjunctNum, !Coverage, [], []) :-
% The empty conjunction is equivalent to 'true' which is deterministic,
ConjGoalPath = goal_path_add_at_end(GoalPath, step_conj(ConjunctNum)),
propagate_det_coverage(ConjGoalPath, !Coverage).
-conj_annotate_coverage(Info, GoalPath, ConjunctNum, !Coverage,
+conj_annotate_coverage_2(Info, GoalPath, ConjunctNum, !Coverage,
[Conj0 | Conjs0], [Conj | Conjs]) :-
split_coverage(!.Coverage, CoverageBefore0, CoverageAfter0),
- conj_annotate_coverage(Info, GoalPath, ConjunctNum+1,
- CoverageAfter0, TailCoverage1, Conjs0, Conjs1),
- split_coverage(TailCoverage1, CoverageBeforeTail1, CoverageAfter1),
- goal_transition_coverage(CoverageAfterHead0, CoverageBeforeTail1),
- HeadCoverage0 = merge_coverage(CoverageBefore0, CoverageAfterHead0),
goal_annotate_coverage(Info,
goal_path_add_at_end(GoalPath, step_conj(ConjunctNum)),
- HeadCoverage0, HeadCoverage, Conj0, Conj),
-
- % If computing the coverage for the head gave us information that can be
- % used to re-compute the coverage for the tail, and we don't already know
- % the coverage at the beginning of the tail. Then re-compute the coverage
- % for the tail.
+ CoverageBefore0, HeadCoverage, Conj0, Conj),
split_coverage(HeadCoverage, CoverageBefore, CoverageAfterHead),
- (
- CoverageBeforeTail1 = coverage_unknown,
- CoverageAfterHead = coverage_known_after(Count)
- ->
- CoverageBeforeTail = coverage_known_before(Count),
- TailCoverage2 = merge_coverage(CoverageBeforeTail, CoverageAfter1),
- conj_annotate_coverage(Info, GoalPath, ConjunctNum+1,
- TailCoverage2, TailCoverage, Conjs0, Conjs),
- CoverageAfter = get_coverage_after(TailCoverage)
- ;
- Conjs = Conjs1,
- CoverageAfter = CoverageAfter1
- ),
+ goal_transition_coverage(CoverageAfterHead, CoverageBeforeTail),
+
+ TailCoverage0 = merge_coverage(CoverageBeforeTail, CoverageAfter0),
+ conj_annotate_coverage_2(Info, GoalPath, ConjunctNum+1,
+ TailCoverage0, TailCoverage, Conjs0, Conjs),
+ CoverageAfter = get_coverage_after(TailCoverage),
+
!:Coverage = merge_coverage(CoverageBefore, CoverageAfter).
% Compute the coverage information for a disjunction.
@@ -713,72 +744,50 @@ conj_annotate_coverage(Info, GoalPath, C
% - The coverage before a disjunction is equal to the coverage before the
% first disjunct.
% - The coverage after a disjunction is equal to the sum of coverages
- % after each disjunct.
- % - If the disjunction has at most one solution, then the coverage
- % entering a disjunct is the failure count of the previous disjunct.
- %
- % Examples:
- % A semidet disjunction.
- % 5 ( 5 D1 2; 3 D2 2; 1 D3 0 ) 4
- %
- % A nondet disjunction.
- % 5 ( 5 D1 2; 5 D2 3; 5 D3 1 ) 6 (2 exit, 4 redo)
- %
- % For simplicity start with a backwards-only traversal, Not all the rules
- % described in this comment are applied.
+ % after each disjunct. This rule is not yet implemented.
%
:- pred disj_annotate_coverage(coverage_reference_info::in, detism_rep::in,
goal_path::in, coverage_info::in, coverage_info::out,
list(goal_rep(unit))::in, list(goal_rep(coverage_info))::out) is det.
-disj_annotate_coverage(Info, _Detism, GoalPath, !Coverage,
+disj_annotate_coverage(Info, Detism, GoalPath, !Coverage,
Disjs0, Disjs) :-
CoverageBefore0 = get_coverage_before(!.Coverage),
- disj_annotate_coverage_2(Info, GoalPath, 1,
- Disjs0, Disjs, CoverageBefore),
+ Solutions = detism_get_solutions(Detism),
+ disj_annotate_coverage_2(Info, GoalPath, 1, Solutions,
+ CoverageBefore0, Disjs0, Disjs).
- % If coverage before the disjunction was unknown before and is now
- % discovered, update it.
+:- pred disj_annotate_coverage_2(coverage_reference_info::in,
+ goal_path::in, int::in, solution_count::in,
+ coverage_info::in(coverage_before),
+ list(goal_rep)::in, list(goal_rep(coverage_info))::out) is det.
+
+disj_annotate_coverage_2(_, _, _, _, _, [], []).
+
+disj_annotate_coverage_2(Info, GoalPath, DisjNum, Solutions, CoverageBefore0,
+ [Disj0 | Disjs0], [Disj | Disjs]) :-
+ DisjGoalPath = goal_path_add_at_end(GoalPath, step_disj(DisjNum)),
(
CoverageBefore0 = coverage_unknown,
- CoverageBefore = coverage_known_before(_)
- ->
- CoverageAfter = get_coverage_after(!.Coverage),
- !:Coverage = merge_coverage(CoverageBefore, CoverageAfter)
+ get_branch_coverage(Info, DisjGoalPath, CoverageBefore1)
;
- true
- ).
-
-:- pred disj_annotate_coverage_2(coverage_reference_info::in,
- goal_path::in, int::in,
- list(goal_rep)::in, list(goal_rep(coverage_info))::out,
- coverage_info::out(coverage_before)) is det.
-
-disj_annotate_coverage_2(_, _, _, [], [], coverage_known_before(0)).
-
-disj_annotate_coverage_2(Info, GoalPath, DisjNum,
- [Disj0 | Disjs0], [Disj | Disjs], CoverageBefore) :-
- disj_annotate_coverage_2(Info, GoalPath, DisjNum + 1,
- Disjs0, Disjs, _),
-
- ThisGoalPath = goal_path_add_at_end(GoalPath, step_disj(DisjNum)),
- get_branch_coverage(Info, ThisGoalPath, CoverageBeforeDisj),
- % This can be set from the coverage entering the next disjunct, however the
- % transformation in the compiler doesn't do this, so for simplicity, this
- % is pessimistic. Otherwise set is using CoverageBeforeTail.
- CoverageAfterDisj = coverage_unknown,
- CoverageDisj0 = merge_coverage(CoverageBeforeDisj, CoverageAfterDisj),
-
- goal_annotate_coverage(Info, ThisGoalPath, CoverageDisj0, CoverageDisj,
+ CoverageBefore0 = coverage_known_before(_),
+ CoverageBefore1 = CoverageBefore0
+ ),
+ goal_annotate_coverage(Info, DisjGoalPath, CoverageBefore1, _CoverageDisj,
Disj0, Disj),
- CoverageBefore = get_coverage_before(CoverageDisj).
-:- pred switch_annotate_coverage(coverage_reference_info::in, detism_rep::in,
- goal_path::in, coverage_info::in, coverage_info::out,
+ disj_annotate_coverage_2(Info, GoalPath, DisjNum + 1, Solutions,
+ coverage_unknown, Disjs0, Disjs).
+
+:- pred switch_annotate_coverage(coverage_reference_info::in,
+ switch_can_fail_rep::in, goal_path::in,
+ coverage_info::in, coverage_info::out,
list(case_rep(unit))::in, list(case_rep(coverage_info))::out) is det.
-switch_annotate_coverage(Info, Detism, GoalPath, !Coverage, Cases0, Cases) :-
- switch_annotate_coverage_2(Info, Detism, GoalPath, 1,
+switch_annotate_coverage(Info, CanFail, GoalPath, !Coverage, Cases0, Cases) :-
+ Coverage0 = !.Coverage,
+ switch_annotate_coverage_2(Info, CanFail, GoalPath, 1,
coverage_known_det(0), SwitchCoverage, !.Coverage, Cases0, Cases),
% Use the newly computed coverage if it's more informed than the current
% coverage.
@@ -809,10 +818,13 @@ switch_annotate_coverage(Info, Detism, G
!:Coverage = SwitchCoverage
),
- require(check_switch_coverage(Detism, Cases, !.Coverage),
+ trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ]
+ io.format("Switch: Coverage0: %s\n", [s(string(Coverage0))], !IO),
+ trace [ compile_time(not flag("no_coverage_propagation_assertions")) ]
+ require(check_switch_coverage(CanFail, Cases, !.Coverage),
string.format("check_switch_coverage failed\n\t" ++
- "Detism: %s\n\tCases: %s\n\tCoverage: %s\n",
- [s(string(Detism)), s(string(Cases)), s(string(!.Coverage))])).
+ "CanFail: %s\n\tCases: %s\n\tCoverage: %s\n",
+ [s(string(CanFail)), s(string(Cases)), s(string(!.Coverage))])).
% switch_annotate_coverage_2(Info, Detism, GoalPath, CaseNum,
% !CoverageSum, SwitchCoverage, !Cases),
@@ -827,14 +839,14 @@ switch_annotate_coverage(Info, Detism, G
% the end of the last goal may need to be computed from the coverage of
% each of the other goals.
%
-:- pred switch_annotate_coverage_2(coverage_reference_info::in, detism_rep::in,
- goal_path::in, int::in, coverage_info::in, coverage_info::out,
- coverage_info::in,
+:- pred switch_annotate_coverage_2(coverage_reference_info::in,
+ switch_can_fail_rep::in, goal_path::in, int::in, coverage_info::in,
+ coverage_info::out, coverage_info::in,
list(case_rep(unit))::in, list(case_rep(coverage_info))::out) is det.
switch_annotate_coverage_2(_, _, _, _, !CoverageSum, _, [], []).
-switch_annotate_coverage_2(Info, Detism, GoalPath, CaseNum,
+switch_annotate_coverage_2(Info, CanFail, GoalPath, CaseNum,
!CoverageSum, SwitchCoverage, [ Case0 | Cases0 ], [ Case | Cases ]) :-
CaseGoalPath = goal_path_add_at_end(GoalPath,
step_switch(CaseNum, no)),
@@ -849,7 +861,7 @@ switch_annotate_coverage_2(Info, Detism,
%
(
Cases0 = [],
- detism_get_can_fail(Detism) = cannot_fail
+ CanFail = switch_can_not_fail
->
(
coverage_count_before(SwitchCoverage, SwitchCountBefore),
@@ -885,7 +897,8 @@ switch_annotate_coverage_2(Info, Detism,
% Keep a sum of the coverage seen in cases so far.
(
coverage_count_before(!.CoverageSum, SumCountBefore1),
- coverage_count_before(Coverage, CountBefore)
+ coverage_count_before(Coverage, CountBefore),
+ CanFail = switch_can_not_fail
->
CoverageSumBefore = coverage_known_before(SumCountBefore1 + CountBefore)
;
@@ -901,25 +914,24 @@ switch_annotate_coverage_2(Info, Detism,
),
!:CoverageSum = merge_coverage(CoverageSumBefore, CoverageSumAfter),
- switch_annotate_coverage_2(Info, Detism, GoalPath, CaseNum + 1,
+ switch_annotate_coverage_2(Info, CanFail, GoalPath, CaseNum + 1,
!CoverageSum, SwitchCoverage, Cases0, Cases).
% Propagate coverage information for if-then-else goals.
%
% Step 1:
- % Compute the coverage of the Then and Else goals,
+ % Call goal_annotate_coverage for the condition goal.
%
% Step 2:
- % Infer and compute coverage information for the cond goal.
+ % Lookup coverage information for the then and else goals if it cannot be
+ % inferred from the condition goal. Set the coverage before the then and
+ % else goals.
%
% Step 3:
- % Infer coverage information for goals using the determinisms of the then
- % and else branches and the switch as a whole, and any coverage
- % information as computed above.
+ % Call goal_annotate_coverage for the then and else goals.
%
% Step 4:
- % Re-compute coverages for any sub goals within the Then and Else goals
- % whose coverage is more known than after step 1.
+ % Calculate the coverage at the end of the entire switch.
%
:- pred ite_annotate_coverage(coverage_reference_info::in, goal_path::in,
coverage_info::in, coverage_info::out,
@@ -933,147 +945,80 @@ ite_annotate_coverage(Info, GoalPath, !C
ThenGoalPath = goal_path_add_at_end(GoalPath, step_ite_then),
ElseGoalPath = goal_path_add_at_end(GoalPath, step_ite_else),
CondDetism = Cond0 ^ goal_detism_rep,
+ split_coverage(!.Coverage, CoverageBefore0, CoverageAfter0),
- % Step 1, compute coverage of each goal without inference.
- get_branch_coverage(Info, ThenGoalPath, ThenCoverage0),
- goal_annotate_coverage(Info, ThenGoalPath, ThenCoverage0, ThenCoverage1,
- Then0, Then1),
- get_branch_coverage(Info, ElseGoalPath, ElseCoverage0),
- goal_annotate_coverage(Info, ElseGoalPath, ElseCoverage0, ElseCoverage1,
- Else0, Else1),
-
- % Step 2: Infer coverage for the Cond goal..
- (
- get_coverage_before(ThenCoverage1) =
- coverage_known_before(ThenEntryCount)
- ->
- CondCoverageAfter0 = coverage_known_after(ThenEntryCount)
- ;
- CondCoverageAfter0 = coverage_unknown
- ),
- CondCoverage0 = merge_coverage(get_coverage_before(!.Coverage),
- CondCoverageAfter0),
- goal_annotate_coverage(Info, CondGoalPath, CondCoverage0, CondCoverage,
+ % Step 1:
+ % Call goal_annotate_coverage for the condition goal.
+ goal_annotate_coverage(Info, CondGoalPath, CoverageBefore0, CondCoverage,
Cond0, Cond),
- split_coverage(CondCoverage, CondCoverageBefore, CondCoverageAfter),
- % Step 3: Infer coverages for the Then and Else goals if unknown.
- CoverageAfter0 = get_coverage_after(!.Coverage),
- split_coverage(ThenCoverage1, ThenCoverageBefore1, ThenCoverageAfter1),
+ % Step 2:
+ % Lookup coverage information for the then and else goals. Set the
+ % coverage before the then and else goals.
(
- ThenCoverageBefore1 = coverage_unknown,
- CondCoverageAfter = coverage_known_after(CondCountAfterPrime)
+ coverage_count_after(CondCoverage, CountAfterCond)
->
- ThenCoverageBefore2 = coverage_known_before(CondCountAfterPrime),
- trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
- io.format("ITE Set coverage before Then: %d\n",
- [i(CondCountAfterPrime)], !IO)
- )
+ ThenCoverage0 = coverage_known_before(CountAfterCond)
;
- ThenCoverageBefore2 = ThenCoverageBefore1
+ get_branch_coverage(Info, ThenGoalPath, ThenCoverage0)
),
- (
- ThenCoverageAfter1 = coverage_unknown,
- CoverageAfter0 = coverage_known_after(CountAfterPrime),
- ElseCoverageAfter1 = coverage_known_after(ElseCountAfterPrime)
- ->
- ThenCoverageAfter2 =
- coverage_known_after(CountAfterPrime - ElseCountAfterPrime),
+ get_branch_coverage(Info, ElseGoalPath, ElseCoverage0),
+
trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
- io.format("ITE Set coverage after Then: %d - %d\n",
- [i(CountAfterPrime), i(ElseCountAfterPrime)], !IO)
- )
- ;
- ThenCoverageAfter2 = ThenCoverageAfter1
+ io.format("ITE Coverage inferred after then and else branches:\n" ++
+ "\tWhole: %s\n\tThen: %s\n\tElse: %s\n" ++
+ "\tGoalPath %s\n",
+ [s(string(!.Coverage)),
+ s(string(ThenCoverage0)), s(string(ElseCoverage0)),
+ s(goal_path_to_string(GoalPath))], !IO)
),
- ThenCoverage2 = merge_coverage(ThenCoverageBefore2, ThenCoverageAfter2),
- split_coverage(ElseCoverage1, ElseCoverageBefore1, ElseCoverageAfter1),
+
+ % Step 3:
+ % Call goal_annotate_coverage for the then and else goals.
+ goal_annotate_coverage(Info, ThenGoalPath, ThenCoverage0, ThenCoverage,
+ Then0, Then),
+ goal_annotate_coverage(Info, ElseGoalPath, ElseCoverage0, ElseCoverage,
+ Else0, Else),
+
+ % Step 4:
+ % Calculate the coverage at the end of the entire switch.
(
- ElseCoverageBefore1 = coverage_unknown,
- CondCoverageAfter = coverage_known_after(CondCountAfter),
- CondCoverageBefore = coverage_known_before(CondCountBefore),
- detism_get_solutions(CondDetism) = NumSolutions,
- ( NumSolutions = at_most_zero
- ; NumSolutions = at_most_one
- )
- ->
- CondFailures = CondCountBefore - CondCountAfter,
- ElseCoverageBefore2 = coverage_known_before(CondFailures),
- trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
- io.format("ITE Set coverage before Else: %d\n",
- [i(CondFailures)], !IO)
- )
+ CoverageBefore0 = coverage_known_before(_),
+ CoverageBefore = CoverageBefore0
;
- ElseCoverageBefore2 = ElseCoverageBefore1
+ CoverageBefore0 = coverage_unknown,
+ CoverageBefore = get_coverage_before(CondCoverage)
),
(
- ElseCoverageAfter1 = coverage_unknown,
- CoverageAfter0 = coverage_known_after(CountAfter),
- ThenCoverageAfter1 = coverage_known_after(ThenCountAfterPrime)
- ->
- ElseCoverageAfter2 =
- coverage_known_after(CountAfter - ThenCountAfterPrime),
- trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
- io.format("ITE Set coverage after Else: %d - %d\n",
- [i(CountAfter), i(ThenCountAfterPrime)], !IO)
- )
- ;
- ElseCoverageAfter2 = ElseCoverageAfter1
- ),
- ElseCoverage2 = merge_coverage(ElseCoverageBefore2, ElseCoverageAfter2),
-
- % Step 4: If more coverage information was inferred then complete the
- % coverage calculations for any inner goals in Then and Else.
- ( ThenCoverage1 \= ThenCoverage2 ->
- goal_annotate_coverage(Info, ThenGoalPath, ThenCoverage2, ThenCoverage,
- Then0, Then)
- ;
- ThenCoverage = ThenCoverage2,
- % Then1 is the result of the previous call to gaol_annotate_coverage
- % for the then goal.
- Then = Then1
- ),
- ( ElseCoverage1 \= ElseCoverage2 ->
- goal_annotate_coverage(Info, ElseGoalPath, ElseCoverage2, ElseCoverage,
- Else0, Else)
+ CoverageAfter0 = coverage_known_after(_),
+ CoverageAfter = CoverageAfter0
;
- ElseCoverage = ElseCoverage2,
- % Else1 is the result of the previous call to gaol_annotate_coverage
- % for the else goal.
- Else = Else1
- ),
-
- % Finally update the coverage state for the whole switch.
+ CoverageAfter0 = coverage_unknown,
(
- get_coverage_after(ThenCoverage) =
- coverage_known_after(ThenCountAfter),
- get_coverage_after(ElseCoverage) =
- coverage_known_after(ElseCountAfter)
+ coverage_count_after(ThenCoverage, CountAfterThen1),
+ coverage_count_after(ElseCoverage, CountAfterElse1)
->
- CoverageAfter = coverage_known_after(ThenCountAfter + ElseCountAfter),
- trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
- io.format("ITE Set coverage after ITE: %d + %d\n",
- [i(ThenCountAfter), i(ElseCountAfter)], !IO)
- )
+ CoverageAfter =
+ coverage_known_after(CountAfterThen1 + CountAfterElse1)
;
- CoverageAfter = get_coverage_after(!.Coverage)
- ),
- ( get_coverage_before(CondCoverage) = coverage_known_before(CountBefore) ->
- CoverageBefore = coverage_known_before(CountBefore),
- trace [ compile_time(flag("debug_coverage_propagation")), io(!IO) ] (
- io.format("ITE Set coverage before ITE: %d\n", [i(CountBefore)],
- !IO)
+ CoverageAfter = coverage_unknown
)
- ;
- CoverageBefore = get_coverage_before(!.Coverage)
),
!:Coverage = merge_coverage(CoverageBefore, CoverageAfter),
+
+ trace [ compile_time(not flag("no_coverage_propagation_assertions")) ]
require(check_ite_coverage(!.Coverage, CondCoverage, ThenCoverage,
ElseCoverage, CondDetism),
string.format("check_ite_coverage/4 failed\n" ++
- "\tWhole: %s\n\tCond: %s\n\tThen: %s\n\tElse: %s\n",
+ "\tWhole: %s\n\tCond: %s\n\tThen: %s\n\tElse: %s\n" ++
+ "\tGoalPath: %s\n",
[s(string(!.Coverage)), s(string(CondCoverage)),
- s(string(ThenCoverage)), s(string(ElseCoverage))])).
+ s(string(ThenCoverage)), s(string(ElseCoverage)),
+ s(goal_path_to_string(GoalPath))])).
+
+:- pred not_unify(T::in, T::in) is semidet.
+
+not_unify(A, B) :- not unify(A, B).
% Get the coverage information from a coverage point about the branch
% referenced by the given goal path.
@@ -1097,29 +1042,25 @@ get_branch_coverage(Info, GoalPath, Cove
negation_annotate_coverage(Info, GoalPath, Coverage0, Coverage,
NegGoal0, NegGoal) :-
- split_coverage(Coverage0, CoverageBefore, CoverageAfter0),
- (
- CoverageAfter0 = coverage_known_after(CountAfter0),
- CoverageBefore = coverage_known_before(CountBefore)
- ->
- CoverageAfter1 = coverage_known_after(CountBefore - CountAfter0)
- ;
- CoverageAfter1 = coverage_unknown
- ),
- Coverage1 = merge_coverage(CoverageBefore, CoverageAfter1),
+ split_coverage(Coverage0, CoverageBefore0, CoverageAfter0),
+ Coverage1 = merge_coverage(CoverageBefore0, coverage_unknown),
+
NegGoalPath = goal_path_add_at_end(GoalPath, step_neg),
goal_annotate_coverage(Info, NegGoalPath, Coverage1, Coverage2,
NegGoal0, NegGoal),
- CoverageAfter2 = get_coverage_after(Coverage2),
+
+ CoverageBefore2 = get_coverage_before(Coverage2),
(
- CoverageAfter2 = coverage_known_after(CountAfter2),
- CoverageBefore = coverage_known_before(CountBeforePrime)
- ->
- CoverageAfter = coverage_known_after(CountBeforePrime - CountAfter2)
+ CoverageBefore2 = coverage_unknown,
+ CoverageBefore = CoverageBefore0
;
- CoverageAfter = coverage_unknown
+ CoverageBefore2 = coverage_known_before(_),
+ CoverageBefore = CoverageBefore2
),
- Coverage = merge_coverage(CoverageBefore, CoverageAfter).
+ Coverage = merge_coverage(CoverageBefore, CoverageAfter0),
+ trace [compile_time(flag("debug_coverage_propagation")), io(!IO) ]
+ io.format("Negation: setting negation coverage: %s\n",
+ [s(string(Coverage))], !IO).
:- pred scope_annotate_coverage(coverage_reference_info::in, goal_path::in,
maybe_cut::in, coverage_info::in, coverage_info::out,
@@ -1127,11 +1068,19 @@ negation_annotate_coverage(Info, GoalPat
scope_annotate_coverage(Info, GoalPath, MaybeCut, !Coverage,
ScopedGoal0, ScopedGoal) :-
+ ScopeCoverageAfter0 = get_coverage_after(!.Coverage),
maybe_cut_discard_solutions(MaybeCut, !Coverage),
ScopeGoalPath = goal_path_add_at_end(GoalPath, step_scope(MaybeCut)),
goal_annotate_coverage(Info, ScopeGoalPath, !Coverage, ScopedGoal0,
ScopedGoal),
- maybe_cut_discard_solutions(MaybeCut, !Coverage).
+ maybe_cut_discard_solutions(MaybeCut, !Coverage),
+ split_coverage(!.Coverage, ScopeCoverageBefore, ScopeCoverageAfter1),
+ (
+ ScopeCoverageAfter1 = coverage_unknown,
+ !:Coverage = merge_coverage(ScopeCoverageBefore, ScopeCoverageAfter0)
+ ;
+ ScopeCoverageAfter1 = coverage_known_after(_)
+ ).
:- pred maybe_cut_discard_solutions(maybe_cut::in,
coverage_info::in, coverage_info::out) is det.
@@ -1212,17 +1161,12 @@ check_coverage_regarding_detism(_Coverag
% Check that the coverages over the switch make sense. This works only for
% deterministic switches.
%
- % XXX: Re-write this to work on entry counts for switches that cannot fail
- % only.
- %
-:- pred check_switch_coverage(detism_rep::in,
+:- pred check_switch_coverage(switch_can_fail_rep::in,
list(case_rep(coverage_info))::in, coverage_info::in) is semidet.
-check_switch_coverage(Detism, Cases, Coverage) :-
+check_switch_coverage(CanFail, Cases, Coverage) :-
(
- ( Detism = det_rep
- ; Detism = cc_multidet_rep
- ),
+ CanFail = switch_can_not_fail,
list.foldl(sum_switch_case_coverage, Cases, yes(0), MaybeSum),
(
MaybeSum = yes(Sum),
@@ -1238,13 +1182,7 @@ check_switch_coverage(Detism, Cases, Cov
MaybeSum = no
)
;
- ( Detism = semidet_rep
- ; Detism = multidet_rep
- ; Detism = nondet_rep
- ; Detism = cc_nondet_rep
- ; Detism = failure_rep
- ; Detism = erroneous_rep
- )
+ CanFail = switch_can_fail
).
:- pred sum_switch_case_coverage(case_rep(coverage_info)::in,
@@ -1316,6 +1254,64 @@ check_ite_coverage(WholeCoverage, CondCo
true
).
+:- pred check_coverage_complete(coverage_info::in, goal_expr_rep(T)::in)
+ is semidet.
+
+check_coverage_complete(coverage_known(_, _), _GoalExpr).
+check_coverage_complete(coverage_known_det(_), _GoalExpr).
+% Uncomment this clause if, in the future, we allow coverage to be incomplete
+% for trivial goals.
+%check_coverage_complete(Coverage, GoalExpr) :-
+% ( Coverage = coverage_known_before(_)
+% ; Coverage = coverage_known_after(_)
+% ; Coverage = coverage_unknown
+% ),
+% goal_expr_is_trivial(GoalExpr).
+
+:- pred goal_is_trivial(goal_rep(T)::in) is semidet.
+
+goal_is_trivial(Goal) :-
+ GoalExpr = Goal ^ goal_expr_rep,
+ goal_expr_is_trivial(GoalExpr).
+
+:- pred goal_expr_is_trivial(goal_expr_rep(T)::in) is semidet.
+
+goal_expr_is_trivial(conj_rep(Conjs)) :-
+ list.all_true(goal_is_trivial, Conjs).
+
+goal_expr_is_trivial(disj_rep(Disjs)) :-
+ list.all_true(goal_is_trivial, Disjs).
+
+goal_expr_is_trivial(switch_rep(_, _, Cases)) :-
+ list.all_true((pred(Case::in) is semidet :-
+ Case = case_rep(_, _, Goal),
+ goal_is_trivial(Goal)), Cases).
+
+goal_expr_is_trivial(ite_rep(Cond, Then, Else)) :-
+ goal_is_trivial(Cond),
+ goal_is_trivial(Then),
+ goal_is_trivial(Else).
+
+goal_expr_is_trivial(negation_rep(SubGoal)) :-
+ goal_is_trivial(SubGoal).
+
+goal_expr_is_trivial(scope_rep(SubGoal, _)) :-
+ goal_is_trivial(SubGoal).
+
+goal_expr_is_trivial(atomic_goal_rep(_, _, _, AtomicGoal)) :-
+ ( AtomicGoal = unify_construct_rep(_, _, _)
+ ; AtomicGoal = unify_deconstruct_rep(_, _, _)
+ ; AtomicGoal = partial_deconstruct_rep(_, _, _)
+ ; AtomicGoal = partial_construct_rep(_, _, _)
+ ; AtomicGoal = unify_assign_rep(_, _)
+ ; AtomicGoal = cast_rep(_, _)
+ ; AtomicGoal = unify_simple_test_rep(_, _)
+ % Built-in calls are probably cheap enough to consider to be trivial.
+ ; AtomicGoal = builtin_call_rep(_, _, _)
+ ; AtomicGoal = pragma_foreign_code_rep(_)
+ ; AtomicGoal = event_call_rep(_, _)
+ ).
+
%----------------------------------------------------------------------------%
%
% Coverage information helper predicates.
@@ -1348,13 +1344,12 @@ propagate_det_coverage(GoalPath, !Covera
!.Coverage = coverage_known_det(_)
;
!.Coverage = coverage_known(Before, After),
- ( Before = After ->
+ trace [compile_time(not flag("no_coverage_propagation_assertions"))]
+ require(unify(Before, After),
+ format("Coverage before /= after for a det goal: %s, GP: %s",
+ [s(string(!.Coverage)), s(goal_path_to_string(GoalPath))])),
!:Coverage = coverage_known_det(Before)
;
- error(format("Coverage before /= after for a det goal: %s, GP: %s",
- [s(string(!.Coverage)), s(goal_path_to_string(GoalPath))]))
- )
- ;
( !.Coverage = coverage_known_before(Coverage)
; !.Coverage = coverage_known_after(Coverage)
),
@@ -1364,10 +1359,16 @@ propagate_det_coverage(GoalPath, !Covera
% If the determinism is deterministic or cc_multi use
% propagate_det_coverage.
%
-:- pred maybe_propagate_det_coverage(detism_rep::in, goal_path::in,
+:- pred propagate_coverage(detism_rep::in, goal_path::in,
coverage_info::in, coverage_info::out) is det.
-maybe_propagate_det_coverage(Detism, GoalPath, !Coverage) :-
+propagate_coverage(Detism, GoalPath, !Coverage) :-
+ % TODO: Infer that if a goal has a coverage of exactly 0 before it, then it
+ % must have a coverage of exactly 0 after it. And that a goal that cannot
+ % fail that has a coverage of 0 after it, must have a coverage of 0 before
+ % it - Since the coverage profiling and propagation algorithms are already
+ % complete this isn't required. It should be considered if we choose not
+ % to calculate coverage for trivial goals.
(
( Detism = det_rep
; Detism = cc_multidet_rep ),
@@ -1381,9 +1382,12 @@ maybe_propagate_det_coverage(Detism, Goa
;
Detism = cc_nondet_rep
;
- Detism = erroneous_rep
- ;
- Detism = failure_rep
+ ( Detism = erroneous_rep
+ ; Detism = failure_rep
+ ),
+ % Execution never reaches the end of these goals.
+ CoverageBefore = get_coverage_before(!.Coverage),
+ !:Coverage = merge_coverage(CoverageBefore, coverage_known_after(0))
).
% Information about the coverage before a goal only.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20080925/c63e13ad/attachment.sig>
More information about the reviews
mailing list