[m-rev.] for review: fix bug in dep_par_conj
Peter Wang
novalazy at gmail.com
Tue Oct 14 22:43:58 AEDT 2008
On 2008-10-14, Zoltan Somogyi <zs at csse.unimelb.edu.au> wrote:
> On 13-Oct-2008, Zoltan Somogyi <zs at csse.unimelb.edu.au> wrote:
> > Actually, I found a bug when trying to describe the algorithm in the paper,
> > so there is no point in a review until I fix that bug.
>
> Here is the updated diff and log message.
>
> Zoltan.
>
> Fix an old bug in the transformation that implements dependent parallel
> conjunctions. The bug occurred when some arms of a branched control structure
> consumed a shared variable, and some arms didn't. For code like this
>
> q(X::in, Y::in, Z::out) :-
> ( Y = 2 ->
> A = Y
> ;
> A = X
> ),
> Z = X + A
>
> where X is a shared variable in a conjunction that calls q, the transformation
> yielded code that waited for the future version of X only in the else branch,
> not in the then branch. Since each wait was the producer of X from FutureX,
> this led directly to a mode inconsistency between the branches, and hence
> to a compiler crash.
>
> The main part of the fix is to make sure that the code that inserts waits into
> branched goals always inserts the wait either into every branch (if the
> variable is consumed by at least one branch), or into no branch (if no branch
> consumes the variable).
>
> The other part of the fix is to replace the code which tried to ensure,
> in a general sort of way, the invariant that the conjuncts of a parallel
> conjunction should not have any of their shared variables in their nonlocal set
> with code that directly ensures that shared variables are always renamed in
> their consuming conjuncts.
That was quite hard to parse!
> Index: compiler/dep_par_conj.m
> ===================================================================
> RCS file: /home/mercury/mercury1/repository/mercury/compiler/dep_par_conj.m,v
> retrieving revision 1.25
> diff -u -b -r1.25 dep_par_conj.m
> --- compiler/dep_par_conj.m 27 Feb 2008 07:23:04 -0000 1.25
> +++ compiler/dep_par_conj.m 13 Oct 2008 10:35:52 -0000
> @@ -1,5 +1,5 @@
> -%-----------------------------------------------------------------------------%
> -% vim: ft=mercury ts=8 sw=4 et
> +%-----------------------------------------------------------------------------%,
comma
> +% vim: ft=mercury ts=4 sw=4 et
> %-----------------------------------------------------------------------------%
> % Copyright (C) 2006-2008 The University of Melbourne.
> % This file may only be copied under the terms of the GNU General
> @@ -10,36 +10,78 @@
> % Author: wangp.
> %
> % This module implements dependent parallel conjunction using a HLDS->HLDS
> -% transformation. The transformation adds calls to the synchronisation
> -% predicates defined in library/par_builtin.m.
> +% transformation. The transformation has two main components: a synchronization
> +% transformation and a specialization transformation.
> %
> -% For a parallel conjunction (A & B), if the goal B is dependent on a variable
> -% X which is bound by goal A, we first transform the conjunction into the
> -% following:
> +% 1 The synchronization transformation ensures that consumers do not access
> +% shared variables before producers generate them. We do this by adding calls
> +% to the synchronisation primitives defined in library/par_builtin.m.
> +% In general, we make producers signal the availability of shared variables
> +% as soon as possible and we make consumers wait for the shared variables
> +% as late as possible.
> %
> -% par_builtin.new_future(FutureX),
> +% 2 The specialization transformation spots the need for and creates new
> +% versions of procedures. If some shared variables in a parallel conjunction
> +% are produced and/or consumed inside a call, we create a specialized version
> +% of the called procedure that does the signalling of the produced variables
> +% (as early as possible) and/or the waiting for the consumed variables (as
> +% late as possible). In the absence of these specialized procedures, we would
> +% have to assume that all calls consume their inputs immediately and generate
> +% their outputs only when they return, which in many cases is an excessively
> +% optimistic assumption.
I would call that "pessimistic".
> %-----------------------------------------------------------------------------%
>
> - % We found a parallel conjunction. Check for any dependencies
> - % between the conjuncts and, if so, insert sychronisation primitives.
> + % We found a parallel conjunction. Check for any dependencies between
> + % the conjuncts and, if we find som, insert sychronisation primitives.
some
> - % Insert signals into the conjunct as early as possible.
> - list.foldl3(insert_signal_in_goal(!.ModuleInfo, FutureMap),
> - set.to_sorted_list(ProducedVars),
> - Goal1, Goal, !VarSet, !VarTypes)
> + % Each consumer will have its own local name for the consumed variable,
> + % so they can each wait for it when they need to.
> + (
> + ParConjunctStatus = par_conjunct_is_in_conjunction,
> + clone_variables(ConsumedVarsList, !.VarSet, !.VarTypes,
> + !VarSet, !VarTypes, map.init, Renaming),
> + rename_some_vars_in_goal(Renaming, !Goal)
> + ;
> + ParConjunctStatus = par_conjunct_is_proc_body
> + % We don't need to rename anything, XXX.
> + )
What's the XXX for?
> -:- pred insert_wait_in_conj(module_info::in, future_map::in, prog_var::in,
> - hlds_goals::in, hlds_goal::out,
> +insert_wait_in_plain_conj(_ModuleInfo, _FutureMap, _ConsumedVar, !Waited,
> + [], [], !VarSet, !VarTypes).
> +insert_wait_in_plain_conj(ModuleInfo, FutureMap, ConsumedVar, !Waited,
> + [Goal0 | Goals0], Goals, !VarSet, !VarTypes) :-
> + ( var_in_nonlocals(ConsumedVar, Goal0) ->
> + % ConsumedVar appears in Goal0, so wait for it in Goal0. The code
> + % in Goals0 will then be able to access ConsumedVar waiting any further
> + % waiting.
_without_ any further waiting.
> -insert_wait_in_conj(_ModuleInfo, _FutureMap, _ConsumedVar,
> - [], true_goal, !VarSet, !VarTypes).
> -insert_wait_in_conj(ModuleInfo, FutureMap, ConsumedVar,
> - [Goal0 | Goals0], Goal, !VarSet, !VarTypes) :-
> - (if var_in_nonlocals(ConsumedVar, Goal0) then
> +insert_wait_in_par_conj(_ModuleInfo, _FutureMap, _ConsumedVar, !Waited,
> + [], [], !VarSet, !VarTypes).
> +insert_wait_in_par_conj(ModuleInfo, FutureMap, ConsumedVar, !Waited,
> + [Goal0 | Goals0], [Goal | Goals], !VarSet, !VarTypes) :-
> + ( var_in_nonlocals(ConsumedVar, Goal0) ->
> + % ConsumedVar appears in Goal0, so wait for it in Goal0, but the code
> + % in Goals0 will *not* be able to access ConsumedVar waiting, since the
> + % conjuncts are executed independently.
_without_ waiting
> @@ -956,18 +1096,30 @@
> GoalExpr = scope(Reason, SubGoal),
> Goal = hlds_goal(GoalExpr, GoalInfo0)
> ;
> - ( GoalExpr0 = unify(_LHS, _RHS0, _C, _D, _UnifyContext)
> - ; GoalExpr0 = plain_call(_PredId, _ProcId, _Args, _, _, _)
> - ; GoalExpr0 = generic_call(_GenericCall, _Args, _Modes, _Detism)
> - ; GoalExpr0 = call_foreign_proc(_, _PredId, _, _Args, _, _, _)
> + ( GoalExpr0 = unify(_, _, _, _, _)
> + ; GoalExpr0 = plain_call(_, _, _, _, _, _)
> + ; GoalExpr0 = generic_call(_, _, _, _)
> + ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
> ),
> insert_signal_after_goal(ModuleInfo, FutureMap, ProducedVar,
> Goal0, Goal, !VarSet, !VarTypes)
> ;
> GoalExpr0 = shorthand(_),
> - unexpected(this_file,
> - "shorthand goal encountered during dependent parallel " ++
> - "conjunction transformation.")
> + unexpected(this_file, "insert_signal_in_goal: shorthand")
> + )
> + ;
> + % When inserting waits into a goal, it is ok for the goal not to
> + % mention the consumed variable, but when inserting signals into a
> + % goal, the goal must produce the variable if it succeeds, so if
> + % the goal does not mention the variable, it cannot succeed.
> + Detism = goal_info_get_determinism(GoalInfo0),
> + determinism_components(Detism, _CanFail, SolnCount),
> + expect(unify(SolnCount, at_most_zero), this_file,
> + "insert_signal_in_goal: ProducedVar is not in nonlocals"),
> +
> + % There would be no point in adding a signal to the end of Goal0,
> + % since execution cannot get their.
> + Goal = Goal0
> ).
get there.
Thanks for that.
Peter
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list