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