[m-rev.] for review: add --resume dd option

Julien Fischer juliensf at cs.mu.OZ.AU
Thu Feb 24 16:32:37 AEDT 2005



On Thu, 24 Feb 2005, Ian MacLarty wrote:

> For review by anyone.
>
> Estimated hours taken: 25
> Branches: main
>
> Add --resume option to `dd' command.  This resumes the previous declarative
> debugging session and allows the user to switch between the procedural and
> declarative debuggers freely.
>
> browser/declarative_analyser.m
> 	Add analysis_type type which is used to tell the analyser whether
> 	it must start a new session or resume a previous session.
>
> browser/declarative_debugger.m
> 	Add two versions of the exported diagnosis predicate: one to
> 	resume a previous session and one to start a new session.
>
> browser/declarative_user.m
> 	Print usage message to the correct output stream.
>
> runtime/mercury_stack_trace.c
> runtime/mercury_stack_trace.h
> 	Add a function to find the first call on the stack whose event
> 	number is less than or equal to a given event number or whose
> 	call sequence number is less than or equal to a given call sequence
> 	number.
>
> 	Since this new function uses some code very similar to existing
> 	code in the function that prints the stack, seperate this code into
> 	a new function called MR_call_details_are_valid.
>
> trace/mercury_trace_declarative.c
> trace/mercury_trace_declarative.h
> 	Previously it could be safely assumed that the current event would
> 	be somewhere inside the materialized portion of the annotated trace,
> 	so it was sufficient to record the topmost node of the annotated
> 	trace and retry to there whenever we needed to build a new subtree
> 	(and to the topmost node plus some extra for a supertree).
>
> 	Now, however, the user may go to any event in the program before
> 	resuming the previous dd session.  We could just retry to the call
> 	event for main/2, but this would be far from optimal, especially if the
> 	user is debugging code deep down in the program's call tree.
>
> 	Instead we retry to the first call on the stack whose event number
> 	is less than or equal to the call event number of the node we
> 	want to build a subtree for and then start forward execution from
> 	there.  When building a supertree we retry to the first call on the
> 	stack whose event number is less than or equal to the event number of
> 	the call at the top of the currently materialized portion of the
> 	annotated trace.  Then when we get to the call at the top of the
> 	currently materialized portion of the annotated trace through forward
> 	execution, we do a retry to the desired depth and start building the
> 	new supertree.
>
> 	Desribe the function of some of the global variables in more detail.
>
> 	Remove the global MR_edt_topmost_call_depth since it is no longer
> 	needed.
>
> 	Fix an inconsistency where the depth limit was being set to
> 	MR_edt_depth_step_size when starting a dd session, but to
> 	MR_edt_depth_step_size + 1 when building an additional portion of the
> 	annotated trace.
>
> tests/debugger/declarative/Mmakefile
> tests/debugger/declarative/resume.exp
> tests/debugger/declarative/resume.inp
> tests/debugger/declarative/resume.m
> 	Test the --resume option.  Specifically test the creation of a
> 	supertree and subtree from a resumed session where the user
> 	has gone to an event before and after the materialized portion
> 	of the annotated trace.
>
> trace/mercury_trace_internal.c
> 	Handle the --resume option.
>

Do you need to update the user guide as well?

...

> @@ -557,10 +558,10 @@
>  :- pragma export(mdb.declarative_debugger.divide_and_query_search_mode = out,
>  	"MR_DD_decl_divide_and_query_search_mode").
>
> -	% Export a monomorphic version of diagnosis/10, to make it
> -	% easier to call from C code.
> +	% Export a monomorphic version of diagnosis/10 that passes a newly
> +	% materialized tree for use with the C backend code.
>  	%
> -:- pred diagnosis_store(trace_node_store::in, trace_node_id::in,
> +:- pred diagnosis_new_tree(trace_node_store::in, trace_node_id::in,
>  	int::in, int::in, int::in, diagnoser_response(trace_node_id)::out,
>  	diagnoser_state(trace_node_id)::in,
>  	diagnoser_state(trace_node_id)::out,
> @@ -568,13 +569,32 @@
>  	browser_info.browser_persistent_state::out, io::di, io::uo)
>  	is cc_multi.
>
> -:- pragma export(diagnosis_store(in, in, in, in, in, out, in, out, in, out,
> -	di, uo), "MR_DD_decl_diagnosis").
> +:- pragma export(diagnosis_new_tree(in, in, in, in, in, out, in, out, in, out,
> +	di, uo), "MR_DD_decl_diagnosis_new_tree").
> +
> +diagnosis_new_tree(Store, Node, UseOldIoActionMap, IoActionStart, IoActionEnd,
> +		Response, !State, !Browser, !IO) :-
> +	diagnosis(Store, new_tree(dynamic(Node)), UseOldIoActionMap,
> +		IoActionStart, IoActionEnd, Response, !State, !Browser, !IO).
> +
> +	% Export a monomorphic version of diagnosis/10 that requests the
> +	% continuance of a previously suspended declarative debugging session.
s/continuance/continuation/

...

> Index: runtime/mercury_stack_trace.h
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.h,v
> retrieving revision 1.36
> diff -u -r1.36 mercury_stack_trace.h
> --- runtime/mercury_stack_trace.h	17 Jan 2005 05:58:06 -0000	1.36
> +++ runtime/mercury_stack_trace.h	22 Feb 2005 22:25:10 -0000
> @@ -297,4 +297,25 @@
>  			const char *filename, int linenumber,
>  			const char *goal_path, MR_bool context_mismatch);
>
> +/*
> +** Find the first call event in the stack whose event number or sequence number
s/in the stack/on the stack/

> +** is less than or equal to the given event number or sequence number.  The
> +** level of the call in the stack is returned.  This can then be passed to
> +** MR_trace_retry as the ancestor_level.  If no such call is found then -1 is
> +** returned and problem is set to the reason why the call could not be
> +** found.
> +*/
> +

...

> @@ -104,18 +104,29 @@
>  ** MR_trace_start_decl_debug when the back end is started.  They
>  ** are used by MR_trace_decl_debug to decide what action to
>  ** take for a particular trace event.
> -**
> -** Events that are deeper than the maximum depth, or which are
> -** outside the top call being debugged, are ignored.  Events which
> -** are beyond the given last event cause the internal debugger to
> -** be switched back into interactive mode.
>  */
>
> -static	MR_Unsigned	MR_edt_max_depth;
> +/*
> +** If we are building a subtree then reaching this event will cause the
> +** declarative debugger to continue its analysis.  Reaching this event means
> +** generation of the desired subtree is complete.  This variable is not used
> +** when building a new explicit supertree (a supertree is a tree above the
> +** currently materialized portion of the annotated trace).
> +*/
> +
>  static	MR_Unsigned	MR_edt_last_event;
> +
> +/*
> +** If we are materializing a new subtree then MR_edt_start_seqno is the
> +** call sequence number of the call at the top the the subtree we want to
s/the the/of the/

...

> @@ -1284,7 +1363,7 @@
>
>  MR_bool
>  MR_trace_start_decl_debug(MR_Trace_Mode trace_mode, const char *outfile,
> -	MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
> +	MR_bool new_session, MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
>  	MR_Event_Details *event_details, MR_Code **jumpaddr)
>  {
>  	MR_Retry_Result		result;
> @@ -1293,10 +1372,25 @@
>  	MR_Unsigned		edt_depth_limit;
>  	const char		*message;
>  	MR_Trace_Level		trace_level;
> +	static	MR_bool		first_time = MR_TRUE;
>
> -	MR_edt_return_node = (MR_Trace_Node) NULL;
> +	MR_edt_initial_event = event_info->MR_event_number;
> +
> +	/*
> +	** If it was requested that the previous session be resumed and
> +	** there was a previous dd session, then there is no need to
> +	** build a new annotated trace.  Just call the front end, passing
> +	** NULL as the root node to let it know it must resume the
> +	** previous session.
> +	*/
> +	if (!new_session && !first_time) {
> +		MR_trace_decl_mode = trace_mode;
> +		*jumpaddr = MR_decl_diagnosis((MR_Trace_Node) NULL, cmd,
> +			event_info, event_details);
> +		return MR_TRUE;
> +	}
>
> -	MR_edt_initial_event = event_details->MR_event_number;
> +	MR_edt_return_node = (MR_Trace_Node) NULL;
>
>  	if (!MR_port_is_final(event_info->MR_trace_port)) {
>  		fflush(MR_mdb_out);

> @@ -1435,28 +1517,58 @@
>
>  static	const char *
>  MR_trace_start_collecting(MR_Unsigned event, MR_Unsigned seqno,
> -	MR_Unsigned maxdepth, MR_Unsigned topmost_call_depth,
> -	MR_bool create_supertree, MR_Trace_Cmd_Info *cmd, MR_Event_Info
> -	*event_info, MR_Event_Details *event_details, MR_Code **jumpaddr)
> +	MR_Unsigned maxdepth, MR_bool create_supertree, MR_Trace_Cmd_Info *cmd,
> +	MR_Event_Info *event_info, MR_Event_Details *event_details,
> +	MR_Code **jumpaddr)
>  {
>  	const char		*problem;
>  	MR_Retry_Result		retry_result;
> -	MR_Unsigned		retry_levels;
> +	int			retry_distance;
>
> -	/*
> -	** Go back to an event before the topmost call.
> +	/*
> +	** We need to do a retry if the current event is greater than the
> +	** call event number corresponding to seqno.  Since we don't have the
> +	** call event number for seqno (`event' is the final event number,
> +	** not the call event number), we do a retry if:
> +	**    a) The call sequence number of the current call is greater than
> +	**       or equal to seqno, or
> +	**    b) The current event number is greater than the final event
> +	**       for seqno.
> +	**
> +	** Case b) covers the situation where the current event is after the
> +	** final event for seqno and case a) covers the case where the current
> +	** event is greater than or equal to the call event for seqno and less
> +	** than or equal to the final event for seqno.  This means we will do
> +	** a retry if the call event for seqno is equal to the current event
> +	** but thats not a problem since the retry will be a no-op.
s/thats/that's/

...

> @@ -1666,38 +1788,71 @@
>  	const char		*problem;
>  	MR_Retry_Result		retry_result;
>  	MR_Code			*jumpaddr;
> +	int			ancestor_level;
>
>  	/*
> -	** Perform a retry to get to somewhere before the
> -	** bug event.  Then set the command to go to the bug
> -	** event and return to interactive mode.
> -	*/
> +	** We only need to do a retry if the event number we want to be at is
> +	** less than or equal to the current event number (we need to do a
> +	** retry if the event numbers are equal, because MR_trace_real will
> +	** increment the current event number, so the next event displayed by
> +	** mdb will be the current event + 1.
> +	*/
> +	if (event <= event_info->MR_event_number) {
> +		ancestor_level = MR_find_first_call_less_eq_seq_or_event(
> +			MR_FIND_FIRST_CALL_BEFORE_EVENT, event,
> +			event_info->MR_event_sll,
> +			MR_saved_sp(event_info->MR_saved_regs),
> +			MR_saved_curfr(event_info->MR_saved_regs), &problem);
> +
> +		if (ancestor_level >= 0) {
> +			/*
> +			** Perform a retry to get to somewhere before the

"somewhere" is a bit imprecise.

> +			** given event.  Then set the command to go to the
> +			** given event and return to interactive mode.
> +			*/
>  #ifdef	MR_DEBUG_RETRY
> -	MR_print_stack_regs(stdout, event_info->MR_saved_regs);
> -	MR_print_succip_reg(stdout, event_info->MR_saved_regs);

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