mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
mdbcomp/read_trace_counts.m:
Delete the mercury_trace_counts_list predicate, whose last
(and probably only) caller was deleted in 2006. Rename the types
and function symbols originally named after it.
Rename the read_trace_counts_source predicate to just
read_trace_counts_file, because the argument that specified
where it should get trace counts from (a single file, or a
list of files) was also deleted about two decaded ago.
The predicate originally named read_trace_counts, which this diff
renames to read_trace_counts_base, differed from the predicate
now named read_trace_counts_file only in the level of detail
they returned to their callers about any errors they found.
As it happens, the only call to read_trace_counts_base is from
read_trace_counts_file, because no callers need the extra info
about errors (which they can report, but cannot do anything about).
Therefore keep read_trace_counts_base private, and the mark it
for future merging with read_trace_counts_file.
mdbcomp/trace_counts.m:
Use an inst to encode an invariant in types for read_trace_counts.m.
compiler/tupling.m:
mdbcomp/slice_and_dice.m:
slice/mtc_diff.m:
Conform to the changes above.
332 lines
13 KiB
Mathematica
332 lines
13 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ts=4 sw=4 et ft=mercury
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2005-2008, 2010-2012 The University of Melbourne.
|
|
% Copyright (C) 2014-2015, 2017-2018, 2021-2025 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: trace_counts.m.
|
|
% Main author: wangp.
|
|
% Modifications by zs and maclarty.
|
|
%
|
|
% This module defines operations on execution trace summaries
|
|
% generated by programs compiled using the compiler's tracing options.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module mdbcomp.trace_counts.
|
|
:- interface.
|
|
|
|
:- import_module mdbcomp.goal_path.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.sym_name.
|
|
|
|
:- import_module list.
|
|
:- import_module map.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type all_or_nonzero
|
|
---> user_all
|
|
% The file contains counts for all labels from user-defined
|
|
% procedures.
|
|
|
|
; user_nonzero.
|
|
% The file contains counts for all labels from user-defined
|
|
% procedures, provided the count is nonzero.
|
|
|
|
:- type base_count_file_type
|
|
---> base_count_file_type(all_or_nonzero, string).
|
|
% The first argument says whether we have all the counts;
|
|
% the second gives the name of the program.
|
|
|
|
:- type trace_count_file_type
|
|
---> single_file(base_count_file_type)
|
|
% The file contains counts from a single execution.
|
|
|
|
; union_file(int, list(trace_count_file_type))
|
|
% The file is a union of some other trace count files.
|
|
% The number of test cases in the union is recorded, and
|
|
% so is the set of kinds of trace count files they came from.
|
|
% (We represent the set as a sorted list, because we write out
|
|
% values of trace_count_file_type to files, and we don't want to
|
|
% expose the implementation of sets.)
|
|
|
|
; diff_file(trace_count_file_type, trace_count_file_type).
|
|
% The file is a difference between two other trace count files.
|
|
|
|
:- inst union_file for trace_count_file_type/0
|
|
---> union_file(ground, ground).
|
|
|
|
:- func sum_trace_count_file_type(trace_count_file_type, trace_count_file_type)
|
|
= trace_count_file_type.
|
|
:- mode sum_trace_count_file_type(in(union_file), in) = out(union_file) is det.
|
|
:- mode sum_trace_count_file_type(in, in) = out is det.
|
|
|
|
:- type trace_counts == map(proc_label_in_context, proc_trace_counts).
|
|
|
|
:- type proc_label_in_context
|
|
---> proc_label_in_context(
|
|
context_module_symname :: sym_name,
|
|
context_filename :: string,
|
|
proc_label :: proc_label
|
|
).
|
|
|
|
:- type proc_trace_counts == map(path_port, line_no_and_count).
|
|
|
|
:- type path_port
|
|
---> port_only(trace_port)
|
|
; path_only(reverse_goal_path)
|
|
; port_and_path(trace_port, reverse_goal_path).
|
|
|
|
:- type line_no_and_count
|
|
---> line_no_and_count(
|
|
line_number :: int,
|
|
exec_count :: int,
|
|
num_tests :: int
|
|
).
|
|
|
|
:- func make_path_port(reverse_goal_path, trace_port) = path_port.
|
|
|
|
:- pred summarize_trace_counts_list(list(trace_counts)::in, trace_counts::out)
|
|
is det.
|
|
|
|
:- pred sum_trace_counts(trace_counts::in, trace_counts::in, trace_counts::out)
|
|
is det.
|
|
|
|
:- pred diff_trace_counts(trace_counts::in, trace_counts::in,
|
|
trace_counts::out) is det.
|
|
|
|
|
|
:- 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.
|
|
|
|
:- func trace_count_file_id = string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int.
|
|
:- import_module set.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
sum_trace_count_file_type(Type1, Type2) = UnionType :-
|
|
(
|
|
Type1 = single_file(_),
|
|
Type2 = single_file(_),
|
|
UnionType = union_file(2, sort_and_remove_dups([Type1, Type2]))
|
|
;
|
|
Type1 = single_file(_),
|
|
Type2 = union_file(N, IncludedTypes2),
|
|
UnionType = union_file(N + 1,
|
|
insert_into_list_as_set(IncludedTypes2, Type1))
|
|
;
|
|
Type1 = single_file(_),
|
|
Type2 = diff_file(_, _),
|
|
UnionType = union_file(2, sort_and_remove_dups([Type1, Type2]))
|
|
;
|
|
Type1 = union_file(N, IncludedTypes1),
|
|
Type2 = single_file(_),
|
|
UnionType = union_file(N + 1,
|
|
insert_into_list_as_set(IncludedTypes1, Type2))
|
|
;
|
|
Type1 = union_file(N1, IncludedTypes1),
|
|
Type2 = union_file(N2, IncludedTypes2),
|
|
UnionType = union_file(N1 + N2,
|
|
sort_and_remove_dups(IncludedTypes1 ++ IncludedTypes2))
|
|
;
|
|
Type1 = union_file(N, IncludedTypes1),
|
|
Type2 = diff_file(_, _),
|
|
UnionType = union_file(N + 1,
|
|
insert_into_list_as_set(IncludedTypes1, Type2))
|
|
;
|
|
Type1 = diff_file(_, _),
|
|
Type2 = single_file(_),
|
|
UnionType = union_file(2, sort_and_remove_dups([Type1, Type2]))
|
|
;
|
|
Type1 = diff_file(_, _),
|
|
Type2 = union_file(N, IncludedTypes2),
|
|
UnionType = union_file(N + 1,
|
|
insert_into_list_as_set(IncludedTypes2, Type1))
|
|
;
|
|
Type1 = diff_file(_, _),
|
|
Type2 = diff_file(_, _),
|
|
UnionType = union_file(2, sort_and_remove_dups([Type1, Type2]))
|
|
).
|
|
|
|
:- func insert_into_list_as_set(list(T), T) = list(T).
|
|
|
|
insert_into_list_as_set(List0, Item) = List :-
|
|
set.list_to_set(List0, Set0),
|
|
set.insert(Item, Set0, Set),
|
|
set.to_sorted_list(Set, List).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% This function should be kept in sync with the MR_named_count_port array
|
|
% in runtime/mercury_trace_base.c.
|
|
%
|
|
make_path_port(_GoalPath, port_call) = port_only(port_call).
|
|
make_path_port(_GoalPath, port_exit) = port_only(port_exit).
|
|
make_path_port(_GoalPath, port_redo) = port_only(port_redo).
|
|
make_path_port(_GoalPath, port_fail) = port_only(port_fail).
|
|
make_path_port(GoalPath, port_tailrec_call) = path_only(GoalPath).
|
|
make_path_port(_GoalPath, port_exception) = port_only(port_exception).
|
|
make_path_port(GoalPath, port_ite_cond) = path_only(GoalPath).
|
|
make_path_port(GoalPath, port_ite_then) = path_only(GoalPath).
|
|
make_path_port(GoalPath, port_ite_else) = path_only(GoalPath).
|
|
make_path_port(GoalPath, port_neg_enter) =
|
|
port_and_path(port_neg_enter, GoalPath).
|
|
make_path_port(GoalPath, port_neg_success) =
|
|
port_and_path(port_neg_success, GoalPath).
|
|
make_path_port(GoalPath, port_neg_failure) =
|
|
port_and_path(port_neg_failure, GoalPath).
|
|
make_path_port(GoalPath, port_disj_first) = path_only(GoalPath).
|
|
make_path_port(GoalPath, port_disj_later) = path_only(GoalPath).
|
|
make_path_port(GoalPath, port_switch) = path_only(GoalPath).
|
|
make_path_port(_GoalPath, port_user) = port_only(port_user).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
summarize_trace_counts_list(TraceCountsList, TraceCounts) :-
|
|
( if TraceCountsList = [TraceCountsPrime] then
|
|
% optimize the common case
|
|
TraceCounts = TraceCountsPrime
|
|
else
|
|
list.foldl(sum_trace_counts, TraceCountsList, map.init, TraceCounts)
|
|
).
|
|
|
|
sum_trace_counts(TraceCountsA, TraceCountsB, TraceCounts) :-
|
|
map.union(sum_proc_trace_counts, TraceCountsA, TraceCountsB, TraceCounts).
|
|
|
|
:- pred sum_proc_trace_counts(proc_trace_counts::in, proc_trace_counts::in,
|
|
proc_trace_counts::out) is det.
|
|
|
|
sum_proc_trace_counts(ProcTraceCountsA, ProcTraceCountsB, ProcTraceCounts) :-
|
|
ProcTraceCounts = map.union(sum_counts_on_line,
|
|
ProcTraceCountsA, ProcTraceCountsB).
|
|
|
|
:- func sum_counts_on_line(line_no_and_count, line_no_and_count)
|
|
= line_no_and_count.
|
|
|
|
sum_counts_on_line(LC1, LC2) = LC :-
|
|
% We don't check that LineNumber1 = LineNumber2 since that does not
|
|
% necessarily represent an error. (Consider the case when the two trace
|
|
% files are derived from sources that are identical except for the addition
|
|
% of a comment.)
|
|
|
|
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).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
diff_trace_counts(TraceCountsA, TraceCountsB, TraceCounts) :-
|
|
map.foldl(diff_trace_counts_acc(TraceCountsB), TraceCountsA,
|
|
map.init, TraceCounts).
|
|
|
|
:- pred diff_trace_counts_acc(trace_counts::in,
|
|
proc_label_in_context::in, proc_trace_counts::in,
|
|
trace_counts::in, trace_counts::out) is det.
|
|
|
|
diff_trace_counts_acc(TraceCountsB, ProcLabelInContextA, ProcTraceCountsA,
|
|
!TraceCounts) :-
|
|
( if map.search(TraceCountsB, ProcLabelInContextA, ProcTraceCountsB) then
|
|
ProcTraceCounts = diff_proc_counts(ProcTraceCountsA, ProcTraceCountsB),
|
|
map.det_insert(ProcLabelInContextA, ProcTraceCounts, !TraceCounts)
|
|
else
|
|
map.det_insert(ProcLabelInContextA, ProcTraceCountsA, !TraceCounts)
|
|
).
|
|
|
|
:- func diff_proc_counts(proc_trace_counts, proc_trace_counts)
|
|
= proc_trace_counts.
|
|
|
|
diff_proc_counts(ProcTraceCountsA, ProcTraceCountsB) = ProcTraceCounts :-
|
|
map.foldl(diff_proc_counts_acc(ProcTraceCountsB), ProcTraceCountsA,
|
|
map.init, ProcTraceCounts).
|
|
|
|
:- pred diff_proc_counts_acc(proc_trace_counts::in,
|
|
path_port::in, line_no_and_count::in,
|
|
proc_trace_counts::in, proc_trace_counts::out) is det.
|
|
|
|
diff_proc_counts_acc(ProcTraceCountsB, PathPortA, LineNoCountA,
|
|
!ProcTraceCounts) :-
|
|
( if map.search(ProcTraceCountsB, PathPortA, LineNoCountB) then
|
|
LineNoCount = diff_counts_on_line(LineNoCountA, LineNoCountB),
|
|
map.det_insert(PathPortA, LineNoCount, !ProcTraceCounts)
|
|
else
|
|
map.det_insert(PathPortA, LineNoCountA, !ProcTraceCounts)
|
|
).
|
|
|
|
:- func diff_counts_on_line(line_no_and_count, line_no_and_count)
|
|
= line_no_and_count.
|
|
|
|
diff_counts_on_line(LC1, LC2) = LC :-
|
|
% We don't check that LineNumber1 = LineNumber2 since that does not
|
|
% necessarily represent an error. (Consider the case when the two trace
|
|
% files are derived from sources that are identical except for the addition
|
|
% of a comment.)
|
|
|
|
% The number of tests field doesn't make sense in the result of a diff
|
|
% operation. We signal this fact by using a plainly dummy value.
|
|
% XXX It would be better to use a different return type that
|
|
% lacks this meaningless field. Or, sort-of equivalently, we could make
|
|
% line_no_and_count take a type argument, which would specify the type
|
|
% of the third field. This would be set to "int" when the third field
|
|
% is meaningful, and to "unit" when it is not.
|
|
|
|
LC1 = line_no_and_count(LineNumber1, Count1, _NumTests1),
|
|
LC2 = line_no_and_count(_LineNumber, Count2, _NumTests2),
|
|
LC = line_no_and_count(LineNumber1, Count1 - Count2, -1).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
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_context::in,
|
|
proc_trace_counts::in, trace_counts::in, trace_counts::out) is det.
|
|
|
|
restrict_trace_counts_2(ModuleName, ProcLabelInContext, ProcCounts,
|
|
!TraceCounts) :-
|
|
ProcLabel = ProcLabelInContext ^ proc_label,
|
|
( if ProcLabel = ordinary_proc_label(ModuleName, _, _, _, _, _) then
|
|
map.det_insert(ProcLabelInContext, ProcCounts, !TraceCounts)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
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_file(N, _)) = N.
|
|
num_tests_for_file_type(single_file(_)) = 1.
|
|
num_tests_for_file_type(diff_file(_, _)) = -1.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
trace_count_file_id = "Mercury trace counts file".
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module mdbcomp.trace_counts.
|
|
%---------------------------------------------------------------------------%
|