[m-rev.] diff: Fix bug #364: Add a specific cost analysis for nondet disjunctions.
Paul Bone
paul at bone.id.au
Fri Oct 3 19:13:33 AEST 2014
Branches: master, version-14_01-branch
---
Fix bug #364: Add a specific cost analysis for nondet disjunctions.
This bug was caused because we assumed that all disjunctions that the cost
analysis examined were semidet disjunctions. This patch adds a separate
predicate to calculate the cost of nondet disjunctions, it simply sums up
the costs of the disjuncts.
deep_profiler/autopar_costs.m:
As above.
deep_profiler/autopar_search_goals.m
Conform to above changes.
deep_profiler/autopar_search_callgraph.m:
When the auto-parallelisation analysis of a procedure throws an
exception print out the identity of the procedure.
NEWS:
Add news item.
---
NEWS | 2 ++
deep_profiler/autopar_costs.m | 44 ++++++++++++++++++++++++++++----
deep_profiler/autopar_search_callgraph.m | 32 +++++++++++++++++++----
deep_profiler/autopar_search_goals.m | 4 +--
4 files changed, 70 insertions(+), 12 deletions(-)
diff --git a/NEWS b/NEWS
index f2f948b..9079523 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ NEWS for Mercury 14.01.2
This is a bug-fix release.
++ Fix the handling of nondet code by the auto-parallelisation analysis in
+ mdprof_create_feedback. (Bug #364)
NEWS for Mercury 14.01.1
------------------------
diff --git a/deep_profiler/autopar_costs.m b/deep_profiler/autopar_costs.m
index 15f428c..a349830 100644
--- a/deep_profiler/autopar_costs.m
+++ b/deep_profiler/autopar_costs.m
@@ -35,7 +35,7 @@
:- pred conj_calc_cost(list(pard_goal_detail)::in, int::in,
goal_cost_csq::out) is det.
-:- pred disj_calc_cost(list(pard_goal_detail)::in, int::in,
+:- pred disj_calc_cost(detism_rep::in, list(pard_goal_detail)::in, int::in,
goal_cost_csq::out) is det.
:- pred switch_calc_cost(list(case_rep(pard_goal_detail_annotation))::in,
@@ -99,8 +99,25 @@ conj_calc_cost([Conj | Conjs], _, Cost) :-
ConjCost = Conj ^ goal_annotation ^ pgd_cost,
Cost = add_goal_costs_seq(ConjCost, ConjsCost).
-disj_calc_cost([], Calls, simple_goal_cost(Calls)).
-disj_calc_cost([Disj | Disjs], _, Cost) :-
+disj_calc_cost(Detism, Disjs, Calls, Cost) :-
+ Solutions = detism_get_solutions(Detism),
+ (
+ ( Solutions = at_most_zero_rep
+ ; Solutions = at_most_one_rep
+ ),
+ % This is a semidet or committed choice disjunction, there's no
+ % backtracking.
+ disj_calc_cost_semidet(Disjs, Calls, Cost)
+ ;
+ Solutions = at_most_many_rep,
+ disj_calc_cost_nondet(Disjs, Calls, Cost)
+ ).
+
+:- pred disj_calc_cost_semidet(list(pard_goal_detail)::in, int::in,
+ goal_cost_csq::out) is det.
+
+disj_calc_cost_semidet([], Calls, simple_goal_cost(Calls)).
+disj_calc_cost_semidet([Disj | Disjs], _, Cost) :-
Coverage = Disj ^ goal_annotation ^ pgd_coverage,
get_coverage_before_and_after_det(Coverage, Before, After),
( Before = 0 ->
@@ -109,14 +126,31 @@ disj_calc_cost([Disj | Disjs], _, Cost) :-
;
_Successes = After,
Failures = Before - After,
- % XXX: We assume this is a semidet disjunction
- disj_calc_cost(Disjs, Failures, FailureCost),
+ disj_calc_cost_semidet(Disjs, Failures, FailureCost),
DisjCost = Disj ^ goal_annotation ^ pgd_cost,
SuccessCost = atomic_goal_cost(After),
BranchCost = add_goal_costs_branch(Before, FailureCost, SuccessCost),
Cost = add_goal_costs_seq(DisjCost, BranchCost)
).
+:- pred disj_calc_cost_nondet(list(pard_goal_detail)::in, int::in,
+ goal_cost_csq::out) is det.
+
+disj_calc_cost_nondet([], Calls, simple_goal_cost(Calls)).
+disj_calc_cost_nondet([Disj | Disjs], Calls, Cost) :-
+ Coverage = Disj ^ goal_annotation ^ pgd_coverage,
+ get_coverage_before_det(Coverage, Before),
+ ( Before = 0 ->
+ % Avoid a divide by zero.
+ Cost = dead_goal_cost
+ ;
+ % TODO: This is very approximate, it calculates the percall cost.
+ % For nondet code we probably want the per-call and per-redo cost.
+ disj_calc_cost_nondet(Disjs, Calls, DisjsCost),
+ DisjCost = Disj ^ goal_annotation ^ pgd_cost,
+ Cost = add_goal_costs_seq(DisjCost, DisjsCost)
+ ).
+
switch_calc_cost([], Calls, simple_goal_cost(Calls)).
switch_calc_cost([Case | Cases], TotalCalls, Cost) :-
( TotalCalls = 0 ->
diff --git a/deep_profiler/autopar_search_callgraph.m b/deep_profiler/autopar_search_callgraph.m
index a201ce8..5ea6707 100644
--- a/deep_profiler/autopar_search_callgraph.m
+++ b/deep_profiler/autopar_search_callgraph.m
@@ -51,21 +51,23 @@
:- import_module measurement_units.
:- import_module measurements.
:- import_module program_representation_utils.
+:- import_module read_profile.
:- import_module recursion_patterns.
:- import_module report.
:- import_module var_use_analysis.
-:- import_module pair.
-:- import_module list.
:- import_module array.
:- import_module assoc_list.
:- import_module bool.
+:- import_module exception.
:- import_module float.
-:- import_module io.
:- import_module int.
+:- import_module io.
:- import_module lazy.
+:- import_module list.
:- import_module map.
:- import_module maybe.
+:- import_module pair.
:- import_module require.
:- import_module set.
:- import_module string.
@@ -403,8 +405,28 @@ candidate_parallel_conjunctions_clique_proc(Opts, Deep, RecursionType,
),
% Analyse this procedure for parallelism opportunities.
- candidate_parallel_conjunctions_proc(Opts, Deep, PDPtr, RecursionType,
- RecursiveCallSiteCostMap, Candidates, ProcMessages),
+ promise_equivalent_solutions [Candidates, ProcMessages]
+ ( try [] (
+ candidate_parallel_conjunctions_proc(Opts, Deep, PDPtr,
+ RecursionType, RecursiveCallSiteCostMap, CandidatesPrime,
+ ProcMessagesPrime)
+ )
+ then (
+ Candidates = CandidatesPrime,
+ ProcMessages = ProcMessagesPrime
+ )
+ catch_any Exp -> (
+ trace [io(!IO)] (
+ PDPtr = proc_dynamic_ptr(PDId),
+ deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+ deep_lookup_proc_statics(Deep, PD ^ pd_proc_static, PS),
+ ProcName = PS ^ ps_q_refined_id,
+ io.format(io.stderr_stream,
+ "Exception while analyising proc dynamic %d (%s)\n",
+ [i(PDId), s(ProcName)], !IO)
+ ),
+ throw(Exp)
+ )),
!:Messages = !.Messages ++ ProcMessages,
Messages = !.Messages
).
diff --git a/deep_profiler/autopar_search_goals.m b/deep_profiler/autopar_search_goals.m
index de7f17f..b4e0efc 100644
--- a/deep_profiler/autopar_search_goals.m
+++ b/deep_profiler/autopar_search_goals.m
@@ -167,7 +167,7 @@ goal_get_conjunctions_worth_parallelising(Info, RevGoalPath,
Disjs0, Disjs, 1, _, cord.empty, Candidates,
cord.empty, Pushes, cord.empty, Singles,
cord.empty, Messages),
- disj_calc_cost(Disjs, Calls, Cost),
+ disj_calc_cost(DetismRep, Disjs, Calls, Cost),
GoalExpr = disj_rep(Disjs)
;
GoalExpr0 = switch_rep(Var, CanFail, Cases0),
@@ -786,7 +786,7 @@ goal_to_pard_goal(Info, RevGoalPath, Goal, DetailGoal, !Messages) :-
GoalExpr = disj_rep(Disjs),
list.map_foldl2(disj_to_pard_goals(Info, RevGoalPath),
Disjs, DetailDisjs, 1, _, !Messages),
- disj_calc_cost(DetailDisjs, Before, Cost),
+ disj_calc_cost(Detism, DetailDisjs, Before, Cost),
DetailGoalExpr = disj_rep(DetailDisjs)
;
GoalExpr = switch_rep(Var, CanFail, Cases),
--
2.1.0
More information about the reviews
mailing list