[m-rev.] for review: add mdb `dice' command

Ian MacLarty maclarty at cs.mu.OZ.AU
Sun Feb 6 19:36:14 AEDT 2005


For review by anyone.

Estimated hours taken: 40
Branches: main

Add mdb `dice' command which reads in a set of passing trace counts and a
failing trace count and prints a comparison table.  The table can be sorted
by various metrics and is useful for finding parts of a program executed in 
a failing run, but not in passing runs.

browser/dice.m
	Add a new module for generating and manipulating a dice.

browser/mdb.m
	Add the dice module.

doc/user_guide.texi
	Document the `dice' mdb command.  Also document the fact that the
	failing and passing slice file names can be set with the `set' mdb
	command.

	Move the `set' command to the misc section from the browser section
	since it now also sets the passing and failing slice file names, which
	have nothing to do with the browser.
	
mdbcomp/program_representation.m
	Add a predicate to convert a goal path to a string.

mdbcomp/trace_counts.m
	Convert string_to_trace_port into a predicate and add a new mode so
	that a port can be converted back to a string.

runtime/mercury_trace_base.h
trace/mercury_trace_util.h
	Move the MR_TRACE_USE_HP and MR_TRACE_CALL_MERCURY macros to
	runtime/mercury_trace_base.h, so that they can be called from 
	browser/dice.m.

tests/Mmake.common
	Clean up trace counts (which are generated to test the `dice' command).

tests/debugger/Mmakefile
tests/debugger/dice.exp
tests/debugger/dice.inp
tests/debugger/dice.m
tests/debugger/dice.passes
	Test the `dice' command.

trace/mercury_trace_internal.c
	Add the mdb `dice' command and modify the `set' command so the
	`fail_trace_count' and `pass_trace_counts' parameters can be set.

	Add a function to print a dice.

	Move the `set' command to the misc help section.

Index: browser/dice.m
===================================================================
RCS file: browser/dice.m
diff -N browser/dice.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/dice.m	6 Feb 2005 07:47:34 -0000
@@ -0,0 +1,626 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 1999-2005 The University of Melbourne.
+% This file may only be copied under the terms of the GNU Library General
+% Public License - see the file COPYING.LIB in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+% File: dice.m
+% Author: Ian MacLarty
+%
+% This module contains code for generating and manipulating dices.  A dice
+% is the difference between one or more passing test runs and one or more
+% failing test runs.
+%
+
+:- module mdb.dice.
+
+:- interface.
+
+:- import_module map.
+
+:- import_module mdbcomp.prim_data.
+:- import_module mdbcomp.trace_counts.
+
+:- type dice == map(proc_label, proc_dice).
+
+:- type proc_dice == map(path_port, exec_count).
+
+:- type exec_count
+	--->	exec_count(
+				% The number of times the label was executed in
+				% all the passing test runs.
+			pass_count	:: int,
+				% The number of passing test runs the label
+				% was executed in.
+			pass_tests	:: int,
+				% The number of times the label was executed in
+				% failing test runs.
+			fail_count	:: int,
+				% The number of failing test runs the label
+				% was executed in.
+			fail_tests	:: int
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module assoc_list.
+:- import_module bool.
+:- import_module char.
+:- import_module float.
+:- import_module int.
+:- import_module io.
+:- import_module list.
+:- import_module require.
+:- import_module set.
+:- import_module std_util.
+:- import_module string. 
+:- import_module svmap.
+
+:- import_module mdbcomp.program_representation.
+
+:- type trace_counts_kind ---> pass ; fail.
+
+	% Merge the passing or failing trace_counts into the given dice.
+	%
+:- pred merge_trace_counts(trace_counts_kind::in, trace_counts::in,
+	dice::in, dice::out) is det.
+
+merge_trace_counts(Kind, TraceCounts, !Dice) :-
+	map.foldl(merge_proc_trace_counts(Kind), TraceCounts, !Dice).
+
+:- pred merge_proc_trace_counts(trace_counts_kind::in, proc_label::in,
+	proc_trace_counts::in, dice::in, dice::out) is det.
+
+merge_proc_trace_counts(Kind, ProcLabel, ProcTraceCounts, !Dice) :-
+	(
+		map.search(!.Dice, ProcLabel, FoundProcDice)
+	->
+		ProcDice = FoundProcDice
+	;
+		ProcDice = map.init
+	),
+	map.foldl(merge_path_port(Kind), ProcTraceCounts, ProcDice,
+		MergedProcDice),
+	svmap.set(ProcLabel, MergedProcDice, !Dice).
+
+:- pred merge_path_port(trace_counts_kind::in, path_port::in, int::in, 
+	proc_dice::in, proc_dice::out) is det.
+
+merge_path_port(Kind, PathPort, Count, !ProcDice) :-
+	(
+		map.transform_value(add_trace_count(Kind, Count), PathPort,
+			!.ProcDice, UpdatedProcDice)
+	->
+		!:ProcDice = UpdatedProcDice
+	;
+		(
+			Kind = pass,
+			svmap.set(PathPort, exec_count(Count, 1, 0, 0), 
+				!ProcDice)
+		;
+			Kind = fail,
+			svmap.set(PathPort, exec_count(0, 0, Count, 1), 
+				!ProcDice)
+		)
+	).	
+
+:- pred add_trace_count(trace_counts_kind::in, int::in, 
+	exec_count::in, exec_count::out) is det.
+
+add_trace_count(pass, Count, exec_count(PassExec, PassTests, FailExec, 
+	FailTests), exec_count(PassExec + Count, PassTests + 1, FailExec, 
+	FailTests)).
+add_trace_count(fail, Count, exec_count(PassExec, PassTests, FailExec, 
+	FailTests), exec_count(PassExec, PassTests, FailExec + Count, 
+	FailTests + 1)).
+
+:- type read_trace_counts_list_result
+	--->	ok(list(trace_counts))
+	;	error_message(string).
+
+	% Read the trace_counts in the files whose names appear in FileName.
+	%
+:- pred read_trace_counts_list(string::in, read_trace_counts_list_result::out,
+	io::di, io::uo) is det.
+
+read_trace_counts_list(FileName, Result, !IO) :-
+	io.open_input(FileName, OpenResult, !IO),
+	(
+		OpenResult = ok(FileStream),
+		read_trace_counts_list_stream(FileName, FileStream, Result, !IO)
+	;
+		OpenResult = error(IOError),
+		Result = error_message("Error opening file `" ++ FileName ++
+			"': " ++ string.string(IOError))
+	).
+
+	% Same as read_trace_counts_list/4, but read the filenames containing
+	% the trace_counts from the given stream.  MainFileName is the
+	% name of the file being read and is only used for error messages.
+	%
+:- pred read_trace_counts_list_stream(string::in, io.input_stream::in, 
+	read_trace_counts_list_result::out, io::di, io::uo) is det.
+
+read_trace_counts_list_stream(MainFileName, Stream, Result, !IO) :-
+	io.read_line_as_string(Stream, ReadResult, !IO),
+	(
+		ReadResult = ok(Line),
+		% Remove the trailing newline:
+		FileName = string.left(Line, string.length(Line) - 1),
+		trace_counts.read_trace_counts(FileName, ReadTCResult, !IO),
+		(
+			ReadTCResult = ok(TraceCount),
+			read_trace_counts_list_stream(MainFileName, Stream, 
+				RestResult, !IO),
+			(
+				RestResult = ok(TraceCounts)
+			->
+				Result = ok([TraceCount | TraceCounts])
+			;
+				Result = RestResult
+			)
+		;
+			ReadTCResult = io_error(IOError),
+			Result = error_message("IO error reading file "
+				++ "`" ++ FileName ++ "': " 
+				++ string.string(IOError))
+		;
+			ReadTCResult = error_message(Message),
+			Result = error_message("Error reading trace counts "++
+				"from file `" ++ FileName ++ "': " ++ 
+				Message)
+		)
+	;
+		ReadResult = error(Error),
+		Result = error_message("IO error reading file " ++ "`" ++ 
+			MainFileName ++ "': " ++ string.string(Error))
+	;
+		ReadResult = eof,
+		Result = ok([])
+	).
+
+	% read_dice_to_string(PassFiles, FailFile, SortStr, N, DiceStr, 
+	% 	Problem, !IO).
+	% Read the trace_counts in the list of files in the file named
+	% PassFiles, interpretting them as passing slices; read the
+	% trace_counts from the file FailFile, interpretting it as a failing
+	% slice; then produce a dice and convert the dice to a string suitable
+	% for displaying on the screen, sorting it first using SortStr.
+	% SortStr can be any combination of the letters "sSpPfP" and 
+	% indicates how the dice is to be sorted.  See the documentation
+	% for the `dice' command in the user guide for an explaination of the
+	% sort string.  If there was a problem reading the trace_counts then
+	% Problem will contain a string describing the problem encountered and
+	% DiceStr will be the empty string, otherwise Problem will be the
+	% empty string.
+	%
+:- pred read_dice_to_string(string::in, string::in, string::in, int::in,
+	string::out, string::out, io::di, io::uo) is det.
+
+:- pragma export(read_dice_to_string(in, in, in, in, out, out, di, uo), 
+	"MR_MDB_read_dice_to_string").
+
+read_dice_to_string(PassFiles, FailFile, SortStr, N, DiceStr, Problem, !IO) :-
+	(
+		sort_string_is_valid(SortStr)
+	->
+		read_trace_counts_list(PassFiles, ReadPassResult, !IO),
+		(
+			ReadPassResult = ok(PassTraceCountsList),
+			TotalPassTests = length(PassTraceCountsList),
+			TotalFailTests = 1,
+			read_trace_counts(FailFile, ReadFailResult, !IO),
+			(
+				ReadFailResult = ok(FailTraceCounts),
+				list.foldl(merge_trace_counts(pass), 
+					PassTraceCountsList, map.init, 
+					PassDice),
+				merge_trace_counts(fail, FailTraceCounts, 
+					PassDice, Dice),
+				LabelCounts = dice_to_label_counts(Dice),
+				list.sort(label_count_compare(SortStr), 
+					LabelCounts, SortedLabelCounts),
+				(
+					list.take(N, SortedLabelCounts, Taken)
+				->
+					TopNLabelCounts = Taken
+				;
+					TopNLabelCounts = SortedLabelCounts
+				),
+				DiceStr = format_label_counts(TopNLabelCounts, 
+					TotalPassTests, TotalFailTests),
+				Problem = ""
+			;
+				ReadFailResult = error_message(Message),
+				DiceStr = "",
+				Problem = "Error reading trace counts from "
+					++ "file `" ++
+					FailFile ++ "': " ++ Message
+			;
+				ReadFailResult = io_error(IOError),
+				DiceStr = "",
+				Problem = "IO Error reading trace counts from "
+					++"file `" ++ FailFile ++ "': " 
+					++ string.string(IOError)
+			)
+		;
+			ReadPassResult = error_message(Problem),
+			DiceStr = ""
+		)
+	;
+		Problem = "Invalid sort string",
+		DiceStr = ""
+	).
+
+	% Values of this type uniquely identify a label in the program
+	% and contain some statistics about the execution of the label.
+	%
+:- type label_count
+	--->	label_count(
+			proc_label	:: proc_label, 
+			path_port	:: path_port, 
+			counts		:: exec_count
+		).
+
+:- pred label_count_compare(string::in, label_count::in, label_count::in,
+	builtin.comparison_result::out) is det.
+
+label_count_compare(SortStr, LabelCount1, LabelCount2, Result) :-
+	(
+		SortStr = ""
+	->
+		builtin.compare(Result, LabelCount1, LabelCount2)
+	;
+		exec_count_compare(SortStr, LabelCount1 ^ counts, 
+			LabelCount2 ^ counts, Result)
+	).
+
+:- pred exec_count_compare(string::in, exec_count::in, exec_count::in,
+	builtin.comparison_result::out) is det.
+
+exec_count_compare(SortStr, ExecCount1, ExecCount2, Result) :-
+	(
+		string.first_char(SortStr, C, Rest)
+	->
+		(
+			C = 'p'
+		->
+			builtin.compare(Result0, ExecCount1 ^ pass_count, 
+				ExecCount2 ^ pass_count)
+		;
+			C = 'P'
+		->
+			builtin.compare(Result0, ExecCount2 ^ pass_count, 
+				ExecCount1 ^ pass_count)
+		;
+			C = 'f'
+		->
+			builtin.compare(Result0, ExecCount1 ^ fail_count, 
+				ExecCount2 ^ fail_count)
+		;
+			C = 'F'
+		->
+			builtin.compare(Result0, ExecCount2 ^ fail_count, 
+				ExecCount1 ^ fail_count)
+		;
+			C = 's'
+		->
+			builtin.compare(Result0, 
+				suspicion_ratio(ExecCount1 ^ pass_count,
+					ExecCount1 ^ fail_count),
+				suspicion_ratio(ExecCount2 ^ pass_count,
+					ExecCount2 ^ fail_count))
+		;
+			C = 'S'
+		->
+			builtin.compare(Result0, 
+				suspicion_ratio(ExecCount2 ^ pass_count,
+					ExecCount2 ^ fail_count),
+				suspicion_ratio(ExecCount1 ^ pass_count,
+					ExecCount1 ^ fail_count))
+		;
+			error("label_count_compare: invalid sort string")
+		),
+		(
+			Result0 = (=), string.length(Rest) > 0
+		->
+			exec_count_compare(Rest, ExecCount1, ExecCount2,
+				Result)
+		;
+			Result = Result0
+		)
+	;
+		error("label_count_compare: empty sort string")
+	).
+
+:- pred sort_string_is_valid(string::in) is semidet.
+
+sort_string_is_valid(Str) :-
+	Chrs = string.to_char_list(Str),
+	ChrSet = set.list_to_set(Chrs),
+	set.subset(ChrSet, set.list_to_set(['p', 'P', 'f', 'F', 's', 'S'])).
+
+:- func dice_to_label_counts(dice) = list(label_count).
+
+dice_to_label_counts(Dice) = LabelCounts :-
+	map.foldl(append_label_counts, Dice, [], LabelCounts).
+
+:- pred append_label_counts(proc_label::in, proc_dice::in, 
+	list(label_count)::in, list(label_count)::out) is det.
+
+append_label_counts(ProcLabel, ProcDice, !LabelCounts) :-
+	map.to_assoc_list(ProcDice, ProcExecCounts),
+	list.map(make_label_count(ProcLabel), ProcExecCounts, NewLabelCounts),
+	append(!.LabelCounts, NewLabelCounts, !:LabelCounts).
+
+:- pred make_label_count(proc_label::in, pair(path_port, exec_count)::in, 
+	label_count::out) is det.
+
+make_label_count(ProcLabel, PathPort - ExecCount, 
+	label_count(ProcLabel, PathPort, ExecCount)).
+
+	% Produce a formatted table from a list of label_counts.
+	%
+:- func format_label_counts(list(label_count), int, int) = string.
+
+format_label_counts(LabelCounts, TotalPassTests, _TotalFailTests) = Str :-
+	dice.map6(deconstruct_label_count, LabelCounts, ProcLabels,
+		PathPorts, PassCounts, PassTests, FailCounts, _FailTests),
+	FormattedProcLabels = list.map(format_proc_label, ProcLabels),
+	FormattedPathPorts = list.map(format_path_port, PathPorts),
+	FormattedContexts = list.map(format_context, LabelCounts),
+	PassCountStrs = list.map(string.int_to_string_thousands, PassCounts),
+	PassTestsStrs = list.map(bracket_int, PassTests),
+	FailCountStrs = list.map(string.int_to_string_thousands, FailCounts),
+	SuspicionIndices = list.map_corresponding(suspicion_ratio, PassCounts,
+		FailCounts),
+	FormattedSuspicionIndices = list.map(dice.format_float(2),
+		SuspicionIndices),
+	TotalPassTestsStr = "(" ++ int_to_string_thousands(TotalPassTests) 
+		++ ")",
+	Str = string.format_table([
+		left( ["Procedure"       | FormattedProcLabels]), 
+		left( ["Path/Port"       | FormattedPathPorts]), 
+		left( ["File:Line"       | FormattedContexts]),
+		right(["Pass"            | PassCountStrs]), 
+		right([TotalPassTestsStr | PassTestsStrs]), 
+		right(["Fail"            | FailCountStrs]), 
+		right(["Suspicion"       | FormattedSuspicionIndices])], " ").
+
+:- func bracket_int(int) = string.
+
+bracket_int(X) = "(" ++ string.int_to_string_thousands(X) ++ ")".
+
+:- func suspicion_ratio(int, int) = float.
+
+	% suspicion_ration gives an indication of how lightly a label is to
+	% be buggy based on how many times it was executed in passing and
+	% failing test runs.
+	%
+suspicion_ratio(PassCount, FailCount) = 
+	% PassCount + FailCount should never be zero since if a label
+	% isn't executed in any tests then it wouldn't be included in the dice.
+	float(FailCount) / float(PassCount + FailCount).
+
+:- func format_float(int, float) = string.
+
+format_float(DecimalPlaces, Flt) = string.format("%." ++ 
+	int_to_string(DecimalPlaces) ++ "f", [f(Flt)]).
+
+:- pred deconstruct_label_count(label_count::in, proc_label::out, 
+	path_port::out, int::out, int::out, int::out, int::out) is det.
+
+deconstruct_label_count(label_count(PathPort, ProcLabel, 
+	exec_count(PassCount, PassTests, FailCount, FailTests)),
+	PathPort, ProcLabel, PassCount, PassTests, FailCount, FailTests).
+
+:- func format_exec_count(exec_count) = string.
+
+format_exec_count(exec_count(PassCount, PassTests, FailCount, FailTests)) = 
+	string.pad_left(int_to_string(PassCount), ' ', 12)
+	++ string.pad_left("(" ++ int_to_string(PassTests) ++ ")", ' ', 8)
+	++ string.pad_left(int_to_string(FailCount), ' ', 12)
+	++ string.pad_left("(" ++ int_to_string(FailTests) ++ ")", ' ', 8).
+
+:- func make_label_counts_heading(int, int, int) = string.
+
+make_label_counts_heading(MaxProcLabelLength, MaxPathPortLength, 
+		MaxContextLength) =
+	string.pad_right("Procedure", ' ', MaxProcLabelLength + 2)
+	++ string.pad_right("Path/Port", ' ', MaxPathPortLength + 2)
+	++ string.pad_right("Context", ' ', MaxContextLength + 2)
+	++ string.pad_left("Pass Count", ' ', 20)
+	++ string.pad_left("Fail Count", ' ', 20).
+
+:- func format_proc_label(proc_label) = string.
+
+format_proc_label(ProcLabel) = Str :-
+	(
+		ProcLabel = proc(_, PredOrFunc, SymModule, Name, Arity, 
+			ModeNo),
+		Module = sym_name_to_string(SymModule),
+		(
+			PredOrFunc = function,
+			ArityStr = int_to_string(Arity - 1),
+			PredOrFuncStr = "func"
+		;
+			PredOrFunc = predicate,
+			ArityStr = int_to_string(Arity),
+			PredOrFuncStr = "pred"
+		),
+		Str = PredOrFuncStr ++ " " ++ Module ++ "." ++ Name ++
+			"/" ++ ArityStr ++ "-" ++ int_to_string(ModeNo)
+	;
+		ProcLabel = special_proc(_, SpecialPredId, SymModule, TypeName, 
+			Arity, _),
+		Module = sym_name_to_string(SymModule),
+		(
+			SpecialPredId = unify,
+			Name = "__Unify__"
+		;
+			SpecialPredId = index,
+			Name = "__Index__"
+		;
+			SpecialPredId = compare,
+			Name = "__Compare__"
+		;
+			SpecialPredId = initialise,
+			Name = "__Initialise__"
+		),
+		Str = Name ++ " for " ++ Module ++ "." ++ TypeName ++ "/" ++
+			int_to_string(Arity)
+	).
+
+:- func format_context(label_count) = string.
+
+format_context(label_count(ProcLabel, PathPort, _)) = Str :-
+	(
+		find_context(ProcLabel, PathPort, FileName, LineNo)
+	->
+		Str = FileName ++ ":" ++ int_to_string(LineNo)
+	;
+		Str = ""
+	).
+
+:- func format_path_port(path_port) = string.
+
+format_path_port(port_only(Port)) = Str :-
+	mdbcomp.trace_counts.string_to_trace_port(Str, Port).
+format_path_port(path_only(Path)) = Str :-
+	mdbcomp.program_representation.string_from_path(Path, PathStr),
+	Str = "<" ++ PathStr ++ ">".
+format_path_port(port_and_path(Port, Path)) =
+	format_path_port(port_only(Port)) ++
+		" " ++ format_path_port(path_only(Path)).
+
+	% Given a proc_label and path_port, find the source filename and line 
+	% number of the label.  Fail if this is not possible because of
+	% insufficient tracing information.
+	%
+	% We only look up the contexts for user predicates.  This is okay since
+	% compiler generated predicates are not counted anyway and would be
+	% of little interest in a dice.
+	%
+:- pred find_context(proc_label::in, path_port::in, string::out, int::out) 
+	is semidet.
+
+find_context(proc(DeclSymModule, _, _, Name, Arity, ModeNo), PathPort, 
+		FileName, LineNo) :-
+	DeclModule = sym_name_to_string(DeclSymModule),
+	find_context_for_proc(DeclModule, Name, Arity, ModeNo, PathPort, 
+		FileName, LineNo). 
+
+:- pred find_context_for_proc(string::in, string::in, int::in, int::in, 
+	path_port::in, string::out, int::out) is semidet.
+
+:- pragma foreign_proc(c, find_context_for_proc(Module::in, Name::in, 
+	Arity::in, ModeNo::in, PathPort::in, FileName::out, LineNo::out), 
+	[promise_pure, may_call_mercury, thread_safe, terminates],
+"
+    const MR_Module_Layout		*module;
+    const MR_Module_File_Layout		*file;
+    const MR_Label_Layout		*label;
+    const MR_Proc_Layout		*proc;
+    const MR_User_Proc_Id		*id;
+    int					num_modules;
+    int					module_num;
+    int					file_num;
+    int					num_files;
+    int					num_labels;
+    int					label_num;
+    const char*				filename;
+    MR_bool				are_same;
+    
+    num_modules = MR_module_info_next;
+	
+    for (module_num = 0; module_num < num_modules; module_num++) {
+        module = MR_module_infos[module_num];
+        if (MR_streq(Module, module->MR_ml_name)) {
+            num_files = module->MR_ml_filename_count;
+            for (file_num = 0; file_num < num_files; file_num++) {
+                file = module->MR_ml_module_file_layout[file_num];
+                num_labels = file->MR_mfl_label_count;
+                for (label_num = 0; label_num < num_labels; label_num++) {
+                    label = file->MR_mfl_label_layout[label_num];
+                    proc = label->MR_sll_entry;
+                    id = &proc->MR_sle_user;
+                    if (MR_streq(id->MR_user_name, Name) &&
+                            id->MR_user_arity == Arity &&
+                            id->MR_user_mode == ModeNo) {
+                        MR_TRACE_CALL_MERCURY(
+                            MR_MDB_same_path_port(
+			        (MR_String) MR_label_goal_path(label),
+                                label->MR_sll_port, PathPort, &are_same);
+                        );
+                        if (are_same) {
+                            SUCCESS_INDICATOR = MR_find_context(label,
+                                &filename, &LineNo);
+                            MR_TRACE_USE_HP(
+                                MR_make_aligned_string(FileName,
+                                    (MR_String) filename);
+                            );
+                            goto end;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    SUCCESS_INDICATOR = MR_FALSE;
+    end:
+").
+
+	% Return yes if the given goal path string and port correspond to the
+	% given path_port.
+	%
+:- pred same_path_port(string::in, trace_port::in, path_port::in, bool::out)
+	is det.
+
+:- pragma export(same_path_port(in, in, in, out), "MR_MDB_same_path_port").
+
+same_path_port(PathStr1, Port1, PathPort2, Same) :-
+	(
+		PathPort2 = port_only(Port2),
+		(
+			Port1 = Port2
+		->
+			Same = yes
+		;
+			Same = no
+		)
+	;
+		PathPort2 = path_only(Path2),
+		mdbcomp.program_representation.path_from_string_det(PathStr1, 
+			Path1),
+		(
+			Path1 = Path2
+		->
+			Same = yes
+		;
+			Same = no
+		)
+	;
+		PathPort2 = port_and_path(Port2, Path2),
+		mdbcomp.program_representation.path_from_string_det(PathStr1, 
+			Path1),
+		(
+			Path1 = Path2, Port1 = Port2
+		->
+			Same = yes
+		;
+			Same = no
+		)
+	).
+
+:- pred map6(pred(T, T1, T2, T3, T4, T5, T6), list(T), list(T1),
+	list(T2), list(T3), list(T4), list(T5), list(T6)).
+:- mode map6(pred(in, out, out, out, out, out, out) is det, in, out, out, 
+	out, out, out, out) is det.
+
+map6(_, [], [], [], [], [], [], []).
+map6(P, [H | T], [H1 | T1], [H2 | T2], [H3 | T3], [H4 | T4], [H5 | T5], 
+		[H6 | T6]) :-
+	P(H, H1, H2, H3, H4, H5, H6),
+	dice.map6(P, T, T1, T2, T3, T4, T5, T6).
Index: browser/mdb.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/mdb.m,v
retrieving revision 1.18
diff -u -r1.18 mdb.m
--- browser/mdb.m	1 Feb 2005 03:24:21 -0000	1.18
+++ browser/mdb.m	1 Feb 2005 05:47:42 -0000
@@ -22,6 +22,7 @@
 :- include_module debugger_interface.
 :- include_module declarative_debugger.
 :- include_module declarative_execution.
+:- include_module dice.
 :- include_module help.
 :- include_module interactive_query.
 :- include_module io_action.
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.416
diff -u -r1.416 user_guide.texi
--- doc/user_guide.texi	2 Feb 2005 02:59:06 -0000	1.416
+++ doc/user_guide.texi	6 Feb 2005 07:52:24 -0000
@@ -2722,90 +2722,6 @@
 which were printed when control arrived at the event,
 have since scrolled off the screen.
 @sp 1
- at item set [-APBfpv] @var{param} @var{value}
- at kindex set (mdb command)
- at kindex format (mdb command)
- at kindex depth (mdb command)
- at kindex size (mdb command)
- at kindex width (mdb command)
- at kindex lines (mdb command)
- at kindex xml_browser_cmd (mdb command)
- at kindex xml_tmp_filename (mdb command)
-Updates the configuration parameters of the browser.
-The parameters that can be configured are
- at samp{format}, @samp{depth}, @samp{size}, @samp{width}, @samp{lines}, 
- at samp{xml_browser_cmd} and @samp{xml_tmp_filename}.
- at sp 1
- at itemize @bullet
- at item
- at samp{format} can be set to @samp{flat}, @samp{pretty} or @samp{verbose}
-to change the output style of the browser.
- at sp 1
- at item
- at samp{depth} is the maximum depth to which subterms will be displayed.
-Subterms at the depth limit may be abbreviated as functor/arity,
-or (in lists) may be replaced by an ellipsis (@samp{...}).
-The principal functor of any term has depth zero.
-For subterms which are not lists,
-the depth of any argument of the functor is one greater than the
-depth of the functor.
-For subterms which are lists,
-the depth of each element of the list
-is one greater than the depth of the list.
- at sp 1
- at item
- at samp{size} is the suggested maximum number of functors to display.
-Beyond this limit, subterms may be abbreviated as functor/arity,
-or (in lists) may be replaced by an ellipsis (@samp{...}).
-For the purposes of this parameter,
-the size of a list is one greater than
-the sum of the sizes of the elements in the list.
- at sp 1
- at item
- at samp{width} is the width of the screen in characters.
- at sp 1
- at item
- at samp{lines} is the maximum number of lines of one term to display.
- at sp 1
- at item
- at samp{xml_tmp_filename} is the name of the file to dump XML to before
-invoking your XML browser.
- at sp 1
- at item
- at samp{xml_browser_cmd} is the shell command(s) used to invoke your XML browser.
-If you want a stylesheet to be applied to the XML before the browser is invoked
-then you should do that in this command using the appropriate program (such as
-xsltproc).  By default if xsltproc and mozilla (or firefox) are available,
-xsltproc is invoked to apply the xul_tree.xsl stylesheet in
-extras/xml_stylesheets, then mozilla is invoked on the resulting XUL file.  
- at sp 1
-You can use the apostrophe character (') to quote the command string when using
-the @samp{set} command, for example "set xml_browser_cmd 'firefox
-file:///tmp/mdbtmp.xml'".
- at end itemize
- at sp 1
-The browser maintains separate configuration parameters
-for the three commands @samp{print *}, @samp{print @var{var}},
-and @samp{browse @var{var}}.
-A single @samp{set} command can modify the parameters
-for more than one of these;
-the options @samp{-A} or @samp{--print-all}, @samp{-P} or @samp{--print},
-and @samp{-B} or @samp{--browse}
-select which commands will be affected by the change.
-If none of these options is given,
-the default is to affect all commands.
- at sp 1
-The browser also maintains separate configuration parameters
-for the three different output formats.
-This applies to all parameters except for the format itself.
-The options @samp{-f} or @samp{--flat}, @samp{-p} or @samp{--pretty},
-and @samp{-v} or @samp{--verbose}
-select which formats will be affected by the change.
-If none of these options is given,
-the default is to affect all formats.
-In the case that the format itself is being set,
-these options are ignored.
- at sp 1
 @item view [-vf2] [-w @var{window-cmd}] [-s @var{server-cmd}] [-n @var{server-name}] [-t @var{timeout}]
 @itemx view -c [-v] [-s @var{server-cmd}] [-n @var{server-name}]
 @kindex view (mdb command)
@@ -3474,6 +3390,94 @@
 @kindex clear_histogram (mdb command)
 Clears the histogram printed by @samp{histogram_exp},
 i.e.@: sets the counts for all depths to zero.
+ at sp 1
+ at item dice [-p at var{filename}] [-f at var{filename}] [-n at var{num}] [-s[pPfFsS]+] [-o @var{filename}]
+ at kindex dice (mdb command)
+Display a program dice on the screen.  
+ at sp 1
+A dice is a comparison between some successful test runs of the program and a
+failing test run.  Before using the @samp{dice} command one or more passing
+execution summaries and one failing execution summary should be generated.
+This can be done by compiling the program with deep tracing enabled (either by
+compiling in the .debug or .decldebug grades or with the @samp{--trace deep}
+compiler option) and then running the program with the MERCURY_OPTIONS
+environment variable set to @samp{--trace-count}.  
+This will generate a file called
+ at samp{.mercury_trace_counts} which contains a summary of the program's execution
+(called a slice).  Copy the generated slice to a new file for each test case,
+to end up with some passing slices, say @samp{pass1}, @samp{pass2}, 
+ at samp{pass3}, etc. and a
+failing slice, say @samp{fail}.
+ at sp 1
+Once one or more passing slices and a failing slice has been generated the
+ at samp{dice} command can be used to display a table of statistics comparing the
+passing test runs to the failing run.  Each row in the table contains statistics
+about the execution of a seperate goal in the program.  Six columns are
+displayed:
+ at sp 1
+ at itemize @bullet
+ at item @samp{Procedure}:
+The procedure in which the goal appears.
+ at item @samp{Path/Port}:
+The goal path and/or port of the goal.  For atomic goals, statistics about the
+CALL event and the corresponding EXIT, FAIL or EXCP event are displayed on
+seperate rows.  For other types of goals the goal path is displayed, except for
+NEGE, NEGS and NEGF events where the goal path and port is displayed. 
+ at item @samp{File:Line}:
+The file name and line number of the goal.  This can be used to set a
+breakpoint on the goal.
+ at item @samp{Pass (total passing test runs)}:
+The total number of times the goal was executed in all the passing test runs.
+This is followed by a number in braces which indicates the number of test runs
+the goal was executed in.  The heading of this column also has a number in
+braces which is the total number of passing test cases.
+ at item @samp{Fail}:
+The number of times the goal was executed in the failing test run. 
+ at item @samp{Suspicion}:
+A number between 0 and 1 which gives an indication of how lightly a
+particular goal is to be buggy.  The is calculated as 
+Suspicion = F / (P + F) where F is the number of times the goal
+was executed in the failing test run and P is the number of times the goal
+was executed in passing test runs.
+ at end itemize
+ at sp 1
+The name of the file containing the failing slice can be specified with the 
+ at samp{-f} or @samp{--fail-trace-count} option or with a seperate 
+ at samp{set fail_trace_count @var{filename}} command.
+ at sp 1
+The name of a file containing a list of the files containing the passing
+slices can be given with the @samp{-p} or @samp{--pass-trace-counts} option.
+Alternatively a seperate @samp{set pass_trace_counts @var{filename}} command
+can be given.
+ at sp 1
+The table can be sorted on the Pass, Fail or Suspicion columns, or a
+combination of these.  This can be done with the @samp{-s} or @samp{--sort}
+option.  The argument of this option is a string made up of any combination of
+the letters @samp{pPfFsS}.  The letters in the string indicate how the table
+should be sorted:
+ at sp 1
+ at itemize @bullet
+ at item @samp{p}: Pass ascending
+ at item @samp{P}: Pass descending
+ at item @samp{f}: Fail ascending
+ at item @samp{F}: Fail descending
+ at item @samp{s}: Suspicion ascending
+ at item @samp{S}: Suspicion descending
+ at end itemize
+ at sp 1
+For example the string "SF" means sort the table by suspicion, descending, and
+if any two suspicions are the same, then by number of executions in the failing
+test case, descending.
+ at sp 1
+The option @samp{-n} or @samp{--top} can be used to limit the number lines
+displayed.  Only the top @var{num} lines, with respect to
+the ordering specified by the @samp{-s} option, will be displayed.  
+By default the table is limited to 50 lines.
+ at sp 1
+If the @samp{-o} or @samp{--output-to-file} option is given then the output
+will be written to the specified file instead of being displayed on the
+screen.  Note that the file will be overwritten without warning if it 
+already exists.
 @end table
 
 @sp 1
@@ -3482,6 +3486,106 @@
 
 @sp 1
 @table @code
+ at item set [-APBfpv] @var{param} @var{value}
+ at kindex set (mdb command)
+ at kindex format (mdb command)
+ at kindex depth (mdb command)
+ at kindex size (mdb command)
+ at kindex width (mdb command)
+ at kindex lines (mdb command)
+ at kindex xml_browser_cmd (mdb command)
+ at kindex xml_tmp_filename (mdb command)
+ at kindex fail_trace_count (mdb command)
+ at kindex pass_trace_counts (mdb command)
+Updates the given configuration parameter.
+The parameters that can be configured are
+ at samp{format}, @samp{depth}, @samp{size}, @samp{width}, @samp{lines}, 
+ at samp{xml_browser_cmd}, @samp{xml_tmp_filename}, @samp{fail_trace_count},
+ at samp{pass_trace_counts}.
+ at sp 1
+ at itemize @bullet
+ at item
+ at samp{format} can be set to @samp{flat}, @samp{pretty} or @samp{verbose}
+to change the output style of the browser.
+ at sp 1
+ at item
+ at samp{depth} is the maximum depth to which subterms will be displayed.
+Subterms at the depth limit may be abbreviated as functor/arity,
+or (in lists) may be replaced by an ellipsis (@samp{...}).
+The principal functor of any term has depth zero.
+For subterms which are not lists,
+the depth of any argument of the functor is one greater than the
+depth of the functor.
+For subterms which are lists,
+the depth of each element of the list
+is one greater than the depth of the list.
+ at sp 1
+ at item
+ at samp{size} is the suggested maximum number of functors to display.
+Beyond this limit, subterms may be abbreviated as functor/arity,
+or (in lists) may be replaced by an ellipsis (@samp{...}).
+For the purposes of this parameter,
+the size of a list is one greater than
+the sum of the sizes of the elements in the list.
+ at sp 1
+ at item
+ at samp{width} is the width of the screen in characters.
+ at sp 1
+ at item
+ at samp{lines} is the maximum number of lines of one term to display.
+ at sp 1
+ at item
+ at samp{xml_tmp_filename} is the name of the file to dump XML to before
+invoking your XML browser.
+ at sp 1
+ at item
+ at samp{xml_browser_cmd} is the shell command(s) used to invoke your XML browser.
+If you want a stylesheet to be applied to the XML before the browser is invoked
+then you should do that in this command using the appropriate program (such as
+xsltproc).  By default if xsltproc and mozilla (or firefox) are available,
+xsltproc is invoked to apply the xul_tree.xsl stylesheet in
+extras/xml_stylesheets, then mozilla is invoked on the resulting XUL file.  
+ at sp 1
+You can use the apostrophe character (') to quote the command string when using
+the @samp{set} command, for example "set xml_browser_cmd 'firefox
+file:///tmp/mdbtmp.xml'".
+ at item
+ at samp{fail_trace_count} is the name of a file that contains the slice of a
+failing test case run.  This configuration parameter is used by the 
+ at samp{dice} command if no @samp{--fail-trace-count} option is given for that
+command.  See @ref{Experimental commands} for more information on the 
+ at samp{dice} command.
+ at sp 1
+ at item
+ at samp{pass_trace_counts} is the name of a file that contains a list of file
+names which contain the slices of passing test case runs.  This configuration
+parameter is used by the @samp{dice} command if no @samp{--pass-trace-counts}
+option is given for that command.  See @ref{Experimental commands} for more
+information on the @samp{dice} command.
+ at end itemize
+ at sp 1
+The browser maintains separate configuration parameters
+for the three commands @samp{print *}, @samp{print @var{var}},
+and @samp{browse @var{var}}.
+A single @samp{set} command can modify the parameters
+for more than one of these;
+the options @samp{-A} or @samp{--print-all}, @samp{-P} or @samp{--print},
+and @samp{-B} or @samp{--browse}
+select which commands will be affected by the change.
+If none of these options is given,
+the default is to affect all commands.
+ at sp 1
+The browser also maintains separate configuration parameters
+for the three different output formats.
+This applies to all parameters except for the format itself.
+The options @samp{-f} or @samp{--flat}, @samp{-p} or @samp{--pretty},
+and @samp{-v} or @samp{--verbose}
+select which formats will be affected by the change.
+If none of these options is given,
+the default is to affect all formats.
+In the case that the format itself is being set,
+these options are ignored.
+ at sp 1
 @item source [-i] @var{filename}
 @kindex source (mdb command)
 Executes the commands in the file named @var{filename}.
Index: mdbcomp/program_representation.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/program_representation.m,v
retrieving revision 1.1
diff -u -r1.1 program_representation.m
--- mdbcomp/program_representation.m	28 Jan 2005 07:11:52 -0000	1.1
+++ mdbcomp/program_representation.m	2 Feb 2005 05:21:06 -0000
@@ -192,6 +192,8 @@
 :- pred path_from_string_det(string, goal_path).
 :- mode path_from_string_det(in, out) is det.
 
+:- pred string_from_path(goal_path::in, string::out) is det.
+
 :- pred path_from_string(string, goal_path).
 :- mode path_from_string(in, out) is semidet.
 
@@ -342,6 +344,24 @@
 path_step_from_string_2('l', "", later).
 
 is_path_separator(';').
+
+string_from_path(GoalPath, GoalPathStr) :-
+	list.map(string_from_path_step, GoalPath, GoalPathSteps),
+	GoalPathStr = string.join_list(";", GoalPathSteps) ++ ";".
+
+:- pred string_from_path_step(goal_path_step::in, string::out) is det.
+
+string_from_path_step(conj(N), "c" ++ int_to_string(N)).
+string_from_path_step(disj(N), "d" ++ int_to_string(N)).
+string_from_path_step(switch(N), "s" ++ int_to_string(N)).
+string_from_path_step(ite_cond, "?").
+string_from_path_step(ite_then, "t").
+string_from_path_step(ite_else, "e").
+string_from_path_step(neg, "~").
+string_from_path_step(exist(cut), "q!").
+string_from_path_step(exist(no_cut), "q").
+string_from_path_step(first, "f").
+string_from_path_step(later, "l").
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: mdbcomp/trace_counts.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/trace_counts.m,v
retrieving revision 1.1
diff -u -r1.1 trace_counts.m
--- mdbcomp/trace_counts.m	28 Jan 2005 07:11:53 -0000	1.1
+++ mdbcomp/trace_counts.m	2 Feb 2005 04:46:20 -0000
@@ -39,6 +39,10 @@
 :- pred read_trace_counts(string::in, read_trace_counts_result::out,
 	io::di, io::uo) is det.
 
+:- pred string_to_trace_port(string, trace_port).
+:- mode string_to_trace_port(in, out) is semidet.
+:- mode string_to_trace_port(out, in) is det.
+
 %-----------------------------------------------------------------------------%
 
 :- implementation.
@@ -169,7 +173,7 @@
 	Words = string__words(Line),
 	(
 		Words = [Word1, CountStr],
-		( Port = string_to_trace_port(Word1) ->
+		( string_to_trace_port(Word1, Port) ->
 			PathPort = port_only(Port)
 		; Path = string_to_goal_path(Word1) ->
 			PathPort = path_only(Path)
@@ -179,7 +183,7 @@
 		string__to_int(CountStr, Count)
 	;
 		Words = [PortStr, PathStr, CountStr],
-		Port = string_to_trace_port(PortStr),
+		string_to_trace_port(PortStr, Port),
 		Path = string_to_goal_path(PathStr),
 		PathPort = port_and_path(Port, Path),
 		string__to_int(CountStr, Count)
@@ -190,23 +194,21 @@
 string_to_pred_or_func("p", predicate).
 string_to_pred_or_func("f", function).
 
-:- func string_to_trace_port(string) = trace_port is semidet.
-
-string_to_trace_port("CALL") = call.
-string_to_trace_port("EXIT") = exit.
-string_to_trace_port("REDO") = redo.
-string_to_trace_port("FAIL") = fail.
-string_to_trace_port("EXCP") = exception.
-string_to_trace_port("COND") = ite_cond.
-string_to_trace_port("THEN") = ite_then.
-string_to_trace_port("ELSE") = ite_else.
-string_to_trace_port("NEGE") = neg_enter.
-string_to_trace_port("NEGS") = neg_success.
-string_to_trace_port("NEGF") = neg_failure.
-string_to_trace_port("DISJ") = disj.
-string_to_trace_port("SWTC") = switch.
-string_to_trace_port("FRST") = nondet_pragma_first.
-string_to_trace_port("LATR") = nondet_pragma_later.
+string_to_trace_port("CALL", call).
+string_to_trace_port("EXIT", exit).
+string_to_trace_port("REDO", redo).
+string_to_trace_port("FAIL", fail).
+string_to_trace_port("EXCP", exception).
+string_to_trace_port("COND", ite_cond).
+string_to_trace_port("THEN", ite_then).
+string_to_trace_port("ELSE", ite_else).
+string_to_trace_port("NEGE", neg_enter).
+string_to_trace_port("NEGS", neg_success).
+string_to_trace_port("NEGF", neg_failure).
+string_to_trace_port("DISJ", disj).
+string_to_trace_port("SWTC", switch).
+string_to_trace_port("FRST", nondet_pragma_first).
+string_to_trace_port("LATR", nondet_pragma_later).
 
 :- func string_to_goal_path(string) = goal_path is semidet.
 
Index: runtime/mercury_trace_base.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_base.h,v
retrieving revision 1.42
diff -u -r1.42 mercury_trace_base.h
--- runtime/mercury_trace_base.h	10 Jan 2005 05:23:50 -0000	1.42
+++ runtime/mercury_trace_base.h	3 Feb 2005 03:49:33 -0000
@@ -490,4 +490,34 @@
 		if (MR_jumpaddr != NULL) MR_GOTO(MR_jumpaddr);		\
 	}
 
+/*
+** When using the heap pointer, we need to restore it, in case it is
+** transient.
+*/
+#define MR_TRACE_USE_HP(STATEMENTS) do {				\
+		MR_restore_transient_registers();			\
+		STATEMENTS;						\
+		MR_save_transient_registers();				\
+	} while (0)
+
+/*
+** When calling Mercury code defined using `pragma export', we need
+** to call save_registers() and restore_registers() around it.
+** That in turn needs to be preceded/followed by
+** restore/save_transient_registers() if it is in a C function.
+*/
+
+#define MR_TRACE_CALL_MERCURY(STATEMENTS) do {				\
+		MR_bool	saved_io_enabled;				\
+									\
+		saved_io_enabled = MR_io_tabling_enabled;		\
+		MR_io_tabling_enabled = MR_FALSE;			\
+		MR_restore_transient_registers();			\
+		MR_save_registers();					\
+		STATEMENTS;						\
+		MR_restore_registers();					\
+		MR_save_transient_registers();				\
+		MR_io_tabling_enabled = saved_io_enabled;		\
+	} while (0)
+
 #endif /* MERCURY_TRACE_BASE_H */
Index: tests/Mmake.common
===================================================================
RCS file: /home/mercury1/repository/tests/Mmake.common,v
retrieving revision 1.42
diff -u -r1.42 Mmake.common
--- tests/Mmake.common	24 Feb 2004 08:34:34 -0000	1.42
+++ tests/Mmake.common	6 Feb 2005 08:06:05 -0000
@@ -182,7 +182,7 @@
 ERROR_OUTPUT_FILE = runtests.errs
 
 realclean_local: clean_logs clean_errors
-clean_local: clean_out clean_res clean_zip
+clean_local: clean_out clean_res clean_zip clean_trace_counts
 
 # XXX what is this target for??
 clean_mc: clean_c clean_o clean_out clean_res 
@@ -198,6 +198,9 @@
 
 clean_errors:
 	rm -f $(ERROR_OUTPUT_FILE) FAILED_TESTS
+
+clean_trace_counts:
+	rm -f *.pass1 *.pass2 *.pass3 *.fail
 
 # Remove gzipped executables for tests which have failed.
 ifeq ($(TESTS),)
Index: tests/debugger/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/Mmakefile,v
retrieving revision 1.109
diff -u -r1.109 Mmakefile
--- tests/debugger/Mmakefile	1 Feb 2005 03:24:28 -0000	1.109
+++ tests/debugger/Mmakefile	6 Feb 2005 07:53:47 -0000
@@ -22,6 +22,7 @@
 	cmd_quote			\
 	cond				\
 	debugger_regs			\
+	dice				\
 	exception_cmd			\
 	exception_value			\
 	exception_vars			\
@@ -281,6 +282,21 @@
 		rm exception_cmd.tmp;				\
 		true;						\
 	fi
+
+dice.pass1: dice
+	./dice 1 2 3 4 && mv .mercury_trace_counts dice.pass1
+
+dice.pass2: dice
+	./dice 5 6 7 8 && mv .mercury_trace_counts dice.pass2
+
+dice.pass3: dice
+	./dice 10 11 100 && mv .mercury_trace_counts dice.pass3
+
+dice.fail: dice
+	./dice 4 1 2 3 && mv .mercury_trace_counts dice.fail
+
+dice.out: dice dice.inp dice.pass1 dice.pass2 dice.pass3 dice.fail
+	$(MDB_STD) ./dice 4 1 2 3 < dice.inp > dice.out 2>&1
 
 # We need to pipe the output through sed to avoid hard-coding dependencies on
 # particular line numbers in the standard library source code.
Index: tests/debugger/dice.exp
===================================================================
RCS file: tests/debugger/dice.exp
diff -N tests/debugger/dice.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/dice.exp	6 Feb 2005 07:57:32 -0000
@@ -0,0 +1,115 @@
+      E1:     C1 CALL pred dice.main/2-0 (det) dice.m:17
+mdb> mdb> Contexts will not be printed.
+mdb> echo on
+Command echo enabled.
+mdb> dice -f dice.fail -p dice.passes
+Procedure                Path/Port        File:Line Pass (3) Fail Suspicion
+pred dice.main/2-0       CALL             dice.m:17    3 (3)    1      0.25
+pred dice.main/2-0       EXIT             dice.m:17    3 (3)    1      0.25
+pred dice.main/2-0       <c2;?;>          dice.m:20    3 (3)    1      0.25
+pred dice.main/2-0       <c2;t;>          dice.m:22    3 (3)    1      0.25
+pred dice.merge/3-0      CALL             dice.m:64   18 (3)    7      0.28
+pred dice.merge/3-0      EXIT             dice.m:64   18 (3)    7      0.28
+pred dice.merge/3-0      <s1;>            dice.m:64    8 (3)    3      0.27
+pred dice.merge/3-0      <s2;>            dice.m:64   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;>      dice.m:67   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;c4;?;> dice.m:69   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;c4;t;> dice.m:71   10 (3)    3      0.23
+pred dice.merge/3-0      <s2;c2;s2;c4;e;> dice.m:74    0 (0)    1      1.00
+pred dice.merge_sort/2-0 CALL             dice.m:31    3 (3)    1      0.25
+pred dice.merge_sort/2-0 EXIT             dice.m:31    3 (3)    1      0.25
+pred dice.msort_n/4-0    CALL             dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0    EXIT             dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0    <?;>             dice.m:39   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;>             dice.m:54   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;?;>           dice.m:44   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;t;>           dice.m:50   11 (3)    4      0.27
+pred dice.msort_n/4-0    <e;t;s2;>        dice.m:47   11 (3)    4      0.27
+pred dice.msort_n/4-0    <e;e;>           dice.m:55    8 (3)    3      0.27
+mdb> set fail_trace_count dice.fail
+mdb> set pass_trace_counts dice.passes
+mdb> dice -sS
+Procedure                Path/Port        File:Line Pass (3) Fail Suspicion
+pred dice.merge/3-0      <s2;c2;s2;c4;e;> dice.m:74    0 (0)    1      1.00
+pred dice.merge/3-0      <s2;>            dice.m:64   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;>      dice.m:67   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;c4;?;> dice.m:69   10 (3)    4      0.29
+pred dice.merge/3-0      CALL             dice.m:64   18 (3)    7      0.28
+pred dice.merge/3-0      EXIT             dice.m:64   18 (3)    7      0.28
+pred dice.merge/3-0      <s1;>            dice.m:64    8 (3)    3      0.27
+pred dice.msort_n/4-0    <e;e;>           dice.m:55    8 (3)    3      0.27
+pred dice.msort_n/4-0    CALL             dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0    EXIT             dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0    <?;>             dice.m:39   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;>             dice.m:54   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;?;>           dice.m:44   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;t;>           dice.m:50   11 (3)    4      0.27
+pred dice.msort_n/4-0    <e;t;s2;>        dice.m:47   11 (3)    4      0.27
+pred dice.main/2-0       CALL             dice.m:17    3 (3)    1      0.25
+pred dice.main/2-0       EXIT             dice.m:17    3 (3)    1      0.25
+pred dice.main/2-0       <c2;?;>          dice.m:20    3 (3)    1      0.25
+pred dice.main/2-0       <c2;t;>          dice.m:22    3 (3)    1      0.25
+pred dice.merge_sort/2-0 CALL             dice.m:31    3 (3)    1      0.25
+pred dice.merge_sort/2-0 EXIT             dice.m:31    3 (3)    1      0.25
+pred dice.merge/3-0      <s2;c2;s2;c4;t;> dice.m:71   10 (3)    3      0.23
+mdb> dice -sSF
+Procedure                Path/Port        File:Line Pass (3) Fail Suspicion
+pred dice.merge/3-0      <s2;c2;s2;c4;e;> dice.m:74    0 (0)    1      1.00
+pred dice.merge/3-0      <s2;>            dice.m:64   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;>      dice.m:67   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;c4;?;> dice.m:69   10 (3)    4      0.29
+pred dice.merge/3-0      CALL             dice.m:64   18 (3)    7      0.28
+pred dice.merge/3-0      EXIT             dice.m:64   18 (3)    7      0.28
+pred dice.merge/3-0      <s1;>            dice.m:64    8 (3)    3      0.27
+pred dice.msort_n/4-0    <e;e;>           dice.m:55    8 (3)    3      0.27
+pred dice.msort_n/4-0    CALL             dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0    EXIT             dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0    <?;>             dice.m:39   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;>             dice.m:54   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;?;>           dice.m:44   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;t;>           dice.m:50   11 (3)    4      0.27
+pred dice.msort_n/4-0    <e;t;s2;>        dice.m:47   11 (3)    4      0.27
+pred dice.main/2-0       CALL             dice.m:17    3 (3)    1      0.25
+pred dice.main/2-0       EXIT             dice.m:17    3 (3)    1      0.25
+pred dice.main/2-0       <c2;?;>          dice.m:20    3 (3)    1      0.25
+pred dice.main/2-0       <c2;t;>          dice.m:22    3 (3)    1      0.25
+pred dice.merge_sort/2-0 CALL             dice.m:31    3 (3)    1      0.25
+pred dice.merge_sort/2-0 EXIT             dice.m:31    3 (3)    1      0.25
+pred dice.merge/3-0      <s2;c2;s2;c4;t;> dice.m:71   10 (3)    3      0.23
+mdb> dice -n 3 -s P
+Procedure             Path/Port File:Line Pass (3) Fail Suspicion
+pred dice.msort_n/4-0 CALL      dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0 EXIT      dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0 <?;>      dice.m:39   19 (3)    7      0.27
+mdb> dice -s Fp
+Procedure                Path/Port        File:Line Pass (3) Fail Suspicion
+pred dice.merge/3-0      CALL             dice.m:64   18 (3)    7      0.28
+pred dice.merge/3-0      EXIT             dice.m:64   18 (3)    7      0.28
+pred dice.msort_n/4-0    CALL             dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0    EXIT             dice.m:43   19 (3)    7      0.27
+pred dice.msort_n/4-0    <?;>             dice.m:39   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;>             dice.m:54   19 (3)    7      0.27
+pred dice.msort_n/4-0    <e;?;>           dice.m:44   19 (3)    7      0.27
+pred dice.merge/3-0      <s2;>            dice.m:64   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;>      dice.m:67   10 (3)    4      0.29
+pred dice.merge/3-0      <s2;c2;s2;c4;?;> dice.m:69   10 (3)    4      0.29
+pred dice.msort_n/4-0    <e;t;>           dice.m:50   11 (3)    4      0.27
+pred dice.msort_n/4-0    <e;t;s2;>        dice.m:47   11 (3)    4      0.27
+pred dice.merge/3-0      <s1;>            dice.m:64    8 (3)    3      0.27
+pred dice.msort_n/4-0    <e;e;>           dice.m:55    8 (3)    3      0.27
+pred dice.merge/3-0      <s2;c2;s2;c4;t;> dice.m:71   10 (3)    3      0.23
+pred dice.merge/3-0      <s2;c2;s2;c4;e;> dice.m:74    0 (0)    1      1.00
+pred dice.main/2-0       CALL             dice.m:17    3 (3)    1      0.25
+pred dice.main/2-0       EXIT             dice.m:17    3 (3)    1      0.25
+pred dice.main/2-0       <c2;?;>          dice.m:20    3 (3)    1      0.25
+pred dice.main/2-0       <c2;t;>          dice.m:22    3 (3)    1      0.25
+pred dice.merge_sort/2-0 CALL             dice.m:31    3 (3)    1      0.25
+pred dice.merge_sort/2-0 EXIT             dice.m:31    3 (3)    1      0.25
+mdb> dice -sS -n 1
+Procedure           Path/Port        File:Line Pass (3) Fail Suspicion
+pred dice.merge/3-0 <s2;c2;s2;c4;e;> dice.m:74    0 (0)    1      1.00
+mdb> break dice.m:74
+ 0: + stop  linenumber dice.m:74
+mdb> c
+      E2:     C2 ELSE pred dice.merge/3-0 (det) s2;c2;s2;c4;e;
+mdb> quit -y
Index: tests/debugger/dice.inp
===================================================================
RCS file: tests/debugger/dice.inp
diff -N tests/debugger/dice.inp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/dice.inp	6 Feb 2005 07:48:44 -0000
@@ -0,0 +1,14 @@
+register --quiet
+context none
+echo on
+dice -f dice.fail -p dice.passes
+set fail_trace_count dice.fail
+set pass_trace_counts dice.passes
+dice -sS
+dice -sSF
+dice -n 3 -s P
+dice -s Fp
+dice -sS -n 1
+break dice.m:74
+c
+quit -y
Index: tests/debugger/dice.m
===================================================================
RCS file: tests/debugger/dice.m
diff -N tests/debugger/dice.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/dice.m	6 Feb 2005 07:57:26 -0000
@@ -0,0 +1,76 @@
+% Test the mdb `dice' command.
+% Buggy merge sort taken from Lee Naish's probabalistic declarative debugging 
+% paper.
+
+:- module dice.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module int, string, list, exception.
+
+main(!IO) :-
+	io.command_line_arguments(Args, !IO),
+	(
+		list.map(string.to_int, Args, Ints)
+	->
+		merge_sort(Ints, Sorted),
+		io.write(Sorted, !IO),
+		io.nl(!IO)
+	;
+		io.write_string("usage error\n", !IO)
+	).
+
+:- pred merge_sort(list(int)::in, list(int)::out) is det.
+
+merge_sort(Us, Ss) :-
+	N = list.length(Us),
+	msort_n(N, Us, Ss, _).
+
+:- pred msort_n(int::in, list(int)::in, list(int)::out, list(int)::out) is det.
+
+msort_n(N, Unsorted, SortedPart, Rest) :-
+	(
+		N =< 0
+	->
+		SortedPart = [],
+		Rest = Unsorted
+	;
+		N = 1
+	->
+		(
+			Unsorted = [U | Us],
+			SortedPart = [U],
+			Rest = Us
+		;
+			Unsorted = [],
+			throw("Unsorted = [] and N = 0")
+		)
+	;
+		N1 = N // 2,
+		dice.msort_n(N1, Unsorted, Ss1, Us2),
+		N2 = N - N1,
+		msort_n(N2, Us2, Ss2, Rest),
+		dice.merge(Ss1, Ss2, SortedPart)
+	).
+
+:- pred merge(list(int)::in, list(int)::in, list(int)::out) is det.
+
+merge([], [], []).
+merge([S | Ss], [], [S | Ss]).
+merge([], [S | Ss], [S | Ss]).
+merge([A | As], [B | Bs], [C | Cs]) :-
+	(
+		A =< B
+	->
+		dice.merge(As, [B | Bs], Cs),
+		C = A
+	;
+		dice.merge(As, [B | Bs], Cs), % BUG
+		C = B
+	).
Index: tests/debugger/dice.passes
===================================================================
RCS file: tests/debugger/dice.passes
diff -N tests/debugger/dice.passes
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/dice.passes	6 Feb 2005 07:56:15 -0000
@@ -0,0 +1,3 @@
+dice.pass1
+dice.pass2
+dice.pass3
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.191
diff -u -r1.191 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	1 Feb 2005 03:24:32 -0000	1.191
+++ trace/mercury_trace_internal.c	6 Feb 2005 08:11:53 -0000
@@ -37,6 +37,7 @@
 #include "mdb.browse.mh"
 #include "mdb.browser_info.mh"
 #include "mdbcomp.program_representation.mh"
+#include "mdb.dice.mh"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -88,6 +89,12 @@
 /* If a number has more than this many chars, the user is in trouble. */
 #define MR_NUMBER_LEN       80
 
+/*
+** The maximum size of a sort string for the `dice' command
+*/
+
+#define MR_MAX_DICE_SORT_STR_SIZE   10
+
 #define MDBRC_FILENAME      ".mdbrc"
 #define DEFAULT_MDBRC_FILENAME  "mdbrc"
 
@@ -189,6 +196,20 @@
 static  char        *MR_xml_tmp_filename = NULL;
 
 /*
+** This variable holds the name of a file which contains a list of 
+** the file names of passing test case trace counts.
+*/
+
+static  char        *MR_dice_pass_trace_counts_file = NULL;
+
+/*
+** This variable holds the name of the file containing the failing test
+** case trace count.
+*/
+
+static  char        *MR_dice_fail_trace_count_file = NULL;
+
+/*
 ** MR_context_position specifies whether we print context at events,
 ** and if so, where.
 */
@@ -495,6 +516,7 @@
 static  MR_TraceCmdFunc MR_trace_cmd_trust;
 static  MR_TraceCmdFunc MR_trace_cmd_untrust;
 static  MR_TraceCmdFunc MR_trace_cmd_trusted;
+static  MR_TraceCmdFunc MR_trace_cmd_dice;
 
 static  void        MR_maybe_print_spy_point(int slot, const char *problem);
 static  void        MR_print_unsigned_var(FILE *fp, const char *var,
@@ -585,11 +607,18 @@
 static  MR_bool     MR_trace_options_save_to_file(MR_bool *xml,
                         char ***words, int *word_count, const char *cat, 
                         const char *item);
+static  MR_bool     MR_trace_options_dice(char **pass_trace_counts_file,
+                        char **fail_trace_count_file, char **sort_str, 
+                        int *n, char **out_file, char ***words, 
+                        int *word_count, const char *cat, const char *item);
 static  void        MR_trace_usage(const char *cat, const char *item);
 static  void        MR_trace_do_noop(void);
 static  void        MR_mdb_print_proc_id_and_nl(void *data,
                         const MR_Proc_Layout *entry_layout);
 static  int         MR_trace_var_print_list(MR_Spy_Print_List print_list);
+static  void        MR_trace_print_dice(char *pass_trace_counts_file,
+                        char *fail_trace_counts_file, char *sort_str, int n,
+                        char *out_str);
 
 static  const MR_Proc_Layout *MR_find_single_matching_proc(MR_Proc_Spec *spec,
                         MR_bool verbose);
@@ -2346,9 +2375,29 @@
                 strlen(words[2]) + 1);
         }
         strcpy(MR_xml_tmp_filename, words[2]);
+    } else if (word_count == 3 && MR_streq(words[1], "fail_trace_count")) {
+        if (MR_dice_fail_trace_count_file == NULL) {
+            MR_dice_fail_trace_count_file = (char*)malloc(strlen(words[2]) 
+                + 1);
+        } else {
+            MR_dice_fail_trace_count_file = 
+                (char*)realloc(MR_dice_fail_trace_count_file, 
+                    strlen(words[2]) + 1);
+        }
+        strcpy(MR_dice_fail_trace_count_file, words[2]);
+    } else if (word_count == 3 && MR_streq(words[1], "pass_trace_counts")) {
+        if (MR_dice_pass_trace_counts_file == NULL) {
+            MR_dice_pass_trace_counts_file = 
+                (char*)malloc(strlen(words[2]) + 1);
+        } else {
+            MR_dice_pass_trace_counts_file = 
+                (char*)realloc(MR_dice_pass_trace_counts_file, 
+                    strlen(words[2]) + 1);
+        }
+        strcpy(MR_dice_pass_trace_counts_file, words[2]);
     } else if (! MR_trace_options_param_set(&print_set, &browse_set,
         &print_all_set, &flat_format, &raw_pretty_format, &verbose_format,
-        &pretty_format, &words, &word_count, "parameter", "set"))
+        &pretty_format, &words, &word_count, "misc", "set"))
     {
         ; /* the usage message has already been printed */
     } 
@@ -2357,7 +2406,7 @@
             flat_format, raw_pretty_format, verbose_format, pretty_format,
             words[1], words[2]))
     {
-        MR_trace_usage("parameter", "set");
+        MR_trace_usage("misc", "set");
     }
 
     return KEEP_INTERACTING;
@@ -5830,6 +5879,100 @@
     return KEEP_INTERACTING;
 }
 
+static MR_Next
+MR_trace_cmd_dice(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+    MR_Event_Info *event_info, MR_Event_Details *event_details,
+    MR_Code **jumpaddr)
+{
+    char    *pass_trace_counts_file;
+    char    *fail_trace_count_file;
+    char    *sort_str = (char*)malloc(MR_MAX_DICE_SORT_STR_SIZE + 1); 
+    char    *out_file = NULL;
+    int     n = 50;
+
+    pass_trace_counts_file = MR_dice_pass_trace_counts_file;
+    fail_trace_count_file = MR_dice_fail_trace_count_file;
+    strcpy(sort_str, "");
+    
+    if (! MR_trace_options_dice(&pass_trace_counts_file,
+        &fail_trace_count_file, &sort_str, &n, &out_file, &words, &word_count, 
+        "exp", "dice"))
+    {
+        ; /* the usage message has already been printed */
+    } else if (word_count == 1) {
+        if (pass_trace_counts_file == NULL) {
+            fflush(MR_mdb_out);
+            fprintf(MR_mdb_err, "mdb: No passing trace counts file specified."
+                "\nmdb: Specify one with the -p option or using the `set' "
+                "command.\n");
+        } else if (fail_trace_count_file == NULL) {
+            fflush(MR_mdb_out);
+            fprintf(MR_mdb_err, "mdb: No failing trace count file specified."
+                "\nmdb: Specify one with the -f option or using the `set' "
+                "command.\n");
+        } else {
+            MR_trace_print_dice(pass_trace_counts_file, fail_trace_count_file,
+                sort_str, n, out_file);
+        }
+    } else {
+        MR_trace_usage("exp", "dice");
+    }
+
+    free(out_file);
+    free(sort_str);
+
+    return KEEP_INTERACTING;
+}
+
+static  void
+MR_trace_print_dice(char *pass_trace_counts_file, 
+    char *fail_trace_count_file, char *sort_str, int n, char* out_file)
+{
+    MR_String   dice;
+    MR_String   problem;
+    MR_String   aligned_pass_trace_counts_file;
+    MR_String   aligned_fail_trace_count_file;
+    MR_String   aligned_sort_str;
+    FILE        *fp;
+
+    MR_TRACE_USE_HP(
+        MR_make_aligned_string(aligned_pass_trace_counts_file,
+            (MR_String) pass_trace_counts_file);
+        MR_make_aligned_string(aligned_fail_trace_count_file,
+            (MR_String) fail_trace_count_file);
+        MR_make_aligned_string(aligned_sort_str, (MR_String) sort_str);
+    );
+
+    MR_TRACE_CALL_MERCURY(
+        MR_MDB_read_dice_to_string(aligned_pass_trace_counts_file, 
+            aligned_fail_trace_count_file, aligned_sort_str, n, &dice, 
+            &problem);
+    );
+    
+    if (MR_streq(problem, "")) {
+        if (out_file == NULL) {
+            fprintf(MR_mdb_out, "%s\n", dice);
+        } else {
+            fp = fopen(out_file, "w");
+            if (fp != NULL) {
+                fprintf(fp, dice);
+                if (fclose(fp) != 0) {
+                    fflush(MR_mdb_out);
+                    fprintf(MR_mdb_err, "mdb: Error closing file `%s': %s\n", 
+                        out_file, strerror(errno));
+                }
+            } else {
+                fflush(MR_mdb_out);
+                fprintf(MR_mdb_err, "mdb: Error opening file `%s': %s\n", 
+                    out_file, strerror(errno));
+            }
+        }
+    } else {
+        fflush(MR_mdb_out);
+        fprintf(MR_mdb_err, "mdb: %s\n", problem);
+    }
+}
+
 static void
 MR_maybe_print_spy_point(int slot, const char *problem)
 {
@@ -6849,6 +6992,85 @@
     return MR_TRUE;
 }
 
+static struct MR_option MR_trace_dice_opts[] =
+{
+    { "pass-trace-counts",      MR_required_argument,   NULL,   'p' },
+    { "fail-trace-count",       MR_required_argument,   NULL,   'f' },
+    { "sort",                   MR_required_argument,   NULL,   's' },
+    { "top",                    MR_required_argument,   NULL,   'n' },
+    { "output-to-file",         MR_required_argument,   NULL,   'o' },
+    { NULL,                     MR_no_argument,         NULL,   0   }
+};
+
+static MR_bool
+MR_trace_options_dice(char** pass_trace_counts_file, 
+    char** fail_trace_count_file, char** sort_str, int* n, char** out_file,
+    char ***words, int *word_count, const char *cat, const char *item)
+{
+    int c;
+
+    MR_optind = 0;
+    while ((c = MR_getopt_long(*word_count, *words, "p:f:s:n:o:", 
+        MR_trace_dice_opts, NULL)) != EOF)
+    {
+        switch (c) {
+
+            case 'p':
+                if (*pass_trace_counts_file == NULL) {
+                    *pass_trace_counts_file = 
+                        (char*)malloc(strlen(MR_optarg) + 1);
+                } else {
+                    *pass_trace_counts_file = 
+                        (char*)realloc(*pass_trace_counts_file, 
+                            strlen(MR_optarg) + 1);
+                }
+                strcpy(*pass_trace_counts_file, MR_optarg);
+                break;
+
+            case 'f':
+                if (*fail_trace_count_file == NULL) {
+                    *fail_trace_count_file = 
+                        (char*)malloc(strlen(MR_optarg) + 1);
+                } else {
+                    *fail_trace_count_file = 
+                        (char*)realloc(*fail_trace_count_file, 
+                            strlen(MR_optarg) + 1);
+                }
+                strcpy(*fail_trace_count_file, MR_optarg);
+                break;
+
+            case 's':
+                if (strlen(MR_optarg) <= MR_MAX_DICE_SORT_STR_SIZE) {
+                    strcpy(*sort_str, MR_optarg);
+                } else {
+                    MR_trace_usage(cat, item);
+                    return MR_FALSE;
+                }
+                break;
+
+            case 'n':
+                if (! MR_trace_is_natural_number(MR_optarg, n)) {
+                    MR_trace_usage(cat, item);
+                    return MR_FALSE;
+                }
+                break;
+
+            case 'o':
+                *out_file = (char*)malloc(strlen(MR_optarg) + 1);
+                strcpy(*out_file, MR_optarg);
+                break;
+             
+            default:
+                MR_trace_usage(cat, item);
+                return MR_FALSE;
+        }
+    }
+
+    *words = *words + MR_optind - 1;
+    *word_count = *word_count - MR_optind + 1;
+    return MR_TRUE;
+}
+
 static struct MR_option MR_trace_type_ctor_opts[] =
 {
     { "print-rep",      MR_no_argument,     NULL,   'r' },
@@ -7828,8 +8050,6 @@
     { "table_io", "table_io", MR_trace_cmd_table_io,
         MR_trace_table_io_cmd_args, MR_trace_null_completer },
 
-    { "parameter", "set", MR_trace_cmd_set,
-        MR_trace_set_cmd_args, MR_trace_null_completer },
     { "parameter", "printlevel", MR_trace_cmd_printlevel,
         MR_trace_printlevel_cmd_args, MR_trace_null_completer },
     { "parameter", "mmc_options", MR_trace_cmd_mmc_options,
@@ -7867,6 +8087,8 @@
     { "dd", "trusted", MR_trace_cmd_trusted, NULL,
         MR_trace_null_completer },
 
+    { "misc", "set", MR_trace_cmd_set,
+        MR_trace_set_cmd_args, MR_trace_null_completer },
     { "misc", "source", MR_trace_cmd_source,
         MR_trace_source_cmd_args, MR_trace_filename_completer },
     { "misc", "save", MR_trace_cmd_save,
@@ -7879,6 +8101,8 @@
     { "exp", "histogram_exp", MR_trace_cmd_histogram_exp,
         NULL, MR_trace_filename_completer },
     { "exp", "clear_histogram", MR_trace_cmd_clear_histogram,
+        NULL, MR_trace_null_completer },
+    { "exp", "dice", MR_trace_cmd_dice,
         NULL, MR_trace_null_completer },
 
     { "developer", "var_details", MR_trace_cmd_var_details,
Index: trace/mercury_trace_util.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_util.h,v
retrieving revision 1.10
diff -u -r1.10 mercury_trace_util.h
--- trace/mercury_trace_util.h	12 Mar 2004 06:02:19 -0000	1.10
+++ trace/mercury_trace_util.h	3 Feb 2005 03:52:35 -0000
@@ -23,36 +23,6 @@
 #include "mercury_trace.h"		/* for MR_Event_Details */
 
 /*
-** When using the heap pointer, we need to restore it, in case it is
-** transient.
-*/
-#define MR_TRACE_USE_HP(STATEMENTS) do {				\
-		MR_restore_transient_registers();			\
-		STATEMENTS;						\
-		MR_save_transient_registers();				\
-	} while (0)
-
-/*
-** When calling Mercury code defined using `pragma export', we need
-** to call save_registers() and restore_registers() around it.
-** That in turn needs to be preceded/followed by
-** restore/save_transient_registers() if it is in a C function.
-*/
-
-#define MR_TRACE_CALL_MERCURY(STATEMENTS) do {				\
-		MR_bool	saved_io_enabled;				\
-									\
-		saved_io_enabled = MR_io_tabling_enabled;		\
-		MR_io_tabling_enabled = MR_FALSE;			\
-		MR_restore_transient_registers();			\
-		MR_save_registers();					\
-		STATEMENTS;						\
-		MR_restore_registers();					\
-		MR_save_transient_registers();				\
-		MR_io_tabling_enabled = saved_io_enabled;		\
-	} while (0)
-
-/*
 ** MR_c_file_to_mercury_file is used to convert MR_mdb_in and MR_mdb_out
 ** into Mercury streams suitable for use by the browser.
 */
--------------------------------------------------------------------------
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