[m-rev.] for review: mslice and mdice

Zoltan Somogyi zs at cs.mu.OZ.AU
Fri Apr 1 17:25:10 AEST 2005


For review by Ian. The documentation is still to come.

Zoltan.

Make the functionality of mdb's current "dice" command available directly
from the command line, together with simpler functionality involving just
slices.

browser/dice.m:
mdbcomp/slice_and_dice.m:
	Move most of the code of browser/dice.m to mdbcomp/slice_and_dice.m,
	much modified; browser/dice.m is now empty. The modifications are
	as follows.

	Factor out the code for reading dices, since dices are useful
	independent of mdb's dice command.

	Generalize the code for computing dices to allow either or both
	of the slices being subtracted to be specified as the union of
	one or more trace counts files.

	Add two more sort conditions for comparing the execution counts
	in two slices: ascending and descending versions of simple execution
	count differences.

	For each operation we have so far performed on dices, add code
	for performing that operation on slices.

browser/mdb.m:
	Delete the include of dice.m, since it is now empty.

	Delete a duplicate include_module of term_rep, and delete the now
	unnecessary include_modules of set_cc and tree234_cc.

mdbcomp/mdbcomp.m:
	Add slice_and_dice.m as a submodule.

mdbcomp/trace_counts.m:
	Provide a mechanism to allow a slice to be specified as coming not
	from a single trace count file but from the union operation on a set
	of trace count files.

	Convert to four-space indentation to eliminate some excessively
	indented lines.

slice/mercury_dice.m:
slice/mercury_slice.m:
	The main modules of two new commands, which are installed as mslice
	and mdice (just as profiler/mercury_profile.m is installed as mprof).
	Their functionality is almost entirely in mdbcomp/slice_and_dice.m
	and mdbcomp/trace_counts.m.

slice/Mmakefile:
	New Mmakefile for building mslice and mdice. It is modelled on
	profiler/Mmakefile.

Mmakefile:
	Process the slice directory at appropriate points when processing
	other directories.

compiler/tupling.m:
	Conform to the updated interface of mdbcomp/trace_counts.

trace/mercury_trace_internal.c:
	Generalize the code for specifying dices to allow either or both
	of the slices being subtracted to be specified as the union of
	one or more trace counts files.

	Fix several places where we weren't checking the return value of
	malloc. Fix two places where we could conceivably free strings that
	were still alive. Fix some places where we could pass NULL strings
	to Mercury code, and some places where we could free NULL pointers
	(which is not guaranteed to work on all platforms).

	Use existing functions such as MR_copy_string where appropriate.

	Add a new command, slice, for printing information on slices.

tests/run_one_test:
	Fix two small bugs in this script: make the filenames more user
	friendly, and make sure that gzip isn't asked to overwrite an
	existing file, since that causes it to ask a question on stdout
	and to wait for an answer.

cvs diff: Diffing .
Index: Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/Mmakefile,v
retrieving revision 1.107
diff -u -b -r1.107 Mmakefile
--- Mmakefile	28 Jan 2005 07:11:29 -0000	1.107
+++ Mmakefile	23 Mar 2005 04:28:35 -0000
@@ -35,6 +35,7 @@
 		analysis \
 		compiler \
 		doc \
+		slice \
 		profiler \
 		deep_profiler \
 		tools
@@ -69,7 +70,7 @@
 
 .PHONY: dep
 dep: dep_library dep_mdbcomp dep_browser dep_analysis dep_compiler \
-		dep_profiler dep_deep_profiler
+		dep_slice dep_profiler dep_deep_profiler
 
 .PHONY: dep_library
 dep_library: library/$(deps_subdir)$(STD_LIB_NAME).dep
@@ -103,6 +104,20 @@
 compiler/$(deps_subdir)top_level.dep: library/$(deps_subdir)$(STD_LIB_NAME).dep
 	+cd compiler && $(SUBDIR_MMAKE) depend
 
+.PHONY: dep_slice
+dep_slice: slice/$(deps_subdir)mercury_slice.dep \
+	slice/$(deps_subdir)mercury_dice.dep
+
+slice/$(deps_subdir)mercury_slice.dep: \
+		library/$(deps_subdir)$(STD_LIB_NAME).dep
+		mdbcomp/$(deps_subdir)$(MDBCOMP_LIB_NAME).dep
+	+cd slice && $(SUBDIR_MMAKE) mercury_slice.depend
+
+slice/$(deps_subdir)mercury_dice.dep: \
+		library/$(deps_subdir)$(STD_LIB_NAME).dep
+		mdbcomp/$(deps_subdir)$(MDBCOMP_LIB_NAME).dep
+	+cd slice && $(SUBDIR_MMAKE) mercury_dice.depend
+
 .PHONY: dep_profiler
 dep_profiler: profiler/$(deps_subdir)mercury_profile.dep
 
@@ -135,6 +150,7 @@
 	+cd browser && $(SUBDIR_MMAKE) depend
 	+cd analysis && $(SUBDIR_MMAKE) depend
 	+cd compiler && $(SUBDIR_MMAKE) depend
+	+cd slice && $(SUBDIR_MMAKE) depend
 	+cd profiler && $(SUBDIR_MMAKE) depend
 	+cd deep_profiler && $(SUBDIR_MMAKE) depend
 
@@ -154,6 +170,10 @@
 depend_compiler:
 	+cd compiler && $(SUBDIR_MMAKE) depend
 
+.PHONY: depend_slice
+depend_slice:
+	+cd slice && $(SUBDIR_MMAKE) depend
+
 .PHONY: depend_profiler
 depend_profiler:
 	+cd profiler && $(SUBDIR_MMAKE) depend
@@ -223,6 +243,11 @@
 doc: scripts util
 	+cd doc && $(SUBDIR_MMAKE)
 
+.PHONY: slice
+slice: dep_slice scripts util boehm_gc runtime library \
+		mdbcomp browser trace
+	+cd slice && $(SUBDIR_MMAKE)
+
 .PHONY: profiler
 profiler: dep_profiler scripts util boehm_gc runtime library \
 		mdbcomp browser trace
@@ -237,7 +262,7 @@
 
 .PHONY: tags
 tags: tags_compiler tags_library tags_mdbcomp tags_browser tags_analysis \
-		tags_profiler tags_deep_profiler
+		tags_slice tags_profiler tags_deep_profiler
 
 .PHONY: tags_compiler
 tags_compiler:
@@ -259,6 +284,10 @@
 tags_analysis:
 	+cd analysis && $(SUBDIR_MMAKE) tags
 
+.PHONY: tags_slice
+tags_slice:
+	+cd slice && $(SUBDIR_MMAKE) tags
+
 .PHONY: tags_profiler
 tags_profiler:
 	+cd profiler && $(SUBDIR_MMAKE) tags
@@ -273,7 +302,7 @@
 # belong there.
 cleanint:
 	for dir in library mdbcomp browser analysis compiler \
-		profiler deep_profiler; \
+		slice profiler deep_profiler; \
 	do \
 		echo Looking for inappropriate files in the $$dir directory: ; \
 		( cd $$dir && ../tools/cleanint > .cleanint ) ; \
@@ -352,6 +381,8 @@
 	+cd analysis && $(SUBDIR_MMAKE) all-ints cs tags
 	+cd compiler && $(SUBDIR_MMAKE) depend
 	+cd compiler && $(SUBDIR_MMAKE) cs tags
+	+cd slice && $(SUBDIR_MMAKE) depend
+	+cd slice && $(SUBDIR_MMAKE) cs tags
 	+cd profiler && $(SUBDIR_MMAKE) depend
 	+cd profiler && $(SUBDIR_MMAKE) cs tags
 	+cd deep_profiler && $(SUBDIR_MMAKE) depend
@@ -449,8 +480,8 @@
 install_main: all \
 		install_scripts install_util install_runtime install_boehm_gc \
 		install_library install_mdbcomp install_browser install_trace \
-		install_compiler install_profiler install_deep_profiler \
-		install_doc install_config
+		install_compiler install_slice install_profiler \
+		install_deep_profiler install_doc install_config
 
 .PHONY: install_scripts
 install_scripts: scripts
@@ -499,6 +530,10 @@
 install_doc: doc
 	+cd doc && $(SUBDIR_MMAKE) install
 
+.PHONY: install_slice
+install_slice: slice
+	+cd slice && $(SUBDIR_MMAKE) install
+
 .PHONY: install_profiler
 install_profiler: profiler
 	+cd profiler && $(SUBDIR_MMAKE) install
@@ -621,6 +656,9 @@
 	touch compiler/*.date*
 	chmod +w compiler/*.dep
 	touch compiler/*.dep
+	touch slice/*.date*
+	chmod +w slice/*.dep
+	touch slice/*.date*
 	touch profiler/*.date*
 	chmod +w profiler/*.dep
 	touch profiler/*.dep
@@ -636,6 +674,7 @@
 	touch browser/*.c
 	touch trace/*.c
 	touch compiler/*.c
+	touch slice/*.c
 	touch profiler/*.c
 	touch deep_profiler/*.c
 	touch doc/*.info doc/*.dvi doc/*.html config.status
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing browser
Index: browser/dice.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/dice.m,v
retrieving revision 1.3
diff -u -b -r1.3 dice.m
--- browser/dice.m	12 Mar 2005 04:46:30 -0000	1.3
+++ browser/dice.m	30 Mar 2005 05:32:01 -0000
@@ -5,644 +5,7 @@
 %-----------------------------------------------------------------------------%
 % 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 io.
-:- 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
-	).
-
-	% 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.
-
-	% 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_dice_to_string(PassFiles, FailFile, SortStr, N, Module, DiceStr, 
-	% 	Problem, !IO).
-	% Read the trace_counts in the list of files in the file named
-	% PassFiles, interpreting them as passing slices; read the
-	% trace_counts from the file FailFile, interpreting 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 Module is not the empty string then only labels
-	% from the named module will be included in the dice string, otherwise
-	% all modules will be included.  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::in, string::out, string::out, io::di, io::uo) is det.
-
-%-----------------------------------------------------------------------------%
-
-:- implementation.
-
-:- import_module assoc_list.
-:- import_module bool.
-:- import_module char.
-:- import_module float.
-:- import_module int.
-:- 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_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_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([])
-	).
-
-:- pragma export(read_dice_to_string(in, in, in, in, in, out, out, di, uo), 
-	"MR_MDB_read_dice_to_string").
-
-read_dice_to_string(PassFiles, FailFile, SortStr, N, Module, 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),
-				( Module \= "" ->
-					list.filter(label_count_is_for_module(
-						Module), LabelCounts,
-						FilteredLabelCounts)
-				;
-					FilteredLabelCounts = LabelCounts
-				),
-				list.sort(label_count_compare(SortStr), 
-					FilteredLabelCounts, 
-					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 = ""
-	).
-
-:- pred label_count_is_for_module(string::in, label_count::in) is semidet.
-
-label_count_is_for_module(Module, 
-		label_count(proc(_, _, SymDeclModule, _, _, _), _, _)) :-
-	string_to_sym_name(Module, ".", SymModule),
-	is_submodule(SymDeclModule, SymModule).
-label_count_is_for_module(Module, label_count(
-		special_proc(_, _, SymTypeModule, _, _, _), _, _)) :-
-	string_to_sym_name(Module, ".", SymModule),
-	is_submodule(SymTypeModule, SymModule).
-
-	% 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 :-
-	list.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_ratio gives an indication of how likely 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("%.*f", [i(DecimalPlaces), 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, 
-			_, _),
-		Module = sym_name_to_string(SymModule),
-		special_pred_name_arity(SpecialPredId, Name, Arity),
-		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];
-        /* 
-        ** Check if the label occurs in this module.
-        */
-        if (MR_streq(Module, module->MR_ml_name)) {
-            num_files = module->MR_ml_filename_count;
-            /*
-            ** Check each file in the module.
-            */
-            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;
-                /* 
-                ** Check each label in the file.
-                */
-                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;
-                    /*
-                    ** Check if the proc name, arity and mode are the same as
-                    ** the name, arity and mode for the label we are interested
-                    ** in.
-                    */
-                    if (MR_streq(id->MR_user_name, Name) &&
-                            id->MR_user_arity == Arity &&
-                            id->MR_user_mode == ModeNo) {
-                        /*
-                        ** Check if the path/port is the same as the
-                        ** label we are interested in.
-                        */
-                        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) {
-                            /*
-                            ** We have found the label, so return the 
-                            ** filename and line number.
-                            */
-                            filename = file->MR_mfl_filename;
-                            LineNo = file->MR_mfl_label_lineno[label_num];
-                            SUCCESS_INDICATOR = MR_TRUE;
-                            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
-		)
-	).
Index: browser/mdb.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/mdb.m,v
retrieving revision 1.19
diff -u -b -r1.19 mdb.m
--- browser/mdb.m	10 Feb 2005 04:10:27 -0000	1.19
+++ browser/mdb.m	23 Mar 2005 04:30:07 -0000
@@ -22,7 +22,6 @@
 :- 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.
@@ -38,10 +37,6 @@
 :- include_module parse.
 :- include_module sized_pretty.
 :- include_module util.
-:- include_module term_rep.
-
-:- include_module set_cc.
-:- include_module tree234_cc.
 :- include_module term_rep.
 
 	% XXX these modules are more generally useful, but the
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/tupling.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/tupling.m,v
retrieving revision 1.5
diff -u -b -r1.5 tupling.m
--- compiler/tupling.m	24 Mar 2005 05:34:16 -0000	1.5
+++ compiler/tupling.m	31 Mar 2005 08:31:42 -0000
@@ -157,17 +157,16 @@
 		report_warning("Warning: --tuple requires " ++
 			"--tuple-trace-counts-file to work.\n", !IO)
 	;
-		read_trace_counts(TraceCountsFile, Result, !IO),
+		read_trace_counts_source(try_single_first, TraceCountsFile,
+			Result, !IO),
 		(
-			Result = ok(TraceCounts),
+			Result = source_ok(_, TraceCountsList),
+			summarize_trace_counts_list(TraceCountsList,
+				TraceCounts),
 			tuple_arguments_2(!ModuleInfo, TraceCounts, !IO)
 		;
-			Result = error_message(Message),
+			Result = source_error_message(Message),
 			warn_trace_counts_error(TraceCountsFile, Message, !IO)
-		;
-			Result = io_error(IOError),
-			warn_trace_counts_error(TraceCountsFile,
-				io__error_message(IOError), !IO)
 		)
 	).
 
@@ -1880,15 +1879,16 @@
 :- pred get_proc_calls(proc_trace_counts::in, int::out) is det.
 
 get_proc_calls(ProcCounts, Count) :-
-	map__lookup(ProcCounts, port_only(call), Count).
+	map__lookup(ProcCounts, port_only(call), ContextCount),
+	Count = ContextCount ^ exec_count.
 
 :- pred get_path_only_count(proc_trace_counts::in, mdbcomp_goal_path::in,
 	int::out) is det.
 
 get_path_only_count(ProcCounts, GoalPath, Count) :-
 	PathPort = path_only(GoalPath),
-	( map__search(ProcCounts, PathPort, CountPrime) ->
-		Count = CountPrime
+	( map__search(ProcCounts, PathPort, ContextCount) ->
+		Count = ContextCount ^ exec_count
 	;
 		Count = 0
 	).
@@ -1954,15 +1954,14 @@
 	map__foldl(get_switch_total_count_2(MdbGoalPath),
 		ProcCounts, 0, Total).
 
-:- pred get_switch_total_count_2(mdbcomp_goal_path::in, path_port::in, int::in,
-	int::in, int::out) is det.
+:- pred get_switch_total_count_2(mdbcomp_goal_path::in, path_port::in,
+	context_and_count::in, int::in, int::out) is det.
 
-get_switch_total_count_2(SwitchGoalPath, PathPort, Count,
-		TotalAcc0, TotalAcc) :-
+get_switch_total_count_2(SwitchGoalPath, PathPort, ContextCount, !TotalAcc) :-
 	( case_in_switch(SwitchGoalPath, PathPort) ->
-		TotalAcc = TotalAcc0 + Count
+		!:TotalAcc = !.TotalAcc + ContextCount ^ exec_count
 	;
-		TotalAcc = TotalAcc0
+		true
 	).
 
 :- pred case_in_switch(mdbcomp_goal_path::in, path_port::in) is semidet.
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
Index: library/list.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/list.m,v
retrieving revision 1.135
diff -u -b -r1.135 list.m
--- library/list.m	22 Mar 2005 00:48:17 -0000	1.135
+++ library/list.m	31 Mar 2005 02:53:18 -0000
@@ -508,6 +508,42 @@
 :- mode list__map6(pred(in, in, in, in, in, in, in) is semidet, in, in, in, in,
 	in, in, in) is semidet.
 
+	% list__map7(T, L, M1, M2, M3, M4, M5, M6, M7) uses the closure T
+	% to transform the elements of L into the elements of M1, M2, M3, M4, 
+	% M5, M6 and M7.
+:- pred list__map7(pred(A, B, C, D, E, F, G, H), list(A), list(B), list(C), 
+	list(D), list(E), list(F), list(G), list(H)).
+:- mode list__map7(pred(in, out, out, out, out, out, out, out) is det,
+	in, out, out, out, out, out, out, out) is det.
+:- mode list__map7(pred(in, out, out, out, out, out, out, out) is cc_multi,
+	in, out, out, out, out, out, out, out) is cc_multi.
+:- mode list__map7(pred(in, out, out, out, out, out, out, out) is semidet,
+	in, out, out, out, out, out, out, out) is semidet.
+:- mode list__map7(pred(in, out, out, out, out, out, out, out) is multi,
+	in, out, out, out, out, out, out, out) is multi.
+:- mode list__map7(pred(in, out, out, out, out, out, out, out) is nondet,
+	in, out, out, out, out, out, out, out) is nondet.
+:- mode list__map7(pred(in, in, in, in, in, in, in, in) is semidet,
+	in, in, in, in, in, in, in, in) is semidet.
+
+	% list__map8(T, L, M1, M2, M3, M4, M5, M6, M7) uses the closure T
+	% to transform the elements of L into the elements of M1, M2, M3, M4, 
+	% M5, M6, M7 and M8.
+:- pred list__map8(pred(A, B, C, D, E, F, G, H, I), list(A), list(B), list(C), 
+	list(D), list(E), list(F), list(G), list(H), list(I)).
+:- mode list__map8(pred(in, out, out, out, out, out, out, out, out) is det,
+	in, out, out, out, out, out, out, out, out) is det.
+:- mode list__map8(pred(in, out, out, out, out, out, out, out, out) is cc_multi,
+	in, out, out, out, out, out, out, out, out) is cc_multi.
+:- mode list__map8(pred(in, out, out, out, out, out, out, out, out) is semidet,
+	in, out, out, out, out, out, out, out, out) is semidet.
+:- mode list__map8(pred(in, out, out, out, out, out, out, out, out) is multi,
+	in, out, out, out, out, out, out, out, out) is multi.
+:- mode list__map8(pred(in, out, out, out, out, out, out, out, out) is nondet,
+	in, out, out, out, out, out, out, out, out) is nondet.
+:- mode list__map8(pred(in, in, in, in, in, in, in, in, in) is semidet,
+	in, in, in, in, in, in, in, in, in) is semidet.
+
 	% list__map_corresponding(F, [A1, .. An], [B1, .. Bn]) =
 	% 	[F(A1, B1), .., F(An, Bn)].
 	%
@@ -1528,6 +1564,18 @@
 		[H6 | T6]) :-
 	call(P, H0, H1, H2, H3, H4, H5, H6),
 	list__map6(P, T0, T1, T2, T3, T4, T5, T6).
+
+list__map7(_, [], [], [], [], [], [], [], []).
+list__map7(P, [H0 | T0], [H1 | T1], [H2 | T2], [H3 | T3], [H4 | T4], [H5 | T5],
+		[H6 | T6], [H7 | T7]) :-
+	call(P, H0, H1, H2, H3, H4, H5, H6, H7),
+	list__map7(P, T0, T1, T2, T3, T4, T5, T6, T7).
+
+list__map8(_, [], [], [], [], [], [], [], [], []).
+list__map8(P, [H0 | T0], [H1 | T1], [H2 | T2], [H3 | T3], [H4 | T4], [H5 | T5],
+		[H6 | T6], [H7 | T7], [H8 | T8]) :-
+	call(P, H0, H1, H2, H3, H4, H5, H6, H7, H8),
+	list__map8(P, T0, T1, T2, T3, T4, T5, T6, T7, T8).
 
 list__map_corresponding(_, [], []) = [].
 list__map_corresponding(_, [], [_ | _]) =
cvs diff: Diffing mdbcomp
Index: mdbcomp/mdbcomp.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/mdbcomp/mdbcomp.m,v
retrieving revision 1.1
diff -u -b -r1.1 mdbcomp.m
--- mdbcomp/mdbcomp.m	28 Jan 2005 07:11:52 -0000	1.1
+++ mdbcomp/mdbcomp.m	23 Mar 2005 04:09:53 -0000
@@ -22,6 +22,7 @@
 
 :- include_module prim_data.
 :- include_module program_representation.
+:- include_module slice_and_dice.
 :- include_module trace_counts.
 
 :- implementation.
Index: mdbcomp/trace_counts.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/mdbcomp/trace_counts.m,v
retrieving revision 1.4
diff -u -b -r1.4 trace_counts.m
--- mdbcomp/trace_counts.m	6 Mar 2005 05:17:42 -0000	1.4
+++ mdbcomp/trace_counts.m	31 Mar 2005 08:22:07 -0000
@@ -1,4 +1,6 @@
 %-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
+%-----------------------------------------------------------------------------%
 % Copyright (C) 2005 The University of Melbourne.
 % This file may only be copied under the terms of the GNU General
 % Public License - see the file COPYING in the Mercury distribution.
@@ -6,9 +8,10 @@
 %
 % File: trace_counts.m.
 %
-% Author: wangp.
+% Main author: wangp.
+% Modifications by zs.
 %
-% This module defines a predicate to read in the execution trace summaries
+% This module defines predicates to read in the execution trace summaries
 % generated by programs compiled using the compiler's tracing options.
 
 %-----------------------------------------------------------------------------%
@@ -20,25 +23,101 @@
 :- import_module mdbcomp.prim_data.
 :- import_module mdbcomp.program_representation.
 
-:- import_module io, map.
+:- import_module assoc_list.
+:- import_module io.
+:- import_module list.
+:- import_module map.
+:- import_module set.
+
+:- type trace_count_file_type
+    --->    user_all
+            % The file contains counts for all labels from user-defined
+            % procedures.
+
+    ;       user_nonzero.
+            % The file contains counts for all labels from user-defined
+            % procedures, provided the count is nonzero.
 
 :- type trace_counts		== map(proc_label, proc_trace_counts).
 
-:- type proc_trace_counts	== map(path_port, int).
+:- type proc_trace_counts   == map(path_port, context_and_count).
 
 :- type path_port
 	--->	port_only(trace_port)
 	;	path_only(goal_path)
 	;	port_and_path(trace_port, goal_path).
 
+:- type context_and_count
+    --->    context_and_count(
+                file_name   :: string,
+                line_number :: int,
+                exec_count  :: int
+            ).
+
+:- pred summarize_trace_counts_list(list(trace_counts)::in, trace_counts::out)
+    is det.
+
+:- pred sum_trace_counts(trace_counts::in, trace_counts::in, trace_counts::out)
+    is det.
+
+%-----------------------------------------------------------------------------%
+
 :- type read_trace_counts_result
-	--->	ok(trace_counts)
+    --->    ok(trace_count_file_type, trace_counts)
+    ;       syntax_error(string)
 	;	error_message(string)
 	;	io_error(io__error).
 
+    % read_trace_counts(FileName, Result, !IO):
+    %
+    % Read in the trace counts stored in FileName.
+    %
 :- pred read_trace_counts(string::in, read_trace_counts_result::out,
 	io::di, io::uo) is det.
 
+:- type read_trace_counts_list_result
+    --->    list_ok(assoc_list(trace_count_file_type, trace_counts))
+    ;       list_error_message(string).
+
+    % read_trace_counts_list(FileName, Result, !IO):
+    %
+    % 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.
+
+:- type slice_source
+    --->    file_list
+    ;       single_file
+    ;       try_single_first.
+
+:- type read_trace_counts_source_result
+    --->    source_ok(set(trace_count_file_type), list(trace_counts))
+    ;       source_error_message(string).
+
+    % read_trace_counts_source(Source, FileName, Result, !IO):
+    %
+    % Read in trace counts stored in one or more trace count files.
+    %
+    % If Source is file_list, then FileName should contain a list of filenames,
+    % and read_trace_counts_source will read in the trace counts from each
+    % of those files.
+    %
+    % If Source is single_file, then FileName should itself be a file
+    % containing trace counts data.
+    %
+    % If Source is try_single_first, then read_trace_counts_source will
+    % check to see if FileName contains trace counts data. If yes, it will
+    % get trace counts from there. If not, read_trace_counts_source will
+    % interpret FileName as a file that itself contains filenames, and
+    % will treat it as with Source=file_list.
+    %
+    % The list of file types returned will contain the file types of all
+    % the files read during this process.
+    %
+:- pred read_trace_counts_source(slice_source::in, string::in,
+    read_trace_counts_source_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.
@@ -50,54 +129,249 @@
 
 :- implementation.
 
-:- import_module char, exception, int, io, lexer, list, require, std_util.
-:- import_module string, svmap.
+:- import_module char.
+:- import_module exception.
+:- import_module int.
+:- import_module io.
+:- import_module lexer.
+:- import_module require.
+:- import_module std_util.
+:- import_module string.
+:- import_module svmap.
+
+%-----------------------------------------------------------------------------%
+
+summarize_trace_counts_list(TraceCountsList, TraceCounts) :-
+    ( TraceCountsList = [TraceCountsPrime] ->
+        % optimize the common case
+        TraceCounts = TraceCountsPrime
+    ;
+        list.foldl(sum_trace_counts, TraceCountsList, map.init, TraceCounts)
+    ).
+
+sum_trace_counts(TraceCountsA, TraceCountsB, TraceCounts) :-
+    map.union(sum_proc_trace_counts, TraceCountsA, TraceCountsB, TraceCounts).
+
+:- pred sum_proc_trace_counts(proc_trace_counts::in, proc_trace_counts::in,
+    proc_trace_counts::out) is det.
+
+sum_proc_trace_counts(ProcTraceCountsA, ProcTraceCountsB, ProcTraceCounts) :-
+    ProcTraceCounts = map.union(sum_counts_in_context,
+        ProcTraceCountsA, ProcTraceCountsB).
+
+:- func sum_counts_in_context(context_and_count, context_and_count)
+    = context_and_count.
+
+sum_counts_in_context(CC1, CC2) = CC :-
+    % We could add a sanity check that FileName1 = FileName2 and
+    % LineNumber1 = LineNumber2, but that would take time to no good purpose,
+    % since there isn't much we can do to generate a meaningful message,
+    % and that situation doesn't necessarily represent an error anyway.
+    % (Consider the case when the two trace files are derived from sources
+    % that are identical except for the addition of a comment.)
+
+    CC1 = context_and_count(FileName1, LineNumber1, Count1),
+    CC2 = context_and_count(_FileName2, _LineNumber, Count2),
+    CC = context_and_count(FileName1, LineNumber1, Count1 + Count2).
+
+%-----------------------------------------------------------------------------%
+
+read_trace_counts_source(Source, FileName, Result, !IO) :-
+    (
+        Source = file_list,
+        read_trace_counts_list(FileName, ListResult, !IO),
+        (
+            ListResult = list_ok(AssocList),
+            assoc_list__values(AssocList, TraceCounts),
+            assoc_list__keys(AssocList, FileTypeList),
+            set__list_to_set(FileTypeList, FileTypes),
+            Result = source_ok(FileTypes, TraceCounts)
+        ;
+            ListResult = list_error_message(Msg),
+            Result = source_error_message(Msg)
+        )
+    ;
+        Source = single_file,
+        read_trace_counts(FileName, ReadTCResult, !IO),
+        (
+            ReadTCResult = ok(FileType, TraceCount),
+            FileTypes = set__make_singleton_set(FileType),
+            Result = source_ok(FileTypes, [TraceCount])
+        ;
+            ReadTCResult = io_error(IOError),
+            Result = source_error_message("IO error reading file " ++
+                "`" ++ FileName ++ "': " ++ string.string(IOError))
+        ;
+            ReadTCResult = syntax_error(Error),
+            Result = source_error_message("Syntax error in file `" ++
+                FileName ++ "': " ++ Error)
+        ;
+            ReadTCResult = error_message(Message),
+            Result = source_error_message("Error reading trace counts " ++
+                "from file `" ++ FileName ++ "': " ++ Message)
+        )
+    ;
+        Source = try_single_first,
+        read_trace_counts_source(single_file, FileName, TryResult, !IO),
+        (
+            TryResult = source_ok(_, _),
+            Result = TryResult
+        ;
+            TryResult = source_error_message(_),
+            read_trace_counts_source(file_list, FileName, Result, !IO)
+        )
+    ).
+
+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 = list_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),
+        read_trace_counts(FileName, ReadTCResult, !IO),
+        (
+            ReadTCResult = ok(FileType, TraceCount),
+            read_trace_counts_list_stream(MainFileName, Stream, RestResult,
+                !IO),
+            ( RestResult = list_ok(FileTypesTraceCounts) ->
+                Result = list_ok([FileType - TraceCount
+                    | FileTypesTraceCounts])
+            ;
+                Result = RestResult
+            )
+        ;
+            ReadTCResult = io_error(IOError),
+            Result = list_error_message("IO error reading file " ++
+                "`" ++ FileName ++ "': " ++ string.string(IOError))
+        ;
+            ReadTCResult = syntax_error(Error),
+            Result = list_error_message("Syntax error in file `" ++ FileName ++
+                "': " ++ Error)
+        ;
+            ReadTCResult = error_message(Message),
+            Result = list_error_message("Error reading trace counts " ++
+                "from file `" ++ FileName ++ "': " ++ Message)
+        )
+    ;
+        ReadResult = error(Error),
+        Result = list_error_message("IO error reading file " ++ "`" ++
+            MainFileName ++ "': " ++ string.string(Error))
+    ;
+        ReadResult = eof,
+        Result = list_ok([])
+    ).
 
 read_trace_counts(FileName, ReadResult, !IO) :-
-	io__open_input(FileName, Result, !IO),
+    % XXX We should be using zcat here, to avoid deleted the gzipped file
+    % and having to recreate it again. Unfortunately, we don't have any
+    % facilities equivalent to popen in Unix, and I don't know how to
+    % write one in a way that is portable to Windows. zs.
+    ( string__remove_suffix(FileName, ".gz", BaseName) ->
+        io__call_system("gunzip " ++ FileName, _UnzipResult, !IO),
+        ActualFileName = BaseName,
+        GzipCmd = "gzip " ++ BaseName
+    ;
+        ActualFileName = FileName,
+        GzipCmd = ""
+    ),
+    io__open_input(ActualFileName, Result, !IO),
 	(
 		Result = ok(FileStream),
 		io__set_input_stream(FileStream, OldInputStream, !IO),
-		promise_only_solution_io(read_trace_counts_2, ReadResult,
-			!IO),
+        io__read_line_as_string(IdReadResult, !IO),
+        (
+            IdReadResult = ok(FirstLine),
+            FirstLine = trace_count_file_id
+        ->
+            promise_only_solution_io(read_trace_counts_from_cur_stream,
+                ReadResult, !IO)
+        ;
+            ReadResult = syntax_error("no trace count file id")
+        ),
 		io__set_input_stream(OldInputStream, _, !IO),
 		io__close_input(FileStream, !IO)
 	;
 		Result = error(IOError),
 		ReadResult = io_error(IOError)
+    ),
+    ( GzipCmd = "" ->
+        true
+    ;
+        io__call_system(GzipCmd, _ZipResult, !IO)
 	).
 
-:- pred read_trace_counts_2(read_trace_counts_result::out, io::di, io::uo)
-	is cc_multi.
+:- func trace_count_file_id = string.
 
-read_trace_counts_2(ReadResult, !IO) :-
+trace_count_file_id = "Mercury trace counts file\n".
+
+:- pred read_trace_counts_from_cur_stream(read_trace_counts_result::out,
+    io::di, io::uo) is cc_multi.
+
+read_trace_counts_from_cur_stream(ReadResult, !IO) :-
+    io__read_line_as_string(IdResult, !IO),
+    (
+        IdResult = ok(IdStr),
+        (
+            IdStr = "user_all",
+            FileType = user_all
+        ;
+            IdStr = "user_nonzero",
+            FileType = user_nonzero
+        )
+    ->
 	try_io(read_trace_counts_3(map__init), Result, !IO),
 	(
 		Result = succeeded(TraceCounts),
-		ReadResult = ok(TraceCounts)
+            ReadResult = ok(FileType, TraceCounts)
 	;
 		Result = exception(Exception),
 		( Exception = univ(IOError) ->
 			ReadResult = io_error(IOError)
 		; Exception = univ(Message) ->
 			ReadResult = error_message(Message)
+            ; Exception = univ(trace_count_syntax_error(Error)) ->
+                ReadResult = syntax_error(Error)
 		;
-			error("read_trace_counts_2: unexpected exception type")
+                error("read_trace_counts_from_cur_stream: " ++
+                    "unexpected exception type")
 		)
 	;
 		Result = failed,
-		error("read_trace_counts_2: IO failure")
+            error("read_trace_counts_from_cur_stream: IO failure")
+        )
+    ;
+        error("no info on trace count file type")
 	).
 
 :- pred read_trace_counts_3(trace_counts::in, trace_counts::out,
 	io::di, io::uo) is det.
 
 read_trace_counts_3(!TraceCounts, !IO) :-
-	io__get_line_number(LineNum, !IO),
+    io__get_line_number(LineNumber, !IO),
 	io__read_line_as_string(Result, !IO),
 	(
 		Result = ok(Line),
-		read_proc_trace_counts(LineNum, Line, !TraceCounts, !IO)
+        CurFileName = "",
+        read_proc_trace_counts(LineNumber, Line, CurFileName, !TraceCounts,
+            !IO)
 	;
 		Result = eof
 	;
@@ -105,13 +379,26 @@
 		throw(Error)
 	).
 
-:- pred read_proc_trace_counts(int::in, string::in, trace_counts::in,
-	trace_counts::out, io::di, io::uo) is det.
+:- type trace_count_syntax_error
+    --->    trace_count_syntax_error(string).
+
+:- pred read_proc_trace_counts(int::in, string::in, string::in,
+    trace_counts::in, trace_counts::out, io::di, io::uo) is det.
 
-read_proc_trace_counts(HeaderLineNum, HeaderLine, !TraceCounts, !IO) :-
+read_proc_trace_counts(HeaderLineNumber, HeaderLine, CurFileName, !TraceCounts,
+        !IO) :-
 	lexer__string_get_token_list(HeaderLine, string__length(HeaderLine),
-		TokenList, posn(HeaderLineNum, 1, 0), _),
-	(if
+        TokenList, posn(HeaderLineNumber, 1, 0), _),
+    (
+        TokenList =
+            token_cons(name("file"), _,
+            token_cons(name(NextFileName), _,
+            token_nil))
+    ->
+        io__get_line_number(NextHeaderLineNumber, !IO),
+        read_proc_trace_counts(NextHeaderLineNumber, HeaderLine, NextFileName,
+            !TraceCounts, !IO)
+    ;
 		TokenList =
 			token_cons(name("proc"), _,
 			token_cons(name(DefModuleStr), _,
@@ -122,47 +409,49 @@
 			token_cons(integer(Mode), _,
 			token_nil))))))),
 		string_to_pred_or_func(PredOrFuncStr, PredOrFunc)
-	then
+    ->
 		string_to_sym_name(DefModuleStr, ".", DefModuleName),
 		string_to_sym_name(DeclModuleStr, ".", DeclModuleName),
 		% At the moment runtime/mercury_trace_base.c doesn't
-		% write out data for 'special' procedures.
+        % write out data for unify, compare, index or init procedures.
 		ProcLabel = proc(DefModuleName, PredOrFunc, DeclModuleName,
 				Name, Arity, Mode),
 		% For whatever reason some of the trace counts for a single
 		% procedure or function can be split over multiple spans.
 		% We collate them as if they appeared in a single span.
-		(if svmap__remove(ProcLabel, Probe, !TraceCounts) then
-			ProcData = Probe
-		else
-			ProcData = map__init
+        ( svmap__remove(ProcLabel, ProbeCounts, !TraceCounts) ->
+            StartCounts = ProbeCounts
+        ;
+            StartCounts = map__init
 		),
-		read_proc_trace_counts_2(ProcLabel, ProcData, !TraceCounts,
-			!IO)
-	else
+        read_proc_trace_counts_2(ProcLabel, CurFileName, StartCounts,
+            !TraceCounts, !IO)
+    ;
 		string__format("parse error on line %d of execution trace",
-			[i(HeaderLineNum)], Message),
-		throw(Message)
+            [i(HeaderLineNumber)], Message),
+        throw(trace_count_syntax_error(Message))
 	).
 
-:- pred read_proc_trace_counts_2(proc_label::in, proc_trace_counts::in,
-	trace_counts::in, trace_counts::out, io::di, io::uo) is det.
+:- pred read_proc_trace_counts_2(proc_label::in, string::in,
+    proc_trace_counts::in, trace_counts::in, trace_counts::out,
+    io::di, io::uo) is det.
 
-read_proc_trace_counts_2(ProcLabel, ProcCounts0, !TraceCounts, !IO) :-
-	io__get_line_number(LineNum, !IO),
+read_proc_trace_counts_2(ProcLabel, CurFileName, ProcCounts0, !TraceCounts,
+        !IO) :-
 	io__read_line_as_string(Result, !IO),
 	(
 		Result = ok(Line),
-		(if parse_path_port_line(Line, PathPort, Count) then
-			map__det_insert(ProcCounts0, PathPort, Count,
-				ProcCounts),
-			read_proc_trace_counts_2(ProcLabel, ProcCounts,
-				!TraceCounts, !IO)
-		else
-			svmap__det_insert(ProcLabel, ProcCounts0,
-				!TraceCounts),
-			read_proc_trace_counts(LineNum, Line,
+        ( parse_path_port_line(Line, PathPort, ContextLineNumber, Count) ->
+            ContextCount = context_and_count(CurFileName, ContextLineNumber,
+                Count),
+            map__det_insert(ProcCounts0, PathPort, ContextCount, ProcCounts),
+            read_proc_trace_counts_2(ProcLabel, CurFileName, ProcCounts,
 				!TraceCounts, !IO)
+        ;
+            svmap__det_insert(ProcLabel, ProcCounts0, !TraceCounts),
+            io__get_line_number(LineNumber, !IO),
+            read_proc_trace_counts(LineNumber, Line, CurFileName, !TraceCounts,
+                !IO)
 		)
 	;
 		Result = eof,
@@ -172,12 +461,13 @@
 		throw(Error)
 	).
 
-:- pred parse_path_port_line(string::in, path_port::out, int::out) is semidet.
+:- pred parse_path_port_line(string::in, path_port::out, int::out, int::out)
+    is semidet.
 
-parse_path_port_line(Line, PathPort, Count) :-
+parse_path_port_line(Line, PathPort, LineNumber, Count) :-
 	Words = string__words(Line),
 	(
-		Words = [Word1, CountStr],
+        Words = [Word1, CountStr, LineNumberStr],
 		( string_to_trace_port(Word1, Port) ->
 			PathPort = port_only(Port)
 		; Path = string_to_goal_path(Word1) ->
@@ -185,13 +475,15 @@
 		;
 			fail
 		),
-		string__to_int(CountStr, Count)
+        string__to_int(CountStr, Count),
+        string__to_int(LineNumberStr, LineNumber)
 	;
-		Words = [PortStr, PathStr, CountStr],
+        Words = [PortStr, PathStr, CountStr, LineNumberStr],
 		string_to_trace_port(PortStr, Port),
 		Path = string_to_goal_path(PathStr),
 		PathPort = port_and_path(Port, Path),
-		string__to_int(CountStr, Count)
+        string__to_int(CountStr, Count),
+        string__to_int(LineNumberStr, LineNumber)
 	).
 
 :- pred string_to_pred_or_func(string::in, pred_or_func::out) is semidet.
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
Index: runtime/mercury_trace_base.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_trace_base.c,v
retrieving revision 1.65
diff -u -b -r1.65 mercury_trace_base.c
--- runtime/mercury_trace_base.c	31 Mar 2005 04:44:30 -0000	1.65
+++ runtime/mercury_trace_base.c	31 Mar 2005 07:32:34 -0000
@@ -45,6 +45,8 @@
 
 void            (*MR_trace_shutdown)(void) = NULL;
 
+MR_bool         MR_coverage_test_enabled = MR_FALSE;
+
 MR_bool         MR_debug_ever_enabled = MR_FALSE;
 MR_bool         MR_debug_enabled = MR_FALSE;
 MR_bool         MR_trace_count_enabled = MR_FALSE;
@@ -303,6 +305,13 @@
     MR_named_count_port[MR_PORT_NEG_SUCCESS] = PORT_AND_PATH;
     MR_named_count_port[MR_PORT_NEG_FAILURE] = PORT_AND_PATH;
 
+    fprintf(fp, "%s", MR_TRACE_COUNT_FILE_ID);
+    if (MR_coverage_test_enabled) {
+        fprintf(fp, "user_all\n");
+    } else {
+        fprintf(fp, "user_nonzero\n");
+    }
+
     prev_proc = NULL;
     num_modules = MR_module_info_next;
     for (module_num = 0; module_num < num_modules; module_num++) {
@@ -311,14 +320,17 @@
 
         for (file_num = 0; file_num < num_files; file_num++) {
             file = module->MR_ml_module_file_layout[file_num];
+            fprintf(fp, "file ");
+            MR_trace_write_quoted_atom(fp, file->MR_mfl_filename);
+            fprintf(fp, "\n");
             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;
                 label_index = label->MR_sll_label_num_in_module;
                 exec_count = module->MR_ml_label_exec_count[label_index];
-                if (! MR_PROC_LAYOUT_IS_UCI(proc) &&
-                    exec_count > 0 && label_index > 0)
+                if (! MR_PROC_LAYOUT_IS_UCI(proc) && label_index > 0 &&
+                    (exec_count > 0 || MR_coverage_test_enabled))
                 {
                     id = &proc->MR_sle_user;
                     if (proc != prev_proc) {
@@ -344,17 +356,17 @@
                     switch (path_port) {
 
                         case PORT_ONLY:
-                            fprintf(fp, "%s %u\n",
+                            fprintf(fp, "%s %u",
                                 MR_port_names[port], exec_count);
                             break;
 
                         case PATH_ONLY:
-                            fprintf(fp, "<%s> %u\n",
+                            fprintf(fp, "<%s> %u",
                                 MR_label_goal_path(label), exec_count);
                             break;
 
                         case PORT_AND_PATH:
-                            fprintf(fp, "%s <%s> %u\n",
+                            fprintf(fp, "%s <%s> %u",
                                 MR_port_names[port], MR_label_goal_path(label),
                                 exec_count);
                             break;
@@ -364,6 +376,8 @@
                                 "bad path_port");
                             break;
                     }
+
+                    fprintf(fp, " %d\n", file->MR_mfl_label_lineno[label_num]);
 
                     prev_proc = proc;
                 }
Index: runtime/mercury_trace_base.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_trace_base.h,v
retrieving revision 1.46
diff -u -b -r1.46 mercury_trace_base.h
--- runtime/mercury_trace_base.h	31 Mar 2005 04:44:30 -0000	1.46
+++ runtime/mercury_trace_base.h	31 Mar 2005 07:54:02 -0000
@@ -108,8 +108,14 @@
 **
 ** The dummy argument allows this function to be registered with 
 ** MR_register_exception_cleanup.
+**
+** The file can be recognized as a Mercury trace counts file as its first
+** line matches MR_TRACE_COUNT_FILE_ID. The value of that macro should be
+** kept in sync with
 */
 
+#define	MR_TRACE_COUNT_FILE_ID	    "Mercury trace counts file\n"
+
 extern	void	MR_trace_write_label_exec_counts_to_file(void *dummy);
 
 /*
@@ -176,6 +182,14 @@
 extern	MR_bool		MR_debug_ever_enabled;
 
 /*
+** When writing out trace counts at the end of execution, we will write out
+** the identities of labels with zero execution counts if and only if
+** MR_coverage_test_enabled is true.
+*/
+
+extern	MR_bool		MR_coverage_test_enabled;
+
+/*
 ** MR_trace_count_enabled will keep the same value throughout the execution of
 ** the entire program after being set in mercury_wrapper.c to the same value
 ** as MR_debug_enabled. Unlike MR_debug_enabled, it is never reset, so one can
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.146
diff -u -b -r1.146 mercury_wrapper.c
--- runtime/mercury_wrapper.c	31 Mar 2005 07:10:27 -0000	1.146
+++ runtime/mercury_wrapper.c	1 Apr 2005 01:44:39 -0000
@@ -1010,6 +1010,7 @@
 	MR_DEEP_PROF_DEBUG_FILE_OPT,
 	MR_TABLING_STATISTICS_OPT,
 	MR_TRACE_COUNT_OPT,
+	MR_COVERAGE_TEST_OPT,
 	MR_MEM_USAGE_REPORT
 };
 
@@ -1042,6 +1043,7 @@
 	{ "deep-debug-file",		0, 0, MR_DEEP_PROF_DEBUG_FILE_OPT },
 	{ "tabling-statistics",		0, 0, MR_TABLING_STATISTICS_OPT },
 	{ "trace-count",		0, 0, MR_TRACE_COUNT_OPT },
+	{ "coverage-test",		0, 0, MR_COVERAGE_TEST_OPT },
 	{ "mem-usage-report",		0, 0, MR_MEM_USAGE_REPORT }
 };
 
@@ -1237,6 +1239,11 @@
 			break;
 
 		case MR_TRACE_COUNT_OPT:
+			MR_trace_count_enabled = MR_TRUE;
+			break;
+
+		case MR_COVERAGE_TEST_OPT:
+			MR_coverage_test_enabled = MR_TRUE;
 			MR_trace_count_enabled = MR_TRUE;
 			break;
 
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
Index: slice/Mmakefile
===================================================================
RCS file: slice/Mmakefile
diff -N slice/Mmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ slice/Mmakefile	23 Mar 2005 14:48:18 -0000
@@ -0,0 +1,109 @@
+#-----------------------------------------------------------------------------#
+# Copyright (C) 2005 The University of Melbourne. 
+# This file may only be copied under the terms of the GNU General
+# Public Licence - see the file COPYING in the Mercury distribution.
+#-----------------------------------------------------------------------------#
+
+# Mmake - this is Mmake file for building the Mercury slice and dice tools
+
+MERCURY_DIR=..
+LINK_STATIC=yes
+include $(MERCURY_DIR)/Mmake.common
+
+# Module-specific options should go in Mercury.options so they
+# can be found by `mmc --make'.
+include Mercury.options
+
+MAIN_TARGET=all
+MERCURY_MAIN_MODULES=mercury_slice mercury_dice
+
+VPATH = $(MDBCOMP_DIR) $(LIBRARY_DIR)
+
+MCFLAGS = -I $(MDBCOMP_DIR)
+
+#-----------------------------------------------------------------------------#
+
+MLFLAGS += --shared
+MCFLAGS += --linkage shared
+
+#-----------------------------------------------------------------------------#
+
+.PHONY: depend
+depend:	mercury_slice.depend mercury_dice.depend
+
+.PHONY: all
+all:	mercury_slice mercury_dice $(TAGS_FILE_EXISTS)
+
+#-----------------------------------------------------------------------------#
+
+# Add some additional dependencies, so that Mmake knows to remake the
+# slicer and dicer if one of the libraries changes.
+
+ifeq ("$(filter il% java%,$(GRADE))","")        
+mercury_slice: $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
+mercury_slice: $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
+mercury_slice: $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
+mercury_dice: $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
+mercury_dice: $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
+mercury_dice: $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
+# XXX Should also depend on $(BOEHM_GC_DIR)/libgc(_prof).$A, but only
+# if in .gc(.prof) grade.
+endif
+
+$(cs_subdir)mercury_slice_init.c: $(UTIL_DIR)/mkinit
+$(cs_subdir)mercury_dice_init.c: $(UTIL_DIR)/mkinit
+
+#-----------------------------------------------------------------------------#
+
+.PHONY: check
+check:	mercury_slice.check mercury_dice.check
+
+.PHONY: ints 
+ints:	mercury_slice.ints mercury_dice.ints
+
+#-----------------------------------------------------------------------------#
+
+tags:	$(MTAGS) $(mercury_slice.ms) $(mercury_dice.ms) $(LIBRARY_DIR)/*.m
+	$(MTAGS) $(mercury_slice.ms) $(mercury_dice.ms) $(LIBRARY_DIR)/*.m
+
+.PHONY: tags_file_exists
+tags_file_exists:
+	@if test ! -f tags; then echo making tags; \
+	$(MTAGS) $(mercury_slice.ms) $(mercury_dice.ms) $(LIBRARY_DIR)/*.m ; \
+	fi
+
+#-----------------------------------------------------------------------------#
+
+.PHONY: dates
+dates:
+	touch $(mercury_slice.dates) $(mercury_dice.dates)
+
+#-----------------------------------------------------------------------------#
+
+.PHONY: os cs ss ils
+os: $(mercury_slice.os) $(mercury_dice.os) \
+	$(os_subdir)mercury_slice_init.o $(os_subdir)mercury_dice_init.o
+cs: $(mercury_slice.cs) $(mercury_dice.cs) \
+	$(cs_subdir)mercury_slice_init.c $(cs_subdir)mercury_dice_init.c
+ss: $(mercury_slice.ss)$(mercury_dice.ss)
+ils: $(mercury_slice.ils)$(mercury_dice.ils)
+
+#-----------------------------------------------------------------------------#
+
+realclean_local:
+	rm -f tags
+
+#-----------------------------------------------------------------------------#
+
+# Installation targets
+
+.PHONY: install
+install: install_slicer
+
+.PHONY: install_slicer
+install_slice: mercury_slice mercury_dice
+	-[ -d $(INSTALL_MERC_BIN_DIR) ] || mkdir -p $(INSTALL_MERC_BIN_DIR)
+	cp `vpath_find mercury_slice$(EXT_FOR_EXE)` $(INSTALL_MERC_BIN_DIR)
+	cp `vpath_find mercury_dice$(EXT_FOR_EXE)` $(INSTALL_MERC_BIN_DIR)
+
+#-----------------------------------------------------------------------------#
Index: slice/mercury_dice.m
===================================================================
RCS file: slice/mercury_dice.m
diff -N slice/mercury_dice.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ slice/mercury_dice.m	31 Mar 2005 08:31:53 -0000
@@ -0,0 +1,101 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2005 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% Mercury dice tool.
+% Main author: zs.
+%
+%-----------------------------------------------------------------------------%
+
+:- module mercury_dice.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module mdbcomp.
+:- import_module mdbcomp__slice_and_dice.
+
+:- import_module getopt.
+:- import_module list.
+
+%-----------------------------------------------------------------------------%
+
+main(!IO) :-
+	io__command_line_arguments(Args0, !IO),
+	OptionOps = option_ops_multi(short_option, long_option,
+		option_default),
+	getopt__process_options(OptionOps, Args0, Args, GetoptResult),
+	(
+		GetoptResult = ok(OptionTable),
+		(
+			Args = [],
+			usage(!IO)
+		;
+			Args = [_],
+			usage(!IO)
+		;
+			Args = [PassFileName, FailFileName],
+			lookup_string_option(OptionTable, sort, SortStr),
+			lookup_int_option(OptionTable, limit, Limit),
+			lookup_string_option(OptionTable, modulename, Module),
+			read_dice_to_string(PassFileName, FailFileName,
+				SortStr, Limit, Module, DiceStr, Problem, !IO),
+			( Problem = "" ->
+				io__write_string(DiceStr, !IO)
+			;
+				io__write_string(Problem, !IO),
+				io__set_exit_status(1, !IO)
+			)
+		;
+			Args = [_, _, _ | _],
+			usage(!IO)
+		)
+	;
+		GetoptResult = error(GetoptErrorMsg),
+		io__write_string(GetoptErrorMsg, !IO),
+		io__nl(!IO)
+	).
+
+:- pred usage(io::di, io::uo) is det.
+
+usage(!IO) :-
+	io__write_string(
+		"Usage: mdice [-s sortspec] [-l N] [-m module] file1 file2",
+		!IO).
+
+%-----------------------------------------------------------------------------%
+
+:- type option	
+	--->	sort
+	;	limit
+	;	modulename.
+
+:- type option_table == option_table(option).
+		
+:- pred short_option(character::in, option::out) is semidet.
+:- pred long_option(string::in, option::out) is semidet.
+:- pred option_default(option::out, option_data::out) is multi.
+
+option_default(sort,		string("")).
+option_default(limit,		int(100)).
+option_default(modulename,	string("")).
+
+short_option('s',		sort).
+short_option('l',		limit).
+short_option('m',		modulename).
+
+long_option("sort",		sort).
+long_option("limit",		limit).
+long_option("module",		modulename).
+
+%-----------------------------------------------------------------------------%
Index: slice/mercury_slice.m
===================================================================
RCS file: slice/mercury_slice.m
diff -N slice/mercury_slice.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ slice/mercury_slice.m	31 Mar 2005 08:31:53 -0000
@@ -0,0 +1,95 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2005 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% Mercury slice tool.
+%
+%-----------------------------------------------------------------------------%
+
+:- module mercury_slice.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module mdbcomp.
+:- import_module mdbcomp__slice_and_dice.
+
+:- import_module getopt.
+:- import_module list.
+
+main(!IO) :-
+	io__command_line_arguments(Args0, !IO),
+	OptionOps = option_ops_multi(short_option, long_option,
+		option_default),
+	getopt__process_options(OptionOps, Args0, Args, GetoptResult),
+	(
+		GetoptResult = ok(OptionTable),
+		(
+			Args = [],
+			usage(!IO)
+		;
+			Args = [FileName],
+			lookup_string_option(OptionTable, sort, SortStr),
+			lookup_int_option(OptionTable, limit, Limit),
+			lookup_string_option(OptionTable, modulename, Module),
+			read_slice_to_string(FileName, SortStr, Limit, Module,
+				SliceStr, Problem, !IO),
+			( Problem = "" ->
+				io__write_string(SliceStr, !IO)
+			;
+				io__write_string(Problem, !IO),
+				io__set_exit_status(1, !IO)
+			)
+		;
+			Args = [_, _ | _],
+			usage(!IO)
+		)
+	;
+		GetoptResult = error(GetoptErrorMsg),
+		io__write_string(GetoptErrorMsg, !IO),
+		io__nl(!IO)
+	).
+
+:- pred usage(io::di, io::uo) is det.
+
+usage(!IO) :-
+	io__write_string(
+		"Usage: mslice [-s sortspec] [-l N] [-m module] filename",
+		!IO).
+
+%-----------------------------------------------------------------------------%
+
+:- type option	
+	--->	sort
+	;	limit
+	;	modulename.
+
+:- type option_table == option_table(option).
+		
+:- pred short_option(character::in, option::out) is semidet.
+:- pred long_option(string::in, option::out) is semidet.
+:- pred option_default(option::out, option_data::out) is multi.
+
+option_default(sort,		string("")).
+option_default(limit,		int(100)).
+option_default(modulename,	string("")).
+
+short_option('s',		sort).
+short_option('l',		limit).
+short_option('m',		modulename).
+
+long_option("sort",		sort).
+long_option("limit",		limit).
+long_option("module",		modulename).
+
+%-----------------------------------------------------------------------------%
cvs diff: Diffing tests
Index: tests/run_one_test
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/run_one_test,v
retrieving revision 1.1
diff -u -b -r1.1 run_one_test
--- tests/run_one_test	24 Mar 2005 01:58:08 -0000	1.1
+++ tests/run_one_test	31 Mar 2005 03:28:06 -0000
@@ -55,7 +55,7 @@
                     if test -s "$counts_file"
                     then
                         name=`echo "$counts_file" | \
-                            sed -e 's/.mercury_trace_counts//'`
+                            sed -e 's/.mercury_trace_counts.//'`
                         mkdir -p $tests_dir/FAILED_TC_DIR
                         mv $counts_file \
                             $tests_dir/FAILED_TC_DIR/$counts_file.$name
@@ -81,12 +81,10 @@
                         name=`echo "$counts_file" | \
                             sed -e 's/.mercury_trace_counts//'`
                         mkdir -p $tests_dir/PASSED_TC_DIR
-                        mv $counts_file \
-                            $tests_dir/PASSED_TC_DIR/$counts_file.$name
-                        /bin/rm -f \
-                            $tests_dir/PASSED_TC_DIR/$counts_file.$name.gz
-                        gzip $tests_dir/PASSED_TC_DIR/$counts_file.$name
-                        echo $tests_dir/PASSED_TC_DIR/$counts_file.$name \
+                        mv $counts_file $tests_dir/PASSED_TC_DIR/$name
+                        /bin/rm -f $tests_dir/PASSED_TC_DIR/$name.gz
+                        gzip $tests_dir/PASSED_TC_DIR/$name
+                        echo $tests_dir/PASSED_TC_DIR/$name \
                             >> $tests_dir/PASSED_TC_FILES
                     fi
                 done
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.198
diff -u -b -r1.198 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	31 Mar 2005 04:44:33 -0000	1.198
+++ trace/mercury_trace_internal.c	31 Mar 2005 05:06:45 -0000
@@ -38,7 +38,7 @@
 #include "mdb.browser_info.mh"
 #include "mdb.declarative_execution.mh"
 #include "mdbcomp.program_representation.mh"
-#include "mdb.dice.mh"
+#include "mdbcomp.slice_and_dice.mh"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -91,15 +91,10 @@
 #define MR_NUMBER_LEN       80
 
 /*
-** The maximum size of a sort string for the `dice' command
-*/
-
-#define MR_MAX_DICE_SORT_STR_SIZE   10
-
-/*
-** The default number of lines to display for a dice.
+** The default number of lines to display for a slice or dice.
 */
 
+#define MR_DEFAULT_SLICE_LINES  50
 #define MR_DEFAULT_DICE_LINES   50
 
 #define MDBRC_FILENAME      ".mdbrc"
@@ -196,18 +191,20 @@
 static  MR_bool     MR_print_optionals = MR_FALSE;
 
 /*
-** This variable holds the name of a file which contains a list of
-** the file names of passing test case trace counts.
+** This variable holds either the name of a file which contains a list of
+** the file names of passing test case trace counts, or the name of a single
+** file 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.
+** This variable holds either the name of a file which contains a list of
+** the file names of failing test case trace counts, or the name of a single
+** file of failing test case trace counts.
 */
 
-static  char        *MR_dice_fail_trace_count_file = NULL;
+static  char        *MR_dice_fail_trace_counts_file = NULL;
 
 /*
 ** MR_context_position specifies whether we print context at events,
@@ -516,6 +513,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_slice;
 static  MR_TraceCmdFunc MR_trace_cmd_dice;
 
 static  void        MR_maybe_print_spy_point(int slot, const char *problem);
@@ -589,7 +587,7 @@
                         const char **server_cmd, const char **server_name,
                         int *timeout, MR_bool *force, MR_bool *verbose,
                         MR_bool *split, MR_bool *close_window, char ***words,
-                        int *word_count, const char *cat, const char*item);
+                        int *word_count, const char *cat, const char *item);
 static  MR_bool     MR_trace_options_dd(MR_bool *assume_all_io_is_tabled,
                         MR_Integer *depth_step_size,
                         MR_Decl_Search_Mode *search_mode, MR_bool *new_session,
@@ -607,6 +605,10 @@
 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_slice(char **trace_counts_file,
+                        char **sort_str, int *number_of_lines, char **out_file,
+                        char **module, 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 *number_of_lines, char **out_file, char **module,
@@ -617,6 +619,9 @@
 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_slice(char *trace_counts_file,
+                        char *sort_str, int number_of_lines, char *out_str,
+                        char *module);
 static  void        MR_trace_print_dice(char *pass_trace_counts_file,
                         char *fail_trace_counts_file, char *sort_str,
                         int number_of_lines, char *out_str, char *module);
@@ -2337,26 +2342,24 @@
     MR_Word             verbose_format;
     MR_Word             pretty_format;
 
-    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);
+    if (word_count == 3 &&
+        ( MR_streq(words[1], "fail_trace_count")
+        || MR_streq(words[1], "fail_trace_counts")))
+    {
+        if (MR_dice_fail_trace_counts_file != NULL) {
+            free(MR_dice_fail_trace_counts_file);
+        }
+
+        MR_dice_fail_trace_counts_file = MR_copy_string(words[2]);
+    } else if (word_count == 3 &&
+        ( MR_streq(words[1], "pass_trace_count")
+        || MR_streq(words[1], "pass_trace_counts")))
+    {
+        if (MR_dice_pass_trace_counts_file != NULL) {
+            free(MR_dice_pass_trace_counts_file);
         }
-        strcpy(MR_dice_pass_trace_counts_file, words[2]);
+
+        MR_dice_pass_trace_counts_file = MR_copy_string(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, "misc", "set"))
@@ -5851,23 +5854,90 @@
 }
 
 static MR_Next
+MR_trace_cmd_slice(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+    MR_Event_Info *event_info, MR_Event_Details *event_details,
+    MR_Code **jumpaddr)
+{
+    char    *trace_counts_file;
+    char    *sort_str;
+    char    *out_file;
+    char    *module;
+    int     number_of_lines;
+
+    sort_str = NULL;
+    out_file = NULL;
+    module = NULL;
+    number_of_lines = MR_DEFAULT_SLICE_LINES;
+
+    trace_counts_file = NULL;
+
+    if (! MR_trace_options_slice(&trace_counts_file, &sort_str,
+        &number_of_lines, &out_file, &module, &words, &word_count,
+        "exp", "slice"))
+    {
+        ; /* the usage message has already been printed */
+    } else if (word_count == 1) {
+        if (trace_counts_file == NULL) {
+            fflush(MR_mdb_out);
+            fprintf(MR_mdb_err, "mdb: No trace counts file specified.\n"
+                "mdb: Specify one with the -f option.\n");
+        } else {
+            if (sort_str == NULL) {
+                sort_str = MR_copy_string("");
+            }
+
+            if (out_file == NULL) {
+                out_file = MR_copy_string("");
+            }
+
+            if (module == NULL) {
+                module = MR_copy_string("");
+            }
+
+            MR_trace_print_slice(trace_counts_file, sort_str, number_of_lines,
+                out_file, module);
+        }
+    } else {
+        MR_trace_usage("exp", "slice");
+    }
+
+    if (out_file != NULL) {
+        free(out_file);
+    }
+
+    if (sort_str != NULL) {
+        free(sort_str);
+    }
+
+    if (module != NULL) {
+        free(module);
+    }
+
+    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;
-    char    *module = NULL;
-    int     number_of_lines = MR_DEFAULT_DICE_LINES;
+    char    *fail_trace_counts_file;
+    char    *sort_str;
+    char    *out_file;
+    char    *module;
+    int     number_of_lines;
+
+    sort_str = NULL;
+    out_file = NULL;
+    module = NULL;
+    number_of_lines = MR_DEFAULT_DICE_LINES;
 
     pass_trace_counts_file = MR_dice_pass_trace_counts_file;
-    fail_trace_count_file = MR_dice_fail_trace_count_file;
-    strcpy(sort_str, "");
+    fail_trace_counts_file = MR_dice_fail_trace_counts_file;
 
     if (! MR_trace_options_dice(&pass_trace_counts_file,
-        &fail_trace_count_file, &sort_str, &number_of_lines, &out_file,
+        &fail_trace_counts_file, &sort_str, &number_of_lines, &out_file,
             &module, &words, &word_count, "exp", "dice"))
     {
         ; /* the usage message has already been printed */
@@ -5877,21 +5947,39 @@
             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) {
+        } else if (fail_trace_counts_file == NULL) {
             fflush(MR_mdb_out);
-            fprintf(MR_mdb_err, "mdb: No failing trace count file specified."
+            fprintf(MR_mdb_err, "mdb: No failing trace counts 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,
+            if (sort_str == NULL) {
+                sort_str = MR_copy_string("");
+            }
+
+            if (out_file == NULL) {
+                out_file = MR_copy_string("");
+            }
+
+            if (module == NULL) {
+                module = MR_copy_string("");
+            }
+
+            MR_trace_print_dice(pass_trace_counts_file, fail_trace_counts_file,
                 sort_str, number_of_lines, out_file, module);
         }
     } else {
         MR_trace_usage("exp", "dice");
     }
 
+    if (out_file != NULL) {
     free(out_file);
+    }
+
+    if (sort_str != NULL) {
     free(sort_str);
+    }
+
     if (module != NULL) {
         free(module);
     }
@@ -5900,6 +5988,58 @@
 }
 
 static  void
+MR_trace_print_slice(char *trace_counts_file, char *sort_str,
+    int number_of_lines, char *out_file, char *module)
+{
+    MR_String   slice;
+    MR_String   problem;
+    MR_String   aligned_trace_counts_file;
+    MR_String   aligned_sort_str;
+    MR_String   aligned_module;
+    FILE        *fp;
+
+    MR_TRACE_USE_HP(
+        MR_make_aligned_string(aligned_trace_counts_file,
+            (MR_String) trace_counts_file);
+        MR_make_aligned_string(aligned_sort_str, (MR_String) sort_str);
+        if (module == NULL) {
+            MR_make_aligned_string(aligned_module, (MR_String) "");
+        } else {
+            MR_make_aligned_string(aligned_module, (MR_String) module);
+        }
+    );
+
+    MR_TRACE_CALL_MERCURY(
+        MR_MDB_read_slice_to_string(aligned_trace_counts_file,
+            aligned_sort_str, number_of_lines, aligned_module,
+            &slice, &problem);
+    );
+
+    if (MR_streq(problem, "")) {
+        if (out_file == NULL) {
+            fprintf(MR_mdb_out, "%s\n", slice);
+        } else {
+            fp = fopen(out_file, "w");
+            if (fp != NULL) {
+                fprintf(fp, slice);
+                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_trace_print_dice(char *pass_trace_counts_file,
     char *fail_trace_count_file, char *sort_str, int number_of_lines,
     char *out_file, char *module)
@@ -6980,9 +7120,68 @@
     return MR_TRUE;
 }
 
+static struct MR_option MR_trace_slice_opts[] =
+{
+    { "file",                   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' },
+    { "module",                 MR_required_argument,   NULL,   'm' },
+    { NULL,                     MR_no_argument,         NULL,   0   }
+};
+
+static MR_bool
+MR_trace_options_slice(char **trace_counts_file, char **sort_str, int *n,
+    char **out_file, char **module, char ***words, int *word_count,
+    const char *cat, const char *item)
+{
+    int c;
+
+    MR_optind = 0;
+    while ((c = MR_getopt_long(*word_count, *words, "f:s:n:o:m:",
+        MR_trace_slice_opts, NULL)) != EOF)
+    {
+        switch (c) {
+
+            case 'f':
+                *trace_counts_file = MR_copy_string(MR_optarg);
+                break;
+
+            case 's':
+                *sort_str = MR_copy_string(MR_optarg);
+                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 = MR_copy_string(MR_optarg);
+                break;
+
+            case 'm':
+                *module = MR_copy_string(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_dice_opts[] =
 {
     { "pass-trace-counts",      MR_required_argument,   NULL,   'p' },
+    { "pass-trace-count",       MR_required_argument,   NULL,   'p' },
+    { "fail-trace-counts",      MR_required_argument,   NULL,   'f' },
     { "fail-trace-count",       MR_required_argument,   NULL,   'f' },
     { "sort",                   MR_required_argument,   NULL,   's' },
     { "top",                    MR_required_argument,   NULL,   'n' },
@@ -6993,7 +7192,7 @@
 
 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 **fail_trace_counts_file, char **sort_str, int *n, char **out_file,
     char **module, char ***words, int *word_count, const char *cat,
     const char *item)
 {
@@ -7006,36 +7205,33 @@
         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);
+                /*
+                ** Don't free *pass_trace_counts_file even if non-NULL,
+                ** since its initial value comes from a global variable,
+                ** and thus will still be used after the dice command.
+                ** The waste of not freeing of the string allocated by
+                ** MR_copy_string if this option is duplicated can be
+                ** easily lived with.
+                */
+
+                *pass_trace_counts_file = MR_copy_string(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);
+                /*
+                ** Don't free *fail_trace_counts_file even if non-NULL,
+                ** since its initial value comes from a global variable,
+                ** and thus will still be used after the dice command.
+                ** The waste of not freeing of the string allocated by
+                ** MR_copy_string if this option is duplicated can be
+                ** easily lived with.
+                */
+
+                *fail_trace_counts_file = MR_copy_string(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;
-                }
+                *sort_str = MR_copy_string(MR_optarg);
                 break;
 
             case 'n':
@@ -7046,13 +7242,11 @@
                 break;
 
             case 'o':
-                *out_file = (char*)malloc(strlen(MR_optarg) + 1);
-                strcpy(*out_file, MR_optarg);
+                *out_file = MR_copy_string(MR_optarg);
                 break;
 
             case 'm':
-                *module = (char*)malloc(strlen(MR_optarg) + 1);
-                strcpy(*module, MR_optarg);
+                *module = MR_copy_string(MR_optarg);
                 break;
 
             default:
@@ -8101,6 +8295,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", "slice", MR_trace_cmd_slice,
         NULL, MR_trace_null_completer },
     { "exp", "dice", MR_trace_cmd_dice,
         NULL, MR_trace_null_completer },
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
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