[m-rev.] For review: allow declarative debugger to search upward from initial symptom
Julien Fischer
juliensf at cs.mu.OZ.AU
Mon Dec 13 15:18:15 AEDT 2004
On Mon, 29 Nov 2004, Ian MacLarty wrote:
...
> Index: browser/declarative_analyser.m
...
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/browser/declarative_analyser.m,v
> retrieving revision 1.16
> diff -u -r1.16 declarative_analyser.m
> --- browser/declarative_analyser.m 19 Nov 2004 11:54:16 -0000 1.16
> +++ browser/declarative_analyser.m 29 Nov 2004 06:36:40 -0000
> @@ -1,5 +1,5 @@
> %-----------------------------------------------------------------------------%
> -% Copyright (C) 1999-2004 The University of Melbourne.
> +% Copyright (C) 1999-2003 The University of Melbourne.
The year is wrong here.
> @@ -475,9 +521,19 @@
> search_response::out, search_mode::out) is det <= mercury_edt(S, T).
>
> top_down_search(Store, !SearchSpace, Response, NewMode) :-
> - root_det(!.SearchSpace, RootId),
> + %
> + % If there's no root yet (because the oracle hasn't asserted any nodes
> + % are erroneous yet, then use the topmost suspect as a starting point.
> + %
There's unmatched parenthesis in that comment.
> @@ -583,27 +652,61 @@
> ;
> NewLastUnknown = LastUnknown
> ),
> - %
> - % This recursive call will not lead to an infinite loop because
> - % eventually either the sub-term will be bound (and
> - % find_subterm_origin will respond with primitive_op/2) or
> - % there will be insufficient tracing information to continue
> - % (and find_subterm_origin will respond with not_found).
> - %
> - follow_subterm_end_search(Store, !SearchSpace,
> - NewLastUnknown, OriginId, OriginArgPos,
> - OriginTermPath, NewMode, SearchResponse)
> + (
> + %
> + % Check if it's worth continuing tracking the sub-term.
> + % We want to stop if we enter a portion of the search
> + % space known not to contain the bug from which we
> + % can't return (like if we come across an erroneous
> + % node where the sub-term is an input).
> + %
Make that last bit "For example, if we come across ..."
> Index: browser/declarative_debugger.m
...
> @@ -543,8 +574,17 @@
> :- pragma export(diagnoser_require_subtree(in, out, out, out),
> "MR_DD_diagnoser_require_subtree").
>
> -diagnoser_require_subtree(require_subtree(Event, SeqNo, CallPreceding), Event,
> - SeqNo, CallPreceding).
> +diagnoser_require_subtree(require_subtree(Event, SeqNo, CallPreceding),
> + Event, SeqNo, CallPreceding).
> +
> +:- pred diagnoser_require_supertree(diagnoser_response(trace_node_id),
> + event_number, sequence_number).
> +:- mode diagnoser_require_supertree(in, out, out) is semidet.
> +
You can use predmode syntax there.
> Index: browser/declarative_edt.m
>
> suspect_correct_or_inadmissible(SearchSpace, SuspectId) :-
> lookup_suspect(SearchSpace, SuspectId, Suspect),
> @@ -523,7 +603,7 @@
>
> % Succeeds if we haven't got an answer from the oracle about this
> % suspect, and haven't been able to infer anything about this suspect
> - % from other oracle answers?
> + % from other oracle answers.
> %
> :- pred suspect_is_questionable(search_space(T)::in, suspect_id::in)
> is semidet.
> @@ -593,59 +673,125 @@
> in_buggy_subtree(in_erroneous_subtree_complement, no).
> in_buggy_subtree(unknown, yes).
>
> -
> - % Should the suspect's status be propogated to it's children when the
> - % children are added to the search space?
> + % What status should be assigned to children of a node with the given
> + % status, when the children are being added to the search space?
> %
I would reword that comment so that it just describes what the function
does.
> -:- pred propogate_status_to_children(suspect_status::in, bool::out) is det.
> +:- func new_child_status(suspect_status) = suspect_status.
>
> -propogate_status_to_children(ignored, no).
> -propogate_status_to_children(skipped(_), no).
> -propogate_status_to_children(correct, no).
> -propogate_status_to_children(erroneous, no).
> -propogate_status_to_children(inadmissible, no).
> -propogate_status_to_children(pruned, yes).
> -propogate_status_to_children(in_erroneous_subtree_complement, yes).
> -propogate_status_to_children(unknown, no).
> +new_child_status(ignored) = unknown.
> +new_child_status(skipped(_)) = unknown.
> +new_child_status(correct) = pruned.
> +new_child_status(erroneous) = unknown.
> +new_child_status(inadmissible) = pruned.
> +new_child_status(pruned) = pruned.
> +new_child_status(in_erroneous_subtree_complement) =
> + in_erroneous_subtree_complement.
> +new_child_status(unknown) = unknown.
> +
> + % What status should be assigned to the parent of a node with the given
> + % status, when the parent is being added to the search space?
> + %
Likewise here.
> +:- func new_parent_status(suspect_status) = suspect_status.
> +
> +new_parent_status(ignored) = unknown.
> +new_parent_status(skipped(_)) = unknown.
> +new_parent_status(correct) = unknown.
> +new_parent_status(erroneous) = in_erroneous_subtree_complement.
> +new_parent_status(inadmissible) = unknown.
> +new_parent_status(pruned) = pruned.
> +new_parent_status(in_erroneous_subtree_complement) =
> + in_erroneous_subtree_complement.
> +new_parent_status(unknown) = unknown.
> +
> +give_up_subterm_tracking(SearchSpace, SuspectId) :-
> + Status = get_status(SearchSpace, SuspectId),
> + (Status = erroneous ; Status = in_erroneous_subtree_complement).
>
> + % A version of trickle_status which doesn't return Leaves.
> + %
s/Leaves/leaves/.
> +:- pred trickle_status(suspect_status::in, list(suspect_status)::in,
> + suspect_id::in, search_space(T)::in, search_space(T)::out) is det.
> +
> +trickle_status(Status, StopStatusSet, SuspectId, !SearchSpace) :-
> + trickle_status(Status, StopStatusSet, SuspectId, _,
> + !SearchSpace).
>
I'm not sure that using terms like trickle and perculate is very
clear - propagate_upwards and propgate_downwards might be more
straightforward (albeit less colourful).
> -trickle_status(Status, SuspectId, !SearchSpace) :-
> +:- pred trickle_status(suspect_status::in, list(suspect_status)::in,
> + suspect_id::in, list(suspect_id)::in, list(suspect_id)::out,
> + search_space(T)::in, search_space(T)::out) is det.
> +
> +trickle_status(Status, StopStatusSet, SuspectId, !Leaves, !SearchSpace) :-
> lookup_suspect(!.SearchSpace, SuspectId, Suspect),
> (
> - Suspect ^ status \= Status
> + \+ member(Suspect ^ status, StopStatusSet)
> ->
> map.set(!.SearchSpace ^ store, SuspectId,
> Suspect ^ status := Status, Store),
> !:SearchSpace = !.SearchSpace ^ store := Store,
> (
> Suspect ^ children = yes(Children),
> - list.foldl(trickle_status(Status), Children,
> + list.foldl2(trickle_status(Status, StopStatusSet),
> + Children, !Leaves, !SearchSpace)
> + ;
> + Suspect ^ children = no,
> + adjust_unexplored_leaves(yes(Suspect ^ status), Status,
> !SearchSpace)
> + ),
> + adjust_unknown_count(yes(Suspect ^ status), Status,
> + !SearchSpace)
> + ;
> + !:Leaves = [SuspectId | !.Leaves]
You could also write that as
list.cons(SuspectId, !Leaves)
> + % Increments or decremenets the unknown suspect count after a status
s/decremenets/decrements/
> + % change. The 1st argument should be the previous status of the
> + % changed suspect or no if a new suspect is being added and the 2nd
> + % argument should be the suspect's new status.
> + %
Use first and second rather than 1st and 2nd.
> +:- pred adjust_unknown_count(maybe(suspect_status)::in, suspect_status::in,
> + search_space(T)::in, search_space(T)::out) is det.
> +
> +adjust_unknown_count(MaybeOldStatus, NewStatus, !SearchSpace) :-
> + (
> + MaybeOldStatus = yes(OldStatus),
> + questionable(OldStatus, yes),
> + questionable(NewStatus, no)
> + ->
> + !:SearchSpace = !.SearchSpace ^ unknown_count :=
> + !.SearchSpace ^ unknown_count - 1
> + ;
> + questionable(NewStatus, yes),
> + (
> + MaybeOldStatus = no
> + ;
> + MaybeOldStatus = yes(OldStatus),
> + questionable(OldStatus, no)
> + )
> + ->
> + !:SearchSpace = !.SearchSpace ^ unknown_count :=
> + !.SearchSpace ^ unknown_count + 1
> + ;
> + true
> + ).
> +
> + % Increments or decremenets the unexplored leaves count after a status
> + % change. The 1st argument should be the previous status of the
> + % changed suspect or no if a new suspect is being added and the 2nd
> + % argument should be the suspect's new status. The changed suspect
> + % should be a leaf node (i.e. have its children field set to no).
> + %
There are some copy and paste errors from above here.
> + % Add the given EDT node to the top of the search space. The given
> + % node should be the parent of the current topmost node in the search
s/the parent/a parent/
> + % space.
> + %
> +:- pred insert_new_topmost_node(S::in, T::in,
> + search_space(T)::in, search_space(T)::out)
> + is det <= mercury_edt(S, T).
> +
> +insert_new_topmost_node(Store, NewTopMostEDTNode, !SearchSpace) :-
> + (
> + edt_children(Store, NewTopMostEDTNode, EDTChildren)
> + ->
> + topmost_det(!.SearchSpace, OldTopMostId),
> + lookup_suspect(!.SearchSpace, OldTopMostId, OldTopMost),
> + (
> + %
> + % One of the children of the new top most node will be
s/top most/topmost/
> + % the old topmost node so filter it out so it isn't
> + % added twice.
> + %
> + find_node_in_list(Store, EDTChildren,
> + OldTopMost ^ edt_node, Pos),
> + list.split_list(Pos - 1, EDTChildren, LeftChildren,
> + [_ | RightChildren])
> + ->
> + %
> + % Insert the new topmost node.
> + %
> + NewTopMostStatus = new_parent_status(
> + OldTopMost ^ status),
> + NewTopMostDepth = OldTopMost ^ depth - 1,
> + NewTopMost = suspect(no, NewTopMostEDTNode,
> + NewTopMostStatus, NewTopMostDepth, no),
> + some [!Counter, !SuspectStore] (
> + !:Counter = !.SearchSpace ^ suspect_id_counter,
> + counter.allocate(NewTopMostId, !Counter),
> + !:SearchSpace =
> + !.SearchSpace ^ suspect_id_counter :=
> + !.Counter,
> + !:SuspectStore = !.SearchSpace ^ store,
> + map.set(!.SuspectStore, NewTopMostId,
> + NewTopMost, !:SuspectStore),
> + !:SearchSpace = !.SearchSpace ^ store :=
> + !.SuspectStore
> + ),
> + SiblingStatus = new_child_status(NewTopMostStatus),
> + add_children(append(LeftChildren, RightChildren),
> + NewTopMostId, SiblingStatus, !SearchSpace,
> + ChildrenIds),
> +
> + %
> + % Adjust the unexplored leaves count since the new top
> + % most node was added with no children.
topnost again
> + %
> + adjust_unexplored_leaves(no, NewTopMostStatus,
> + !SearchSpace),
> +
> + %
> + % Now add the old topmost node as a child to the new
> + % topmost node.
> + %
> + (
> + list.split_list(Pos - 1, ChildrenIds,
> + LeftChildrenIds, RightChildrenIds)
> + ->
> + append(LeftChildrenIds, [OldTopMostId |
> + RightChildrenIds],
> + NewTopMostChildrenIds)
> + ;
> + throw(internal_error("insert_new_topmost_node",
> + "invalid position"))
> + ),
> + some [!SuspectStore] (
> + !:SuspectStore = !.SearchSpace ^ store,
> + map.set(!.SuspectStore, NewTopMostId,
> + NewTopMost ^ children :=
> + yes(NewTopMostChildrenIds),
> + !:SuspectStore),
> + map.set(!.SuspectStore, OldTopMostId,
> + OldTopMost ^ parent :=
> + yes(NewTopMostId),
> + !:SuspectStore),
> + !:SearchSpace = !.SearchSpace ^ store :=
> + !.SuspectStore
> + ),
> + !:SearchSpace = !.SearchSpace ^ topmost :=
> + yes(NewTopMostId),
> +
> + adjust_unknown_count(no, NewTopMostStatus,
> + !SearchSpace)
> + ;
> + throw(internal_error("insert_new_topmost_node",
> + "couldn't find event number"))
> + )
> +
> ;
> - map.set(!.SearchSpace ^ store, SuspectId,
> - Suspect ^ status := unknown, Store),
> - !:SearchSpace = !.SearchSpace ^ store := Store
> - ),
> + throw(internal_error("insert_new_topmost_node",
> + "couldn't get new topmost node's children"))
> + ).
> +
...
> Index: browser/declarative_tree.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/browser/declarative_tree.m,v
> retrieving revision 1.10
> diff -u -r1.10 declarative_tree.m
> --- browser/declarative_tree.m 24 Nov 2004 08:46:28 -0000 1.10
> +++ browser/declarative_tree.m 24 Nov 2004 22:57:59 -0000
> @@ -1,5 +1,5 @@
> %-----------------------------------------------------------------------------%
> -% Copyright (C) 2002-2004 The University of Melbourne.
> +% Copyright (C) 2002-2003 The University of Melbourne.
The year is now wrong.
> Index: trace/mercury_trace_declarative.c
...
> @@ -273,22 +325,102 @@
> }
>
> /*
> - ** If this event is an interface event then increase or decrease
> - ** the EDT depth appropriately.
> + ** Filter out events for compiler generated procedures.
> + ** XXX Compiler generated unify procedures should be included
> + ** in the annotated trace so that sub-term dependencies can be
> + ** tracked through them.
> + */
The comment should mention that uncommenting the code below is necessary
for this to work.
> + if (MR_PROC_LAYOUT_IS_UCI(entry)) {
> + /* && !MR_streq("__Unify__",
> + entry->MR_sle_proc_id.MR_proc_uci.MR_uci_pred_name)) {
> + */
> + return NULL;
> + }
> +
> + /*
> + ** Decide if we are inside or outside the subtree or supertree that
> + ** needs to be materialized, ignoring for now any depth limit.
> + ** If we are materializing a supertree then MR_edt_inside will
> + ** be true whenever we are not in the subtree rooted at the call
> + ** corresponding to MR_edt_start_seqno. If we are materializing a
> + ** subtree then MR_edt_inside will be true whenever we are in the
> + ** subtree rooted at the call corresponding to MR_edt_start_segno.
> + */
> + if (MR_edt_building_supertree) {
> + if (!MR_edt_inside) {
> + if (event_info->MR_call_seqno == MR_edt_start_seqno &&
> + MR_port_is_final(event_info->MR_trace_port))
> + {
> + /*
> + ** We are exiting the subtree rooted at
> + ** MR_edt_start_seqno.
> + */
> + MR_edt_inside = MR_TRUE;
> + } else {
> + /*
> + ** We are in an existing explicit subtree.
> + */
> + MR_decl_checkpoint_filter(event_info);
> + return NULL;
> + }
> + } else {
> + if (event_info->MR_call_seqno == MR_edt_start_seqno) {
> + /*
> + ** The port must be either CALL or REDO;
> + ** we are leaving the supertree and entering
> + ** the existing explicit subtree.
> + ** We must still however add this node to the
> + ** genertaed EDT, so we don't return here.
> + */
s/genertaed/generated/
> + MR_edt_inside = MR_FALSE;
> + }
> + }
> + } else {
> + if (MR_edt_inside) {
> + if (event_info->MR_call_seqno == MR_edt_start_seqno &&
> + MR_port_is_final(event_info->MR_trace_port))
> + {
> + /*
> + ** We are leaving the topmost call.
> + */
> + MR_edt_inside = MR_FALSE;
> + }
> + } else {
> + if (event_info->MR_call_seqno == MR_edt_start_seqno) {
> + /*
> + ** The port must be either CALL or REDO;
> + ** we are (re)entering the topmost call.
> + */
> + MR_edt_inside = MR_TRUE;
> + } else {
> + /*
> + ** Ignore this event---it is outside the
> + ** topmost call.
> + */
> + MR_decl_checkpoint_filter(event_info);
> + return NULL;
> + }
> + }
> + }
> +
> + /*
> + ** If the current event is an interface event then increase or decrease
> + ** the EDT depth appropriately. Note that we must be inside the
> + ** portion of the trace being materialized (ignoring the depth limit)
> + ** when we reach this point.
> */
> if (event_info->MR_trace_port == MR_PORT_CALL
> || event_info->MR_trace_port == MR_PORT_REDO) {
> MR_edt_depth++;
> + depth_check_adjustment = 0;
> }
> - if (event_info->MR_trace_port == MR_PORT_EXIT
> - || event_info->MR_trace_port == MR_PORT_FAIL
> - || event_info->MR_trace_port == MR_PORT_EXCEPTION) {
> + if (MR_port_is_final(event_info->MR_trace_port)) {
> /*
> - ** The depth of the EXIT, FAIL or EXCP event is actually
> - ** MR_edt_depth (not MR_edt_depth-1), however we need to
> - ** adjust the depth here for future events. This
> - ** inconsistency is neutralised by adjusting the depth
> - ** limit check by setting depth_check_adjustment.
> + ** The depth of the EXIT, FAIL or EXCP event is
> + ** actually MR_edt_depth (not MR_edt_depth-1), however
> + ** we need to adjust the depth here for future events.
> + ** This inconsistency is neutralised by adjusting the
> + ** depth limit check by setting depth_check_adjustment.
> */
> MR_edt_depth--;
> depth_check_adjustment = 1;
...
> @@ -1237,26 +1348,39 @@
> static MR_Code *
> MR_trace_restart_decl_debug(
> MR_Trace_Node call_preceding, MR_Unsigned event, MR_Unsigned seqno,
> - MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
> - MR_Event_Details *event_details)
> + MR_bool create_supertree, MR_Trace_Cmd_Info *cmd, MR_Event_Info
> + *event_info, MR_Event_Details *event_details)
> {
> - MR_Unsigned depth_limit;
> + MR_Unsigned edt_depth_limit;
> const char *message;
> MR_Code *jumpaddr;
>
> - depth_limit = MR_edt_max_depth + MR_edt_depth_step_size;
> + MR_edt_return_node = (MR_Trace_Node) NULL;
>
> /*
> - ** Set this to the preceding node, so the new subtree's parent is
> + ** Set this to the preceding node, so the new explicit tree's parent is
> ** resolved correcly.
s/correcly /correctly/
> */
> MR_trace_current_node = call_preceding;
>
> - MR_edt_depth = MR_edt_initial_depth;
> + /*
> + ** If we're going to build a supertree above the current root, then
> + ** adjust the depth of the topmost node.
> + */
> + if (create_supertree) {
> + if (MR_edt_depth_step_size < MR_edt_topmost_call_depth) {
> + MR_edt_topmost_call_depth -= MR_edt_depth_step_size;
> + } else {
> + MR_edt_topmost_call_depth = 1;
> + }
> + }
> + edt_depth_limit = MR_edt_depth_step_size + 1;
> +
> + MR_edt_depth = 0;
> Index: trace/mercury_trace_internal.c
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
> retrieving revision 1.180
> diff -u -r1.180 mercury_trace_internal.c
> --- trace/mercury_trace_internal.c 16 Nov 2004 00:45:14 -0000 1.180
> +++ trace/mercury_trace_internal.c 19 Nov 2004 11:56:02 -0000
> @@ -532,8 +532,8 @@
> MR_bool *split, MR_bool *close_window, char ***words,
> int *word_count, const char *cat, const char*item);
> static MR_bool MR_trace_options_dd(MR_bool *assume_all_io_is_tabled,
> - char ***words, int *word_count,
> - const char *cat, const char *item);
> + MR_Integer *depth_step_size, char ***words,
> + int *word_count, const char *cat, const char *item);
> static MR_bool MR_trace_options_type_ctor(MR_bool *print_rep,
> MR_bool *print_functors, char ***words,
> int *word_count, const char *cat, const char *item);
> @@ -5335,8 +5335,9 @@
> MR_Code **jumpaddr)
> {
> MR_trace_decl_assume_all_io_is_tabled = MR_FALSE;
> + MR_edt_depth_step_size = 3;
Why 3?
> if (! MR_trace_options_dd(&MR_trace_decl_assume_all_io_is_tabled,
> - &words, &word_count, "dd", "dd"))
> + &MR_edt_depth_step_size, &words, &word_count, "dd", "dd"))
> {
> ; /* the usage message has already been printed */
> } else if (word_count == 1) {
> @@ -5369,8 +5370,9 @@
> const char *filename;
>
> MR_trace_decl_assume_all_io_is_tabled = MR_FALSE;
> + MR_edt_depth_step_size = 3;
and here? I think you should use a symbolic constant.
That's all.
Cheers,
Julien.
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list