[m-dev.] request for test cases to exercise tabling statistics
Zoltan Somogyi
zs at csse.unimelb.edu.au
Mon Nov 5 17:53:14 AEDT 2007
I have a draft diff for fixing the current code for collecting statistics
about tabling. This diff makes the system collect a better set of measures
and hopefully fixes the bugs people found.
So far, I have a couple of test cases, but these are just variants of
fibonacci. I would prefer some real test cases. If you have a program
that uses tabling, please consider sending it to me.
The draft module that defines the structure of the collected statistics
is shown below. I am also looking for feedback on whether this is the right
set of measures to collect.
Zoltan.
%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
%---------------------------------------------------------------------------%
% Copyright (C) 2007 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: table_statistics.m.
% Author: zs.
% Stability: low.
%
% This file is automatically imported, as if via `use_module', into every
% module that contains a `pragma memo' that asks the compiler to create
% a predicate for returning statistics about the memo table. It defines
% the data structure that this predicate will return, and some operations
% on this data structure.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module table_statistics.
:- interface.
:- import_module io.
:- import_module list.
:- import_module maybe.
:- type proc_table_statistics
---> proc_table_statistics(
call_table_stats :: table_stats_curr_prev,
maybe_answer_table_stats :: maybe(table_stats_curr_prev)
).
:- type table_stats_curr_prev
---> table_stats_curr_prev(
current_stats :: table_stats,
stats_at_last_call :: table_stats
).
:- type table_stats
---> table_stats(
num_lookups :: int,
num_lookups_is_dupl :: int,
step_statistics :: list(table_step_stats)
).
% The definition of this type be an enum whose implementation matches
% the type MR_TableTrieStep in runtime/mercury_tabling.h. It should also
% be kept in sync with the type table_trie_step in hlds_pred.m.
:- type table_step_kind
---> table_step_dummy
; table_step_int
; table_step_char
; table_step_string
; table_step_float
; table_step_enum
; table_step_general
; table_step_general_addr
; table_step_general_poly
; table_step_general_poly_addr
; table_step_typeinfo
; table_step_typeclassinfo
; table_step_promise_implied.
:- type table_step_stats
---> table_step_stats(
table_step_num_lookups :: int,
table_step_num_lookups_is_dupl :: int,
table_step_detail :: table_step_stat_details
).
:- type table_step_stat_details
---> step_stats_none
; step_stats_start(
start_num_node_allocs :: int
)
; step_stats_enum(
enum_num_node_allocs :: int
)
; step_stats_hash(
hash_num_table_allocs :: int,
hash_num_link_chunk_allocs :: int,
hash_num_num_key_compares_not_dupl :: int,
hash_num_num_key_compares_dupl :: int,
hash_num_resizes :: int,
hash_resizes_num_old_entries :: int,
hash_resizes_num_new_entries :: int
)
; step_stats_du(
du_num_node_allocs :: int,
du_num_arg_lookups :: int,
du_num_exist_lookups :: int,
du_enum_num_node_allocs :: int,
du_hash_num_table_allocs :: int,
du_hash_num_link_chunk_allocs :: int,
du_hash_num_num_key_compares_not_dupl :: int,
du_hash_num_num_key_compares_dupl :: int,
du_hash_num_resizes :: int,
du_hash_resizes_num_old_entries :: int,
du_hash_resizes_num_new_entries :: int
)
; step_stats_poly(
poly_du_num_node_allocs :: int,
poly_du_num_arg_lookups :: int,
poly_du_num_exist_lookups :: int,
poly_enum_num_node_allocs :: int,
poly_hash_num_table_allocs :: int,
poly_hash_num_link_chunk_allocs :: int,
poly_hash_num_num_key_compares_not_dupl :: int,
poly_hash_num_num_key_compares_dupl :: int,
poly_hash_num_resizes :: int,
poly_hash_resizes_num_old_entries :: int,
poly_hash_resizes_num_new_entries :: int
).
:- func table_stats_difference(table_stats, table_stats) = table_stats.
:- pred write_table_stats(table_stats::in, io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module bool.
:- import_module float.
:- import_module int.
:- import_module io.
:- import_module require.
:- import_module string.
:- import_module table_builtin.
:- pred get_tabling_stats(ml_proc_table_info::in, proc_table_statistics::out,
io::di, io::uo) is det.
:- pragma foreign_export("C", get_tabling_stats(in, out, di, uo),
"MR_get_tabling_stats").
:- pragma foreign_export("IL", get_tabling_stats(in, out, di, uo),
"MR_get_tabling_stats").
get_tabling_stats(Info, Statistics, !IO) :-
get_proc_info_direct_fields(Info, HasAnswerTable, NumInputs, NumOutputs,
CurCallStatsPtr, PrevCallStatsPtr,
CurAnswerStatsPtr, PrevAnswerStatsPtr, !IO),
get_one_table_stats(CurCallStatsPtr, NumInputs, CurCallStats, !IO),
get_one_table_stats(PrevCallStatsPtr, NumInputs, PrevCallStats, !IO),
CallStats = table_stats_curr_prev(CurCallStats, PrevCallStats),
copy_current_stats_to_prev(CurCallStatsPtr, PrevCallStatsPtr,
NumInputs, !IO),
( HasAnswerTable > 0 ->
get_one_table_stats(CurAnswerStatsPtr, NumOutputs,
CurAnswerStats, !IO),
get_one_table_stats(PrevAnswerStatsPtr, NumOutputs,
PrevAnswerStats, !IO),
AnswerStats = table_stats_curr_prev(CurAnswerStats, PrevAnswerStats),
copy_current_stats_to_prev(CurAnswerStatsPtr, PrevAnswerStatsPtr,
NumOutputs, !IO),
MaybeAnswerStats = yes(AnswerStats)
;
MaybeAnswerStats = no
),
Statistics = proc_table_statistics(CallStats, MaybeAnswerStats).
:- type ml_table_stats_ptr ---> ml_table_stats_ptr(c_pointer).
:- pragma foreign_type("C", ml_table_stats_ptr, "MR_TableStats *",
[can_pass_as_mercury_type]).
:- pragma foreign_type(il, ml_table_stats_ptr,
"class [mscorlib]System.Object").
:- pred get_proc_info_direct_fields(ml_proc_table_info::in,
int::out, int::out, int::out,
ml_table_stats_ptr::out, ml_table_stats_ptr::out,
ml_table_stats_ptr::out, ml_table_stats_ptr::out, io::di, io::uo) is det.
:- pragma foreign_proc("C",
get_proc_info_direct_fields(Info::in,
HasAnswerTable::out, NumInputs::out, NumOutputs::out,
CurCallStatsPtr::out, PrevCallStatsPtr::out,
CurAnswerStatsPtr::out, PrevAnswerStatsPtr::out,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, does_not_affect_liveness],
"
HasAnswerTable = ( Info->MR_pt_has_answer_table ? 1 : 0 );
NumInputs = Info->MR_pt_num_inputs;
NumOutputs = Info->MR_pt_num_outputs;
CurCallStatsPtr = &(Info->
MR_pt_stats[MR_TABLE_STATS_CALL_TABLE][MR_TABLE_STATS_CURR]);
PrevCallStatsPtr = &(Info->
MR_pt_stats[MR_TABLE_STATS_CALL_TABLE][MR_TABLE_STATS_PREV]);
CurAnswerStatsPtr = &(Info->
MR_pt_stats[MR_TABLE_STATS_ANSWER_TABLE][MR_TABLE_STATS_CURR]);
PrevAnswerStatsPtr = &(Info->
MR_pt_stats[MR_TABLE_STATS_ANSWER_TABLE][MR_TABLE_STATS_PREV]);
").
:- pred get_one_table_stats(ml_table_stats_ptr::in, int::in, table_stats::out,
io::di, io::uo) is det.
get_one_table_stats(StatsPtr, NumSteps, Stats, !IO) :-
get_one_table_overall_stats(StatsPtr, NumLookups, NumLookupsIsDupl, !IO),
get_one_table_stats_step_loop(StatsPtr, 0, NumSteps, [], StepStats, !IO),
Stats = table_stats(NumLookups, NumLookupsIsDupl, StepStats).
:- pred get_one_table_overall_stats(ml_table_stats_ptr::in,
int::out, int::out, io::di, io::uo) is det.
:- pragma foreign_proc("C",
get_one_table_overall_stats(StatsPtr::in,
NumLookups::out, NumLookupsIsDupl::out, _IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, does_not_affect_liveness],
"
NumLookups = StatsPtr->MR_ts_num_lookups;
NumLookupsIsDupl = StatsPtr->MR_ts_num_lookups_is_dupl;
").
:- pred get_one_table_stats_step_loop(ml_table_stats_ptr::in, int::in, int::in,
list(table_step_stats)::in, list(table_step_stats)::out,
io::di, io::uo) is det.
get_one_table_stats_step_loop(StatsPtr, CurStep, NumSteps, !StepStats, !IO) :-
( CurStep >= NumSteps ->
true
;
get_one_table_stats_step_loop(StatsPtr, CurStep + 1, NumSteps,
!StepStats, !IO),
get_one_table_step_stats(StatsPtr, CurStep, StepStats, !IO),
!:StepStats = [StepStats | !.StepStats]
).
:- pred get_one_table_step_stats(ml_table_stats_ptr::in, int::in,
table_step_stats::out, io::di, io::uo) is det.
get_one_table_step_stats(StatsPtr, StepNum, Stats, !IO) :-
get_one_table_step_stat_details(StatsPtr, StepNum,
NumLookups, NumLookupsIsDupl, KindInt,
HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries,
EnumNodeAllocs, DuNodeAllocs, DuArgLookups, DuExistLookups,
StartAllocs, !IO),
( KindInt = 0 -> % MR_TABLE_STATS_DETAIL_HASH
(
EnumNodeAllocs = 0,
DuNodeAllocs = 0,
DuArgLookups = 0,
DuExistLookups = 0,
StartAllocs = 0
->
Details = step_stats_hash(HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries)
;
error("get_one_table_step_stat_details: extra counts for hash")
)
; KindInt = 1 -> % MR_TABLE_STATS_DETAIL_ENUM
(
HashTableAllocs = 0,
HashLinkChunkAllocs = 0,
HashKeyComparesNotDupl = 0,
HashKeyComparesIsDupl = 0,
HashResizes = 0,
HashResizeOldEntries = 0,
HashResizeNewEntries = 0,
DuNodeAllocs = 0,
DuArgLookups = 0,
DuExistLookups = 0,
StartAllocs = 0
->
Details = step_stats_enum(EnumNodeAllocs)
;
error("get_one_table_step_stat_details: extra counts for enum")
)
; KindInt = 2 -> % MR_TABLE_STATS_DETAIL_START
(
HashTableAllocs = 0,
HashLinkChunkAllocs = 0,
HashKeyComparesNotDupl = 0,
HashKeyComparesIsDupl = 0,
HashResizes = 0,
HashResizeOldEntries = 0,
HashResizeNewEntries = 0,
EnumNodeAllocs = 0,
DuNodeAllocs = 0,
DuArgLookups = 0,
DuExistLookups = 0
->
Details = step_stats_start(StartAllocs)
;
error("get_one_table_step_stat_details: extra counts for start")
)
; KindInt = 3 -> % MR_TABLE_STATS_DETAIL_DU
(
StartAllocs = 0
->
Details = step_stats_du(DuNodeAllocs,
DuArgLookups, DuExistLookups, EnumNodeAllocs,
HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries)
;
error("get_one_table_step_stat_details: extra counts for du")
)
; KindInt = 4 -> % MR_TABLE_STATS_DETAIL_POLY
(
StartAllocs = 0
->
Details = step_stats_poly(DuNodeAllocs,
DuArgLookups, DuExistLookups, EnumNodeAllocs,
HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries)
;
error("get_one_table_step_stat_details: extra counts for poly")
)
; KindInt = 5 -> % MR_TABLE_STATS_DETAIL_NONE
(
HashTableAllocs = 0,
HashLinkChunkAllocs = 0,
HashKeyComparesNotDupl = 0,
HashKeyComparesIsDupl = 0,
HashResizes = 0,
HashResizeOldEntries = 0,
HashResizeNewEntries = 0,
EnumNodeAllocs = 0,
DuNodeAllocs = 0,
DuArgLookups = 0,
DuExistLookups = 0,
StartAllocs = 0
->
Details = step_stats_none
;
error("get_one_table_step_stat_details: extra counts for none")
)
;
error("get_one_table_step_stat_details: unexpected detail kind")
),
Stats = table_step_stats(NumLookups, NumLookupsIsDupl, Details).
:- pred get_one_table_step_stat_details(ml_table_stats_ptr::in, int::in,
int::out, int::out, int::out,
int::out, int::out, int::out, int::out, int::out, int::out, int::out,
int::out, int::out, int::out, int::out, int::out,
io::di, io::uo) is det.
:- pragma foreign_proc("C",
get_one_table_step_stat_details(StatsStructPtr::in, StepNum::in,
NumLookups::out, NumLookupsIsDupl::out, KindInt::out,
HashTableAllocs::out, HashLinkChunkAllocs::out,
HashKeyComparesNotDupl::out, HashKeyComparesIsDupl::out,
HashResizes::out, HashResizeOldEntries::out, HashResizeNewEntries::out,
EnumNodeAllocs::out,
DuNodeAllocs::out, DuArgLookups::out, DuExistLookups::out,
StartAllocs::out, _IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, does_not_affect_liveness],
"
const MR_TableStepStats *ptr;
ptr = &(StatsStructPtr->MR_ts_steps[StepNum]);
NumLookups = ptr->MR_tss_num_lookups;
NumLookupsIsDupl = ptr->MR_tss_num_lookups_is_dupl;
KindInt = (MR_Integer) ptr->MR_tss_detail_kind;
HashTableAllocs = ptr->MR_tss_hash_details.MR_tssh_num_table_allocs;
HashLinkChunkAllocs =
ptr->MR_tss_hash_details.MR_tssh_num_link_chunk_allocs;
HashKeyComparesNotDupl = ptr->MR_tss_hash_details.MR_tssh_num_key_compares_not_dupl;
HashKeyComparesIsDupl = ptr->MR_tss_hash_details.MR_tssh_num_key_compares_dupl;
HashResizes = ptr->MR_tss_hash_details.MR_tssh_num_resizes;
HashResizeOldEntries = ptr->MR_tss_hash_details.MR_tssh_resize_old_entries;
HashResizeNewEntries = ptr->MR_tss_hash_details.MR_tssh_resize_new_entries;
EnumNodeAllocs = ptr->MR_tss_enum_details.MR_tsse_num_node_allocs;
DuNodeAllocs = ptr->MR_tss_du_details.MR_tssdu_num_node_allocs;
DuArgLookups = ptr->MR_tss_du_details.MR_tssdu_num_arg_lookups;
DuExistLookups = ptr->MR_tss_du_details.MR_tssdu_num_exist_lookups;
StartAllocs = ptr->MR_tss_start_details.MR_tsss_num_allocs;
").
:- pred copy_current_stats_to_prev(ml_table_stats_ptr::in,
ml_table_stats_ptr::in, int::in, io::di, io::uo) is det.
:- pragma foreign_proc("C",
copy_current_stats_to_prev(CurPtr::in, PrevPtr::in, NumSteps::in,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, does_not_affect_liveness],
"
MR_TableStepStats *cur;
MR_TableStepStats *prev;
int i;
PrevPtr->MR_ts_num_lookups = CurPtr->MR_ts_num_lookups;
PrevPtr->MR_ts_num_lookups_is_dupl = CurPtr->MR_ts_num_lookups_is_dupl;
for (i = 0; i < NumSteps; i++) {
cur = &(CurPtr->MR_ts_steps[i]);
prev = &(PrevPtr->MR_ts_steps[i]);
prev->MR_tss_num_lookups = cur->MR_tss_num_lookups;
prev->MR_tss_num_lookups_is_dupl = cur->MR_tss_num_lookups_is_dupl;
prev->MR_tss_hash_details.MR_tssh_num_table_allocs =
cur->MR_tss_hash_details.MR_tssh_num_table_allocs;
prev->MR_tss_hash_details.MR_tssh_num_link_chunk_allocs =
cur->MR_tss_hash_details.MR_tssh_num_link_chunk_allocs;
prev->MR_tss_hash_details.MR_tssh_num_key_compares_not_dupl =
cur->MR_tss_hash_details.MR_tssh_num_key_compares_not_dupl;
prev->MR_tss_hash_details.MR_tssh_num_key_compares_dupl =
cur->MR_tss_hash_details.MR_tssh_num_key_compares_dupl;
prev->MR_tss_hash_details.MR_tssh_num_resizes =
cur->MR_tss_hash_details.MR_tssh_num_resizes;
prev->MR_tss_hash_details.MR_tssh_resize_old_entries =
cur->MR_tss_hash_details.MR_tssh_resize_old_entries;
prev->MR_tss_hash_details.MR_tssh_resize_new_entries =
cur->MR_tss_hash_details.MR_tssh_resize_new_entries;
prev->MR_tss_enum_details.MR_tsse_num_node_allocs =
cur->MR_tss_enum_details.MR_tsse_num_node_allocs;
prev->MR_tss_du_details.MR_tssdu_num_node_allocs =
cur->MR_tss_du_details.MR_tssdu_num_node_allocs;
prev->MR_tss_du_details.MR_tssdu_num_arg_lookups =
cur->MR_tss_du_details.MR_tssdu_num_arg_lookups;
prev->MR_tss_du_details.MR_tssdu_num_exist_lookups =
cur->MR_tss_du_details.MR_tssdu_num_exist_lookups;
prev->MR_tss_start_details.MR_tsss_num_allocs =
cur->MR_tss_start_details.MR_tsss_num_allocs;
}
").
%-----------------------------------------------------------------------------%
table_stats_difference(StatsA, StatsB) = StatsDiff :-
StatsA = table_stats(LookupsA, LookupsIsDuplA, StepsA),
StatsB = table_stats(LookupsB, LookupsIsDuplB, StepsB),
LookupsDiff = LookupsA - LookupsB,
LookupsIsDuplDiff = LookupsIsDuplA - LookupsIsDuplB,
StepsDiff = table_step_stats_diff(StepsA, StepsB),
StatsDiff = table_stats(LookupsDiff, LookupsIsDuplDiff, StepsDiff).
:- func table_step_stats_diff(list(table_step_stats), list(table_step_stats))
= list(table_step_stats).
table_step_stats_diff([], []) = [].
table_step_stats_diff([_ | _], []) = func_error("mismatched table stats").
table_step_stats_diff([], [_ | _]) = func_error("mismatched table stats").
table_step_stats_diff([StepA | StepsA], [StepB | StepsB])
= [StepDiff | StepDiffs] :-
StepA = table_step_stats(LookupsA, LookupsIsDuplA, DetailsA),
StepB = table_step_stats(LookupsB, LookupsIsDuplB, DetailsB),
LookupsDiff = LookupsA - LookupsB,
LookupsIsDuplDiff = LookupsIsDuplA - LookupsIsDuplB,
( table_step_stats_detail_diff(DetailsA, DetailsB, DetailsDiffPrime) ->
DetailsDiff = DetailsDiffPrime
;
error("table_step_stats_diff: mismatches in details")
),
StepDiff = table_step_stats(LookupsDiff, LookupsIsDuplDiff, DetailsDiff),
StepDiffs = table_step_stats_diff(StepsA, StepsB).
:- pred table_step_stats_detail_diff(table_step_stat_details::in,
table_step_stat_details::in, table_step_stat_details::out) is semidet.
table_step_stats_detail_diff(DetailsA, DetailsB, DetailsDiff) :-
(
DetailsA = step_stats_none,
DetailsB = step_stats_none,
DetailsDiff = step_stats_none
;
DetailsA = step_stats_start(StartAllocsA),
DetailsB = step_stats_start(StartAllocsB),
DetailsDiff = step_stats_start(StartAllocsA - StartAllocsB)
;
DetailsA = step_stats_enum(EnumNodeAllocsA),
DetailsB = step_stats_enum(EnumNodeAllocsB),
DetailsDiff = step_stats_enum(EnumNodeAllocsA - EnumNodeAllocsB)
;
DetailsA = step_stats_hash(HashTableAllocsA, HashLinkChunkAllocsA,
HashKeyComparesNotDuplA, HashKeyComparesIsDuplA,
HashResizesA, HashResizeOldEntriesA, HashResizeNewEntriesA),
DetailsB = step_stats_hash(HashTableAllocsB, HashLinkChunkAllocsB,
HashKeyComparesNotDuplB, HashKeyComparesIsDuplB,
HashResizesB, HashResizeOldEntriesB, HashResizeNewEntriesB),
DetailsDiff = step_stats_hash(HashTableAllocsA - HashTableAllocsB,
HashLinkChunkAllocsA - HashLinkChunkAllocsB,
HashKeyComparesNotDuplA - HashKeyComparesNotDuplB,
HashKeyComparesIsDuplA - HashKeyComparesIsDuplB,
HashResizesA - HashResizesB,
HashResizeOldEntriesA - HashResizeOldEntriesB,
HashResizeNewEntriesA - HashResizeNewEntriesB)
;
DetailsA = step_stats_du(DuNodeAllocsA,
DuArgLookupsA, DuExistLookupsA, EnumNodeAllocsA,
HashTableAllocsA, HashLinkChunkAllocsA,
HashKeyComparesNotDuplA, HashKeyComparesIsDuplA,
HashResizesA, HashResizeOldEntriesA, HashResizeNewEntriesA),
DetailsB = step_stats_du(DuNodeAllocsB,
DuArgLookupsB, DuExistLookupsB, EnumNodeAllocsB,
HashTableAllocsB, HashLinkChunkAllocsB,
HashKeyComparesNotDuplB, HashKeyComparesIsDuplB,
HashResizesB, HashResizeOldEntriesB, HashResizeNewEntriesB),
DetailsDiff = step_stats_du(DuNodeAllocsA - DuNodeAllocsB,
DuArgLookupsA - DuArgLookupsB,
DuExistLookupsA - DuExistLookupsB,
EnumNodeAllocsA - EnumNodeAllocsB,
HashTableAllocsA - HashTableAllocsB,
HashLinkChunkAllocsA - HashLinkChunkAllocsB,
HashKeyComparesNotDuplA - HashKeyComparesNotDuplB,
HashKeyComparesIsDuplA - HashKeyComparesIsDuplB,
HashResizesA - HashResizesB,
HashResizeOldEntriesA - HashResizeOldEntriesB,
HashResizeNewEntriesA - HashResizeNewEntriesB)
;
DetailsA = step_stats_poly(DuNodeAllocsA,
DuArgLookupsA, DuExistLookupsA, EnumNodeAllocsA,
HashTableAllocsA, HashLinkChunkAllocsA,
HashKeyComparesNotDuplA, HashKeyComparesIsDuplA,
HashResizesA, HashResizeOldEntriesA, HashResizeNewEntriesA),
DetailsB = step_stats_poly(DuNodeAllocsB,
DuArgLookupsB, DuExistLookupsB, EnumNodeAllocsB,
HashTableAllocsB, HashLinkChunkAllocsB,
HashKeyComparesNotDuplB, HashKeyComparesIsDuplB,
HashResizesB, HashResizeOldEntriesB, HashResizeNewEntriesB),
DetailsDiff = step_stats_poly(DuNodeAllocsA - DuNodeAllocsB,
DuArgLookupsA - DuArgLookupsB,
DuExistLookupsA - DuExistLookupsB,
EnumNodeAllocsA - EnumNodeAllocsB,
HashTableAllocsA - HashTableAllocsB,
HashLinkChunkAllocsA - HashLinkChunkAllocsB,
HashKeyComparesNotDuplA - HashKeyComparesNotDuplB,
HashKeyComparesIsDuplA - HashKeyComparesIsDuplB,
HashResizesA - HashResizesB,
HashResizeOldEntriesA - HashResizeOldEntriesB,
HashResizeNewEntriesA - HashResizeNewEntriesB)
).
%-----------------------------------------------------------------------------%
write_table_stats(Stats, !IO) :-
Stats = table_stats(Lookups, LookupsIsDupl, Steps),
LookupsNotDupl = Lookups - LookupsIsDupl,
LookupsStr = string.int_to_string_thousands(Lookups),
LookupsIsDuplStr = string.int_to_string_thousands(LookupsIsDupl),
LookupsNotDuplStr = string.int_to_string_thousands(LookupsNotDupl),
io.format("number of lookups: %9s\n",
[s(LookupsStr)], !IO),
( Lookups > 0 ->
FractionIsDupl = float(100) * float(LookupsIsDupl) / float(Lookups),
FractionNotDupl = float(100) * float(LookupsNotDupl) / float(Lookups),
string.format("(%.2f%%)", [f(FractionIsDupl)], FractionIsDuplStr),
string.format("(%.2f%%)", [f(FractionNotDupl)], FractionNotDuplStr),
io.format("number of successful lookups (old calls): %9s %9s\n",
[s(LookupsIsDuplStr), s(FractionIsDuplStr)], !IO),
io.format("number of unsuccessful lookups (new calls): %9s %9s\n",
[s(LookupsNotDuplStr), s(FractionNotDuplStr)], !IO),
io.write_string("statistics for the individual steps:\n", !IO),
list.foldl2(write_table_step_stats_loop, Steps, 1, _, !IO)
;
true
).
:- pred write_table_step_stats_loop(table_step_stats::in, int::in, int::out,
io::di, io::uo) is det.
write_table_step_stats_loop(Step, !StepNum, !IO) :-
write_table_step_stats(Step, !.StepNum, !IO),
!:StepNum = !.StepNum + 1.
:- pred write_table_step_stats_header(int::in, string::in,
int::in, int::in, io::di, io::uo) is det.
write_table_step_stats_header(StepNum, KindStr, Lookups, LookupsIsDupl, !IO) :-
io.format("\nstep %d: %s\n", [i(StepNum), s(KindStr)], !IO),
LookupsNotDupl = Lookups - LookupsIsDupl,
LookupsStr = string.int_to_string_thousands(Lookups),
LookupsIsDuplStr = string.int_to_string_thousands(LookupsIsDupl),
LookupsNotDuplStr = string.int_to_string_thousands(LookupsNotDupl),
io.format(" number of lookups: %9s\n",
[s(LookupsStr)], !IO),
( Lookups > 0 ->
FractionIsDupl = float(100) * float(LookupsIsDupl) / float(Lookups),
FractionNotDupl = float(100) * float(LookupsNotDupl) / float(Lookups),
string.format("(%.2f%%)", [f(FractionIsDupl)], FractionIsDuplStr),
string.format("(%.2f%%)", [f(FractionNotDupl)], FractionNotDuplStr),
io.format(" number of successful lookups: %9s %9s\n",
[s(LookupsIsDuplStr), s(FractionIsDuplStr)], !IO),
io.format(" number of unsuccessful lookups: %9s %9s\n",
[s(LookupsNotDuplStr), s(FractionNotDuplStr)], !IO)
;
true
).
:- pred write_table_step_stats_start(int::in, io::di, io::uo) is det.
write_table_step_stats_start(StartAllocs, !IO) :-
StartAllocsStr = string.int_to_string_thousands(StartAllocs),
io.format(" number of array (re)allocations: %9s\n",
[s(StartAllocsStr)], !IO).
:- pred write_table_step_stats_enum(int::in, io::di, io::uo) is det.
write_table_step_stats_enum(EnumNodeAllocs, !IO) :-
EnumNodeAllocsStr = string.int_to_string_thousands(EnumNodeAllocs),
io.format(" number of enum node allocations: %9s\n",
[s(EnumNodeAllocsStr)], !IO).
:- pred write_table_step_stats_hash(int::in, int::in, int::in,
int::in, int::in, int::in, int::in, io::di, io::uo) is det.
write_table_step_stats_hash(HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries, !IO) :-
HashTableAllocsStr =
string.int_to_string_thousands(HashTableAllocs),
HashLinkChunkAllocsStr =
string.int_to_string_thousands(HashLinkChunkAllocs),
HashKeyComparesNotDuplStr =
string.int_to_string_thousands(HashKeyComparesNotDupl),
HashKeyComparesIsDuplStr =
string.int_to_string_thousands(HashKeyComparesIsDupl),
HashResizesStr =
string.int_to_string_thousands(HashResizes),
HashResizeOldEntriesStr =
string.int_to_string_thousands(HashResizeOldEntries),
HashResizeNewEntriesStr =
string.int_to_string_thousands(HashResizeNewEntries),
io.format(" number of hash table allocations: %9s\n",
[s(HashTableAllocsStr)], !IO),
io.format(" number of bulk hash link allocations: %9s\n",
[s(HashLinkChunkAllocsStr)], !IO),
io.format(" number of key compares (when not duplicate):%9s\n",
[s(HashKeyComparesNotDuplStr)], !IO),
io.format(" number of key compares (when duplicate): %9s\n",
[s(HashKeyComparesIsDuplStr)], !IO),
io.format(" number of hash table resizes: %9s\n",
[s(HashResizesStr)], !IO),
( HashResizes > 0 ->
io.format(" number of old entries in resizes: %9s\n",
[s(HashResizeOldEntriesStr)], !IO),
io.format(" number of new entries in resizes: %9s\n",
[s(HashResizeNewEntriesStr)], !IO)
;
true
).
:- pred write_table_step_stats_du(int::in, int::in, int::in, io::di, io::uo)
is det.
write_table_step_stats_du(DuNodeAllocs, DuArgLookups, DuExistLookups, !IO) :-
DuNodeAllocsStr = string.int_to_string_thousands(DuNodeAllocs),
DuArgLookupsStr = string.int_to_string_thousands(DuArgLookups),
DuExistLookupsStr = string.int_to_string_thousands(DuExistLookups),
io.format(" number of du functor node allocations: %9s\n",
[s(DuNodeAllocsStr)], !IO),
io.format(" number of du functor argument lookups: %9s\n",
[s(DuArgLookupsStr)], !IO),
( DuExistLookups > 0 ->
io.format(" number of du existential type lookups: %9s\n",
[s(DuExistLookupsStr)], !IO)
;
true
).
:- pred write_table_step_stats(table_step_stats::in, int::in,
io::di, io::uo) is det.
write_table_step_stats(Step, StepNum, !IO) :-
Step = table_step_stats(Lookups, LookupsIsDupl, Details),
(
Details = step_stats_none,
write_table_step_stats_header(StepNum, "none", Lookups, LookupsIsDupl,
!IO)
;
Details = step_stats_start(StartAllocs),
write_table_step_stats_header(StepNum, "expandable array",
Lookups, LookupsIsDupl, !IO),
( Lookups > 0 ->
write_table_step_stats_start(StartAllocs, !IO)
;
true
)
;
Details = step_stats_enum(EnumNodeAllocs),
write_table_step_stats_header(StepNum, "enum trie",
Lookups, LookupsIsDupl, !IO),
( Lookups > 0 ->
write_table_step_stats_enum(EnumNodeAllocs, !IO)
;
true
)
;
Details = step_stats_hash(HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries),
write_table_step_stats_header(StepNum, "hash table",
Lookups, LookupsIsDupl, !IO),
( Lookups > 0 ->
write_table_step_stats_hash(HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries, !IO)
;
true
)
;
(
Details = step_stats_du(DuNodeAllocs,
DuArgLookups, DuExistLookups, EnumNodeAllocs,
HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries),
KindStr = "discriminated union nested trie",
MustHaveDu = yes
;
Details = step_stats_poly(DuNodeAllocs,
DuArgLookups, DuExistLookups, EnumNodeAllocs,
HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries),
KindStr = "polymorphic table",
MustHaveDu = no
),
write_table_step_stats_header(StepNum, KindStr,
Lookups, LookupsIsDupl, !IO),
( Lookups > 0 ->
( DuNodeAllocs > 0 ->
write_table_step_stats_du(DuNodeAllocs,
DuArgLookups, DuExistLookups, !IO)
;
(
MustHaveDu = no
;
MustHaveDu = yes,
error("write_table_step_stats: no du stats")
)
),
( EnumNodeAllocs > 0 ->
write_table_step_stats_enum(EnumNodeAllocs, !IO)
;
true
),
( HashTableAllocs > 0 ->
write_table_step_stats_hash(
HashTableAllocs, HashLinkChunkAllocs,
HashKeyComparesNotDupl, HashKeyComparesIsDupl,
HashResizes, HashResizeOldEntries, HashResizeNewEntries,
!IO)
;
true
)
;
true
)
).
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at csse.unimelb.edu.au
Administrative Queries: owner-mercury-developers at csse.unimelb.edu.au
Subscriptions: mercury-developers-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the developers
mailing list