[m-rev.] for review: mtc_union

Ian MacLarty maclarty at cs.mu.OZ.AU
Fri Aug 5 00:05:15 AEST 2005


I'd like to make some test cases for mtc_union as well as mslice and mdice.
Are there any examples of test cases for programs other than the compiler
(like the profiler) I can have a look at?  If so where are they?

Also why are mdice and mslice installed in
$INSTALL_PATH/lib/mercury/bin/i686-pc-linux-gnu/ instead of just
$INSTALL_PATH/bin?

For review by anyone.

Estimated hours taken: 10
Branches: main

Implement mtc_union program.  mtc_union takes a set of trace count files and
combines them into one trace count file.  This is useful when slicing or dicing
lots of files as it means all the files don't have to be individually loaded
each time, which can take a long time.

Mmakefile:
	Make mtc_union.

compiler/tupling.m:
	Adjust for new trace_counts.m interface.

mdbcomp/slice_and_dice.m:
	Do not return the individual trace counts file types when reading a
	slice.
	This information will not necessarily be available now, because
	the source may be a union.  Anyway this information is not used.
	The important bit of data, namely how many test cases were used
	to construct the slice, is still returned.

	Adjust for new trace_counts.m interface.

mdbcomp/trace_counts.m:
	Introduce a new trace count file type: union(N), where
	N is how many test cases were used to construct the union.

	For the trace_counts type, store the filename with the proc id, instead
	of with each label.  The line numbers are still stored with each label.
	This makes it easier to write out the trace counts again and also
	probably uses less memory.

	Store the number of tests each label is executed in with each
	label.  This must be done to preserve this informationn after
	trace counts have been unioned together.  The test case count
	may be omitted in the trace counts file, in which case it will be
	assumed to be one.

	Implement predicates to write out a trace count to a file.

	Add predicates to calculate the number of test cases used given
	a trace count file type.

	Modify read_trace_counts_list so that it merges the trace counts
	as it reads them.  This allows it to be used with long lists
	of trace count files without using excessive memory.
	Also optionally print out the name of each file read as it is
	read.

slice/Mmakefile:
	Make mtc_union.

slice/mtc_union.m:
	The mtc_union program.

Index: Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/Mmakefile,v
retrieving revision 1.111
diff -u -r1.111 Mmakefile
--- Mmakefile	6 May 2005 08:41:59 -0000	1.111
+++ Mmakefile	27 May 2005 06:25:00 -0000
@@ -118,7 +118,8 @@

 .PHONY: dep_slice
 dep_slice: slice/$(deps_subdir)mslice.dep \
-	slice/$(deps_subdir)mdice.dep
+	slice/$(deps_subdir)mdice.dep \
+	slice/$(deps_subdir)mtc_union.dep

 slice/$(deps_subdir)mslice.dep: \
 		library/$(deps_subdir)$(STD_LIB_NAME).dep \
@@ -130,6 +131,11 @@
 		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
+
 .PHONY: dep_profiler
 dep_profiler: profiler/$(deps_subdir)mercury_profile.dep

Index: compiler/tupling.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/tupling.m,v
retrieving revision 1.6
diff -u -r1.6 tupling.m
--- compiler/tupling.m	29 Apr 2005 01:03:09 -0000	1.6
+++ compiler/tupling.m	26 Jul 2005 14:00:03 -0000
@@ -157,13 +157,10 @@
 		report_warning("Warning: --tuple requires " ++
 			"--tuple-trace-counts-file to work.\n", !IO)
 	;
-		read_trace_counts_source(try_single_first, TraceCountsFile,
+		read_trace_counts_source(no, try_single_first, TraceCountsFile,
 			Result, !IO),
 		(
-			Result = list_ok(AssocList),
-			assoc_list__values(AssocList, TraceCountsList),
-			summarize_trace_counts_list(TraceCountsList,
-				TraceCounts),
+			Result = list_ok(_, TraceCounts),
 			tuple_arguments_2(!ModuleInfo, TraceCounts, !IO)
 		;
 			Result = list_error_message(Message),
@@ -967,7 +964,10 @@
 			pred_info_name(PredInfo),
 			pred_info_orig_arity(PredInfo),
 			proc_id_to_int(ProcId)),
-	( get_proc_counts(TraceCounts, ProcLabel, yes(ProcCounts)) ->
+	pred_info_context(PredInfo, Context),
+	Context = context(FileName, _),
+	ProcLabelAndFile = proc_label_and_filename(ProcLabel, FileName),
+	( get_proc_counts(TraceCounts, ProcLabelAndFile, yes(ProcCounts)) ->
 		count_load_stores_in_proc(count_info(PredProcId, ProcInfo,
 			ModuleInfo, ProcCounts, TuningParams, TuplingScheme),
 			ProcLoads, ProcStores),
@@ -1867,11 +1867,11 @@
 :- type mdbcomp_goal_path
 	== mdbcomp__program_representation__goal_path.

-:- pred get_proc_counts(trace_counts::in, proc_label::in,
+:- pred get_proc_counts(trace_counts::in, proc_label_and_filename::in,
 	maybe(proc_trace_counts)::out) is det.

-get_proc_counts(TraceCounts, ProcLabel, MaybeProcCounts) :-
-	( map__search(TraceCounts, ProcLabel, ProcCounts) ->
+get_proc_counts(TraceCounts, ProcLabelAndFile, MaybeProcCounts) :-
+	( map__search(TraceCounts, ProcLabelAndFile, ProcCounts) ->
 		MaybeProcCounts = yes(ProcCounts)
 	;
 		MaybeProcCounts = no
@@ -1956,11 +1956,12 @@
 		ProcCounts, 0, Total).

 :- pred get_switch_total_count_2(mdbcomp_goal_path::in, path_port::in,
-	context_and_count::in, int::in, int::out) is det.
+	line_no_and_count::in, int::in, int::out) is det.

-get_switch_total_count_2(SwitchGoalPath, PathPort, ContextCount, !TotalAcc) :-
+get_switch_total_count_2(SwitchGoalPath, PathPort, LineNoAndCount,
+		!TotalAcc) :-
 	( case_in_switch(SwitchGoalPath, PathPort) ->
-		!:TotalAcc = !.TotalAcc + ContextCount ^ exec_count
+		!:TotalAcc = !.TotalAcc + LineNoAndCount ^ exec_count
 	;
 		true
 	).
Index: mdbcomp/slice_and_dice.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/slice_and_dice.m,v
retrieving revision 1.1
diff -u -r1.1 slice_and_dice.m
--- mdbcomp/slice_and_dice.m	29 Apr 2005 01:03:14 -0000	1.1
+++ mdbcomp/slice_and_dice.m	29 Jul 2005 06:17:13 -0000
@@ -22,7 +22,6 @@

 :- import_module io.
 :- import_module map.
-:- import_module set.
 :- import_module std_util.

 %-----------------------------------------------------------------------------%
@@ -56,8 +55,7 @@
     % Read the slice(s) from Source and File.
     %
 :- pred read_slice(slice_source::in, string::in,
-    maybe_error(pair(set(trace_count_file_type), slice))::out,
-    io::di, io::uo) is det.
+    maybe_error(slice)::out, io::di, io::uo) is det.

     % read_slice_to_string(File, SortStr, N, Module, SliceStr, Problem, !IO):
     %
@@ -163,6 +161,7 @@
 :- import_module int.
 :- import_module list.
 :- import_module require.
+:- import_module set.
 :- import_module std_util.
 :- import_module string.
 :- import_module svmap.
@@ -173,17 +172,13 @@
 % mechanism for reading in dices below.

 read_slice(Source, File, Result, !IO) :-
-    read_trace_counts_source(Source, File, ReadResult, !IO),
+    read_trace_counts_source(no, Source, File, ReadResult, !IO),
     (
-        ReadResult = list_ok(AssocList),
-        assoc_list__values(AssocList, TraceCounts),
-        assoc_list__keys(AssocList, FileTypeList),
-        set__list_to_set(FileTypeList, FileTypes),
-        list.foldl(slice_merge_trace_counts, TraceCounts,
-            map.init, SliceProcMap),
-        TotalTests = length(TraceCounts),
-        Slice = slice(TotalTests, SliceProcMap),
-        Result = ok(FileTypes - Slice)
+        ReadResult = list_ok(FileType, TraceCounts),
+        slice_merge_trace_counts(TraceCounts, map.init, SliceProcMap),
+        NumTests = num_tests_for_file_type(FileType),
+        Slice = slice(NumTests, SliceProcMap),
+        Result = ok(Slice)
     ;
         ReadResult = list_error_message(Problem),
         Result = error(Problem)
@@ -197,43 +192,46 @@
 slice_merge_trace_counts(TraceCounts, !SliceProcMap) :-
     map.foldl(slice_merge_proc_trace_counts, TraceCounts, !SliceProcMap).

-:- pred slice_merge_proc_trace_counts(proc_label::in, proc_trace_counts::in,
-    slice_proc_map::in, slice_proc_map::out) is det.
+:- pred slice_merge_proc_trace_counts(proc_label_and_filename::in,
+    proc_trace_counts::in, slice_proc_map::in, slice_proc_map::out) is det.

-slice_merge_proc_trace_counts(ProcLabel, ProcTraceCounts, !SliceProcMap) :-
+slice_merge_proc_trace_counts(ProcLabelAndFile, ProcTraceCounts,
+        !SliceProcMap) :-
+    ProcLabelAndFile = proc_label_and_filename(ProcLabel, FileName),
     ( map.search(!.SliceProcMap, ProcLabel, FoundProcSlice) ->
-        map.foldl(slice_merge_path_port, ProcTraceCounts,
+        map.foldl(slice_merge_path_port(FileName), ProcTraceCounts,
             FoundProcSlice, MergedProcSlice),
         svmap.det_update(ProcLabel, MergedProcSlice, !SliceProcMap)
     ;
-        map.foldl(slice_merge_path_port, ProcTraceCounts,
+        map.foldl(slice_merge_path_port(FileName), ProcTraceCounts,
             map.init, MergedProcSlice),
         svmap.det_insert(ProcLabel, MergedProcSlice, !SliceProcMap)
     ).

-:- pred slice_merge_path_port(path_port::in, context_and_count::in,
+:- pred slice_merge_path_port(string::in, path_port::in, line_no_and_count::in,
     proc_slice::in, proc_slice::out) is det.

-slice_merge_path_port(PathPort, ContextCount, !ProcSlice) :-
+slice_merge_path_port(FileName, PathPort, LineNoAndCount, !ProcSlice) :-
     (
-        map.transform_value(slice_add_trace_count(ContextCount), PathPort,
-            !.ProcSlice, UpdatedProcSlice)
+        map.transform_value(slice_add_trace_count(LineNoAndCount),
+            PathPort, !.ProcSlice, UpdatedProcSlice)
     ->
         !:ProcSlice = UpdatedProcSlice
     ;
-        ContextCount = context_and_count(FileName, LineNumber, Count),
-        ExecCount = slice_exec_count(FileName, LineNumber, Count, 1),
-        svmap.det_insert(PathPort, ExecCount, !ProcSlice)
+        LineNoAndCount = line_no_and_count(LineNumber, ExecCount, NumTests),
+        SliceExecCount = slice_exec_count(FileName, LineNumber, ExecCount,
+            NumTests),
+        svmap.det_insert(PathPort, SliceExecCount, !ProcSlice)
     ).

-:- pred slice_add_trace_count(context_and_count::in,
+:- pred slice_add_trace_count(line_no_and_count::in,
     slice_exec_count::in, slice_exec_count::out) is det.

-slice_add_trace_count(ContextCount, ExecCounts0, ExecCounts) :-
-    ContextCount = context_and_count(_FileName, _LineNumber, Count),
+slice_add_trace_count(LineNoAndCount, ExecCounts0, ExecCounts) :-
+    LineNoAndCount = line_no_and_count(_LineNumber, ExecCount, NumTests),
     ExecCounts0 = slice_exec_count(FileName, LineNumber, Exec, Tests),
-    ExecCounts = slice_exec_count(FileName, LineNumber, Exec + Count,
-        Tests + 1).
+    ExecCounts = slice_exec_count(FileName, LineNumber, Exec + ExecCount,
+        Tests + NumTests).

 %-----------------------------------------------------------------------------%
 %
@@ -241,20 +239,19 @@
 % mechanism for reading in slices above.

 read_dice(PassSource, PassFile, FailSource, FailFile, Result, !IO) :-
-    read_trace_counts_source(PassSource, PassFile, ReadPassResult, !IO),
+    read_trace_counts_source(no, PassSource, PassFile, ReadPassResult, !IO),
     (
-        ReadPassResult = list_ok(PassAssocList),
-        assoc_list__values(PassAssocList, PassTraceCountsList),
-        read_trace_counts_source(FailSource, FailFile, ReadFailResult, !IO),
+        ReadPassResult = list_ok(PassFileType, PassTraceCounts),
+        read_trace_counts_source(no, FailSource, FailFile, ReadFailResult,
+            !IO),
         (
-            ReadFailResult = list_ok(FailAssocList),
-            assoc_list__values(FailAssocList, FailTraceCountsList),
-            list.foldl(dice_merge_trace_counts(pass), PassTraceCountsList,
-                map.init, PassDiceProcMap),
-            list.foldl(dice_merge_trace_counts(fail), FailTraceCountsList,
+            ReadFailResult = list_ok(FailFileType, FailTraceCounts),
+            dice_merge_trace_counts(pass, PassTraceCounts, map.init,
+                PassDiceProcMap),
+            dice_merge_trace_counts(fail, FailTraceCounts,
                 PassDiceProcMap, DiceProcMap),
-            TotalPassTests = length(PassTraceCountsList),
-            TotalFailTests = length(FailTraceCountsList),
+            TotalPassTests = num_tests_for_file_type(PassFileType),
+            TotalFailTests = num_tests_for_file_type(FailFileType),
             Dice = dice(TotalPassTests, TotalFailTests, DiceProcMap),
             Result = ok(Dice)
         ;
@@ -278,56 +275,61 @@
 dice_merge_trace_counts(Kind, TraceCounts, !DiceProcMap) :-
     map.foldl(dice_merge_proc_trace_counts(Kind), TraceCounts, !DiceProcMap).

-:- pred dice_merge_proc_trace_counts(trace_counts_kind::in, proc_label::in,
-    proc_trace_counts::in, dice_proc_map::in, dice_proc_map::out) is det.
-
-dice_merge_proc_trace_counts(Kind, ProcLabel, ProcTraceCounts, !DiceProcMap) :-
+:- pred dice_merge_proc_trace_counts(trace_counts_kind::in,
+    proc_label_and_filename::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),
     ( map.search(!.DiceProcMap, ProcLabel, FoundProcDice) ->
-        map.foldl(dice_merge_path_port(Kind), ProcTraceCounts, FoundProcDice,
-            MergedProcDice),
+        map.foldl(dice_merge_path_port(FileName, Kind), ProcTraceCounts,
+            FoundProcDice, MergedProcDice),
         svmap.det_update(ProcLabel, MergedProcDice, !DiceProcMap)
     ;
-        map.foldl(dice_merge_path_port(Kind), ProcTraceCounts,
+        map.foldl(dice_merge_path_port(FileName, Kind), ProcTraceCounts,
             map.init, MergedProcDice),
         svmap.det_insert(ProcLabel, MergedProcDice, !DiceProcMap)
     ).

-:- pred dice_merge_path_port(trace_counts_kind::in, path_port::in,
-    context_and_count::in, proc_dice::in, proc_dice::out) is det.
+:- pred dice_merge_path_port(string::in, trace_counts_kind::in, path_port::in,
+    line_no_and_count::in, proc_dice::in, proc_dice::out) is det.

-dice_merge_path_port(Kind, PathPort, ContextCount, !ProcDice) :-
+dice_merge_path_port(FileName, Kind, PathPort, LineNoAndCount, !ProcDice) :-
     (
-        map.transform_value(dice_add_trace_count(Kind, ContextCount), PathPort,
-            !.ProcDice, UpdatedProcDice)
+        map.transform_value(dice_add_trace_count(Kind, LineNoAndCount),
+            PathPort, !.ProcDice, UpdatedProcDice)
     ->
         !:ProcDice = UpdatedProcDice
     ;
-        ContextCount = context_and_count(FileName, LineNumber, Count),
+        LineNoAndCount = line_no_and_count(LineNumber, ExecCount, NumTests),
         (
             Kind = pass,
-            InitCount = dice_exec_count(FileName, LineNumber, Count, 1, 0, 0)
+            InitCount = dice_exec_count(FileName, LineNumber,
+                ExecCount, NumTests, 0, 0)
         ;
             Kind = fail,
-            InitCount = dice_exec_count(FileName, LineNumber, 0, 0, Count, 1)
+            InitCount = dice_exec_count(FileName, LineNumber, 0, 0,
+                ExecCount, NumTests)
         ),
         svmap.det_insert(PathPort, InitCount, !ProcDice)
     ).

-:- pred dice_add_trace_count(trace_counts_kind::in, context_and_count::in,
+:- pred dice_add_trace_count(trace_counts_kind::in, line_no_and_count::in,
     dice_exec_count::in, dice_exec_count::out) is det.

-dice_add_trace_count(pass, ContextCount, ExecCounts0, ExecCounts) :-
-    ContextCount = context_and_count(_FileName, _LineNumber, Count),
+dice_add_trace_count(pass, LineNoAndCount, ExecCounts0, ExecCounts) :-
+    LineNoAndCount = line_no_and_count(_LineNumber, ExecCount, NumTests),
     ExecCounts0 = dice_exec_count(FileName, LineNumber,
         PassExec, PassTests, FailExec, FailTests),
-    ExecCounts  = dice_exec_count(FileName, LineNumber,
-        PassExec + Count, PassTests + 1, FailExec, FailTests).
-dice_add_trace_count(fail, ContextCount, ExecCounts0, ExecCounts) :-
-    ContextCount = context_and_count(_FileName, _LineNumber, Count),
+    ExecCounts = dice_exec_count(FileName, LineNumber,
+        PassExec + ExecCount, PassTests + NumTests, FailExec, FailTests).
+dice_add_trace_count(fail, LineNoAndCount, ExecCounts0, ExecCounts) :-
+    LineNoAndCount = line_no_and_count(_LineNumber, ExecCount, NumTests),
     ExecCounts0 = dice_exec_count(FileName, LineNumber,
         PassExec, PassTests, FailExec, FailTests),
     ExecCounts  = dice_exec_count(FileName, LineNumber,
-        PassExec, PassTests, FailExec + Count, FailTests + 1).
+        PassExec, PassTests, FailExec + ExecCount, FailTests + NumTests).

 %-----------------------------------------------------------------------------%
 %
@@ -341,7 +343,7 @@
     ( slice_sort_string_is_valid(SortStr0) ->
         read_slice(try_single_first, File, ReadSliceResult, !IO),
         (
-            ReadSliceResult = ok(_ - Slice),
+            ReadSliceResult = ok(Slice),
             Slice = slice(TotalTests, SliceProcMap),
             LabelCounts = slice_to_label_counts(SliceProcMap),
             ( Module \= "" ->
Index: mdbcomp/trace_counts.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/trace_counts.m,v
retrieving revision 1.5
diff -u -r1.5 trace_counts.m
--- mdbcomp/trace_counts.m	29 Apr 2005 01:03:15 -0000	1.5
+++ mdbcomp/trace_counts.m	4 Aug 2005 08:53:59 -0000
@@ -9,7 +9,7 @@
 % File: trace_counts.m.
 %
 % Main author: wangp.
-% Modifications by zs.
+% Modifications by zs and maclarty.
 %
 % This module defines predicates to read in the execution trace summaries
 % generated by programs compiled using the compiler's tracing options.
@@ -23,7 +23,7 @@
 :- import_module mdbcomp.prim_data.
 :- import_module mdbcomp.program_representation.

-:- import_module assoc_list.
+:- import_module bool.
 :- import_module io.
 :- import_module list.
 :- import_module map.
@@ -33,24 +33,34 @@
             % 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.

-:- type trace_counts        == map(proc_label, proc_trace_counts).
+    ;       union(int).
+            % The file is a union of some other trace count files.
+            % The number of test cases in the union is recorded.
+
+:- type trace_counts == map(proc_label_and_filename, proc_trace_counts).
+
+:- type proc_label_and_filename
+    --->    proc_label_and_filename(
+                proc_label  ::  proc_label,
+                filename    ::  string
+            ).

-:- type proc_trace_counts   == map(path_port, context_and_count).
+:- type proc_trace_counts   == map(path_port, line_no_and_count).

 :- type path_port
     --->    port_only(trace_port)
     ;       path_only(goal_path)
     ;       port_and_path(trace_port, goal_path).

-:- type context_and_count
-    --->    context_and_count(
-                file_name   :: string,
+:- type line_no_and_count
+    --->    line_no_and_count(
                 line_number :: int,
-                exec_count  :: int
+                exec_count  :: int,
+                num_tests   :: int
             ).

 :- pred summarize_trace_counts_list(list(trace_counts)::in, trace_counts::out)
@@ -76,22 +86,25 @@
     io::di, io::uo) is det.

 :- type read_trace_counts_list_result
-    --->    list_ok(assoc_list(trace_count_file_type, trace_counts))
+    --->    list_ok(trace_count_file_type, trace_counts)
     ;       list_error_message(string).

-    % read_trace_counts_list(FileName, Result, !IO):
+    % read_trace_counts_list(ShowProgress, FileName, Result, !IO):
     %
     % Read the trace_counts in the files whose names appear in FileName.
+    % The result is a union of all the trace counts.
+    % If ShowProgress is yes then print the name of each file to the current
+    % output stream just before it is read.
     %
-:- pred read_trace_counts_list(string::in, read_trace_counts_list_result::out,
-    io::di, io::uo) is det.
+:- pred read_trace_counts_list(bool::in, string::in,
+    read_trace_counts_list_result::out, io::di, io::uo) is det.

 :- type slice_source
     --->    file_list
     ;       single_file
     ;       try_single_first.

-    % read_trace_counts_source(Source, FileName, Result, !IO):
+    % read_trace_counts_source(ShowProgress, Source, FileName, Result, !IO):
     %
     % Read in trace counts stored in one or more trace count files.
     %
@@ -108,9 +121,20 @@
     % interpret FileName as a file that itself contains filenames, and
     % will treat it as with Source=file_list.
     %
-:- pred read_trace_counts_source(slice_source::in, string::in,
+    % If the source is a list of files and ShowProgress is yes then
+    % the name of each file read will be printed to the current output
+    % stream just before it is read.
+    %
+:- 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).
+    % 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.
+
 :- 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.
@@ -118,6 +142,16 @@
 :- pred restrict_trace_counts_to_module(module_name::in, trace_counts::in,
     trace_counts::out) is det.

+    % Return the number of tests cases used to generate the trace counts with
+    % the given list of file types.
+    %
+:- func calc_num_tests(list(trace_count_file_type)) = int.
+
+    % Return the number of tests used to create a trace counts file of the
+    % given type.
+    %
+:- func num_tests_for_file_type(trace_count_file_type) = int.
+
 %-----------------------------------------------------------------------------%

 :- implementation.
@@ -132,6 +166,7 @@
 :- import_module std_util.
 :- import_module string.
 :- import_module svmap.
+:- import_module term_io.

 %-----------------------------------------------------------------------------%

@@ -150,43 +185,44 @@
     proc_trace_counts::out) is det.

 sum_proc_trace_counts(ProcTraceCountsA, ProcTraceCountsB, ProcTraceCounts) :-
-    ProcTraceCounts = map.union(sum_counts_in_context,
+    ProcTraceCounts = map.union(sum_counts_on_line,
         ProcTraceCountsA, ProcTraceCountsB).

-:- func sum_counts_in_context(context_and_count, context_and_count)
-    = context_and_count.
+:- func sum_counts_on_line(line_no_and_count, line_no_and_count)
+    = line_no_and_count.

-sum_counts_in_context(CC1, CC2) = CC :-
-    % We could add a sanity check that FileName1 = FileName2 and
-    % LineNumber1 = LineNumber2, but that would take time to no good purpose,
-    % since there isn't much we can do to generate a meaningful message,
-    % and that situation doesn't necessarily represent an error anyway.
-    % (Consider the case when the two trace files are derived from sources
-    % that are identical except for the addition of a comment.)
-
-    CC1 = context_and_count(FileName1, LineNumber1, Count1),
-    CC2 = context_and_count(_FileName2, _LineNumber, Count2),
-    CC = context_and_count(FileName1, LineNumber1, Count1 + Count2).
+sum_counts_on_line(LC1, LC2) = LC :-
+    % We could add a sanity check that LineNumber1 = LineNumber2, but that
+    % would take time to no good purpose, since there isn't much we can do to
+    % generate a meaningful message, and that situation doesn't necessarily
+    % represent an error anyway.  (Consider the case when the two trace files
+    % are derived from sources that are identical except for the addition of a
+    % comment.)
+
+    LC1 = line_no_and_count(LineNumber1, Count1, NumTests1),
+    LC2 = line_no_and_count(_LineNumber, Count2, NumTests2),
+    LC = line_no_and_count(LineNumber1, Count1 + Count2,
+        NumTests1 + NumTests2).

 %-----------------------------------------------------------------------------%

-read_trace_counts_source(Source, FileName, Result, !IO) :-
+read_trace_counts_source(ShowProgress, Source, FileName, Result, !IO) :-
     (
         Source = file_list,
-        read_trace_counts_list(FileName, ListResult, !IO),
-        (
-            ListResult = list_ok(AssocList),
-            Result = list_ok(AssocList)
-        ;
-            ListResult = list_error_message(Msg),
-            Result = list_error_message(Msg)
-        )
+        read_trace_counts_list(ShowProgress, FileName, Result, !IO)
     ;
         Source = single_file,
+        (
+            ShowProgress = yes,
+            io.write_string(FileName, !IO),
+            io.nl(!IO)
+        ;
+            ShowProgress = no
+        ),
         read_trace_counts(FileName, ReadTCResult, !IO),
         (
             ReadTCResult = ok(FileType, TraceCount),
-            Result = list_ok([FileType - TraceCount])
+            Result = list_ok(FileType, TraceCount)
         ;
             ReadTCResult = io_error(IOError),
             Result = list_error_message("IO error reading file " ++
@@ -206,67 +242,85 @@
         )
     ;
         Source = try_single_first,
-        read_trace_counts_source(single_file, FileName, TryResult, !IO),
+        read_trace_counts_source(ShowProgress, single_file, FileName,
+            TryResult, !IO),
         (
-            TryResult = list_ok(_),
+            TryResult = list_ok(_, _),
             Result = TryResult
         ;
             TryResult = list_error_message(_),
-            read_trace_counts_source(file_list, FileName, Result, !IO)
+            read_trace_counts_source(ShowProgress, file_list, FileName,
+                Result, !IO)
         )
     ).

-read_trace_counts_list(FileName, Result, !IO) :-
+read_trace_counts_list(ShowProgress, FileName, Result, !IO) :-
     io.open_input(FileName, OpenResult, !IO),
     (
         OpenResult = ok(FileStream),
-        read_trace_counts_list_stream(FileName, FileStream, Result, !IO)
+        read_trace_counts_list_stream(ShowProgress, union(0), map.init,
+            FileName, FileStream, Result, !IO)
     ;
         OpenResult = error(IOError),
         Result = list_error_message("Error opening file `" ++ FileName ++
             "': " ++ string.string(IOError))
     ).

-    % Same as read_trace_counts_list/4, but read the filenames containing
+    % Same as read_trace_counts_list/5, but read the filenames containing
     % the trace_counts from the given stream.  MainFileName is the
     % name of the file being read and is only used for error messages.
     %
-:- pred read_trace_counts_list_stream(string::in, io.input_stream::in,
+:- pred read_trace_counts_list_stream(bool::in, trace_count_file_type::in,
+    trace_counts::in, string::in, io.input_stream::in,
     read_trace_counts_list_result::out, io::di, io::uo) is det.

-read_trace_counts_list_stream(MainFileName, Stream, Result, !IO) :-
+read_trace_counts_list_stream(ShowProgress, FileType0, TraceCounts0,
+        MainFileName, Stream, Result, !IO) :-
     io.read_line_as_string(Stream, ReadResult, !IO),
     (
         ReadResult = ok(Line),
         % Remove the trailing newline:
         FileName = string.left(Line, string.length(Line) - 1),
-        read_trace_counts(FileName, ReadTCResult, !IO),
         (
-            ReadTCResult = ok(FileType, TraceCount),
-            read_trace_counts_list_stream(MainFileName, Stream, RestResult,
-                !IO),
-            ( RestResult = list_ok(FileTypesTraceCounts) ->
-                Result = list_ok([FileType - TraceCount
-                    | FileTypesTraceCounts])
+            % Ignore blank lines.
+            FileName = ""
+        ->
+            read_trace_counts_list_stream(ShowProgress, FileType0,
+                TraceCounts0, MainFileName, Stream, Result, !IO)
+        ;
+            (
+                ShowProgress = yes,
+                io.write_string(FileName, !IO),
+                io.nl(!IO)
+            ;
+                ShowProgress = no
+            ),
+            read_trace_counts(FileName, ReadTCResult, !IO),
+            (
+                ReadTCResult = ok(FileType1, TraceCounts1),
+                summarize_trace_counts_list([TraceCounts0, TraceCounts1],
+                    TraceCounts),
+                NumTests = calc_num_tests([FileType0, FileType1]),
+                FileType = union(NumTests),
+                read_trace_counts_list_stream(ShowProgress, FileType,
+                    TraceCounts, MainFileName, Stream, Result, !IO)
             ;
-                Result = RestResult
+                ReadTCResult = io_error(IOError),
+                Result = list_error_message("I/O error reading file " ++
+                    "`" ++ FileName ++ "': " ++ string.string(IOError))
+            ;
+                ReadTCResult = open_error(IOError),
+                Result = list_error_message("I/O error opening file " ++
+                    "`" ++ FileName ++ "': " ++ string.string(IOError))
+            ;
+                ReadTCResult = syntax_error(Error),
+                Result = list_error_message("Syntax error in file `" ++
+                    FileName ++ "': " ++ Error)
+            ;
+                ReadTCResult = error_message(Message),
+                Result = list_error_message("Error reading trace counts " ++
+                    "from file `" ++ FileName ++ "': " ++ Message)
             )
-        ;
-            ReadTCResult = io_error(IOError),
-            Result = list_error_message("IO error reading file " ++
-                "`" ++ FileName ++ "': " ++ string.string(IOError))
-        ;
-            ReadTCResult = open_error(IOError),
-            Result = list_error_message("IO error opening file " ++
-                "`" ++ FileName ++ "': " ++ string.string(IOError))
-        ;
-            ReadTCResult = syntax_error(Error),
-            Result = list_error_message("Syntax error in file `" ++ FileName ++
-                "': " ++ Error)
-        ;
-            ReadTCResult = error_message(Message),
-            Result = list_error_message("Error reading trace counts " ++
-                "from file `" ++ FileName ++ "': " ++ Message)
         )
     ;
         ReadResult = error(Error),
@@ -274,7 +328,7 @@
             MainFileName ++ "': " ++ string.string(Error))
     ;
         ReadResult = eof,
-        Result = list_ok([])
+        Result = list_ok(FileType0, TraceCounts0)
     ).

 read_trace_counts(FileName, ReadResult, !IO) :-
@@ -327,13 +381,8 @@
     io__read_line_as_string(IdResult, !IO),
     (
         IdResult = ok(IdStr),
-        (
-            IdStr = "user_all\n",
-            FileType = user_all
-        ;
-            IdStr = "user_nonzero\n",
-            FileType = user_nonzero
-        )
+        string.append(IdStrNoNL, "\n", IdStr),
+        string_to_file_type(IdStrNoNL, FileType)
     ->
         try_io(read_trace_counts_setup(map__init), Result, !IO),
         (
@@ -349,7 +398,7 @@
                 ReadResult = syntax_error(Error)
             ;
                 error("read_trace_counts_from_cur_stream: " ++
-                    "unexpected exception type")
+                    "unexpected exception type: " ++ string(Exception))
             )
         ;
             Result = failed,
@@ -423,15 +472,16 @@
         % write out data for unify, compare, index or init procedures.
         ProcLabel = proc(DefModuleName, PredOrFunc, DeclModuleName,
                 Name, Arity, Mode),
+        ProcLabelAndFile = proc_label_and_filename(ProcLabel, CurFileName),
         % 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(ProcLabel, ProbeCounts, !TraceCounts) ->
+        ( svmap__remove(ProcLabelAndFile, ProbeCounts, !TraceCounts) ->
             StartCounts = ProbeCounts
         ;
             StartCounts = map__init
         ),
-        read_proc_trace_counts_2(ProcLabel, CurFileName, StartCounts,
+        read_proc_trace_counts_2(ProcLabelAndFile, StartCounts,
             !TraceCounts, !IO)
     ;
         string__format("parse error on line %d of execution trace",
@@ -439,61 +489,84 @@
         throw(trace_count_syntax_error(Message))
     ).

-:- pred read_proc_trace_counts_2(proc_label::in, string::in,
+:- pred read_proc_trace_counts_2(proc_label_and_filename::in,
     proc_trace_counts::in, trace_counts::in, trace_counts::out,
     io::di, io::uo) is det.

-read_proc_trace_counts_2(ProcLabel, CurFileName, ProcCounts0, !TraceCounts,
-        !IO) :-
+read_proc_trace_counts_2(ProcLabelAndFile, ProcCounts0, !TraceCounts, !IO) :-
+    CurFileName = ProcLabelAndFile ^ filename,
     io__read_line_as_string(Result, !IO),
     (
         Result = ok(Line),
-        ( parse_path_port_line(Line, PathPort, ContextLineNumber, Count) ->
-            ContextCount = context_and_count(CurFileName, ContextLineNumber,
-                Count),
-            map__det_insert(ProcCounts0, PathPort, ContextCount, ProcCounts),
-            read_proc_trace_counts_2(ProcLabel, CurFileName, ProcCounts,
+        (
+            parse_path_port_line(Line, PathPort, LineNumber, ExecCount,
+                NumTests)
+        ->
+            LineNoAndCount = line_no_and_count(LineNumber, ExecCount,
+                NumTests),
+            map__det_insert(ProcCounts0, PathPort, LineNoAndCount, ProcCounts),
+            read_proc_trace_counts_2(ProcLabelAndFile, ProcCounts,
                 !TraceCounts, !IO)
         ;
-            svmap__det_insert(ProcLabel, ProcCounts0, !TraceCounts),
+            svmap__det_insert(ProcLabelAndFile, ProcCounts0, !TraceCounts),
             io__get_line_number(LineNumber, !IO),
             read_proc_trace_counts(LineNumber, Line, CurFileName, !TraceCounts,
                 !IO)
         )
     ;
         Result = eof,
-        svmap__det_insert(ProcLabel, ProcCounts0, !TraceCounts)
+        svmap__det_insert(ProcLabelAndFile, ProcCounts0, !TraceCounts)
     ;
         Result = error(Error),
         throw(Error)
     ).

-:- pred parse_path_port_line(string::in, path_port::out, int::out, int::out)
-    is semidet.
+:- pred parse_path_port_line(string::in, path_port::out, int::out, int::out,
+    int::out) is semidet.

-parse_path_port_line(Line, PathPort, LineNumber, Count) :-
+parse_path_port_line(Line, PathPort, LineNumber, ExecCount, NumTests) :-
     Words = string__words(Line),
-    (
-        Words = [Word1, CountStr, LineNumberStr],
+    (
+        (
+            Words = [Word1, ExecCountStr, LineNumberStr],
+            NumTestsStr = "1"
+        ;
+            Words = [Word1, ExecCountStr, NumTestsStr, LineNumberStr]
+        ),
         ( string_to_trace_port(Word1, Port) ->
-            PathPort = port_only(Port)
+            PathPort0 = port_only(Port)
         ; Path = string_to_goal_path(Word1) ->
-            PathPort = path_only(Path)
+            PathPort0 = path_only(Path)
         ;
             fail
         ),
-        string__to_int(CountStr, Count),
-        string__to_int(LineNumberStr, LineNumber)
+        string__to_int(ExecCountStr, ExecCount0),
+        string__to_int(NumTestsStr, NumTests0),
+        string__to_int(LineNumberStr, LineNumber0)
+    ->
+        PathPort = PathPort0,
+        ExecCount = ExecCount0,
+        NumTests = NumTests0,
+        LineNumber = LineNumber0
     ;
-        Words = [PortStr, PathStr, CountStr, LineNumberStr],
+        (
+            Words = [PortStr, PathStr, ExecCountStr, LineNumberStr],
+            NumTestsStr = "1"
+        ;
+            Words = [PortStr, PathStr, ExecCountStr, NumTestsStr,
+                LineNumberStr]
+        ),
         string_to_trace_port(PortStr, Port),
         Path = string_to_goal_path(PathStr),
         PathPort = port_and_path(Port, Path),
-        string__to_int(CountStr, Count),
+        string__to_int(ExecCountStr, ExecCount),
+        string__to_int(NumTestsStr, NumTests),
         string__to_int(LineNumberStr, LineNumber)
     ).

-:- pred string_to_pred_or_func(string::in, pred_or_func::out) is semidet.
+:- 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.

 string_to_pred_or_func("p", predicate).
 string_to_pred_or_func("f", function).
@@ -525,16 +598,139 @@

 %-----------------------------------------------------------------------------%

+write_trace_counts_to_file(FileType, TraceCounts, FileName, Res, !IO) :-
+    io__open_output(FileName, Result, !IO),
+    (
+        Result = ok(FileStream),
+        Res = ok,
+        io.set_output_stream(FileStream, OldOutputStream, !IO),
+        io.write_string(trace_count_file_id, !IO),
+        write_trace_counts(FileType, TraceCounts, !IO),
+        io__set_output_stream(OldOutputStream, _, !IO),
+        io__close_output(FileStream, !IO)
+    ;
+        Result = error(Error),
+        Res = error(Error)
+    ).
+
+:- 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.
+
+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),
+    map.foldl(write_path_port_count, PathPortCounts, !IO).
+
+:- pred write_proc_label(proc_label::in, io::di, io::uo) is det.
+
+write_proc_label(proc(DefModuleSym, PredOrFunc, DeclModuleSym, Name, Arity,
+        Mode), !IO) :-
+    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),
+    term_io.quote_atom(Name, !IO),
+    io.write_string(" ", !IO),
+    io.write_int(Arity, !IO),
+    io.write_string(" ", !IO),
+    io.write_int(Mode, !IO),
+    io.nl(!IO).
+
+    % We don't record special preds in trace counts.
+write_proc_label(special_proc(_, _, _, _, _, _), !IO) :-
+    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) :-
+    string_to_trace_port(PortStr, Port),
+    io.write_strings([
+        PortStr, " ",
+        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) :-
+    string_from_path(Path, PathStr),
+    io.write_strings([
+        "<", PathStr, "> ",
+        int_to_string(ExecCount), " ",
+        int_to_string(NumTests), " ",
+        int_to_string(LineNo),
+        "\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(ExecCount), " ",
+        int_to_string(NumTests), " ",
+        int_to_string(LineNo), "\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).
+
+:- 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) ->
+        string.to_int(NumTestsStr, NumTests),
+        FileType = union(NumTests)
+    ;
+        Str = "user_all",
+        FileType = user_all
+    ;
+        Str = "user_nonzero",
+        FileType = user_nonzero
+    ).
+
+%-----------------------------------------------------------------------------%
+
 restrict_trace_counts_to_module(ModuleName, TraceCounts0, TraceCounts) :-
     map__foldl(restrict_trace_counts_2(ModuleName), TraceCounts0,
         map__init, TraceCounts).

-:- pred restrict_trace_counts_2(module_name::in, proc_label::in,
+:- pred restrict_trace_counts_2(module_name::in, proc_label_and_filename::in,
     proc_trace_counts::in, trace_counts::in, trace_counts::out) is det.

-restrict_trace_counts_2(ModuleName, ProcLabel, ProcCounts, Acc0, Acc) :-
+restrict_trace_counts_2(ModuleName, ProcLabelAndFile, ProcCounts, Acc0, Acc) :-
+    ProcLabel = ProcLabelAndFile ^ proc_label,
     (if ProcLabel = proc(ModuleName, _, _, _, _, _) then
-        map__det_insert(Acc0, ProcLabel, ProcCounts, Acc)
+        map__det_insert(Acc0, ProcLabelAndFile, ProcCounts, Acc)
     else
         Acc = Acc0
     ).
+
+%-----------------------------------------------------------------------------%
+
+calc_num_tests([]) = 0.
+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.
Index: slice/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/slice/Mmakefile,v
retrieving revision 1.2
diff -u -r1.2 Mmakefile
--- slice/Mmakefile	6 May 2005 08:42:28 -0000	1.2
+++ slice/Mmakefile	26 Jul 2005 05:41:52 -0000
@@ -17,7 +17,7 @@
 include Mercury.options

 MAIN_TARGET		= all
-MERCURY_MAIN_MODULES	= mslice mdice
+MERCURY_MAIN_MODULES	= mslice mdice mtc_union
 DEPENDS	= $(patsubst %,%.depend,$(MERCURY_MAIN_MODULES))
 INTS	= $(patsubst %,%.ints,$(MERCURY_MAIN_MODULES))
 INT3S	= $(patsubst %,%.int3s,$(MERCURY_MAIN_MODULES))
@@ -54,10 +54,14 @@
 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

 #-----------------------------------------------------------------------------#

@@ -69,30 +73,32 @@

 #-----------------------------------------------------------------------------#

-tags:	$(MTAGS) $(mslice.ms) $(mdice.ms) $(LIBRARY_DIR)/*.m
-	$(MTAGS) $(mslice.ms) $(mdice.ms) $(LIBRARY_DIR)/*.m
+tags:	$(MTAGS) $(mslice.ms) $(mdice.ms) $(mtc_union.ms) $(LIBRARY_DIR)/*.m
+	$(MTAGS) $(mslice.ms) $(mdice.ms) $(mtc_union.ms) $(LIBRARY_DIR)/*.m

 .PHONY: tags_file_exists
 tags_file_exists:
 	@if test ! -f tags; then echo making tags; \
-	$(MTAGS) $(mslice.ms) $(mdice.ms) $(LIBRARY_DIR)/*.m ; \
+	$(MTAGS) $(mslice.ms) $(mdice.ms) $(mtc_union.ms) $(LIBRARY_DIR)/*.m; \
 	fi

 #-----------------------------------------------------------------------------#

 .PHONY: dates
 dates:
-	touch $(mslice.dates) $(mdice.dates)
+	touch $(mslice.dates) $(mdice.dates) $(mtc_union.dates)

 #-----------------------------------------------------------------------------#

 .PHONY: os cs ss ils
-os:	$(mslice.os) $(mdice.os) \
-	$(os_subdir)mslice_init.o $(os_subdir)mdice_init.o
-cs:	$(mslice.cs) $(mdice.cs) \
-	$(cs_subdir)mslice_init.c $(cs_subdir)mdice_init.c
-ss:	$(mslice.ss) $(mdice.ss)
-ils:	$(mslice.ils) $(mdice.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)

 #-----------------------------------------------------------------------------#

@@ -107,11 +113,13 @@
 install: install_slicer

 .PHONY: install_slicer
-install_slicer: mslice mdice
+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)

 #-----------------------------------------------------------------------------#
Index: slice/mtc_union.m
===================================================================
RCS file: slice/mtc_union.m
diff -N slice/mtc_union.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ slice/mtc_union.m	4 Aug 2005 08:44:13 -0000
@@ -0,0 +1,129 @@
+%-----------------------------------------------------------------------------%
+% 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.
+%-----------------------------------------------------------------------------%
+%
+% Tool to combine several trace counts into one.
+%
+%-----------------------------------------------------------------------------%
+
+:- module mtc_union.
+
+:- 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 string.
+:- import_module require.
+
+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 \= [],
+			OutputFile \= ""
+		->
+			lookup_bool_option(OptionTable, show_progress,
+				ShowProgress),
+			union_trace_counts(ShowProgress, Args, 0, map.init,
+				OutputFile, !IO)
+		;
+			usage(!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),
+	(
+		WriteResult = ok
+	;
+		WriteResult = error(Error),
+		stderr_stream(StdErr, !IO),
+		io.write_string(StdErr, "Error writing to " ++
+			"file `" ++ OutputFile ++
+			"'" ++ ": " ++ string(Error), !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)
+	).
+
+:- pred usage(io::di, io::uo) is det.
+
+usage(!IO) :-
+	io__write_strings([
+		"Usage: mtc_union [-p] -o output_file file1 file2 ...\n",
+		"The -p or --progress 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).
+
+%-----------------------------------------------------------------------------%
+
+:- type option
+	--->	show_progress
+	;	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(show_progress,	bool(no)).
+option_default(output_filename,	string("")).
+
+short_option('p',		show_progress).
+short_option('o',		output_filename).
+
+long_option("progress",		show_progress).
+long_option("out",		output_filename).
+
+%-----------------------------------------------------------------------------%

--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list