[m-rev.] for review: coverage testing

Zoltan Somogyi zs at csse.unimelb.edu.au
Mon Sep 18 14:55:25 AEST 2006


For review by anyone.

Zoltan.

Implement coverage testing. There is still at least one bug that prevents us
from succcessfully coverage testing the compiler, but the system ought to work
for smaller programs, and people have been asking for this capability.

The main problem tackled in this diff is that coverage testing requires
gathering information from a lot of program executions, and the execution count
files for all these executions require a huge amount of disk space. We now
therefore put a limit on the number of files we keep; when this limit is
exceeded, the program execution that reaches the limit will automatically
summarize all these files back into a single file before it exits.

This diff also tackles the same problem along a different axis by changing
the format of execution count files to make them smaller. One way is to factor
out and represent just once some information that is common to many procedures:
the file name and the module name. Another is to abbreviate some keywords,
e.g. "fproc" instead of "proc function". The third is not to write out the
defining module's name unless it differs from the declaring module's name,
which it almost never does. (The two differ only when the compiler is invoked
with intermodule optimization, and creates a specialized version of a predicate
in a module other than its home module.)

When doing coverage testing of the compiler, the compiler *must* be in a debug
grade. However, the tools for summarizing trace files, invoked from the
compiler executable when the compiler is being coverage tested, *cannot* be
in debug grade, because debug grade disables tail recursion, and without tail
recursion the summarization program runs out of stack space. This diff
therefore arranges for the slice directory to not be affected by the parameters
applying to the rest of the workspace (including the top level Mmake.params).

Mmakefile:
	Don't apply the top level mmake's parameters to recursive mmakes in
	the slice directory.

	Factor out some common code.

mdbcomp/trace_counts.m:
	Update the parsing code to parse the new format for trace count files,
	and update the code for writing out trace counts to generate the new
	format.

	Replace the proc_label_and_filename type with the proc_label_in_context
	type, which makes it easier to keep track of the current module as well
	as the current file (this is required by the new, more compact format
	for trace count files).

	When considering the union of multiple trace counts files, keep track
	of whether they contained all counts or just the nonzero counts. This
	requires keeping track of this info for single files as well.

	Provide ways to represent and to compute differences between trace
	count files, to support the new program in slice/mtc_diff.m.

mdbcomp/slice_and_dice.m:
	Reformat to conform to our Mercury style guide.

	Conform to the change to trace_counts.m.

compiler/tupling.m:
	Conform to the change to mdbcomp.

runtime/mercury_wrapper.c:
	Implement the new option values used to implement coverage testing.
	These allow control of the limit on the number of execution count
	files, and collecting execution counts only from a specified
	executable.

	Add MR_ prefixes.

runtime/mercury_trace_base.[ch]:
	Provide the mechanism for summarizing execution counts when we reach
	the limit on the number of execution counts files.

	Update the code that writes out trace counts files to generate
	the new format for trace counts files. Make this code take the boolean
	that says whether to include labels with zero counts in the output
	as an explicit parameter, not as a global variable.

	Break up an excessively large function.

scripts/mtc:
	Add the options needed to control the process of automatic
	summarization of trace counts files.

slice/.mgnuc_copts:
slice/.mgnuc_opts:
slice/SLICE_FLAGS.in:
	Make these files empty, since we don't want to refer to the rest of the
	workspace. (We could delete them as well, but CVS doesn't handle
	resurrection of deleted files very well, and we don't want to burn any
	bridges.)

slice/Mmakefile:
	Add the new executables, and make the code in this directory
	independent of the other directories in the workspace.

	Since we need the code of the modules in the mdbcomp directory
	but don't want to link to the object files in that directory (since
	the grades may differ), make copies of those modules in this directory.

slice/mtc.m:
	Add this module, the code for the Mercury coverage test tool.

slice/mtc_diff.m:
	Add this module, the code for computing the diff between two trace
	counts files. The intended use is to compare two trace counts files
	dumped at different stages of execution. (Since foreign_procs can be
	used to invoke the C functions in the runtime tghat write out the trace
	counts files in the middle of a program's execution, not just the end.)

slice/mdice.m:
slice/mslice.m:
slice/mtc_union.m:
	Convert to four space indentation.

tools/bootcheck:
	Since the slice directory's grade is independent of the grade of the
	other directories, don't copy it to the stage2 and stage3 by default.
	If it is copied, then still compile it (and otherwise handle it)
	separate from the other directories.

	Add an option for gathering coverage test data during bootchecking.

cvs diff: Diffing .
Index: Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/Mmakefile,v
retrieving revision 1.112
diff -u -b -r1.112 Mmakefile
--- Mmakefile	11 Aug 2005 15:56:57 -0000	1.112
+++ Mmakefile	24 Mar 2006 14:18:52 -0000
@@ -52,6 +52,17 @@
 		MMAKE_DIR=../../scripts \
 		../../scripts/mmake $(MMAKEFLAGS)
 
+# Note that we compile the slice directory using the version of mmc,
+# mmake etc that we find in $PATH. We don't want to override this mmc
+# with the one in scripts, since that one will probably refer to a
+# nonexistent executable in /usr/local/mercury-DEV. This is why actions
+# referring to the slice directory should use $(PLAIN_SUBDIR_MMAKE)
+# instead of $(SUBDIR_MMAKE).
+
+PLAIN_SUBDIR_MMAKE = unset MMAKE; unset MMAKE_VPATH; unset MMAKE_DIR; \
+		unset MERCURY_CONFIG_DIR; unset MERCURY_STDLIB_DIR; \
+		mmake $(MMAKEFLAGS)
+
 GENERATED_DOCS = README INSTALL WORK_IN_PROGRESS TODO
 
 # If you change these, you will also need to change the files indicated
@@ -117,24 +128,18 @@
 	+cd compiler && $(SUBDIR_MMAKE) depend
 
 .PHONY: dep_slice
-dep_slice: slice/$(deps_subdir)mslice.dep \
+dep_slice: slice/$(deps_subdir)mct.dep \
+	slice/$(deps_subdir)mslice.dep \
 	slice/$(deps_subdir)mdice.dep \
-	slice/$(deps_subdir)mtc_union.dep
+	slice/$(deps_subdir)mtc_union.dep \
+	slice/$(deps_subdir)mtc_diff.dep
 
-slice/$(deps_subdir)mslice.dep: \
-		library/$(deps_subdir)$(STD_LIB_NAME).dep \
-		mdbcomp/$(deps_subdir)$(MDBCOMP_LIB_NAME).dep
-	+cd slice && $(SUBDIR_MMAKE) mslice.depend
-
-slice/$(deps_subdir)mdice.dep: \
-		library/$(deps_subdir)$(STD_LIB_NAME).dep \
-		mdbcomp/$(deps_subdir)$(MDBCOMP_LIB_NAME).dep
-	+cd slice && $(SUBDIR_MMAKE) mdice.depend
-
-slice/$(deps_subdir)mtc_union.dep: \
-		library/$(deps_subdir)$(STD_LIB_NAME).dep \
-		mdbcomp/$(deps_subdir)$(MDBCOMP_LIB_NAME).dep
-	+cd slice && $(SUBDIR_MMAKE) mtc_union.depend
+slice/$(deps_subdir)mct.dep \
+slice/$(deps_subdir)mslice.dep \
+slice/$(deps_subdir)mdice.dep \
+slice/$(deps_subdir)mtc_union.dep \
+slice/$(deps_subdir)mtc_diff.dep:
+	+cd slice && $(PLAIN_SUBDIR_MMAKE) depend
 
 .PHONY: dep_profiler
 dep_profiler: profiler/$(deps_subdir)mercury_profile.dep
@@ -167,15 +172,9 @@
 # depend_library MUST be done before depend_compiler and depend_profiler
 
 .PHONY: depend
-depend:
-	+cd library && $(SUBDIR_MMAKE) depend
-	+cd mdbcomp && $(SUBDIR_MMAKE) depend
-	+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
+depend: depend_library depend_mdbcomp depend_browser \
+		depend_analysis depend_compiler \
+		depend_slice depend_profiler depend_deep_profiler
 
 .PHONY: depend_library
 depend_library:
@@ -189,13 +188,17 @@
 depend_browser:
 	+cd browser && $(SUBDIR_MMAKE) depend
 
+.PHONY: depend_analysis
+depend_analysis:
+	+cd analysis && $(SUBDIR_MMAKE) depend
+
 .PHONY: depend_compiler
 depend_compiler:
 	+cd compiler && $(SUBDIR_MMAKE) depend
 
 .PHONY: depend_slice
 depend_slice:
-	+cd slice && $(SUBDIR_MMAKE) depend
+	+cd slice && $(PLAIN_SUBDIR_MMAKE) depend
 
 .PHONY: depend_profiler
 depend_profiler:
@@ -267,9 +270,8 @@
 	+cd doc && $(SUBDIR_MMAKE)
 
 .PHONY: slice
-slice: dep_slice scripts util boehm_gc runtime library \
-		mdbcomp browser trace
-	+cd slice && $(SUBDIR_MMAKE)
+slice: dep_slice
+	+cd slice && $(PLAIN_SUBDIR_MMAKE)
 
 .PHONY: profiler
 profiler: dep_profiler scripts util boehm_gc runtime library \
@@ -309,7 +311,7 @@
 
 .PHONY: tags_slice
 tags_slice:
-	+cd slice && $(SUBDIR_MMAKE) tags
+	+cd slice && $(PLAIN_SUBDIR_MMAKE) tags
 
 .PHONY: tags_profiler
 tags_profiler:
@@ -404,8 +406,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 slice && $(PLAIN_SUBDIR_MMAKE) depend
+	+cd slice && $(PLAIN_SUBDIR_MMAKE) cs tags
 	+cd profiler && $(SUBDIR_MMAKE) depend
 	+cd profiler && $(SUBDIR_MMAKE) cs tags
 	+cd deep_profiler && $(SUBDIR_MMAKE) depend
@@ -553,9 +555,19 @@
 install_doc: doc
 	+cd doc && $(SUBDIR_MMAKE) install
 
+# We can't leave the install actions for the slice directory to be executed
+# directly from slice/Mmakefile, since slice/Mmakefile doesn't have access
+# to the value of $(INSTALL_MERC_BIN_DIR).
+
 .PHONY: install_slice
 install_slice: slice
-	+cd slice && $(SUBDIR_MMAKE) install
+	-[ -d $(INSTALL_MERC_BIN_DIR) ] || mkdir -p $(INSTALL_MERC_BIN_DIR)
+	+cd slice &&							\
+	mmake PROGS &&							\
+	for prog in `cat PROGS` ; do					\
+		cp `vpath_find $$prog$(EXT_FOR_EXE)` 			\
+			$(INSTALL_MERC_BIN_DIR)/$$prog$(EXT_FOR_EXE);	\
+	done
 
 .PHONY: install_profiler
 install_profiler: profiler
Index: configure.in
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/configure.in,v
retrieving revision 1.471
diff -u -b -r1.471 configure.in
--- configure.in	10 Sep 2006 23:38:53 -0000	1.471
+++ configure.in	10 Sep 2006 23:41:10 -0000
@@ -4360,7 +4360,6 @@
 mdbcomp/MDBCOMP_FLAGS
 browser/MDB_FLAGS
 analysis/ANALYSIS_FLAGS
-slice/SLICE_FLAGS
 profiler/PROF_FLAGS
 deep_profiler/DEEP_FLAGS
 "$test_flags"
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/libatomic_ops-1.2
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/doc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/tests
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing boehm_gc/windows-untested
cvs diff: Diffing boehm_gc/windows-untested/vc60
cvs diff: Diffing boehm_gc/windows-untested/vc70
cvs diff: Diffing boehm_gc/windows-untested/vc71
cvs diff: Diffing browser
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.29
diff -u -b -r1.29 tupling.m
--- compiler/tupling.m	16 Sep 2006 10:46:40 -0000	1.29
+++ compiler/tupling.m	18 Sep 2006 03:18:30 -0000
@@ -946,8 +946,9 @@
         proc_id_to_int(ProcId)),
     pred_info_context(PredInfo, Context),
     Context = context(FileName, _),
-    ProcLabelAndFile = proc_label_and_filename(ProcLabel, FileName),
-    ( get_proc_counts(TraceCounts, ProcLabelAndFile, yes(ProcCounts)) ->
+    ProcLabelInContext = proc_label_in_context(pred_info_module(PredInfo),
+        FileName, ProcLabel),
+    ( get_proc_counts(TraceCounts, ProcLabelInContext, yes(ProcCounts)) ->
         count_load_stores_in_proc(count_info(PredProcId, ProcInfo,
             ModuleInfo, ProcCounts, TuningParams, TuplingScheme),
             ProcLoads, ProcStores),
@@ -1858,11 +1859,11 @@
 :- type mdbcomp_goal_path
     == mdbcomp.program_representation.goal_path.
 
-:- pred get_proc_counts(trace_counts::in, proc_label_and_filename::in,
+:- pred get_proc_counts(trace_counts::in, proc_label_in_context::in,
     maybe(proc_trace_counts)::out) is det.
 
-get_proc_counts(TraceCounts, ProcLabelAndFile, MaybeProcCounts) :-
-    ( map.search(TraceCounts, ProcLabelAndFile, ProcCounts) ->
+get_proc_counts(TraceCounts, ProcLabelInContext, MaybeProcCounts) :-
+    ( map.search(TraceCounts, ProcLabelInContext, ProcCounts) ->
         MaybeProcCounts = yes(ProcCounts)
     ;
         MaybeProcCounts = no
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing debian/patches
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
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/gator
cvs diff: Diffing extras/gator/generations
cvs diff: Diffing extras/gator/generations/1
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/solver_types
cvs diff: Diffing extras/solver_types/library
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/windows_installer_generator
cvs diff: Diffing extras/windows_installer_generator/sample
cvs diff: Diffing extras/windows_installer_generator/sample/images
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
cvs diff: Diffing mdbcomp
Index: mdbcomp/mdbcomp.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/mdbcomp/mdbcomp.m,v
retrieving revision 1.5
diff -u -b -r1.5 mdbcomp.m
--- mdbcomp/mdbcomp.m	8 Jun 2006 08:19:53 -0000	1.5
+++ mdbcomp/mdbcomp.m	8 Jun 2006 08:21:50 -0000
@@ -22,6 +22,7 @@
 
 :- pred mdbcomp.version(string::out) is det.
 
+% If you add any modules here, you should update the list in slice/Mmakefile.
 :- include_module prim_data.
 :- include_module program_representation.
 :- include_module rtti_access.
Index: mdbcomp/slice_and_dice.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/mdbcomp/slice_and_dice.m,v
retrieving revision 1.8
diff -u -b -r1.8 slice_and_dice.m
--- mdbcomp/slice_and_dice.m	14 Sep 2006 00:49:43 -0000	1.8
+++ mdbcomp/slice_and_dice.m	14 Sep 2006 02:58:35 -0000
@@ -26,8 +26,8 @@
 
 %-----------------------------------------------------------------------------%
 
-:- type slice --->
-    slice(
+:- type slice
+    --->    slice(
         num_tests       :: int,
         slice_proc_map  :: map(proc_label, proc_slice)
     ).
@@ -36,14 +36,14 @@
 
 :- type proc_slice       == map(path_port, slice_exec_count).
 
-:- type slice_exec_count --->
-    slice_exec_count(
+:- type slice_exec_count
+    --->    slice_exec_count(
             slice_filename      ::  string,
             slice_linenumber    ::  int,
 
             slice_count         :: int,
-                                % The number of times the label was executed in
-                                % all the test runs.
+                                    % The number of times the label was
+                                    % executed in all the test runs.
 
             slice_tests         :: int
                                 % The number of test runs the label was
@@ -79,8 +79,8 @@
 
 %-----------------------------------------------------------------------------%
 
-:- type dice --->
-    dice(
+:- type dice
+    --->    dice(
         num_pass_tests  :: int,
         num_fail_tests  :: int,
         dice_proc_map   :: map(proc_label, proc_dice)
@@ -90,8 +90,8 @@
 
 :- type proc_dice       == map(path_port, dice_exec_count).
 
-:- type dice_exec_count --->
-    dice_exec_count(
+:- type dice_exec_count
+    --->    dice_exec_count(
             dice_filename   ::  string,
             dice_linenumber ::  int,
 
@@ -221,12 +221,13 @@
 slice_merge_trace_counts(TraceCounts, !SliceProcMap) :-
     map.foldl(slice_merge_proc_trace_counts, TraceCounts, !SliceProcMap).
 
-:- pred slice_merge_proc_trace_counts(proc_label_and_filename::in,
+:- pred slice_merge_proc_trace_counts(proc_label_in_context::in, 
     proc_trace_counts::in, slice_proc_map::in, slice_proc_map::out) is det.
 
 slice_merge_proc_trace_counts(ProcLabelAndFile, ProcTraceCounts,
         !SliceProcMap) :-
-    ProcLabelAndFile = proc_label_and_filename(ProcLabel, FileName),
+    ProcLabelAndFile = proc_label_in_context(_ModuleNameSym, FileName,
+        ProcLabel),
     ( map.search(!.SliceProcMap, ProcLabel, FoundProcSlice) ->
         map.foldl(slice_merge_path_port(FileName), ProcTraceCounts,
             FoundProcSlice, MergedProcSlice),
@@ -330,12 +331,13 @@
     map.foldl(dice_merge_proc_trace_counts(Kind), TraceCounts, !DiceProcMap).
 
 :- pred dice_merge_proc_trace_counts(trace_counts_kind::in,
-    proc_label_and_filename::in, proc_trace_counts::in, dice_proc_map::in,
+    proc_label_in_context::in, proc_trace_counts::in, dice_proc_map::in,
     dice_proc_map::out) is det.
 
 dice_merge_proc_trace_counts(Kind, ProcLabelAndFile, ProcTraceCounts,
         !DiceProcMap) :-
-    ProcLabelAndFile = proc_label_and_filename(ProcLabel, FileName),
+    ProcLabelAndFile = proc_label_in_context(_ModuleNameSym, FileName,
+        ProcLabel),
     ( map.search(!.DiceProcMap, ProcLabel, FoundProcDice) ->
         map.foldl(dice_merge_path_port(FileName, Kind), ProcTraceCounts,
             FoundProcDice, MergedProcDice),
@@ -436,8 +438,8 @@
     % Values of this type uniquely identify a label in the program
     % and contain some statistics about the execution of the label.
     %
-:- type slice_label_count --->
-    slice_label_count(
+:- type slice_label_count
+    --->    slice_label_count(
         slc_proc_label  :: proc_label,
         slc_path_port   :: path_port,
         slc_counts      :: slice_exec_count
@@ -613,8 +615,8 @@
     % Values of this type uniquely identify a label in the program
     % and contain some statistics about the execution of the label.
     %
-:- type dice_label_count --->
-    dice_label_count(
+:- type dice_label_count
+    --->    dice_label_count(
         dlc_proc_label  :: proc_label,
         dlc_path_port   :: path_port,
         dlc_counts      :: dice_exec_count
@@ -774,9 +776,7 @@
 
 suspicion_ratio(PassCount, FailCount) = R1 :-
     Denominator = PassCount + FailCount,
-    (
-        Denominator \= 0
-    ->
+    ( Denominator \= 0 ->
         R = float(FailCount) / float(Denominator),
         ( R >= 0.20 ->
             R1 = R
Index: mdbcomp/trace_counts.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/mdbcomp/trace_counts.m,v
retrieving revision 1.11
diff -u -b -r1.11 trace_counts.m
--- mdbcomp/trace_counts.m	8 Jun 2006 08:19:53 -0000	1.11
+++ mdbcomp/trace_counts.m	18 Sep 2006 03:18:18 -0000
@@ -25,28 +25,46 @@
 :- import_module io.
 :- import_module list.
 :- import_module map.
+:- import_module maybe.
+:- import_module set.
 
 %-----------------------------------------------------------------------------%
 
-:- type trace_count_file_type
+:- type all_or_nonzero
     --->    user_all
             % The file contains counts for all labels from user-defined
             % procedures.
 
-    ;       user_nonzero
+    ;       user_nonzero.
             % The file contains counts for all labels from user-defined
             % procedures, provided the count is nonzero.
 
-    ;       union(int).
+:- type trace_count_file_type
+    --->    single_file(all_or_nonzero)
+            % The file contains counts from a single execution, which
+            % wrote out the indicated counts.
+
+    ;       union_file(int, set(all_or_nonzero))
             % The file is a union of some other trace count files.
-            % The number of test cases in the union is recorded.
+            % The number of test cases in the union is recorded, and
+            % so is the set of kinds of trace count files they came from.
+
+    ;       diff_file.
+            % The file is a difference between two other trace count files.
 
-:- type trace_counts == map(proc_label_and_filename, proc_trace_counts).
+:- func maybe_sum_trace_count_file_type(trace_count_file_type,
+    trace_count_file_type) = maybe(trace_count_file_type).
 
-:- type proc_label_and_filename
-    --->    proc_label_and_filename(
-                proc_label  ::  proc_label, 
-                filename    ::  string
+:- func sum_trace_count_file_type(trace_count_file_type, trace_count_file_type)
+    = trace_count_file_type.
+
+:- type trace_counts == map(proc_label_in_context, proc_trace_counts).
+
+:- type proc_label_in_context
+    --->    proc_label_in_context(
+                context_module_symname  :: sym_name,
+                context_filename        :: string,
+                proc_label              :: proc_label
             ).
 
 :- type proc_trace_counts   == map(path_port, line_no_and_count).
@@ -71,6 +89,9 @@
 :- pred sum_trace_counts(trace_counts::in, trace_counts::in, trace_counts::out)
     is det.
 
+:- pred diff_trace_counts(trace_counts::in, trace_counts::in,
+    trace_counts::out) is det.
+
 %-----------------------------------------------------------------------------%
 
 :- type read_trace_counts_result
@@ -130,13 +151,32 @@
 :- pred read_trace_counts_source(bool::in, slice_source::in, string::in,
     read_trace_counts_list_result::out, io::di, io::uo) is det.
 
-    % write_trace_counts_to_file(FileType, TraceCounts, FileName, Result, !IO).
+    % read_and_union_trace_counts(ShowProgress, Source, FileNames,
+    %   NumTests, TestKinds, TraceCounts, MaybeError, !IO):
+    %
+    % Invoke read_trace_counts_source for each of the supplied filenames, and
+    % union the resulting trace counts. If there is a problem with reading in
+    % the trace counts, MaybeError will be `yes' wrapped around the error
+    % message. Otherwise, MaybeError will be `no', TraceCounts will contain
+    % the union of the trace counts and NumTests will contain the number of
+    % tests the trace counts come from.
+    %
+:- pred read_and_union_trace_counts(bool::in, slice_source::in,
+    list(string)::in, int::out, set(all_or_nonzero)::out, trace_counts::out,
+    maybe(string)::out, io::di, io::uo) is det.
+
+    % write_trace_counts_to_file(FileType, TraceCounts, FileName, Result, !IO):
+    %
     % Write the given trace counts to FileName in a format suitable for 
     % reading with read_trace_counts/4.
     %
 :- pred write_trace_counts_to_file(trace_count_file_type::in, trace_counts::in,
     string::in, io.res::out, io::di, io::uo) is det.
 
+    % Write out the given proc_label.
+    %
+:- pred write_proc_label(proc_label::in, 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.
@@ -165,7 +205,6 @@
 :- import_module io.
 :- import_module lexer.
 :- import_module require.
-:- import_module set.
 :- import_module string.
 :- import_module svmap.
 :- import_module term_io.
@@ -207,6 +246,61 @@
 
 %-----------------------------------------------------------------------------%
 
+diff_trace_counts(TraceCountsA, TraceCountsB, TraceCounts) :-
+    map.foldl(diff_trace_counts_acc(TraceCountsB), TraceCountsA,
+        map.init, TraceCounts).
+
+:- pred diff_trace_counts_acc(trace_counts::in,
+    proc_label_in_context::in, proc_trace_counts::in,
+    trace_counts::in, trace_counts::out) is det.
+
+diff_trace_counts_acc(TraceCountsB, ProcLabelInContextA, ProcTraceCountsA,
+        !TraceCounts) :-
+    ( map.search(TraceCountsB, ProcLabelInContextA, ProcTraceCountsB) ->
+        ProcTraceCounts = diff_proc_counts(ProcTraceCountsA, ProcTraceCountsB),
+        svmap.det_insert(ProcLabelInContextA, ProcTraceCounts, !TraceCounts)
+    ;
+        svmap.det_insert(ProcLabelInContextA, ProcTraceCountsA, !TraceCounts)
+    ).
+
+:- func diff_proc_counts(proc_trace_counts, proc_trace_counts)
+    = proc_trace_counts.
+
+diff_proc_counts(ProcTraceCountsA, ProcTraceCountsB) = ProcTraceCounts :-
+    map.foldl(diff_proc_counts_acc(ProcTraceCountsB), ProcTraceCountsA,
+        map.init, ProcTraceCounts).
+
+:- pred diff_proc_counts_acc(proc_trace_counts::in,
+    path_port::in, line_no_and_count::in,
+    proc_trace_counts::in, proc_trace_counts::out) is det.
+
+diff_proc_counts_acc(ProcTraceCountsB, PathPortA, LineNoCountA,
+        !ProcTraceCounts) :-
+    ( map.search(ProcTraceCountsB, PathPortA, LineNoCountB) ->
+        LineNoCount = diff_counts_on_line(LineNoCountA, LineNoCountB),
+        svmap.det_insert(PathPortA, LineNoCount, !ProcTraceCounts)
+    ;
+        svmap.det_insert(PathPortA, LineNoCountA, !ProcTraceCounts)
+    ).
+
+:- func diff_counts_on_line(line_no_and_count, line_no_and_count)
+    = line_no_and_count.
+
+diff_counts_on_line(LC1, LC2) = LC :-
+    % We don't check that LineNumber1 = LineNumber2 since that does not
+    % necessarily represent an error. (Consider the case when the two trace
+    % files are derived from sources that are identical except for the addition
+    % of a comment.)
+
+    % The number of tests field doesn't make sense in the result of a diff
+    % operation. We signal this fact by using a plainly dummy value.
+
+    LC1 = line_no_and_count(LineNumber1, Count1, _NumTests1),
+    LC2 = line_no_and_count(_LineNumber, Count2, _NumTests2),
+    LC = line_no_and_count(LineNumber1, Count1 - Count2, -1).
+
+%-----------------------------------------------------------------------------%
+
 read_trace_counts_source(ShowProgress, Source, FileName, Result, !IO) :-
     (
         Source = file_list,
@@ -261,8 +355,8 @@
     io.open_input(FileName, OpenResult, !IO),
     (
         OpenResult = ok(FileStream),
-        read_trace_counts_list_stream(ShowProgress, union(0), map.init, 
-            FileName, FileStream, Result, !IO)
+        read_trace_counts_list_stream(ShowProgress, union_file(0, set.init),
+            map.init, FileName, FileStream, Result, !IO)
     ;
         OpenResult = error(IOError),
         Result = list_error_message("Error opening file `" ++ FileName ++
@@ -303,8 +397,7 @@
                 ReadTCResult = ok(FileType1, TraceCounts1),
                 summarize_trace_counts_list([TraceCounts0, TraceCounts1],
                     TraceCounts),
-                NumTests = calc_num_tests([FileType0, FileType1]),
-                FileType = union(NumTests),
+                FileType = sum_trace_count_file_type(FileType0, FileType1),
                 read_trace_counts_list_stream(ShowProgress, FileType, 
                     TraceCounts, MainFileName, Stream, Result, !IO)
             ;
@@ -418,9 +511,13 @@
     io.read_line_as_string(Result, !IO),
     (
         Result = ok(Line),
+        % The code in mercury_trace_counts.c always generates output that will
+        % cause read_proc_trace_counts below to override these dummy module
+        % and file names before they are referenced.
+        CurModuleNameSym = unqualified(""),
         CurFileName = "",
-        read_proc_trace_counts(LineNumber, Line, CurFileName, !TraceCounts,
-            !IO)
+        read_proc_trace_counts(LineNumber, Line, CurModuleNameSym, CurFileName,
+            !TraceCounts, !IO)
     ;
         Result = eof
     ;
@@ -431,25 +528,45 @@
 :- type trace_count_syntax_error
     --->    trace_count_syntax_error(string).
 
-:- pred read_proc_trace_counts(int::in, string::in, string::in,
+:- pred read_proc_trace_counts(int::in, string::in, sym_name::in, string::in,
     trace_counts::in, trace_counts::out, io::di, io::uo) is det.
 
-read_proc_trace_counts(HeaderLineNumber, HeaderLine, CurFileName, !TraceCounts,
-        !IO) :-
+read_proc_trace_counts(HeaderLineNumber, HeaderLine, CurModuleNameSym,
+        CurFileName, !TraceCounts, !IO) :-
     lexer.string_get_token_list(HeaderLine, string.length(HeaderLine),
         TokenList, posn(HeaderLineNumber, 1, 0), _),
+    ( TokenList = token_cons(name(TokenName), _, TokenListRest) ->
     (
-        TokenList =
-            token_cons(name("file"), _,
+            TokenName = "module",
+            TokenListRest =
+                token_cons(name(NextModuleName), _,
+                token_nil)
+        ->
+            string_to_sym_name(NextModuleName, ".", NextModuleNameSym),
+            io.read_line_as_string(Result, !IO),
+            (
+                Result = ok(Line),
+                io.get_line_number(LineNumber, !IO),
+                read_proc_trace_counts(LineNumber, Line,
+                    NextModuleNameSym, CurFileName, !TraceCounts, !IO)
+            ;
+                Result = eof
+            ;
+                Result = error(Error),
+                throw(Error)
+            )
+        ;
+            TokenName = "file",
+            TokenListRest =
             token_cons(name(NextFileName), _,
-            token_nil))
+                token_nil)
     ->
         io.read_line_as_string(Result, !IO),
         (
             Result = ok(Line),
             io.get_line_number(LineNumber, !IO),
-            read_proc_trace_counts(LineNumber, Line, NextFileName,
-                !TraceCounts, !IO)
+                read_proc_trace_counts(LineNumber, Line,
+                    CurModuleNameSym, NextFileName, !TraceCounts, !IO)
         ;
             Result = eof
         ;
@@ -457,46 +574,78 @@
             throw(Error)
         )
     ;
-        TokenList =
-            token_cons(name("proc"), _,
-            token_cons(name(DefModuleStr), _,
-            token_cons(name(PredOrFuncStr), _,
-            token_cons(name(DeclModuleStr), _,
+            % At the moment runtime/mercury_trace_base.c doesn't write out
+            % data for unify, compare, index or init procedures.
+            (
+                TokenName = "pproc",
+                TokenListRest =
+                    token_cons(name(Name), _,
+                    token_cons(integer(Arity), _,
+                    token_cons(integer(Mode), _,
+                    token_nil))),
+                ProcLabel = ordinary_proc_label(CurModuleNameSym, predicate,
+                    CurModuleNameSym, Name, Arity, Mode)
+            ;
+                TokenName = "fproc",
+                TokenListRest =
             token_cons(name(Name), _,
             token_cons(integer(Arity), _,
             token_cons(integer(Mode), _,
-            token_nil))))))),
-        string_to_pred_or_func(PredOrFuncStr, PredOrFunc)
+                    token_nil))),
+                ProcLabel = ordinary_proc_label(CurModuleNameSym, function,
+                    CurModuleNameSym, Name, Arity, Mode)
+            ;
+                TokenName = "pprocdecl",
+                TokenListRest =
+                    token_cons(name(DeclModuleName), _,
+                    token_cons(name(Name), _,
+                    token_cons(integer(Arity), _,
+                    token_cons(integer(Mode), _,
+                    token_nil)))),
+                string_to_sym_name(DeclModuleName, ".", DeclModuleNameSym),
+                ProcLabel = ordinary_proc_label(CurModuleNameSym, predicate,
+                    DeclModuleNameSym, Name, Arity, Mode)
+            ;
+                TokenName = "fprocdecl",
+                TokenListRest =
+                    token_cons(name(DeclModuleName), _,
+                    token_cons(name(Name), _,
+                    token_cons(integer(Arity), _,
+                    token_cons(integer(Mode), _,
+                    token_nil)))),
+                string_to_sym_name(DeclModuleName, ".", DeclModuleNameSym),
+                ProcLabel = ordinary_proc_label(CurModuleNameSym, function,
+                    DeclModuleNameSym, Name, Arity, Mode)
+            )
     ->
-        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 unify, compare, index or init procedures.
-        ProcLabel = ordinary_proc_label(DefModuleName, PredOrFunc,
-            DeclModuleName, Name, Arity, Mode),
-        ProcLabelAndFile = proc_label_and_filename(ProcLabel, CurFileName),
+            ProcLabelInContext = proc_label_in_context(CurModuleNameSym,
+                CurFileName, ProcLabel),
         % 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.
-        ( svmap.remove(ProcLabelAndFile, ProbeCounts, !TraceCounts) ->
+            ( svmap.remove(ProcLabelInContext, ProbeCounts, !TraceCounts) ->
             StartCounts = ProbeCounts
         ;
             StartCounts = map.init
         ),
-        read_proc_trace_counts_2(ProcLabelAndFile, StartCounts,
+            read_proc_trace_counts_2(ProcLabelInContext, StartCounts,
             !TraceCounts, !IO)
     ;
         string.format("parse error on line %d of execution trace",
             [i(HeaderLineNumber)], Message),
         throw(trace_count_syntax_error(Message))
+        )
+    ;
+        string.format("parse error on line %d of execution trace",
+            [i(HeaderLineNumber)], Message),
+        throw(trace_count_syntax_error(Message))
     ).
 
-:- pred read_proc_trace_counts_2(proc_label_and_filename::in,
+:- pred read_proc_trace_counts_2(proc_label_in_context::in,
     proc_trace_counts::in, trace_counts::in, trace_counts::out,
     io::di, io::uo) is det.
 
-read_proc_trace_counts_2(ProcLabelAndFile, ProcCounts0, !TraceCounts, !IO) :-
-    CurFileName = ProcLabelAndFile ^ filename,
+read_proc_trace_counts_2(ProcLabelInContext, ProcCounts0, !TraceCounts, !IO) :-
     io.read_line_as_string(Result, !IO),
     (
         Result = ok(Line),
@@ -507,17 +656,19 @@
             LineNoAndCount = line_no_and_count(LineNumber, ExecCount, 
                 NumTests),
             map.det_insert(ProcCounts0, PathPort, LineNoAndCount, ProcCounts),
-            read_proc_trace_counts_2(ProcLabelAndFile, ProcCounts,
+            read_proc_trace_counts_2(ProcLabelInContext, ProcCounts,
                 !TraceCounts, !IO)
         ;
-            svmap.det_insert(ProcLabelAndFile, ProcCounts0, !TraceCounts),
+            svmap.det_insert(ProcLabelInContext, ProcCounts0, !TraceCounts),
             io.get_line_number(LineNumber, !IO),
-            read_proc_trace_counts(LineNumber, Line, CurFileName, !TraceCounts,
-                !IO)
+            CurModuleNameSym = ProcLabelInContext ^ context_module_symname,
+            CurFileName = ProcLabelInContext ^ context_filename,
+            read_proc_trace_counts(LineNumber, Line, CurModuleNameSym,
+                CurFileName, !TraceCounts, !IO)
         )
     ;
         Result = eof,
-        svmap.det_insert(ProcLabelAndFile, ProcCounts0, !TraceCounts)
+        svmap.det_insert(ProcLabelInContext, ProcCounts0, !TraceCounts)
     ;
         Result = error(Error),
         throw(Error)
@@ -529,49 +680,46 @@
 parse_path_port_line(Line, PathPort, LineNumber, ExecCount, NumTests) :-
     Words = string.words(Line),
     ( 
-        (
-            Words = [Word1, ExecCountStr, LineNumberStr],
-            NumTestsStr = "1"
-        ;
-            Words = [Word1, ExecCountStr, NumTestsStr, LineNumberStr]
-        ),
+        Words = [Word1, LineNumberStr | Rest],
         ( string_to_trace_port(Word1, Port) ->
-            PathPort0 = port_only(Port)
+            PathPortPrime = port_only(Port)
         ; Path = string_to_goal_path(Word1) ->
-            PathPort0 = path_only(Path)
+            PathPortPrime = path_only(Path)
         ;
             fail
         ),
-        string.to_int(ExecCountStr, ExecCount0),
-        string.to_int(NumTestsStr, NumTests0),
-        string.to_int(LineNumberStr, LineNumber0)
+        string.to_int(LineNumberStr, LineNumberPrime),
+        parse_rest(Rest, ExecCountPrime, NumTestsPrime)
     ->
-        PathPort = PathPort0,
-        ExecCount = ExecCount0,
-        NumTests = NumTests0,
-        LineNumber = LineNumber0
-    ;
-        (
-            Words = [PortStr, PathStr, ExecCountStr, LineNumberStr],
-            NumTestsStr = "1"
+        PathPort = PathPortPrime,
+        LineNumber = LineNumberPrime,
+        ExecCount = ExecCountPrime,
+        NumTests = NumTestsPrime
         ;
-            Words = [PortStr, PathStr, ExecCountStr, NumTestsStr,
-                LineNumberStr]
-        ),
+        Words = [PortStr, PathStr, LineNumberStr | Rest],
         string_to_trace_port(PortStr, Port),
         Path = string_to_goal_path(PathStr),
         PathPort = port_and_path(Port, Path),
-        string.to_int(ExecCountStr, ExecCount),
-        string.to_int(NumTestsStr, NumTests),
-        string.to_int(LineNumberStr, LineNumber)
+        string.to_int(LineNumberStr, LineNumber),
+        parse_rest(Rest, ExecCount, NumTests)
     ).
 
-:- pred string_to_pred_or_func(string, pred_or_func).
-:- mode string_to_pred_or_func(in, out) is semidet.
-:- mode string_to_pred_or_func(out, in) is det.
+:- pred parse_rest(list(string)::in, int::out, int::out) is semidet.
 
-string_to_pred_or_func("p", predicate).
-string_to_pred_or_func("f", function).
+parse_rest(Rest, ExecCount, NumTests) :-
+    (
+        Rest = [],
+        ExecCount = 0,
+        NumTests = 1
+    ;
+        Rest = [ExecCountStr],
+        string.to_int(ExecCountStr, ExecCount),
+        NumTests = 1
+    ;
+        Rest = [ExecCountStr, NumTestsStr],
+        string.to_int(ExecCountStr, ExecCount),
+        string.to_int(NumTestsStr, NumTests)
+    ).
 
 string_to_trace_port("CALL", call).
 string_to_trace_port("EXIT", exit).
@@ -619,56 +767,136 @@
 
 %-----------------------------------------------------------------------------%
 
-write_trace_counts_to_file(FileType, TraceCounts, FileName, Res, !IO) :-
-    io.open_output(FileName, Result, !IO),
+read_and_union_trace_counts(ShowProgress, SliceSource, Files,
+        NumTests, TestKinds, TraceCounts, MaybeError, !IO) :-
+    read_and_union_trace_counts_2(ShowProgress, SliceSource, Files,
+        union_file(0, set.init), FileType, map.init, TraceCounts, MaybeError,
+        !IO),
     (
-        Result = ok(FileStream),
-        Res = ok,
-        io.set_output_stream(FileStream, OldOutputStream, !IO),
+        FileType = union_file(NumTests, TestKinds)
+    ;
+        FileType = single_file(_),
+        error("read_and_union_trace_counts: single_file")
+    ;
+        FileType = diff_file,
+        error("read_and_union_trace_counts: diff_file")
+    ).
+
+:- pred read_and_union_trace_counts_2(bool::in, slice_source::in,
+    list(string)::in, trace_count_file_type::in, trace_count_file_type::out,
+    trace_counts::in, trace_counts::out, maybe(string)::out,
+    io::di, io::uo) is det.
+
+read_and_union_trace_counts_2(_, _, [], !FileType, !TraceCounts,
+        no, !IO).
+read_and_union_trace_counts_2(ShowProgress, SliceSource, [File | Files],
+        !FileType, !TraceCounts, MaybeError, !IO) :-
+    read_trace_counts_source(ShowProgress, SliceSource, File, TCResult, !IO),
+    (
+        TCResult = list_ok(FileType, NewTraceCounts),
+        summarize_trace_counts_list([!.TraceCounts, NewTraceCounts],
+            !:TraceCounts),
+        !:FileType = sum_trace_count_file_type(!.FileType, FileType),
+        read_and_union_trace_counts_2(ShowProgress, SliceSource, Files,
+            !FileType, !TraceCounts, MaybeError, !IO)
+    ;
+        TCResult = list_error_message(Message),
+        MaybeError = yes(Message)
+    ).
+
+%-----------------------------------------------------------------------------%
+
+write_trace_counts_to_file(FileType, TraceCounts, FileName, Result, !IO) :-
+    io.tell(FileName, TellResult, !IO),
+    (
+        TellResult = ok,
+        Result = ok,
         io.write_string(trace_count_file_id, !IO),
         io.nl(!IO),
         write_trace_counts(FileType, TraceCounts, !IO),
-        io.set_output_stream(OldOutputStream, _, !IO),
-        io.close_output(FileStream, !IO)
+        io.told(!IO)
     ;
-        Result = error(Error),
-        Res = error(Error)
+        TellResult = error(Error),
+        Result = error(Error)
     ).
 
-:- pred write_trace_counts(trace_count_file_type::in, trace_counts::in, 
-    io::di, io::uo) is det.
+:- pred write_trace_counts(trace_count_file_type::in,
+    trace_counts::in, io::di, io::uo) is det.
 
 write_trace_counts(FileType, TraceCounts, !IO) :-
     FileTypeStr = file_type_to_string(FileType),
     io.write_string(FileTypeStr ++ "\n", !IO),
-    map.foldl(write_proc_label_and_file_trace_counts, TraceCounts, !IO).
-
-:- pred write_proc_label_and_file_trace_counts(proc_label_and_filename::in, 
-    proc_trace_counts::in, io::di, io::uo) is det.
+    map.foldl3(write_proc_label_and_file_trace_counts, TraceCounts,
+        unqualified(""), _, "", _, !IO).
 
-write_proc_label_and_file_trace_counts(ProcLabelAndFileName, PathPortCounts, 
-        !IO) :-
-    ProcLabelAndFileName = proc_label_and_filename(ProcLabel, FileName),
-    io.write_strings(["file '", FileName, "'\n"], !IO),
-    write_proc_label(ProcLabel, !IO),
+:- pred write_proc_label_and_file_trace_counts(proc_label_in_context::in,
+    proc_trace_counts::in, sym_name::in, sym_name::out,
+    string::in, string::out, io::di, io::uo) is det.
+
+write_proc_label_and_file_trace_counts(ProcLabelInContext, PathPortCounts,
+        !CurModuleNameSym, !CurFileName, !IO) :-
+    ProcLabelInContext = proc_label_in_context(ModuleNameSym, FileName,
+        ProcLabel),
+    ( ModuleNameSym = !.CurModuleNameSym ->
+        true
+    ;
+        ModuleName = sym_name_to_string(ModuleNameSym),
+        io.write_string("module ", !IO),
+        term_io.quote_atom(ModuleName, !IO),
+        io.write_string("\n", !IO),
+        !:CurModuleNameSym = ModuleNameSym
+    ),
+    ( FileName = !.CurFileName ->
+        true
+    ;
+        io.write_string("file ", !IO),
+        term_io.quote_atom(FileName, !IO),
+        io.write_string("\n", !IO),
+        !:CurFileName = FileName
+    ),
+    write_proc_label_and_check(ModuleNameSym, ProcLabel, !IO),
     map.foldl(write_path_port_count, PathPortCounts, !IO).
 
-:- pred write_proc_label(proc_label::in, io::di, io::uo) is det.
+:- pred write_proc_label_and_check(sym_name::in, proc_label::in,
+    io::di, io::uo) is det.
+
+write_proc_label_and_check(ModuleNameSym, ProcLabel, !IO) :-
+    (
+        ProcLabel = ordinary_proc_label(DefModuleSym, _, _, _, _, _),
+        require(unify(ModuleNameSym, DefModuleSym),
+            "write_proc_label_and_check: module mismatch")
+    ;
+        % We don't record trace counts in special preds.
+        ProcLabel = special_proc_label(_, _, _, _, _, _),
+        error("write_proc_label: special_pred")
+    ),
+    write_proc_label(ProcLabel, !IO).
 
 write_proc_label(ProcLabel, !IO) :-
     (
         ProcLabel = ordinary_proc_label(DefModuleSym, PredOrFunc,
             DeclModuleSym, Name, Arity, Mode),
-        sym_name_to_string(DefModuleSym, DefModuleStr),
-        sym_name_to_string(DeclModuleSym, DeclModuleStr),
-        string_to_pred_or_func(PredOrFuncStr, PredOrFunc),
-        io.write_string("proc ", !IO),
-        term_io.quote_atom(DefModuleStr, !IO),
-        io.write_string(" ", !IO),
-        io.write_string(PredOrFuncStr, !IO),
-        io.write_string(" ", !IO),
-        term_io.quote_atom(DeclModuleStr, !IO),
-        io.write_string(" ", !IO),
+        (
+            PredOrFunc = predicate,
+            ( DeclModuleSym = DefModuleSym ->
+                io.write_string("pproc ", !IO)
+            ;
+                DeclModule = sym_name_to_string(DeclModuleSym),
+                io.write_string("pprocdecl ", !IO),
+                term_io.quote_atom(DeclModule, !IO),
+                io.write_string(" ", !IO)
+            )
+        ;
+            PredOrFunc = function,
+            ( DeclModuleSym = DefModuleSym ->
+                io.write_string("fproc ", !IO)
+            ;
+                DeclModule = sym_name_to_string(DeclModuleSym),
+                io.write_string("fprocdecl ", !IO),
+                term_io.quote_atom(DeclModule, !IO),
+                io.write_string(" ", !IO)
+            )
+        ),
         term_io.quote_atom(Name, !IO),
         io.write_string(" ", !IO),
         io.write_int(Arity, !IO),
@@ -676,61 +904,86 @@
         io.write_int(Mode, !IO),
         io.nl(!IO)
     ;
+        % We don't record trace counts in special preds.
         ProcLabel = special_proc_label(_, _, _, _, _, _),
-        % We don't record special preds in trace counts.
-        error("write_proc_label: special_pred_label")
+        error("write_proc_label: special_pred")
     ).
 
 :- pred write_path_port_count(path_port::in, line_no_and_count::in, 
     io::di, io::uo) is det.
 
-write_path_port_count(port_only(Port), line_no_and_count(LineNo, 
-        ExecCount, NumTests), !IO) :-
+write_path_port_count(port_only(Port),
+        line_no_and_count(LineNo, ExecCount, NumTests), !IO) :-
     string_to_trace_port(PortStr, Port),
     io.write_strings([
         PortStr, " ", 
+        int_to_string(LineNo), " ",
         int_to_string(ExecCount), " ", 
-        int_to_string(NumTests), " ", 
-        int_to_string(LineNo), "\n"], !IO).
-write_path_port_count(path_only(Path), line_no_and_count(LineNo, ExecCount,
-        NumTests), !IO) :-
+        int_to_string(NumTests), "\n"], !IO).
+write_path_port_count(path_only(Path),
+        line_no_and_count(LineNo, ExecCount, NumTests), !IO) :-
     string_from_path(Path, PathStr),
     io.write_strings([
         "<", PathStr, "> ", 
+        int_to_string(LineNo), " ",
         int_to_string(ExecCount), " ", 
-        int_to_string(NumTests), " ", 
-        int_to_string(LineNo), 
-        "\n"], !IO).
+        int_to_string(NumTests), "\n"], !IO).
 write_path_port_count(port_and_path(Port, Path), 
         line_no_and_count(LineNo, ExecCount, NumTests), !IO) :-
     string_to_trace_port(PortStr, Port),
     string_from_path(Path, PathStr),
     io.write_strings([
         PortStr, " <", PathStr, "> ", 
+        int_to_string(LineNo), " ",
         int_to_string(ExecCount), " ", 
-        int_to_string(NumTests), " ", 
-        int_to_string(LineNo), "\n"], !IO).
+        int_to_string(NumTests), "\n"], !IO).
 
 %-----------------------------------------------------------------------------%
 
 :- func file_type_to_string(trace_count_file_type) = string.
 
-file_type_to_string(user_all) = "user_all".
-file_type_to_string(user_nonzero) = "user_nonzero".
-file_type_to_string(union(N)) = "union " ++ int_to_string(N).
+file_type_to_string(single_file(Kind)) =
+    "single " ++ all_or_nonzero_to_string(Kind).
+file_type_to_string(union_file(N, Kinds)) =
+    "union " ++ int_to_string(N)
+        ++ string.append_list(list.map(all_or_nonzero_to_space_string,
+            to_sorted_list(Kinds))).
+file_type_to_string(diff_file) = "diff".
+
+:- func all_or_nonzero_to_space_string(all_or_nonzero) = string.
+
+all_or_nonzero_to_space_string(Kind) = " " ++ all_or_nonzero_to_string(Kind).
+
+:- func all_or_nonzero_to_string(all_or_nonzero) = string.
+
+all_or_nonzero_to_string(user_all) = "all".
+all_or_nonzero_to_string(user_nonzero) = "nonzero".
+
+:- pred string_to_all_or_nonzero(string::in, all_or_nonzero::out) is semidet.
+
+string_to_all_or_nonzero("all", user_all).
+string_to_all_or_nonzero("nonzero", user_nonzero).
 
 :- pred string_to_file_type(string::in, trace_count_file_type::out) is semidet.
 
 string_to_file_type(Str, FileType) :-
-    ( string.append("union ", NumTestsStr, Str) ->
+    Words = string.words(Str),
+    Words = [Word1 | Rest],
+    (
+        Word1 = "union",
+        Rest = [NumTestsStr | KindStrs],
         string.to_int(NumTestsStr, NumTests),
-        FileType = union(NumTests)
-    ;
-        Str = "user_all",
-        FileType = user_all
+        list.map(string_to_all_or_nonzero, KindStrs, Kinds),
+        FileType = union_file(NumTests, list_to_set(Kinds))
     ;
-        Str = "user_nonzero",
-        FileType = user_nonzero
+        Word1 = "single",
+        Rest = [KindStr],
+        string_to_all_or_nonzero(KindStr, Kind),
+        FileType = single_file(Kind)
+    ;
+        Word1 = "diff",
+        Rest = [],
+        FileType = diff_file
     ).
 
 %-----------------------------------------------------------------------------%
@@ -739,15 +992,16 @@
     map.foldl(restrict_trace_counts_2(ModuleName), TraceCounts0,
         map.init, TraceCounts).
     
-:- pred restrict_trace_counts_2(module_name::in, proc_label_and_filename::in, 
+:- pred restrict_trace_counts_2(module_name::in, proc_label_in_context::in,
     proc_trace_counts::in, trace_counts::in, trace_counts::out) is det.
 
-restrict_trace_counts_2(ModuleName, ProcLabelAndFile, ProcCounts, Acc0, Acc) :-
-    ProcLabel = ProcLabelAndFile ^ proc_label,
-    (if ProcLabel = ordinary_proc_label(ModuleName, _, _, _, _, _) then
-        map.det_insert(Acc0, ProcLabelAndFile, ProcCounts, Acc)
-    else
-        Acc = Acc0
+restrict_trace_counts_2(ModuleName, ProcLabelInContext, ProcCounts,
+        !TraceCounts) :-
+    ProcLabel = ProcLabelInContext ^ proc_label,
+    ( ProcLabel = ordinary_proc_label(ModuleName, _, _, _, _, _) ->
+        svmap.det_insert(ProcLabelInContext, ProcCounts, !TraceCounts)
+    ;
+        true
     ).
 
 %-----------------------------------------------------------------------------%
@@ -756,6 +1010,55 @@
 calc_num_tests([FileType | Rest]) = 
     num_tests_for_file_type(FileType) + calc_num_tests(Rest).
 
-num_tests_for_file_type(union(N)) = N.
-num_tests_for_file_type(user_nonzero) = 1.
-num_tests_for_file_type(user_all) = 1.
+num_tests_for_file_type(union_file(N, _)) = N.
+num_tests_for_file_type(single_file(_)) = 1.
+num_tests_for_file_type(diff_file) = -1.
+
+maybe_sum_trace_count_file_type(Type1, Type2) = MaybeType :-
+
+    (
+        Type1 = single_file(Kind1),
+        Type2 = single_file(Kind2),
+        MaybeType = yes(union_file(2, list_to_set([Kind1, Kind2])))
+    ;
+        Type1 = single_file(Kind1),
+        Type2 = union_file(N, Kinds2),
+        MaybeType = yes(union_file(N + 1, set.insert(Kinds2, Kind1)))
+    ;
+        Type1 = single_file(_),
+        Type2 = diff_file,
+        MaybeType = no
+    ;
+        Type1 = union_file(N, Kinds1),
+        Type2 = single_file(Kind2),
+        MaybeType = yes(union_file(N + 1, set.insert(Kinds1, Kind2)))
+    ;
+        Type1 = union_file(N1, Kinds1),
+        Type2 = union_file(N2, Kinds2),
+        MaybeType = yes(union_file(N1 + N2, set.union(Kinds1, Kinds2)))
+    ;
+        Type1 = union_file(_, _),
+        Type2 = diff_file,
+        MaybeType = no
+    ;
+        Type1 = diff_file,
+        Type2 = single_file(_),
+        MaybeType = no
+    ;
+        Type1 = diff_file,
+        Type2 = union_file(_, _),
+        MaybeType = no
+    ;
+        Type1 = diff_file,
+        Type2 = diff_file,
+        MaybeType = no
+    ).
+
+sum_trace_count_file_type(Type1, Type2) = Type :-
+    maybe_sum_trace_count_file_type(Type1, Type2) = MaybeType,
+    (
+        MaybeType = yes(Type)
+    ;
+        MaybeType = no,
+        error("sum_trace_count_file_type: inconsistent file types")
+    ).
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.74
diff -u -b -r1.74 mercury_trace_base.c
--- runtime/mercury_trace_base.c	14 Sep 2006 00:15:46 -0000	1.74
+++ runtime/mercury_trace_base.c	14 Sep 2006 04:14:49 -0000
@@ -43,10 +43,16 @@
   #include <sys/wait.h>     /* for the wait system call */
 #endif
 
+#define MR_TRACE_COUNT_SUMMARY_MAX_DEFAULT  20
+
 void            (*MR_trace_shutdown)(void) = NULL;
 
 MR_bool         MR_trace_count_enabled = MR_FALSE;
 MR_bool         MR_coverage_test_enabled = MR_FALSE;
+const char      *MR_trace_count_summary_file = NULL;
+const char      *MR_trace_count_summary_cmd = "mtc_union";
+unsigned int    MR_trace_count_summary_max =
+                    MR_TRACE_COUNT_SUMMARY_MAX_DEFAULT;
 char            *MR_trace_counts_file = NULL;
 
 MR_bool         MR_debug_ever_enabled = MR_FALSE;
@@ -245,30 +251,70 @@
 }
 
 static  void    MR_trace_write_quoted_atom(FILE *fp, const char *atom);
-static  void    MR_trace_write_label_exec_counts(FILE *fp);
+static  void    MR_trace_write_label_exec_counts_for_file(FILE *fp,
+                    const MR_Module_Layout *module,
+                    const MR_Module_File_Layout *file, const char *module_name,
+                    MR_bool coverage_test);
 
 MR_PathPort     MR_named_count_port[MR_PORT_NONE + 1];
 
 #define MERCURY_TRACE_COUNTS_PREFIX  "mercury_trace_counts"
+#define UNION_CMD                       "mtc_union -o"
+#define TEMP_SUFFIX                     ".tmp"
+
+#define MR_FILE_EXISTS(filename)        (access(filename, F_OK) == 0)
 
 void
-MR_trace_write_label_exec_counts_to_file(void *dummy)
+MR_trace_record_label_exec_counts(void *dummy)
 {
     FILE    *fp;
     int     len;
     char    *name;
-    char    *s;
+    MR_bool summarize;
+
+    summarize = MR_FALSE;
+    if (MR_trace_count_summary_file != NULL) {
+        name = MR_copy_string(MR_trace_count_summary_file);
 
+        if (MR_FILE_EXISTS(name)) {
+            int     i;
+
+            /* 30 bytes must be enough for the dot, the value of i, and '\0' */
+            len = strlen(MR_trace_count_summary_file) + 30;
+            name = MR_malloc(len);
+
+            fp = NULL;
+            /* search for a suffix that doesn't exist yet */
+            for (i = 1; i <= MR_trace_count_summary_max; i++) {
+                snprintf(name, len, "%s.%d", MR_trace_count_summary_file, i);
+                if (! MR_FILE_EXISTS(name)) {
+                    /* file doesn't exist, commit to this one */
+                    fp = fopen(name, "w");
+                    if (i == MR_trace_count_summary_max) {
+                        summarize = MR_TRUE;
+                    }
+
+                    break;
+                }
+            }
+        } else {
+            /* the summary file doesn't yet exist, create it */
+            fp = fopen(name, "w");
+        }
+    } else {
     if (MR_trace_counts_file) {
         name = MR_trace_counts_file;
     } else {
+            char    *s;
+
         /*
         ** If no trace counts file name is provided, then we generate
         ** a file name.
         */
 
         /* 100 bytes must be enough for the process id, dots and '\0' */
-        len = strlen(MERCURY_TRACE_COUNTS_PREFIX) + strlen(MR_progname) + 100;
+            len = strlen(MERCURY_TRACE_COUNTS_PREFIX) + strlen(MR_progname)
+                + 100;
         name = MR_malloc(len);
         snprintf(name, len, ".%s.%s.%d", MERCURY_TRACE_COUNTS_PREFIX,
             MR_progname, getpid());
@@ -282,61 +328,160 @@
     }
 
     fp = fopen(name, "w");
+    }
+
     if (fp != NULL) {
-        MR_do_init_modules_debugger();
-        MR_trace_write_label_exec_counts(fp);
+        MR_trace_write_label_exec_counts(fp, MR_coverage_test_enabled);
         (void) fclose(fp);
     } else {
         fprintf(stderr, "%s: %s\n", name, strerror(errno));
+        /*
+        ** You can't summarize a file list if you can't create
+        ** one of its files.
+        */
+        summarize = MR_FALSE;
     }
-}
 
-/*
-** For every label reachable from the module table, write the id of the label
-** and the number of times it has been executed to the specified file, with the
-** exception of labels that haven't been executed.
-*/
+    free(name);
 
-static void
-MR_trace_write_label_exec_counts(FILE *fp)
+    if (summarize) {
+        char        *cmd;
+        int         cmd_len;
+        int         status;
+        int         i;
+        const char  *old_options;
+
+        /* 30 bytes must be enough for the dot, the value of i, and space */
+        len = strlen(MR_trace_count_summary_file) + 30;
+        name = MR_malloc(len);
+
+        cmd_len = strlen(UNION_CMD) + 4;
+        cmd_len += strlen(MR_trace_count_summary_file)
+            + strlen(TEMP_SUFFIX) + 1;
+        cmd_len += (MR_trace_count_summary_max + 1) * len;
+
+        cmd = MR_malloc(cmd_len);
+
+        strcpy(cmd, MR_trace_count_summary_cmd);
+        strcat(cmd, " -o ");
+        strcat(cmd, MR_trace_count_summary_file);
+        strcat(cmd, TEMP_SUFFIX);
+        strcat(cmd, " ");
+        strcat(cmd, MR_trace_count_summary_file);
+        strcat(cmd, " ");
+
+        for (i = 1; i <= MR_trace_count_summary_max; i++) {
+            snprintf(name, len, "%s.%d", MR_trace_count_summary_file, i);
+            strcat(cmd, name);
+            strcat(cmd, " ");
+        }
+
+#if 0
+        fp = fopen("/tmp/zs_summaries", "a");
+        if (fp != NULL) {
+            fprintf(fp, "%s\n", cmd);
+            fclose(fp);
+        }
+#endif
+
+        old_options = getenv("MERCURY_OPTIONS");
+        if (old_options != NULL) {
+            (void) setenv("MERCURY_OPTIONS", "", MR_TRUE);
+            status = system(cmd);
+            (void) setenv("MERCURY_OPTIONS", old_options, MR_TRUE);
+        } else {
+            status = system(cmd);
+        }
+
+        if (status == 0) {
+            strcpy(cmd, "mv ");
+            strcat(cmd, MR_trace_count_summary_file);
+            strcat(cmd, TEMP_SUFFIX);
+            strcat(cmd, " ");
+            strcat(cmd, MR_trace_count_summary_file);
+            status = system(cmd);
+
+#if 0
+            fp = fopen("/tmp/zs_summaries", "a");
+            if (fp != NULL) {
+                fprintf(fp, "%s\n", cmd);
+                fclose(fp);
+            }
+#endif
+        }
+
+        if (status == 0) {
+            /* delete all the files whose data is now in the summary file */
+            for (i = 1; i <= MR_trace_count_summary_max; i++) {
+                snprintf(name, len, "%s.%d", MR_trace_count_summary_file, i);
+                unlink(name);
+            }
+        } else {
+            MR_fatal_error("couldn't create summary of trace data");
+        }
+
+        free(name);
+        free(cmd);
+    }
+}
+
+void
+MR_trace_write_label_exec_counts(FILE *fp, MR_bool coverage_test)
 {
     const MR_Module_Layout      *module;
     const MR_Module_File_Layout *file;
-    const MR_Label_Layout       *label;
-    const MR_Proc_Layout        *prev_proc;
-    const MR_Proc_Layout        *proc;
-    const MR_User_Proc_Id       *id;
-    MR_Trace_Port               port;
     int                         num_modules;
     int                         num_files;
-    int                         num_labels;
     int                         module_num;
     int                         file_num;
-    int                         label_num;
-    int                         label_index;
-    MR_Unsigned                 exec_count;
-    MR_PathPort                 path_port;
 
     MR_trace_name_count_port_ensure_init();
 
     fprintf(fp, "%s", MR_TRACE_COUNT_FILE_ID);
-    if (MR_coverage_test_enabled) {
-        fprintf(fp, "user_all\n");
+    if (coverage_test) {
+        fprintf(fp, "single all\n");
     } else {
-        fprintf(fp, "user_nonzero\n");
+        fprintf(fp, "single nonzero\n");
     }
 
-    prev_proc = NULL;
     num_modules = MR_module_info_next;
     for (module_num = 0; module_num < num_modules; module_num++) {
         module = MR_module_infos[module_num];
         num_files = module->MR_ml_filename_count;
 
+        fputs("module ", fp);
+        MR_trace_write_quoted_atom(fp, module->MR_ml_name);
+        fputc('\n', fp);
+
         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_label_exec_counts_for_file(fp, module, file,
+                module->MR_ml_name, coverage_test);
+        }
+    }
+}
+
+static void
+MR_trace_write_label_exec_counts_for_file(FILE *fp,
+    const MR_Module_Layout *module, const MR_Module_File_Layout *file,
+    const char *module_name, MR_bool coverage_test)
+{
+    const MR_Label_Layout       *label;
+    const MR_Proc_Layout        *prev_proc;
+    const MR_Proc_Layout        *proc;
+    const MR_User_Proc_Id       *id;
+    MR_Trace_Port               port;
+    int                         num_labels;
+    int                         label_num;
+    int                         label_index;
+    MR_Unsigned                 exec_count;
+    MR_PathPort                 path_port;
+
+    fputs("file ", fp);
             MR_trace_write_quoted_atom(fp, file->MR_mfl_filename);
-            fprintf(fp, "\n");
+    fputc('\n', fp);
+
+    prev_proc = NULL;
             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];
@@ -344,21 +489,31 @@
                 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) && label_index > 0 &&
-                    (exec_count > 0 || MR_coverage_test_enabled))
+            (exec_count > 0 || coverage_test))
                 {
                     id = &proc->MR_sle_user;
                     if (proc != prev_proc) {
-                        fprintf(fp, "proc ");
-                        MR_trace_write_quoted_atom(fp, id->MR_user_def_module);
-                        fprintf(fp, " %c ",
-                            ( id->MR_user_pred_or_func == MR_PREDICATE
-                                ? 'p' : 'f'));
-                        MR_trace_write_quoted_atom(fp,
-                            id->MR_user_decl_module);
+                if (MR_strdiff(module_name, id->MR_user_def_module)) {
+                    MR_fatal_error(
+                        "MR_trace_write_label_exec_counts_for_file: "
+                        "module name mismatch");
+                }
+
+                if (id->MR_user_pred_or_func == MR_PREDICATE) {
+                    fputs("pproc", fp);
+                } else {
+                    fputs("fproc", fp);
+                }
+
+                if (MR_strdiff(module_name, id->MR_user_decl_module)) {
+                    /* turn pproc/fproc into pprocdecl/fprocdecl */
+                    fputs("decl ", fp);
+                    MR_trace_write_quoted_atom(fp, id->MR_user_decl_module);
+                }
+
                         fputc(' ', fp);
                         MR_trace_write_quoted_atom(fp, id->MR_user_name);
-                        fprintf(fp, " %d %d\n",
-                            id->MR_user_arity, id->MR_user_mode);
+                fprintf(fp, " %d %d\n", id->MR_user_arity, id->MR_user_mode);
                     }
 
                     port = label->MR_sll_port;
@@ -367,34 +522,41 @@
                     switch (path_port) {
 
                         case PORT_ONLY:
-                            fprintf(fp, "%s %" MR_INTEGER_LENGTH_MODIFIER "u",
-                                MR_port_names[port], exec_count);
+                    fputs(MR_port_names[port], fp);
                             break;
 
                         case PATH_ONLY:
-                            fprintf(fp,
-                                "<%s> %" MR_INTEGER_LENGTH_MODIFIER "u",
-                                MR_label_goal_path(label), exec_count);
+                    putc('<', fp);
+                    fputs(MR_label_goal_path(label), fp);
+                    putc('>', fp);
                             break;
 
                         case PORT_AND_PATH:
-                            fprintf(fp,
-                                "%s <%s> %" MR_INTEGER_LENGTH_MODIFIER "u",
-                                MR_port_names[port], MR_label_goal_path(label),
-                                exec_count);
+                    fputs(MR_port_names[port], fp);
+                    putc(' ', fp);
+                    putc('<', fp);
+                    fputs(MR_label_goal_path(label), fp);
+                    putc('>', fp);
                             break;
 
                         default:
-                            MR_fatal_error("MR_trace_write_label_exec_counts: "
+                    MR_fatal_error(
+                        "MR_trace_write_label_exec_counts_for_file: "
                                 "bad path_port");
                             break;
                     }
 
-                    fprintf(fp, " %d\n", file->MR_mfl_label_lineno[label_num]);
+            putc(' ', fp);
+            fprintf(fp, "%d", file->MR_mfl_label_lineno[label_num]);
 
-                    prev_proc = proc;
-                }
+            if (exec_count > 0) {
+                putc(' ', fp);
+                fprintf(fp, "%" MR_INTEGER_LENGTH_MODIFIER "u", exec_count);
             }
+
+            putc('\n', fp);
+
+            prev_proc = proc;
         }
     }
 }
@@ -404,6 +566,8 @@
 {
     static MR_bool  done = MR_FALSE;
     
+    MR_do_init_modules_debugger();
+
     if (! done) {
         MR_Trace_Port   port;
 
Index: runtime/mercury_trace_base.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_trace_base.h,v
retrieving revision 1.53
diff -u -b -r1.53 mercury_trace_base.h
--- runtime/mercury_trace_base.h	14 Sep 2006 00:15:47 -0000	1.53
+++ runtime/mercury_trace_base.h	14 Sep 2006 02:58:37 -0000
@@ -117,11 +117,9 @@
 
 /*
 ** For every label reachable from the module table, write the id of the label
-** and the number of times it has been executed to trace counts file of this
-** program, with the exception of labels that haven't been executed.
-**
-** The dummy argument allows this function to be registered with
-** MR_register_exception_cleanup.
+** and the number of times it has been executed to the specified file. For 
+** labels that haven't been executed, write them out only if the coverage_test
+** argument is true.
 **
 ** 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
@@ -130,7 +128,19 @@
 
 #define	MR_TRACE_COUNT_FILE_ID	    "Mercury trace counts file\n"
 
-extern	void	MR_trace_write_label_exec_counts_to_file(void *dummy);
+extern	void		MR_trace_write_label_exec_counts(FILE *fp,
+				MR_bool coverage_test);
+
+/*
+** Figout out where (to which file) to write out the label execution counts,
+** and then invoke MR_trace_write_label_exec_counts to write it out there.
+** If the user has asked for this data to be summarized, do that too.
+**
+** The dummy argument allows this function to be registered with
+** MR_register_exception_cleanup.
+*/
+
+extern	void		MR_trace_record_label_exec_counts(void *dummy);
 
 /*
 ** MR_trace_init() is called from mercury_runtime_init()
@@ -204,6 +214,21 @@
 extern	MR_bool		MR_coverage_test_enabled;
 
 /*
+** If MR_trace_count_summary_file is not NULL, then its value gives the
+** name of the file in which to accumulate trace count information. If this
+** file doesn't exist, the trace counts data will be printed to it. If this
+** file does exist, the trace counts data will be printed to files with this
+** name as a base name plus a suffix .1, .2, .3 etc until the number reaches
+** MR_trace_count_summary_max, at which point the program will invoke
+** the command named by MR_trace_count_summary_cmd to consolidate all those
+** trace counts in one file (the one named by MR_trace_count_summary_file).
+*/
+
+extern	const char	*MR_trace_count_summary_file;
+extern	const char	*MR_trace_count_summary_cmd;
+extern	unsigned int	MR_trace_count_summary_max;
+
+/*
 ** 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
@@ -253,7 +278,6 @@
 extern	MR_Code *(*volatile MR_selected_trace_func_ptr)(
 			const MR_Label_Layout *);
 
-
 /*
 ** MR_trace_call_seqno counts distinct calls. The prologue of every
 ** procedure assigns the current value of this counter as the sequence number
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.166
diff -u -b -r1.166 mercury_wrapper.c
--- runtime/mercury_wrapper.c	14 Sep 2006 00:15:47 -0000	1.166
+++ runtime/mercury_wrapper.c	14 Sep 2006 04:05:56 -0000
@@ -422,10 +422,11 @@
 
 #endif
 
-static  void    process_args(int argc, char **argv);
-static  void    process_environment_options(void);
-static  void    process_options(int argc, char **argv);
-static  void    usage(void);
+static  void    MR_process_args(int argc, char **argv);
+static  void    MR_process_environment_options(void);
+static  void    MR_process_options(int argc, char **argv);
+static  void    MR_usage(void);
+static  MR_bool MR_matches_exec_name(const char *option);
 
 #ifdef MR_TYPE_CTOR_STATS
 static  void    MR_print_type_ctor_stats(void);
@@ -505,8 +506,8 @@
     ** variable MERCURY_OPTIONS, and save results in global variables.
     */
 
-    process_args(argc, argv);
-    process_environment_options();
+    MR_process_args(argc, argv);
+    MR_process_environment_options();
 
 #ifdef  MR_STACK_FRAME_STATS
     MR_init_stack_frame_stats();
@@ -654,8 +655,7 @@
         ** In case the program terminates with an exception,
         ** we still want the trace count to be written out.
         */
-        MR_register_exception_cleanup(MR_trace_write_label_exec_counts_to_file,
-            NULL);
+        MR_register_exception_cleanup(MR_trace_record_label_exec_counts, NULL);
     }
 
     /*
@@ -922,13 +922,13 @@
 }
 
 /*  
-** process_args() is a function that sets some global variables from the
+** MR_process_args() is a function that sets some global variables from the
 ** command line.  `mercury_arg[cv]' are `arg[cv]' without the program name.
 ** `progname' is program name.
 */
 
 static void
-process_args(int argc, char **argv)
+MR_process_args(int argc, char **argv)
 {
     MR_progname = argv[0];
     mercury_argc = argc - 1;
@@ -936,12 +936,12 @@
 }
 
 /*
-** process_environment_options() is a function to parse the MERCURY_OPTIONS
+** MR_process_environment_options() is a function to parse the MERCURY_OPTIONS
 ** environment variable.  
 */ 
 
 static void
-process_environment_options(void)
+MR_process_environment_options(void)
 {
     char    *env_options;
 
@@ -983,7 +983,7 @@
         }
         MR_GC_free(dummy_command_line);
 
-        process_options(argc, argv);
+        MR_process_options(argc, argv);
 
         MR_GC_free(arg_str);
         MR_GC_free(argv);
@@ -1041,7 +1041,12 @@
     MR_DEEP_PROF_DEBUG_FILE_OPT,
     MR_TABLING_STATISTICS_OPT,
     MR_TRACE_COUNT_OPT,
+    MR_TRACE_COUNT_IF_EXEC_OPT,
+    MR_TRACE_COUNT_SUMMARY_FILE_OPT,
+    MR_TRACE_COUNT_SUMMARY_CMD_OPT,
+    MR_TRACE_COUNT_SUMMARY_MAX_OPT,
     MR_COVERAGE_TEST_OPT,
+    MR_COVERAGE_TEST_IF_EXEC_OPT,
     MR_TRACE_COUNT_FILE,
     MR_MEM_USAGE_REPORT
 };
@@ -1112,7 +1117,12 @@
     { "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 },
+    { "trace-count-if-exec",            1, 0, MR_TRACE_COUNT_IF_EXEC_OPT },
+    { "trace-count-summary-file",       1, 0, MR_TRACE_COUNT_SUMMARY_FILE_OPT },
+    { "trace-count-summary-cmd",        1, 0, MR_TRACE_COUNT_SUMMARY_CMD_OPT },
+    { "trace-count-summary-max",        1, 0, MR_TRACE_COUNT_SUMMARY_MAX_OPT },
     { "coverage-test",                  0, 0, MR_COVERAGE_TEST_OPT },
+    { "coverage-test-if-exec",          1, 0, MR_COVERAGE_TEST_IF_EXEC_OPT },
     { "tc-output-file",                 1, 0, MR_TRACE_COUNT_FILE },
     { "mem-usage-report",               0, 0, MR_MEM_USAGE_REPORT },
 
@@ -1121,7 +1131,7 @@
 };
 
 static void
-process_options(int argc, char **argv)
+MR_process_options(int argc, char **argv)
 {
     unsigned long   size;
     int             c;
@@ -1134,7 +1144,7 @@
         {
             case MR_HEAP_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_heap_size = size;
@@ -1142,7 +1152,7 @@
 
             case MR_HEAP_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_heap_size = size * sizeof(MR_Word);
@@ -1150,7 +1160,7 @@
 
             case MR_DETSTACK_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_detstack_size = size;
@@ -1158,7 +1168,7 @@
 
             case MR_DETSTACK_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_detstack_size = size * sizeof(MR_Word);
@@ -1166,7 +1176,7 @@
 
             case MR_NONDETSTACK_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_nondstack_size = size;
@@ -1174,7 +1184,7 @@
 
             case MR_NONDETSTACK_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_nondstack_size = size * sizeof(MR_Word);
@@ -1182,7 +1192,7 @@
 
             case MR_SOLUTIONS_HEAP_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_solutions_heap_size = size;
@@ -1190,7 +1200,7 @@
 
             case MR_SOLUTIONS_HEAP_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_solutions_heap_size = size * sizeof(MR_Word);
@@ -1198,7 +1208,7 @@
 
             case MR_TRAIL_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_trail_size = size;
@@ -1206,7 +1216,7 @@
 
             case MR_TRAIL_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_trail_size = size * sizeof(MR_Word);
@@ -1214,7 +1224,7 @@
 
             case MR_HEAP_REDZONE_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_heap_zone_size = size;
@@ -1222,7 +1232,7 @@
 
             case MR_HEAP_REDZONE_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_heap_zone_size = size * sizeof(MR_Word);
@@ -1230,7 +1240,7 @@
 
             case MR_DETSTACK_REDZONE_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_detstack_zone_size = size;
@@ -1238,7 +1248,7 @@
 
             case MR_DETSTACK_REDZONE_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_detstack_zone_size = size * sizeof(MR_Word);
@@ -1246,7 +1256,7 @@
 
             case MR_NONDETSTACK_REDZONE_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_nondstack_zone_size = size;
@@ -1254,7 +1264,7 @@
 
             case MR_NONDETSTACK_REDZONE_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_nondstack_zone_size = size * sizeof(MR_Word);
@@ -1262,7 +1272,7 @@
 
             case MR_SOLUTIONS_HEAP_REDZONE_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_solutions_heap_zone_size = size;
@@ -1270,7 +1280,7 @@
 
             case MR_SOLUTIONS_HEAP_REDZONE_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_solutions_heap_zone_size = size * sizeof(MR_Word);
@@ -1278,7 +1288,7 @@
 
             case MR_TRAIL_REDZONE_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_trail_zone_size = size;
@@ -1286,7 +1296,7 @@
 
             case MR_TRAIL_REDZONE_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_trail_zone_size = size * sizeof(MR_Word);
@@ -1294,7 +1304,7 @@
 
             case MR_HEAP_MARGIN_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_heap_margin_size = size;
@@ -1302,7 +1312,7 @@
 
             case MR_HEAP_MARGIN_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_heap_margin_size = size * sizeof(MR_Word);
@@ -1310,13 +1320,13 @@
 
             case MR_HEAP_EXPANSION_FACTOR:
                 if (sscanf(MR_optarg, "%lf", &MR_heap_expansion_factor) != 1) {
-                    usage();
+                    MR_usage();
                 }
                 break;
 
             case MR_GENSTACK_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_genstack_size = size;
@@ -1324,7 +1334,7 @@
 
             case MR_GENSTACK_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_genstack_size = size * sizeof(MR_Word);
@@ -1332,7 +1342,7 @@
 
             case MR_CUTSTACK_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_cutstack_size = size;
@@ -1340,7 +1350,7 @@
 
             case MR_CUTSTACK_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_cutstack_size = size * sizeof(MR_Word);
@@ -1348,7 +1358,7 @@
 
             case MR_PNEGSTACK_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_pnegstack_size = size;
@@ -1356,7 +1366,7 @@
 
             case MR_PNEGSTACK_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_pnegstack_size = size * sizeof(MR_Word);
@@ -1364,7 +1374,7 @@
 
             case MR_GEN_DETSTACK_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_gen_detstack_size = size;
@@ -1372,7 +1382,7 @@
 
             case MR_GEN_DETSTACK_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_gen_detstack_size = size * sizeof(MR_Word);
@@ -1380,7 +1390,7 @@
 
             case MR_GEN_NONSTACK_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_gen_nonstack_size = size;
@@ -1388,7 +1398,7 @@
 
             case MR_GEN_NONSTACK_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_gen_nonstack_size = size * sizeof(MR_Word);
@@ -1396,7 +1406,7 @@
 
             case MR_GEN_DETSTACK_REDZONE_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_gen_detstack_zone_size = size;
@@ -1404,7 +1414,7 @@
 
             case MR_GEN_DETSTACK_REDZONE_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_gen_detstack_zone_size = size * sizeof(MR_Word);
@@ -1412,7 +1422,7 @@
 
             case MR_GEN_NONSTACK_REDZONE_SIZE:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_gen_nonstack_zone_size = size;
@@ -1420,7 +1430,7 @@
 
             case MR_GEN_NONSTACK_REDZONE_SIZE_KWORDS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_gen_nonstack_zone_size = size * sizeof(MR_Word);
@@ -1451,7 +1461,7 @@
             case 'n':
             case MR_NUM_OUTPUT_ARGS:
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_num_output_args = size;
@@ -1499,12 +1509,58 @@
                 MR_trace_count_enabled = MR_TRUE;
                 break;
 
+            case MR_TRACE_COUNT_IF_EXEC_OPT:
+                if (MR_matches_exec_name(MR_optarg)) {
+                    MR_trace_count_enabled = MR_TRUE;
+                }
+                break;
+
+            case MR_TRACE_COUNT_SUMMARY_FILE_OPT:
+                if (MR_trace_counts_file != NULL) {
+                    MR_fatal_error(
+                        "--trace-count-file and --trace-count-summary-file"
+                        " are mutually exclusive\n");
+                }
+
+                MR_trace_count_summary_file = MR_copy_string(MR_optarg);
+                MR_trace_count_enabled = MR_TRUE;
+                break;
+
+            case MR_TRACE_COUNT_SUMMARY_CMD_OPT:
+                MR_trace_count_summary_cmd = MR_copy_string(MR_optarg);
+                break;
+
+            case MR_TRACE_COUNT_SUMMARY_MAX_OPT:
+                if (sscanf(MR_optarg, "%lu", &size) != 1) {
+                    MR_usage();
+                }
+
+                if (size < 2) {
+                    MR_usage();
+                }
+
+                MR_trace_count_summary_max = size;
+                break;
+
             case MR_COVERAGE_TEST_OPT:
                 MR_coverage_test_enabled = MR_TRUE;
                 MR_trace_count_enabled = MR_TRUE;
                 break;
 
+            case MR_COVERAGE_TEST_IF_EXEC_OPT:
+                if (MR_matches_exec_name(MR_optarg)) {
+                    MR_coverage_test_enabled = MR_TRUE;
+                    MR_trace_count_enabled = MR_TRUE;
+                }
+                break;
+
             case MR_TRACE_COUNT_FILE:
+                if (MR_trace_count_summary_file != NULL) {
+                    MR_fatal_error(
+                        "--trace-count-file and --trace-count-summary-file"
+                        " are mutually exclusive\n");
+                }
+
                 MR_trace_counts_file = MR_copy_string(MR_optarg);
                 break;
 
@@ -1522,7 +1578,7 @@
 
             case 'C':
                 if (sscanf(MR_optarg, "%lu", &size) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 MR_pcache_size = size * 1024;
@@ -1548,7 +1604,7 @@
                     MR_nondstackdebug = MR_TRUE;
                 } else if (MR_streq(MR_optarg, "B")) {
                     if (sscanf(MR_optarg+1, "%u", &MR_lld_start_block) != 1) {
-                        usage();
+                        MR_usage();
                     }
                 } else if (MR_streq(MR_optarg, "c")) {
                     MR_calldebug    = MR_TRUE;
@@ -1609,11 +1665,11 @@
 
                     if (MR_optarg[1] == '0' && MR_optarg[2] == 'x') {
                         if (sscanf(MR_optarg+3, "%lx", &addr) != 1) {
-                            usage();
+                            MR_usage();
                         }
                     } else {
                         if (sscanf(MR_optarg+1, "%lu", &addr) != 1) {
-                            usage();
+                            MR_usage();
                         }
                     }
 
@@ -1630,7 +1686,7 @@
                     */
                     MR_calldebug = MR_TRUE;
                 } else {
-                    usage();
+                    MR_usage();
                 }
 
                 use_own_timer = MR_FALSE;
@@ -1647,7 +1703,7 @@
                     MR_trace_handler = MR_TRACE_EXTERNAL;
 #endif
                 } else {
-                    usage();
+                    MR_usage();
                 }
 
                 break;
@@ -1659,18 +1715,18 @@
             case 'P':
 #ifdef  MR_THREAD_SAFE
                 if (sscanf(MR_optarg, "%u", &MR_num_threads) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 if (MR_num_threads < 1) {
-                    usage();
+                    MR_usage();
                 }
 #endif
                 break;
 
             case 'r':   
                 if (sscanf(MR_optarg, "%d", &repeats) != 1) {
-                    usage();
+                    MR_usage();
                 }
 
                 break;
@@ -1704,7 +1760,7 @@
                 } else if (MR_streq(MR_optarg, "p")) {
                     MR_time_profile_method = MR_profile_user_plus_system_time;
                 } else {
-                    usage();
+                    MR_usage();
                 }
                 break;
 
@@ -1721,7 +1777,7 @@
                 break;
 
             default:    
-                usage();
+                MR_usage();
 
         }
     }
@@ -1743,7 +1799,7 @@
 }
 
 static void 
-usage(void)
+MR_usage(void)
 {
     printf("The MERCURY_OPTIONS environment variable "
         "contains an invalid option.\n"
@@ -1753,6 +1809,26 @@
     exit(1);
 }
 
+static MR_bool
+MR_matches_exec_name(const char *option)
+{
+    char        *s;
+    const char  *exec_name;
+
+    s = strrchr(MR_progname, '/');
+    if (s == NULL) {
+        exec_name = MR_progname;
+    } else {
+        exec_name = s + 1;
+    }
+
+    if (MR_streq(option, exec_name)) {
+        return MR_TRUE;
+    } else {
+        return MR_FALSE;
+    }
+}
+
 /*
 ** Get the next interval from *more_str_ptr, which should point to a string
 ** containing a comma-separated list of integer intervals. The last interval
@@ -2280,7 +2356,7 @@
     MR_trace_final();
 
     if (MR_trace_count_enabled) {
-        MR_trace_write_label_exec_counts_to_file(NULL);
+        MR_trace_record_label_exec_counts(NULL);
     }
 
 #if defined(MR_MPROF_PROFILE_TIME) || defined(MR_MPROF_PROFILE_CALLS) \
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
Index: scripts/mtc
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/scripts/mtc,v
retrieving revision 1.2
diff -u -b -r1.2 mtc
--- scripts/mtc	14 Sep 2006 00:15:48 -0000	1.2
+++ scripts/mtc	18 Sep 2006 03:37:56 -0000
@@ -17,68 +17,164 @@
 	enabled (e.g. using the \`--debug' option), or if that command invokes
 	such a program, then mtc will cause the program to count the
 	number of times each event is executed, and to write out that data
-	to a file with a .mercury_trace_counts prefix when the program exits.
-	Otherwise, mtc will execute the command line as if the mtc prefix
-	weren't there.
+	to a file. Otherwise, mtc will execute the command line as if the
+	mtc prefix weren't there.
 
 Options:
-	-o <file-name>, --output-file <file-name>
-		Save the generated trace counts to <file-name>.  If this
-		option is not given then a filename is automatically
-		generated.
+	-c, --coverage-test
+		Ordinarily, the generated trace count file contains only
+		nonzero trace counts. This option causes even zero counts
+		to be written out, since coverage testing needs to know
+		which parts of the code are not executed.
+
+	-o <filename>, --output-file <filename>
+		Save the generated trace counts to <filename>.
+
+	-s <basename>, --summary-file=<basename>
+		If this option is given, the trace counts are put into a new
+		file whose name is <basename>.N for a small integer N, choosing
+		N to be the smallest integer for which <basename>.N doesn't yet
+		exist. If this is not initially possible for a small enough N
+		(due probably to previous runs), then the program will replace
+		all of the <basename>.N files with a summary named just
+		<basename>; if <basename> existed already, it will be included
+		in the summary as well. This way, at the end of a sequence of
+		runs of the program, the command \"mtc_union <basename>*\"
+		will compute a summary of all the trace counts files.
+
+	--summary-count=<maxN>
+		Gives the maximum value of N to use with --summary-file.
 
 	--help
 		Display this message.
 
+If neither the -o nor the -s option is given, then the trace counts are put
+into a file whose name is automatically generated. This name will start with
+the prefix ".mercury_trace_counts", followed by a mangled version of the
+name of the executable, and then the process id.
+
+The -o and -s options are mutually exclusive.
+
 Environment variables:
 	MERCURY_OPTIONS.
 "
 
-output_file=""
-
 #-----------------------------------------------------------------------------#
 #
 # process the command line options
 #
 
-case $# in
-	0)	echo "Usage: mtc <executable> [<arg> ...]" 1>&2
-		exit 1 ;;
-esac
+coverage_test=false
+output_file=""
+summary_file=""
+summary_limit=""
 
-while : ; do
+while test "$#" -gt 0
+do
 	case "$1" in
+		-c|--coverage-test)
+			coverage_test=true
+			;;
+
 		--help)
 			echo "$Help"
-			exit 0 ;;
+			exit 0
+			;;
+
 		-o|--output-file)
 			output_file="$2";
-			shift; shift ;;
+			shift
+			;;
+
+		-o*)
+			output_file="`expr $1 : '-o\(.*\)'`"
+			;;
+
+		--output-file=*)
+			output_file="`expr $1 : '--output-file=\(.*\)'`"
+			;;
+
+		-s|--summary-file)
+			summary_file="$2"
+			shift
+			;;
+
+		-s*)
+			summary_file="`expr $1 : '-s\(.*\)'`"
+			;;
+
+		--summary-file=*)
+			summary_file="`expr $1 : '--summary-file=\(.*\)'`"
+			;;
+
+		--summary-limit)
+			summary_limit="$2"
+			shift
+			;;
+
+		--summary-limit=*)
+			summary_limit="`expr $1 : '--summary-limit=\(.*\)'`"
+			;;
+
 		--)
-			shift; break ;;
+			shift
+			break
+			;;
+
 		-*)
 			echo "$0: unknown option \`$1'" 1>&2
-			exit 1 ;;
+			exit 1
+			;;
+
 		*)
-			break ;;
+			break
+			;;
 	esac
+	shift
 done
 
+case $# in
+	0)	echo "Usage: mtc [options] <executable> [<arg> ...]" 1>&2
+		exit 1
+		;;
+esac
+
+if test "$output_file" != "" -a "$summary_file" != ""
+then
+	echo "The options --output-file and --summary-file are incompatible."
+	exit 1
+fi
+
 #-----------------------------------------------------------------------------#
 #
-# Set the environment variables used by the Mercury runtime to the
-# the appropriate values to enable the gathering of trace counts,
-# and then finally use $invoke_cmd to invoke the command.
+# Set the environment variables used by the Mercury runtime to the appropriate
+# values to enable the gathering of trace counts, and then finally use
+# $invoke_cmd to invoke the command.
 #
 
-case $output_file in
-    "") enable_trace_count_opt="--trace-count"
-    	;;
-    *)	enable_trace_count_opt="--trace-count --tc-output-file $output_file"
+MERCURY_OPTIONS="$MERCURY_OPTIONS --trace-count"
+
+if "$coverage_test"
+then
+	MERCURY_OPTIONS="$MERCURY_OPTIONS --coverage-test"
+fi
+
+if test "$summary_file" != ""
+then
+	MERCURY_OPTIONS="$MERCURY_OPTIONS --trace-count-summary-file=$summary_file"
+fi
+
+if test "$summary_limit" != ""
+then
+	MERCURY_OPTIONS="$MERCURY_OPTIONS --trace-count-summary-limit=$summary_limit"
+fi
+
+if test "$output_file" != ""
+then
+	MERCURY_OPTIONS="$MERCURY_OPTIONS --tc-output-file $output_file"
     	;;
 esac
 
-MERCURY_OPTIONS="$MERCURY_OPTIONS $enable_trace_count_opt"
 export MERCURY_OPTIONS
 exec "$@"
 
cvs diff: Diffing slice
Index: slice/.mgnuc_copts
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/slice/.mgnuc_copts,v
retrieving revision 1.1
diff -u -b -r1.1 .mgnuc_copts
--- slice/.mgnuc_copts	20 May 2005 06:15:22 -0000	1.1
+++ slice/.mgnuc_copts	18 Sep 2006 03:41:11 -0000
@@ -1,10 +0,0 @@
--I../boehm_gc
--I../boehm_gc/include
--I../runtime
--I../library
--I../library/Mercury/mihs
--I../mdbcomp
--I../mdbcomp/Mercury/mihs
--I../browser
--I../browser/Mercury/mihs
--I../trace
Index: slice/.mgnuc_opts
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/slice/.mgnuc_opts,v
retrieving revision 1.1
diff -u -b -r1.1 .mgnuc_opts
--- slice/.mgnuc_opts	19 Sep 2005 08:07:12 -0000	1.1
+++ slice/.mgnuc_opts	18 Sep 2006 03:41:14 -0000
@@ -1 +0,0 @@
---no-mercury-stdlib-dir
Index: slice/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/slice/Mmakefile,v
retrieving revision 1.4
diff -u -b -r1.4 Mmakefile
--- slice/Mmakefile	16 Dec 2005 05:49:40 -0000	1.4
+++ slice/Mmakefile	24 Mar 2006 14:18:29 -0000
@@ -6,9 +6,8 @@
 
 # Mmakefile for building the Mercury slice and dice tools.
 
-MERCURY_DIR=..
-LINK_STATIC=yes
-include $(MERCURY_DIR)/Mmake.common
+GRADE = $(DEFAULT_GRADE)
+MC = mmc
 
 -include Mmake.slice.params
 
@@ -21,51 +20,53 @@
 include Mercury.options
 
 MAIN_TARGET		= all
-MERCURY_MAIN_MODULES	= mslice mdice mtc_union
+
+# If you add more modules, you'll also have to modify ../Mmakefile.
+MERCURY_MAIN_MODULES	= mct mslice mdice mtc_union mtc_diff
+MERCURY_MAIN_MODULES_MS	= $(mct.ms) $(mslice.ms) $(mdice.ms) $(mtc_union.ms) \
+				$(mtc_diff.ms)
+
 DEPENDS	= $(patsubst %,%.depend,$(MERCURY_MAIN_MODULES))
 INTS	= $(patsubst %,%.ints,$(MERCURY_MAIN_MODULES))
 INT3S	= $(patsubst %,%.int3s,$(MERCURY_MAIN_MODULES))
 CHECKS	= $(patsubst %,%.check,$(MERCURY_MAIN_MODULES))
 
-VPATH = $(MDBCOMP_DIR) $(LIBRARY_DIR)
-
 #-----------------------------------------------------------------------------#
 
-MLFLAGS += --shared
-MCFLAGS += --flags SLICE_FLAGS $(CONFIG_OVERRIDE)
+MDBCOMP_DIR = ../mdbcomp
+
+MDBCOMP_MODULES = \
+	mdbcomp.m \
+	prim_data.m \
+	program_representation.m \
+	rtti_access.m \
+	slice_and_dice.m \
+	trace_counts.m
+
+MDBCOMP_ORIG_MODULES = $(patsubst %,$(MDBCOMP_DIR)/%,$(MDBCOMP_MODULES))
 
 #-----------------------------------------------------------------------------#
 
 .PHONY: depend
-depend:	$(DEPENDS)
-
-$(DEPENDS): SLICE_FLAGS
+depend:	$(MDBCOMP_MODULES) $(DEPENDS)
 
 .PHONY: all
-all:	$(MERCURY_MAIN_MODULES) $(TAGS_FILE_EXISTS)
-
-#-----------------------------------------------------------------------------#
+all:	$(MDBCOMP_MODULES) $(MERCURY_MAIN_MODULES) tags_file_exists
 
-# Add some additional dependencies, so that Mmake knows to remake the
-# slicer and dicer if one of the libraries changes.
+# We need to start by turn write permission on for each copied file
+# in case some exist, but we need to ignore errors in case some don't exist.
+# The exit 0 is to prevent make itself from printing a message about the
+# (ignored) failure of an action.
+#
+# We could modify the action here to copy only the changed files.
+
+$(MDBCOMP_MODULES): $(MDBCOMP_ORIG_MODULES)
+	- at chmod a+w $(MDBCOMP_MODULES) > /dev/null 2>&1; exit 0
+	cp $(MDBCOMP_ORIG_MODULES) .
+	@chmod a-w $(MDBCOMP_MODULES)
 
-ifeq ("$(filter il% java%,$(GRADE))","")        
-mslice: $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
-mslice: $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
-mslice: $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
-mdice: $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
-mdice: $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
-mdice: $(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.
-mtc_union: $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
-mtc_union: $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
-mtc_union: $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
-endif
-
-$(cs_subdir)mslice_init.c: $(UTIL_DIR)/mkinit
-$(cs_subdir)mdice_init.c: $(UTIL_DIR)/mkinit
-$(cs_subdir)mtc_union.c: $(UTIL_DIR)/mkinit
+PROGS:
+	echo $(MERCURY_MAIN_MODULES) > PROGS
 
 #-----------------------------------------------------------------------------#
 
@@ -77,53 +78,47 @@
 
 #-----------------------------------------------------------------------------#
 
-tags:	$(MTAGS) $(mslice.ms) $(mdice.ms) $(mtc_union.ms) $(LIBRARY_DIR)/*.m
-	$(MTAGS) $(mslice.ms) $(mdice.ms) $(mtc_union.ms) $(LIBRARY_DIR)/*.m
+tags:	$(MERCURY_MAIN_MODULES_MS) $(MDBCOMP_DIR)/*.m ../library/*.m
+	mtags $(MERCURY_MAIN_MODULES_MS) $(MDBCOMP_DIR)/*.m ../library/*.m
 
 .PHONY: tags_file_exists
 tags_file_exists:
 	@if test ! -f tags; then echo making tags; \
-	$(MTAGS) $(mslice.ms) $(mdice.ms) $(mtc_union.ms) $(LIBRARY_DIR)/*.m; \
+	mtags $(MERCURY_MAIN_MODULES_MS) $(MDBCOMP_DIR)/*.m ../library/*.m; \
 	fi
 
 #-----------------------------------------------------------------------------#
 
 .PHONY: dates
 dates:
-	touch $(mslice.dates) $(mdice.dates) $(mtc_union.dates)
+	touch $(mct.dates) $(mslice.dates) $(mdice.dates) \
+		$(mtc_union.dates) $(mtc_diff.dates)
 
 #-----------------------------------------------------------------------------#
 
 .PHONY: os cs ss ils
-os:	$(mslice.os) $(mdice.os) $(mtc_union.os) \
-	$(os_subdir)mslice_init.o $(os_subdir)mdice_init.o \
-	$(os_subdir)mtc_union.o
-cs:	$(mslice.cs) $(mdice.cs) $(mtc_union.cs) \
-	$(cs_subdir)mslice_init.c $(cs_subdir)mdice_init.c \
-	$(cs_subdir)mtc_union.c
-ss:	$(mslice.ss) $(mdice.ss) $(mtc_union.ss)
-ils:	$(mslice.ils) $(mdice.ils) $(mtc_union.ils)
+os:	$(mct.os) $(mslice.os) $(mdice.os) $(mtc_union.os) $(mtc_diff.os) \
+	$(os_subdir)mct_init.o \
+	$(os_subdir)mslice_init.o \
+	$(os_subdir)mdice_init.o \
+	$(os_subdir)mtc_union_init.o \
+	$(os_subdir)mtc_diff_init.o
+cs:	$(mct.cs) $(mslice.cs) $(mdice.cs) $(mtc_union.cs) $(mtc_diff.cs) \
+	$(cs_subdir)mct_init.c \
+	$(cs_subdir)mslice_init.c \
+	$(cs_subdir)mdice_init.c \
+	$(cs_subdir)mtc_union_init.c \
+	$(cs_subdir)mtc_diff_init.c
+ss:	$(mct.ss) $(mslice.ss) $(mdice.ss) $(mtc_union.ss) $(mtc_diff.ss)
+ils:	$(mct.ils) $(mslice.ils) $(mdice.ils) $(mtc_union.ils) $(mtc_diff.ils)
 
 #-----------------------------------------------------------------------------#
 
 realclean_local:
-	rm -f tags SLICE_FLAGS SLICE_FLAGS.date
+	/bin/rm -fr $(MDBCOMP_MODULES) mdbcomp.*.err tags
 
 #-----------------------------------------------------------------------------#
 
-# Installation targets
-
-.PHONY: install
-install: install_slicer
-
-.PHONY: install_slicer
-install_slicer: mslice mdice mtc_union
-	-[ -d $(INSTALL_MERC_BIN_DIR) ] || mkdir -p $(INSTALL_MERC_BIN_DIR)
-	cp `vpath_find mslice$(EXT_FOR_EXE)` \
-		$(INSTALL_MERC_BIN_DIR)/mslice$(EXT_FOR_EXE)
-	cp `vpath_find mdice$(EXT_FOR_EXE)` \
-		$(INSTALL_MERC_BIN_DIR)/mdice$(EXT_FOR_EXE)
-	cp `vpath_find mtc_union$(EXT_FOR_EXE)` \
-		$(INSTALL_MERC_BIN_DIR)/mtc_union$(EXT_FOR_EXE)
+# The installation targets are in the top-level Mmakefile.
 
 #-----------------------------------------------------------------------------#
Index: slice/SLICE_FLAGS.in
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/slice/SLICE_FLAGS.in,v
retrieving revision 1.2
diff -u -b -r1.2 SLICE_FLAGS.in
--- slice/SLICE_FLAGS.in	12 Jan 2006 07:07:31 -0000	1.2
+++ slice/SLICE_FLAGS.in	18 Sep 2006 03:41:32 -0000
@@ -1,19 +0,0 @@
- at BOOTSTRAP_MC_ARGS@
---no-infer-all
---halt-at-warn
---no-warn-inferred-erroneous
---no-mercury-stdlib-dir
--I../library
--I../browser
--I../mdbcomp
---c-include-directory ../boehm_gc
---c-include-directory ../boehm_gc/include
---c-include-directory ../runtime
---c-include-directory ../library
---c-include-directory ../library/Mercury/mihs
---c-include-directory ../mdbcomp
---c-include-directory ../mdbcomp/Mercury/mihs
---c-include-directory ../browser
---c-include-directory ../browser/Mercury/mihs
---c-include-directory ../trace
---config-file ../scripts/Mercury.config.bootstrap
Index: slice/mct.m
===================================================================
RCS file: slice/mct.m
diff -N slice/mct.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ slice/mct.m	1 Apr 2006 05:56:19 -0000
@@ -0,0 +1,287 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 expandtab
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2006 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 coverage test tool.
+%
+% Author: Zoltan Somogyi.
+%
+%-----------------------------------------------------------------------------%
+
+:- module mct.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module mdbcomp.
+:- import_module mdbcomp.prim_data.
+:- import_module mdbcomp.trace_counts.
+
+:- import_module assoc_list.
+:- import_module bool.
+:- import_module getopt.
+:- import_module int.
+:- import_module list.
+:- import_module map.
+:- import_module maybe.
+:- import_module pair.
+:- import_module require.
+:- import_module set.
+:- import_module string.
+:- import_module svmap.
+
+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 = [_ | _],
+            lookup_bool_option(OptionTable, verbose, Verbose),
+            read_and_union_trace_counts(Verbose, try_single_first, Args,
+                _NumTests, Kinds, TraceCounts, MaybeReadError, !IO),
+            stderr_stream(StdErr, !IO),
+            (
+                MaybeReadError = yes(ReadErrorMsg),
+                io.write_string(StdErr, ReadErrorMsg, !IO),
+                io.nl(StdErr, !IO)
+            ;
+                MaybeReadError = no,
+                set.to_sorted_list(Kinds, KindList),
+                ( KindList = [user_all] ->
+                    true
+                ;
+                    io.write_string(StdErr,
+                        "warning: some of the original trace count files\n",
+                        !IO),
+                    io.write_string(StdErr, "did not include all counts.\n",
+                        !IO)
+                ),
+                lookup_bool_option(OptionTable, detailed, Detailed),
+                lookup_string_option(OptionTable, output_filename, OutputFile),
+                ( OutputFile = "" ->
+                    write_coverage_test(Detailed, TraceCounts, !IO)
+                ;
+                    io.tell(OutputFile, OpenRes, !IO),
+                    (
+                        OpenRes = ok,
+                        write_coverage_test(Detailed, TraceCounts, !IO)
+                    ;
+                        OpenRes = error(OpenErrorMsg),
+                        io.write_string(StdErr, "Error opening " ++
+                            "file `" ++ OutputFile ++ "'" ++ ": " ++
+                            string(OpenErrorMsg), !IO),
+                        io.nl(StdErr, !IO)
+                    )
+                )
+            )
+        ;
+            Args = [],
+            usage(!IO)
+        )
+    ;
+        GetoptResult = error(GetoptErrorMsg),
+        io.write_string(GetoptErrorMsg, !IO),
+        io.nl(!IO)
+    ).
+
+%-----------------------------------------------------------------------------%
+
+:- type proc_info
+    --->    proc_info(
+                proc_source_file    :: string,
+                proc_line_number    :: int,
+                proc_proc           :: proc_label
+            ).
+
+:- type label_info
+    --->    label_info(
+                label_source_file   :: string,
+                label_line_number   :: int,
+                label_proc          :: proc_label,
+                label_path_port     :: path_port
+            ).
+
+:- pred write_coverage_test(bool::in, trace_counts::in, io::di, io::uo) is det.
+
+write_coverage_test(Detailed, TraceCountMap, !IO) :-
+    map.to_assoc_list(TraceCountMap, TraceCounts),
+    (
+        Detailed = no,
+        collect_zero_count_procs(TraceCounts, ZeroCountProcs),
+        sort(ZeroCountProcs, SortedZeroCountProcs),
+        io.write_string("Unexecuted procedures:\n\n", !IO),
+        list.foldl(write_proc_info, SortedZeroCountProcs, !IO)
+    ;
+        Detailed = yes,
+        collect_zero_count_labels(TraceCounts, [], ZeroCountLabels),
+        sort(ZeroCountLabels, SortedZeroCountLabels),
+        io.write_string("Unexecuted labels:\n\n", !IO),
+        list.foldl(write_label_info, SortedZeroCountLabels, !IO)
+    ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred collect_zero_count_procs(
+    assoc_list(proc_label_in_context, proc_trace_counts)::in,
+    list(proc_info)::out) is det.
+
+collect_zero_count_procs(TraceCounts, ZeroCountProcInfos) :-
+    collect_proc_infos_counts(TraceCounts, map.init, ProcInfoMap,
+        map.init, CountMap),
+    map.to_assoc_list(CountMap, CountList),
+    list.filter_map(is_zero_count_proc(ProcInfoMap), CountList,
+        ZeroCountProcInfos).
+
+:- pred collect_proc_infos_counts(
+    assoc_list(proc_label_in_context, proc_trace_counts)::in,
+    map(proc_label, proc_info)::in, map(proc_label, proc_info)::out,
+    map(proc_label, int)::in, map(proc_label, int)::out) is det.
+
+collect_proc_infos_counts([], !ProcInfoMap, !CountMap).
+collect_proc_infos_counts([Assoc | Assocs], !ProcInfoMap, !CountMap) :-
+    Assoc = LabelFilename - PathPortCountMap,
+    LabelFilename = proc_label_in_context(_ModuleNameSym, FileName, ProcLabel),
+    map.foldl2(proc_process_path_port_count, PathPortCountMap,
+        no, MaybeCallInfo, 0, CurCount),
+    ( map.search(!.CountMap, ProcLabel, OldCount) ->
+        svmap.det_update(ProcLabel, OldCount + CurCount, !CountMap)
+    ;
+        svmap.det_insert(ProcLabel, CurCount, !CountMap)
+    ),
+    (
+        MaybeCallInfo = no
+    ;
+        MaybeCallInfo = yes(LineNumber),
+        ProcInfo = proc_info(FileName, LineNumber, ProcLabel),
+        svmap.det_insert(ProcLabel, ProcInfo, !ProcInfoMap)
+    ),
+    collect_proc_infos_counts(Assocs, !ProcInfoMap, !CountMap).
+
+:- pred proc_process_path_port_count(path_port::in, line_no_and_count::in,
+    maybe(int)::in, maybe(int)::out, int::in, int::out) is det.
+
+proc_process_path_port_count(PathPort, LineNumberAndCount, !MaybeCallInfo,
+        !Count) :-
+    LineNumberAndCount = line_no_and_count(LineNumber, CurCount, _NumTests),
+    !:Count = !.Count + CurCount,
+    ( PathPort = port_only(call) ->
+        require(unify(!.MaybeCallInfo, no),
+            "proc_process_path_port_count: duplicate call port:"),
+        !:MaybeCallInfo = yes(LineNumber)
+    ;
+        true
+    ).
+
+:- pred is_zero_count_proc(map(proc_label, proc_info)::in,
+    pair(proc_label, int)::in, proc_info::out) is semidet.
+
+is_zero_count_proc(ProcInfoMap, ProcLabel - Count, ProcInfo) :-
+    Count = 0,
+    map.lookup(ProcInfoMap, ProcLabel, ProcInfo).
+
+%-----------------------------------------------------------------------------%
+
+:- pred collect_zero_count_labels(
+    assoc_list(proc_label_in_context, proc_trace_counts)::in,
+    list(label_info)::in, list(label_info)::out) is det.
+
+collect_zero_count_labels([], !ZeroLabelInfos).
+collect_zero_count_labels([Assoc | Assocs], !ZeroLabelInfos) :-
+    Assoc = LabelFilename - PathPortCountMap,
+    LabelFilename = proc_label_in_context(_ModuleNameSym, FileName, ProcLabel),
+    map.foldl(label_process_path_port_count(ProcLabel, FileName),
+        PathPortCountMap, !ZeroLabelInfos),
+    collect_zero_count_labels(Assocs, !ZeroLabelInfos).
+
+:- pred label_process_path_port_count(proc_label::in, string::in,
+    path_port::in, line_no_and_count::in,
+    list(label_info)::in, list(label_info)::out) is det.
+
+label_process_path_port_count(ProcLabel, FileName,
+        PathPort, LineNumberAndCount, !ZeroLabelInfos) :-
+    LineNumberAndCount = line_no_and_count(LineNumber, Count, _NumTests),
+    ( Count = 0 ->
+        LabelInfo = label_info(FileName, LineNumber, ProcLabel, PathPort),
+        !:ZeroLabelInfos = [LabelInfo | !.ZeroLabelInfos]
+    ;
+        true
+    ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred write_proc_info(proc_info::in, io::di, io::uo) is det.
+
+write_proc_info(ProcInfo, !IO) :-
+    ProcInfo = proc_info(FileName, LineNumber, ProcLabel),
+    io.write(FileName, !IO),
+    io.write_char(':', !IO),
+    io.write_int(LineNumber, !IO),
+    io.write_string(": ", !IO),
+    write_proc_label(ProcLabel, !IO).
+
+:- pred write_label_info(label_info::in, io::di, io::uo) is det.
+
+write_label_info(LabelInfo, !IO) :-
+    LabelInfo = label_info(FileName, LineNumber, ProcLabel, _),
+    io.write(FileName, !IO),
+    io.write_char(':', !IO),
+    io.write_int(LineNumber, !IO),
+    io.write_string(": ", !IO),
+    write_proc_label(ProcLabel, !IO).
+
+%-----------------------------------------------------------------------------%
+
+:- pred usage(io::di, io::uo) is det.
+
+usage(!IO) :-
+    io.write_strings([
+        "Usage: mct [-d] [-v] [-o output_file] file1 file2 ...\n",
+        "The -d or --detailed option causes a report for each label\n",
+        "that has not been executed, even if some other code has been\n",
+        "executed in the same procedure.\n",
+        "The -v or --verbose option causes each trace count file name\n",
+        "to be printed as it is added to the union.\n",
+        "file1, file2, etc can be trace count files or they can be files\n",
+        "that contains lists of the names of other trace count files.\n"],
+        !IO).
+
+%-----------------------------------------------------------------------------%
+
+:- type option
+    --->    detailed
+    ;       output_filename
+    ;       verbose.
+
+:- 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(detailed,        bool(no)).
+option_default(output_filename, string("")).
+option_default(verbose,         bool(no)).
+
+short_option('d',               detailed).
+short_option('o',               output_filename).
+short_option('v',               verbose).
+
+long_option("detailed",         detailed).
+long_option("out",              output_filename).
+long_option("verbose",          verbose).
+
+%-----------------------------------------------------------------------------%
Index: slice/mdice.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/slice/mdice.m,v
retrieving revision 1.2
diff -u -b -r1.2 mdice.m
--- slice/mdice.m	22 May 2005 03:35:00 -0000	1.2
+++ slice/mdice.m	31 Jan 2006 04:48:53 -0000
@@ -1,10 +1,13 @@
 %-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 expandtab
+%-----------------------------------------------------------------------------%
 % 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.
 %
 %-----------------------------------------------------------------------------%
@@ -23,7 +26,7 @@
 :- implementation.
 
 :- import_module mdbcomp.
-:- import_module mdbcomp__slice_and_dice.
+:- import_module mdbcomp.slice_and_dice.
 
 :- import_module getopt.
 :- import_module list.
@@ -31,10 +34,9 @@
 %-----------------------------------------------------------------------------%
 
 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),
+    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),
 		(
@@ -48,14 +50,14 @@
 			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),
+            read_dice_to_string(PassFileName, FailFileName, SortStr, Limit,
+                Module, DiceStr, Problem, !IO),
 			( Problem = "" ->
-				io__write_string(DiceStr, !IO)
+                io.write_string(DiceStr, !IO)
 			;
-				io__write_string(Problem, !IO),
-				io__nl(!IO),
-				io__set_exit_status(1, !IO)
+                io.write_string(Problem, !IO),
+                io.nl(!IO),
+                io.set_exit_status(1, !IO)
 			)
 		;
 			Args = [_, _, _ | _],
@@ -63,15 +65,14 @@
 		)
 	;
 		GetoptResult = error(GetoptErrorMsg),
-		io__write_string(GetoptErrorMsg, !IO),
-		io__nl(!IO)
+        io.write_string(GetoptErrorMsg, !IO),
+        io.nl(!IO)
 	).
 
 :- pred usage(io::di, io::uo) is det.
 
 usage(!IO) :-
-	io__write_strings(
-		["Usage: mdice [-s sortspec] [-l N] [-m module] ",
+    io.write_strings(["Usage: mdice [-s sortspec] [-l N] [-m module] ",
 		"passfile failfile\n"], !IO).
 
 %-----------------------------------------------------------------------------%
Index: slice/mslice.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/slice/mslice.m,v
retrieving revision 1.2
diff -u -b -r1.2 mslice.m
--- slice/mslice.m	22 May 2005 03:35:00 -0000	1.2
+++ slice/mslice.m	31 Jan 2006 04:23:40 -0000
@@ -1,4 +1,6 @@
 %-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 expandtab
+%-----------------------------------------------------------------------------%
 % 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.
@@ -22,16 +24,15 @@
 :- implementation.
 
 :- import_module mdbcomp.
-:- import_module mdbcomp__slice_and_dice.
+:- 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),
+    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),
 		(
@@ -42,14 +43,14 @@
 			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),
+            read_slice_to_string(FileName, SortStr, Limit, Module, SliceStr,
+                Problem, !IO),
 			( Problem = "" ->
-				io__write_string(SliceStr, !IO)
+                io.write_string(SliceStr, !IO)
 			;
-				io__write_string(Problem, !IO),
-				io__nl(!IO),
-				io__set_exit_status(1, !IO)
+                io.write_string(Problem, !IO),
+                io.nl(!IO),
+                io.set_exit_status(1, !IO)
 			)
 		;
 			Args = [_, _ | _],
@@ -57,16 +58,15 @@
 		)
 	;
 		GetoptResult = error(GetoptErrorMsg),
-		io__write_string(GetoptErrorMsg, !IO),
-		io__nl(!IO)
+        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\n",
-		!IO).
+    io.write_string(
+        "Usage: mslice [-s sortspec] [-l N] [-m module] filename\n", !IO).
 
 %-----------------------------------------------------------------------------%
 
Index: slice/mtc_diff.m
===================================================================
RCS file: slice/mtc_diff.m
diff -N slice/mtc_diff.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ slice/mtc_diff.m	1 Apr 2006 05:56:36 -0000
@@ -0,0 +1,126 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 expandtab
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2006 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.
+%-----------------------------------------------------------------------------%
+%
+% Tool to take the difference of two trace counts.
+%
+% Author: Zoltan Somogyi.
+%
+%-----------------------------------------------------------------------------%
+
+:- module mtc_diff.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module mdbcomp.
+:- import_module mdbcomp.trace_counts.
+
+:- import_module assoc_list.
+:- import_module bool.
+:- import_module getopt.
+:- import_module int.
+:- import_module list.
+:- import_module map.
+:- import_module require.
+:- import_module string.
+:- import_module std_util.
+
+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),
+        lookup_string_option(OptionTable, output_filename, OutputFile),
+        (
+            Args = [Arg1, Arg2],
+            OutputFile \= ""
+        ->
+            stderr_stream(StdErr, !IO),
+            read_trace_counts_source(no, try_single_first, Arg1,
+                MaybeTraceCounts1, !IO),
+            (
+                MaybeTraceCounts1 = list_ok(_, _)
+            ;
+                MaybeTraceCounts1 = list_error_message(Msg1),
+                io.write_string(StdErr, Msg1, !IO),
+                io.nl(StdErr, !IO)
+            ),
+            read_trace_counts_source(no, try_single_first, Arg2,
+                MaybeTraceCounts2, !IO),
+            (
+                MaybeTraceCounts2 = list_ok(_, _)
+            ;
+                MaybeTraceCounts2 = list_error_message(Msg2),
+                io.write_string(StdErr, Msg2, !IO),
+                io.nl(StdErr, !IO)
+            ),
+            (
+                MaybeTraceCounts1 = list_ok(_, TraceCounts1),
+                MaybeTraceCounts2 = list_ok(_, TraceCounts2)
+            ->
+                diff_trace_counts(TraceCounts1, TraceCounts2, TraceCounts),
+                write_trace_counts_to_file(diff_file, TraceCounts, OutputFile,
+                    WriteResult, !IO),
+                (
+                    WriteResult = ok
+                ;
+                    WriteResult = error(WriteErrorMsg),
+                    io.write_string(StdErr, "Error writing to " ++
+                        "file `" ++ OutputFile ++ "'" ++ ": " ++
+                        string(WriteErrorMsg), !IO),
+                    io.nl(StdErr, !IO)
+                )
+            ;
+                % The error message has already been printed above.
+                true
+            )
+        ;
+            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_strings([
+        "Usage: mtc_diff -o outputfile file1 file2\n",
+        "file1, file2, etc can be trace count files or they can be files\n",
+        "that contains lists of the names of other trace count files.\n"],
+        !IO).
+
+%-----------------------------------------------------------------------------%
+
+:- type option
+    --->    output_filename.
+
+:- 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(output_filename, string("")).
+
+short_option('o',               output_filename).
+
+long_option("out",              output_filename).
+
+%-----------------------------------------------------------------------------%
Index: slice/mtc_union.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/slice/mtc_union.m,v
retrieving revision 1.2
diff -u -b -r1.2 mtc_union.m
--- slice/mtc_union.m	14 Sep 2006 00:49:44 -0000	1.2
+++ slice/mtc_union.m	14 Sep 2006 04:16:37 -0000
@@ -1,10 +1,13 @@
 %-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 expandtab
+%-----------------------------------------------------------------------------%
 % Copyright (C) 2005-2006 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.
 %-----------------------------------------------------------------------------%
 %
 % Tool to combine several trace counts into one.
+%
 % Main Author: Ian MacLarty.
 %
 %-----------------------------------------------------------------------------%
@@ -31,85 +34,68 @@
 :- import_module int.
 :- import_module list.
 :- import_module map.
-:- import_module string.
+:- import_module maybe.
 :- import_module require.
+:- import_module string.
 
 main(!IO) :-
 	io.command_line_arguments(Args0, !IO),
-	OptionOps = option_ops_multi(short_option, long_option,
-		option_default),
+    OptionOps = option_ops_multi(short_option, long_option, option_default),
 	getopt.process_options(OptionOps, Args0, Args, GetoptResult),
 	(
 		GetoptResult = ok(OptionTable),
-		lookup_string_option(OptionTable, output_filename, 
-			OutputFile),
+        lookup_string_option(OptionTable, output_filename, OutputFile),
 		(
-			Args \= [],
+            Args = [_ | _],
 			OutputFile \= ""
 		->
 			lookup_bool_option(OptionTable, verbose, Verbose),
-			union_trace_counts(Verbose, Args, 0, map.init,
-				OutputFile, !IO)
-		;
-			usage(!IO)
-		)
+            read_and_union_trace_counts(Verbose, try_single_first, Args,
+                NumTests, Kinds, TraceCounts, MaybeReadError, !IO),
+            stderr_stream(StdErr, !IO),
+            (
+                MaybeReadError = yes(ReadErrorMsg),
+                io.write_string(StdErr, ReadErrorMsg, !IO),
+                io.nl(StdErr, !IO)
 	;
-		GetoptResult = error(GetoptErrorMsg),
-		io.write_string(GetoptErrorMsg, !IO),
-		io.nl(!IO)
-	).
-
-:- pred union_trace_counts(bool::in, list(string)::in, int::in, 
-	trace_counts::in, string::in, io::di, io::uo) is det.
-
-union_trace_counts(_, [], NumTests, TraceCounts, OutputFile, !IO) :-
-	write_trace_counts_to_file(union(NumTests), TraceCounts,
-		OutputFile, WriteResult, !IO),
+                MaybeReadError = no,
+                write_trace_counts_to_file(union_file(NumTests, Kinds),
+                    TraceCounts, OutputFile, WriteResult, !IO),
 	(
 		WriteResult = ok
 	;
-		WriteResult = error(Error),
-		stderr_stream(StdErr, !IO),
+                    WriteResult = error(WriteErrorMsg),
 		io.write_string(StdErr, "Error writing to " ++
-			"file `" ++ OutputFile ++
-			"'" ++ ": " ++ string(Error), !IO),
+                        "file `" ++ OutputFile ++ "'" ++ ": " ++
+                        string(WriteErrorMsg), !IO),
 		io.nl(StdErr, !IO)
-	).
-union_trace_counts(ShowProgress, [File | Files], NumTests0, TraceCounts0, 
-		OutputFile, !IO) :-
-	read_trace_counts_source(ShowProgress, try_single_first, File, 
-		TCResult, !IO),
-	(
-		TCResult = list_ok(FileType, TraceCounts1),
-		summarize_trace_counts_list([TraceCounts0, TraceCounts1], 
-			TraceCounts),
-		NumTests = NumTests0 + num_tests_for_file_type(FileType),
-		union_trace_counts(ShowProgress, Files, NumTests, TraceCounts, 
-			OutputFile, !IO)
+                )
+            )
 	;
-		TCResult = list_error_message(Message),
-		stderr_stream(StdErr, !IO),
-		io.write_string(StdErr, Message, !IO),
-		io.nl(StdErr, !IO)
+            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_strings([
+    io.write_strings([
 		"Usage: mtc_union [-v] -o output_file file1 file2 ...\n",
-		"The -v or --verbose option causes each trace count ",
-		"file name\n",
+        "The -v or --verbose option causes each trace count file name\n",
 		"to be printed as it is added to the union.\n",
-		"file1, file2, etc can be trace count files or they\n",
-		"can be files which contains lists of other trace count ",
-		"files.\n"], !IO).
+        "file1, file2, etc can be trace count files or they can be files\n",
+        "that contains lists of the names of other trace count files.\n"],
+        !IO).
 
 %-----------------------------------------------------------------------------%
 
 :- type option	
-	--->	verbose
-	;	output_filename.
+    --->    output_filename
+    ;       verbose.
 
 :- type option_table == option_table(option).
 		
@@ -117,13 +103,13 @@
 :- pred long_option(string::in, option::out) is semidet.
 :- pred option_default(option::out, option_data::out) is multi.
 
-option_default(verbose,		bool(no)).
 option_default(output_filename,	string("")).
+option_default(verbose,         bool(no)).
 
-short_option('v',		verbose).
 short_option('o',		output_filename).
+short_option('v',               verbose).
 
-long_option("verbose",		verbose).
 long_option("out",		output_filename).
+long_option("verbose",          verbose).
 
 %-----------------------------------------------------------------------------%
cvs diff: Diffing tests
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/par_conj
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/trailing
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
Index: tools/bootcheck
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/tools/bootcheck,v
retrieving revision 1.184
diff -u -b -r1.184 bootcheck
--- tools/bootcheck	15 Aug 2006 04:19:40 -0000	1.184
+++ tools/bootcheck	16 Aug 2006 01:28:45 -0000
@@ -181,6 +181,7 @@
 test_params=false
 copy_runtime=false
 copy_boehm_gc=false
+copy_slice=false
 copy_profilers=false
 mmake_stage_2=true
 keep_stage_2=false
@@ -199,6 +200,7 @@
 write_out_profile_data=true
 type_stats=""
 trace_count=false
+coverage_test=false
 disable_debug_libs=false
 delete_deep_data=true
 progress=false
@@ -305,6 +307,9 @@
     -p|--copy-profilers)
         copy_profilers=true ;;
 
+    --copy-slice)
+        copy_slice=true ;;
+
     --check-namespace)
         check_namespace=true ;;
     --no-check-namespace)
@@ -353,6 +358,9 @@
     --trace-count|--trace-counts)
         trace_count=true ;;
 
+    --coverage-test)
+        coverage_test=true ;;
+
     -W|--windows)
         windows=true; use_cp=true; A=lib ;;
 
@@ -421,6 +429,7 @@
         # but the stage 2 will be built with `--target asm',
         # then we need to copy the profiler directories.
         # So to be safe, we just enable this by default.
+        copy_slice=true
         copy_profilers=true
         ;;
 esac
@@ -430,6 +439,7 @@
         target_subdir=$ils_subdir
         target_opt=
         # See comment above
+        copy_slice=true
         copy_profilers=true
         # The IL back-end generates native Windows executables,
         # which do not understand symlinks.  So we need to use cp.
@@ -535,6 +545,19 @@
     true
 fi
 
+if $coverage_test
+then
+    mkdir -p $root/coverage
+    # Don't contaminate the coverage test with old data.
+    /bin/rm $root/coverage/COVERAGE_TEST_DATA* > /dev/null 2>&1
+    MERCURY_OPTIONS="$MERCURY_OPTIONS ---coverage-test-if-exec=mercury_compile --trace-count-summary-file=$root/coverage/COVERAGE_TEST_DATA --trace-count-summary-cmd=$root/slice/mtc_union"
+    export MERCURY_OPTIONS
+    # Check whether we can compile the slice directory.
+    copy_slice=true
+else
+    true
+fi
+
 NEW_MERCURY_OPTIONS="$MERCURY_OPTIONS --mdb-disable-progress"
 
 MMAKE_USE_SUBDIRS=$use_subdirs
@@ -729,15 +752,18 @@
         $LN_S $root/scripts .
         $LN_S $root/tools .
         $LN_S $root/util .
-        if $copy_profilers
+        if $copy_slice
         then
             mkdir slice
             cd slice
             $LN_S $root/slice/*.m .
             cp $root/slice/Mmake* $root/slice/Mercury.options .
-            cp $root/slice/*_FLAGS.in .
-            cp $root/slice/.mgnu* .
             cd $root/$stage2dir
+        else
+            $LN_S $root/slice .
+        fi
+        if $copy_profilers
+        then
             mkdir profiler
             cd profiler
             $LN_S $root/profiler/*.m .
@@ -754,7 +780,6 @@
             cp $root/deep_profiler/.mgnu* .
             cd $root/$stage2dir
         else
-            $LN_S $root/slice .
             $LN_S $root/profiler .
             $LN_S $root/deep_profiler .
         fi
@@ -770,6 +795,11 @@
             /bin/rm -f Mmake.params
             cp $root/Mmake.stage.params Mmake.params
         fi
+        if test -f $root/Mmake.stage.slice.params
+        then
+            /bin/rm -f slice/Mmake.slice.params
+            cp $root/Mmake.stage.slice.params slice/Mmake.slice.params
+        fi
         if test -f $root/Mmake.stage.mdbcomp.params
         then
             /bin/rm -f mdbcomp/Mmake.mdbcomp.params
@@ -838,8 +868,7 @@
                 if (cd $stage2dir && \
                     $MMAKE compiler/COMP_FLAGS library/LIB_FLAGS \
                     mdbcomp/MDBCOMP_FLAGS analysis/ANALYSIS_FLAGS \
-                    slice/SLICE_FLAGS profiler/PROF_FLAGS \
-                    deep_profiler/DEEP_FLAGS)
+                    profiler/PROF_FLAGS deep_profiler/DEEP_FLAGS)
                 then
                     echo "building of stage 2 flags files successful"
                 else
@@ -851,7 +880,7 @@
         
         if (cd $stage2dir && \
             $MMAKE $mmake_opts dep_library dep_mdbcomp \
-            dep_browser dep_analysis dep_compiler dep_slice \
+            dep_browser dep_analysis dep_compiler \
             dep_profiler dep_deep_profiler)
         then
             echo "building of stage 2 dependencies successful"
@@ -887,7 +916,8 @@
             exit 1
         fi
 
-        if (cd $stage2dir && $MMAKE $mmake_opts $jfactor trace)
+        if (cd $stage2dir/trace && \
+            $MMAKE $mmake_opts $jfactor trace)
         then
             echo "building of stage 2 trace successful"
         else
@@ -903,7 +933,8 @@
             ar cr $stage2dir/trace/lib$TRACE_LIB_NAME.a
         fi
 
-        if (cd $stage2dir && $MMAKE $mmake_opts $jfactor analysis)
+        if (cd $stage2dir/analysis \
+            && $MMAKE $mmake_opts $jfactor all)
         then
             echo "building of stage 2 analysis successful"
         else
@@ -920,7 +951,27 @@
             exit 1
         fi
 
-        if (cd $stage2dir && $MMAKE $mmake_opts MMAKEFLAGS=$jfactor all)
+        # We use "mmake" instead $MMAKE because we don't want to override
+        # the mmc in $PATH with the one in scripts, since that one will
+        # probably refer to a nonexistent executable in /usr/local/mercury-DEV.
+
+        if (cd $stage2dir/slice && \
+            unset MMAKE && \
+            unset MMAKE_VPATH && \
+            unset MMAKE_DIR && \
+            unset MERCURY_CONFIG_DIR && \
+            unset MERCURY_STDLIB_DIR && \
+            mmake $mmake_opts $jfactor depend && \
+            mmake $mmake_opts $jfactor all)
+        then
+            echo "building of stage 2 slice successful"
+        else
+            echo "building of stage 2 slice not successful"
+            exit 1
+        fi
+
+        if (cd $stage2dir && \
+            $MMAKE $mmake_opts MMAKEFLAGS=$jfactor all)
         then
             echo "building of stage 2 successful"
         else
@@ -938,6 +989,7 @@
             ls -lt $stage2dir/compiler/mercury_compile
         fi
     fi
+    echo "finishing stage 2 at `date`"
 
     # Build the check_namespace target in the relevant directories.
     # We want to do so before we delete any of the stage 2 object files.
@@ -986,9 +1038,15 @@
         true
     else
         libdirs="library mdbcomp browser"
+        if $copy_slice
+        then
+            slicedirs="slice"
+        else
+            slicedirs=
+        fi
         if $copy_profilers
         then
-            profdirs="slice profiler deep_profiler"
+            profdirs="profiler deep_profiler"
         else
             profdirs=
         fi
@@ -999,7 +1057,7 @@
             rundirs=
         fi
 
-        objdirs="$libdirs $profdirs $rundirs"
+        objdirs="$libdirs $slicedirs $profdirs $rundirs"
         for rmdir in $objdirs
         do
             cd $root/$stage2dir/$rmdir
cvs diff: Diffing trace
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 messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list