Permalink
Switch branches/tags
version-14_01_1 version-14_01 version-13_05_2 version-13_05_1 version-13_05 version-12_08-branchpoint version-12_08-GIT version-11_07_2 version-11_07_1 version-11_07 version-11_07-branchpoint version-11_01 version-11_01-branchpoint version-10_04_2 version-10_04_1 version-10_04 version-10_04-branchpoint version-0_13_1 version-0_13-branchpoint version-0_12_2 version-0_12_1 version-0_12-branchpoint version-0_11_0 version-0_11-branchpoint version-0_10 version-0_9_1 version-0_9 version-0_9_x-snapshot version-0_9_x-snapshot-19991220 unstable-version-0_13_1-x86_64-unknown-linux-gnu-libc2_3 unstable-version-0_13_1-i686-pc-linux-libc2_3-gnu-O5-intermod unstable-version-0_13-branch-x86_64-unknown-linux-gnu-libc2_3 unstable-version-0_13-branch-i686-pc-linux-libc2_3-gnu-O5-intermod unstable-version-0_12_2-i686-pc-linux-libc2_2-gnu-O5-intermod unstable-version-0_12_2-i386-pc-solaris2_8 unstable-version-0_12_1-i686-pc-linux-libc2_3-gnu-O4-intermod unstable-version-0_12_1-i686-pc-linux-libc2_3-gnu-O2 unstable-version-0_12_1-i686-pc-linux-libc2_2-gnu-O5-intermod unstable-version-0_12_1-i386-pc-solaris2_8 unstable-version-0_12-branch-i686-pc-linux-libc2_3-gnu-O5 unstable-version-0_12-branch-i686-pc-linux-libc2_3-gnu-O4-intermod unstable-version-0_12-branch-i686-pc-linux-libc2_3-gnu-O4-hlc unstable-version-0_12-branch-i686-pc-linux-libc2_3-gnu-O2 unstable-version-0_12-branch-i686-pc-linux-libc2_2-gnu-O5 unstable-version-0_12-branch-i686-pc-linux-libc2_2-gnu-O5-intermod unstable-version-0_12-branch-i686-pc-linux-libc2_2-gnu-O3 unstable-version-0_12-branch-i386-pc-solaris2_8 unstable-version-0_11_0-sparc-sun-solaris2_7 unstable-version-0_11_0-i686-pc-linux-libc2_3-gnu-O5-intermod unstable-version-0_11_0-i686-pc-linux-libc2_2-gnu-O5 unstable-version-0_11_0-i686-pc-linux-libc2_2-gnu-O5-lcc unstable-version-0_11_0-i686-pc-linux-libc2_2-gnu-O5-hlc unstable-version-0_11_0-i686-pc-linux-libc2_1-gnu-O4 unstable-version-0_11_0-i686-pc-linux-libc2_1-gnu-O4-asm unstable-version-0_11_0-i686-pc-linux-libc2_1-gnu-O3 unstable-version-0_11_0-i386-pc-solaris2_8 unstable-version-0_11-branch-i686-pc-linux-libc2_3-gnu-O5-intermod unstable-version-0_11-branch-i686-pc-linux-libc2_2-gnu-O5-intermod unstable-version-0_11-branch-i686-pc-linux-libc2_2-gnu-O5-hlc unstable-version-0_11-branch-i686-pc-linux-libc2_1-gnu-O5 unstable-version-0_11-branch-i686-pc-linux-libc2_1-gnu-O5-lcc unstable-version-0_11-branch-i686-pc-linux-libc2_1-gnu-O5-intermod unstable-version-0_11-branch-i686-pc-linux-libc2_1-gnu-O5-hlc unstable-version-0_11-branch-alpha-dec-osf5_1 unstable-version-0_10_y-sparc-sun-solaris2_7 unstable-version-0_10_y-i686-pc-linux-libc2_1-gnu-O5 unstable-version-0_10_y-i686-pc-linux-libc2_1-gnu-O5-lcc unstable-version-0_10_y-i686-pc-linux-libc2_1-gnu-O5-intermod unstable-version-0_10_y-i686-pc-linux-libc2_1-gnu-O5-hlc unstable-version-0_10_y-i686-pc-linux-libc2_1-gnu-O4 unstable-version-0_10_y-i686-pc-linux-libc2_1-gnu-O4-hlc unstable-version-0_10_y-i686-pc-linux-libc2_1-gnu-O2 unstable-version-0_10_y-i586-pc-linux-libc2_1-gnu-O0 unstable-version-0_10_y-alpha-dec-osf5_1 unstable-version-0_10_y-alpha-dec-osf3_2 unstable-version-0_10_x-sparc-sun-solaris2_7 unstable-version-0_10_x-i686-pc-linux-libc2_1-gnu-O5 unstable-version-0_10_x-i686-pc-linux-libc2_1-gnu-O5-lcc unstable-version-0_10_x-i686-pc-linux-libc2_1-gnu-O4 unstable-version-0_10_x-i686-pc-linux-libc2_1-gnu-O4-hlc unstable-version-0_10_x-i686-pc-linux-libc2_1-gnu-O3 unstable-version-0_10_x-i686-pc-linux-libc2_1-gnu-O2 unstable-version-0_10_x-i586-pc-linux-libc2_1-gnu-O0 unstable-version-0_10_x-alpha-dec-osf3_2 termination2_trunk stable-version-0_11_0-i686-pc-linux-libc2_3-gnu-O5-intermod stable-version-0_11_0-i686-pc-linux-libc2_2-gnu-O5 stable-version-0_11_0-i686-pc-linux-libc2_2-gnu-O5-lcc stable-version-0_11_0-i686-pc-linux-libc2_2-gnu-O5-hlc stable-version-0_11_0-i686-pc-linux-libc2_1-gnu-O4 stable-version-0_11_0-i686-pc-linux-libc2_1-gnu-O4-asm stable-version-0_11_0-i686-pc-linux-libc2_1-gnu-O3 stable-version-0_11-branch-i686-pc-linux-libc2_3-gnu-O5-intermod stable-version-0_11-branch-i686-pc-linux-libc2_2-gnu-O5-lcc stable-version-0_11-branch-i686-pc-linux-libc2_2-gnu-O5-intermod stable-version-0_11-branch-i686-pc-linux-libc2_1-gnu-O5 stable-version-0_11-branch-i686-pc-linux-libc2_1-gnu-O5-lcc stable-version-0_11-branch-i686-pc-linux-libc2_1-gnu-O5-intermod stable-version-0_11-branch-i686-pc-linux-libc2_1-gnu-O5-hlc stable-version-0_11-branch-alpha-dec-osf5_1
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
5382 lines (4730 sloc) 207 KB
%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2008-2011 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% File: display_report.m.
% Author: pbone.
%
% This module contains code to create a display data structure from a deep
% profiling report.
%
%---------------------------------------------------------------------------%
:- module display_report.
:- interface.
:- import_module display.
:- import_module profile.
:- import_module report.
% XXX: This include should be removed or replaced. Some data structures
% such as preferences are currently defined in query; they should be moved
% into a different module so that this module doesn't need to include
% the whole of query.
:- import_module query.
%---------------------------------------------------------------------------%
:- func report_to_display(deep, preferences, deep_report) = display.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module coverage.
:- import_module exclude.
:- import_module mdbcomp.
:- import_module mdbcomp.goal_path.
:- import_module mdbcomp.program_representation.
:- import_module measurement_units.
:- import_module program_representation_utils.
:- import_module var_use_analysis.
:- import_module array.
:- import_module assoc_list.
:- import_module bool.
:- import_module cord.
:- import_module counter.
:- import_module float.
:- import_module int.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module pair.
:- import_module require.
:- import_module set.
:- import_module string.
:- import_module unit.
%---------------------------------------------------------------------------%
report_to_display(Deep, Prefs, Report) = Display :-
(
Report = report_message(message_report(Msg)),
Display = display(no, [display_heading(Msg)])
;
Report = report_menu(MaybeMenuReport),
(
MaybeMenuReport = ok(MenuReport),
display_report_menu(Deep, Prefs, MenuReport, Display)
;
MaybeMenuReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_clique(MaybeCliqueReport),
(
MaybeCliqueReport = ok(CliqueReport),
display_report_clique(Prefs, CliqueReport, Display)
;
MaybeCliqueReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_clique_recursion_costs(MaybeCliqueRecursionReport),
(
MaybeCliqueRecursionReport = ok(CliqueRecursionReport),
display_report_clique_recursion(Prefs, CliqueRecursionReport,
Display)
;
MaybeCliqueRecursionReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_recursion_types_frequency(MaybeRecTypesFreqReport),
(
MaybeRecTypesFreqReport = ok(RecTypesFreqReport),
display_report_recursion_types_frequency(Prefs, RecTypesFreqReport,
Display)
;
MaybeRecTypesFreqReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_program_modules(MaybeProgramModulesReport),
(
MaybeProgramModulesReport = ok(ProgramModulesReport),
display_report_program_modules(Prefs, ProgramModulesReport,
Display)
;
MaybeProgramModulesReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_module(MaybeModuleReport),
(
MaybeModuleReport = ok(ModuleReport),
display_report_module(Prefs, ModuleReport, Display)
;
MaybeModuleReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_module_getter_setters(MaybeModuleGetterSettersReport),
(
MaybeModuleGetterSettersReport = ok(ModuleGetterSettersReport),
display_report_module_getter_setters(Prefs,
ModuleGetterSettersReport, Display)
;
MaybeModuleGetterSettersReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_module_rep(MaybeModuleRepReport),
(
MaybeModuleRepReport = ok(ModuleRepReport),
display_report_module_rep(Prefs, ModuleRepReport, Display)
;
MaybeModuleRepReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_top_procs(MaybeTopProcsReport),
(
MaybeTopProcsReport = ok(TopProcsReport),
display_report_top_procs(Prefs, TopProcsReport, Display)
;
MaybeTopProcsReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_proc(MaybeProcReport),
(
MaybeProcReport = ok(ProcReport),
display_report_proc(Deep, Prefs, ProcReport, Display)
;
MaybeProcReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_procrep_coverage(MaybeProcrepCoverageInfo),
(
MaybeProcrepCoverageInfo = ok(ProcrepCoverageInfo),
display_report_procrep_coverage_info(Prefs, ProcrepCoverageInfo,
Display)
;
MaybeProcrepCoverageInfo = error(Msg),
Display = display(no, [display_text(Msg)])
)
;
Report = report_proc_callers(MaybeProcCallersReport),
(
MaybeProcCallersReport = ok(ProcCallersReport),
display_report_proc_callers(Deep, Prefs, ProcCallersReport,
Display)
;
MaybeProcCallersReport = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_proc_static_dump(MaybeProcStaticDumpInfo),
(
MaybeProcStaticDumpInfo = ok(ProcStaticDumpInfo),
display_report_proc_static_dump(ProcStaticDumpInfo, Display)
;
MaybeProcStaticDumpInfo = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_proc_dynamic_dump(MaybeProcDynamicDumpInfo),
(
MaybeProcDynamicDumpInfo = ok(ProcDynamicDumpInfo),
display_report_proc_dynamic_dump(Deep, Prefs, ProcDynamicDumpInfo,
Display)
;
MaybeProcDynamicDumpInfo = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_call_site_static_dump(MaybeCallSiteStaticDumpInfo),
(
MaybeCallSiteStaticDumpInfo = ok(CallSiteStaticDumpInfo),
display_report_call_site_static_dump(Prefs, CallSiteStaticDumpInfo,
Display)
;
MaybeCallSiteStaticDumpInfo = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_call_site_dynamic_dump(MaybeCallSiteDynamicDumpInfo),
(
MaybeCallSiteDynamicDumpInfo = ok(CallSiteDynamicDumpInfo),
display_report_call_site_dynamic_dump(Prefs,
CallSiteDynamicDumpInfo, Display)
;
MaybeCallSiteDynamicDumpInfo = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_clique_dump(MaybeCliqueDumpInfo),
(
MaybeCliqueDumpInfo = ok(CliqueDumpInfo),
display_report_clique_dump(Prefs, CliqueDumpInfo, Display)
;
MaybeCliqueDumpInfo = error(Msg),
Display = display(no, [display_heading(Msg)])
)
;
Report = report_call_site_dynamic_var_use(MaybeVarUseInfo),
(
MaybeVarUseInfo = ok(VarUseInfo),
display_report_call_site_dynamic_var_use(Prefs, VarUseInfo,
Display)
;
MaybeVarUseInfo = error(Msg),
Display = display(no, [display_heading(Msg)])
)
).
%---------------------------------------------------------------------------%
%
% Code to display menu report.
%
:- pred display_report_menu(deep::in, preferences::in, menu_report::in,
display::out) is det.
display_report_menu(Deep, Prefs, MenuReport, Display) :-
MenuReport = menu_report(ProgramName, QuantaPerSec, UserQuanta, InstQuanta,
NumCallseqs, NumCSD, NumCSS, NumPD, NumPS, NumClique),
TotalQuanta = UserQuanta + InstQuanta,
TotalTime = ticks_to_time(TotalQuanta, QuantaPerSec),
ShouldDisplayTimes = should_display_times(Deep),
% Display the links section of the report.
ActionPrefs0 = Prefs,
ActionPrefs1 = ActionPrefs0 ^ pref_inactive :=
inactive_items(inactive_hide, inactive_hide, inactive_hide),
ActionPrefs = ActionPrefs1 ^ pref_criteria :=
by_cost(cost_time, self_and_desc, overall),
LinksExploration = [
link_base(deep_cmd_root(no), yes(ActionPrefs),
"Exploring the call graph, starting at the root."),
link_base(deep_cmd_root(yes(90)), yes(ActionPrefs),
"Exploring the call graph, starting at the action."),
link_base(deep_cmd_program_modules, yes(Prefs),
"Exploring the program module by module.")
],
(
ShouldDisplayTimes = yes,
Top100SelfCmd = deep_cmd_top_procs(rank_range(1, 100),
cost_time, self, overall),
Top100SelfAndDescCmd = deep_cmd_top_procs(rank_range(1, 100),
cost_time, self_and_desc, overall),
LinksTopProcsByLimitTime = [
link_base(Top100SelfCmd, yes(Prefs),
"Top 100 most expensive procedures: time, self."),
link_base(Top100SelfAndDescCmd, yes(Prefs),
"Top 100 most expensive procedures: time, self+descendants.")
]
;
ShouldDisplayTimes = no,
LinksTopProcsByLimitTime = []
),
TopLimitCallSeqsSelf = deep_cmd_top_procs(rank_range(1, 100),
cost_callseqs, self, overall),
TopLimitCallSeqsSelfAndDesc = deep_cmd_top_procs(rank_range(1, 100),
cost_callseqs, self_and_desc, overall),
TopLimitWordsSelf = deep_cmd_top_procs(rank_range(1, 100),
cost_words, self, overall),
TopLimitWordsSelfAndDesc = deep_cmd_top_procs(rank_range(1, 100),
cost_words, self_and_desc, overall),
LinksTopProcsByLimit = [
link_base(TopLimitCallSeqsSelf, yes(Prefs),
"Top 100 most expensive procedures: callseqs, self."),
link_base(TopLimitCallSeqsSelfAndDesc, yes(Prefs),
"Top 100 most expensive procedures: callseqs, self+descendants."),
link_base(TopLimitWordsSelf, yes(Prefs),
"Top 100 most expensive procedures: words, self."),
link_base(TopLimitWordsSelfAndDesc, yes(Prefs),
"Top 100 most expensive procedures: words, self+descendants.")
],
(
ShouldDisplayTimes = yes,
TimeAbove01PercentCmd = deep_cmd_top_procs(threshold_percent(0.1),
cost_time, self, overall),
TimeAbove1PercentCmd = deep_cmd_top_procs(threshold_percent(1.0),
cost_time, self, overall),
TimeAbove1SecondCmd = deep_cmd_top_procs(threshold_value(100.0),
cost_time, self_and_desc, overall),
LinksTopProcsByPercentTime = [
link_base(TimeAbove01PercentCmd, yes(Prefs),
"Procedures above 0.1% threshold: time, self."),
link_base(TimeAbove1PercentCmd, yes(Prefs),
"Procedures above 1% threshold: time, self+descendants."),
link_base(TimeAbove1SecondCmd, yes(Prefs),
"Procedures above 1 second threshold: time, self+descendants.")
]
;
ShouldDisplayTimes = no,
LinksTopProcsByPercentTime = []
),
CallSeqsAbove01PercentCmd = deep_cmd_top_procs(threshold_percent(0.1),
cost_callseqs, self, overall),
CallSeqsAbove1PercentCmd = deep_cmd_top_procs(threshold_percent(1.0),
cost_callseqs, self_and_desc, overall),
CallSeqsAboveMillionCmd = deep_cmd_top_procs(threshold_value(1000000.0),
cost_callseqs, self_and_desc, overall),
WordsAbove01PercentCmd = deep_cmd_top_procs(threshold_percent(0.1),
cost_words, self, overall),
WordsAbove1PercentCmd = deep_cmd_top_procs(threshold_percent(1.0),
cost_words, self_and_desc, overall),
% 2M words is 8MB on ia32.
WordsAbove2Megawords = deep_cmd_top_procs(
threshold_value(float(1024 * 1024 * 2)),
cost_words, self_and_desc, overall),
LinksTopProcsByPercent = [
link_base(CallSeqsAbove01PercentCmd, yes(Prefs),
"Procedures above 0.1% threshold: callseqs, self."),
link_base(CallSeqsAbove1PercentCmd, yes(Prefs),
"Procedures above 1% threshold: callseqs, self+descendants."),
link_base(CallSeqsAboveMillionCmd, yes(Prefs),
("Procedures above 1,000,000 callseqs threshold: callseqs, " ++
"self+descendants.")),
link_base(WordsAbove01PercentCmd, yes(Prefs),
"Procedures above 0.1% threshold: words, self."),
link_base(WordsAbove1PercentCmd, yes(Prefs),
"Procedures above 1% threshold: words, self+descendants."),
link_base(WordsAbove2Megawords, yes(Prefs),
"Procedures above 2M words threshold: words, self+descendants.")
],
LinkCmds = LinksExploration ++
LinksTopProcsByLimitTime ++ LinksTopProcsByLimit ++
LinksTopProcsByPercentTime ++ LinksTopProcsByPercent,
list.map(make_link, LinkCmds, LinksList),
Links = display_list(list_class_vertical_bullets,
yes("You can start exploring the deep profile at the following" ++
" points."), LinksList),
%
% Produce the developer-only options list.
%
RecursionTypeFrequenciesCmd = deep_cmd_recursion_types_frequency,
LinksDeveloperCmds = [
link_base(RecursionTypeFrequenciesCmd, yes(Prefs),
"Frequencies of different types of recursion used in the program.")
],
list.map(make_link, LinksDeveloperCmds, DeveloperLinksList),
DeveloperLinks = display_developer(
display_list(list_class_vertical_bullets,
yes("Options that are only useful to Mercury developers"),
DeveloperLinksList)),
% Display the table section of the report.
ProfilingStatistics =
[("Profile generated for:" - td_s(ProgramName)),
("Quanta per second:" - td_i(QuantaPerSec)),
("Quanta in user code:" - td_i(UserQuanta)),
("Quanta in instrumentation:" - td_i(InstQuanta)),
("Total quanta:" - td_i(TotalQuanta)),
("Total time:" - td_t(TotalTime)),
("Call sequence numbers:" - td_i(NumCallseqs)),
("CallSiteDynamic structures:" - td_i(NumCSD)),
("ProcDynamic structures:" - td_i(NumPD)),
("CallSiteStatic structures:" - td_i(NumCSS)),
("ProcStatic structures:" - td_i(NumPS)),
("Cliques:" - td_i(NumClique))],
Rows = list.map(make_labelled_table_row, ProfilingStatistics),
Table = table(table_class_do_not_box, 2, no, Rows),
OptionsControls = general_options_controls(deep_cmd_menu, Prefs),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
% Construct the complete representation of what to display.
Display = display(yes("Deep profiler menu"),
[Links, DeveloperLinks, display_table(Table),
display_paragraph_break, MenuRestartQuitControls,
display_paragraph_break, OptionsControls]).
%---------------------------------------------------------------------------%
%
% Code to display a clique report.
%
% Create a display_report structure for a clique report.
%
:- pred display_report_clique(preferences::in, clique_report::in,
display::out) is det.
display_report_clique(Prefs, CliqueReport, Display) :-
CliqueReport = clique_report(CliquePtr, InnerToOuterAncestorCallSites0,
CliqueProcs0),
Cmd = deep_cmd_clique(CliquePtr),
CliquePtr = clique_ptr(CliqueNum),
Title = string.format("Clique %d:", [i(CliqueNum)]),
% Build the table of all modules.
SortByContextPrefs = Prefs ^ pref_criteria := by_context,
SortByNamePrefs = Prefs ^ pref_criteria := by_name,
SourceHeaderCell = td_l(deep_link(Cmd, yes(SortByContextPrefs),
attr_str([], "Source"), link_class_link)),
ProcHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "Procedure"), link_class_link)),
SourceHeaderGroup =
make_single_table_header_group(SourceHeaderCell,
table_column_class_source_context, column_do_not_colour),
ProcHeaderGroup =
make_single_table_header_group(ProcHeaderCell,
table_column_class_proc, column_do_not_colour),
MakeHeaderData = override_order_criteria_header_data(Cmd),
perf_table_header(total_columns_meaningful, Prefs, MakeHeaderData,
PerfHeaderGroups),
AllHeaderGroups = [SourceHeaderGroup, ProcHeaderGroup] ++ PerfHeaderGroups,
header_groups_to_header(AllHeaderGroups, NumColumns, Header),
list.length(InnerToOuterAncestorCallSites0, NumAncestors),
MaybeAncestorLimit = Prefs ^ pref_anc,
( if
MaybeAncestorLimit = yes(AncestorLimit),
NumAncestors > AncestorLimit
then
AncestorTitle = string.format("The %d closest ancestor call sites:",
[i(AncestorLimit)]),
list.take_upto(AncestorLimit,
InnerToOuterAncestorCallSites0, InnerToOuterAncestorCallSites)
else
AncestorTitle = "Ancestor call sites:",
InnerToOuterAncestorCallSites = InnerToOuterAncestorCallSites0
),
list.reverse(InnerToOuterAncestorCallSites, AncestorCallSites),
ModuleQual = Prefs ^ pref_module_qual,
CliqueModuleNames = list.map(clique_proc_report_module_name, CliqueProcs0),
( if
CliqueModuleNames = [FirstModuleName | _],
list.all_same(CliqueModuleNames)
then
MaybeCurModuleName = yes(FirstModuleName)
else
MaybeCurModuleName = no
),
AncestorDataRows = list.map(
clique_ancestor_to_row(MaybeCurModuleName, ModuleQual, Prefs),
AncestorCallSites),
AncestorSectionHeaderRow = table_section_header(td_s(AncestorTitle)),
AncestorRows = [AncestorSectionHeaderRow, table_separator_row] ++
AncestorDataRows,
list.length(CliqueProcs0, NumCliqueprocs),
( if NumCliqueprocs > 1 then
ProcsTitle = "Procedures of the clique:"
else
ProcsTitle = "The clique has one procedure:"
),
CliqueProcsHeaderRow = table_section_header(td_s(ProcsTitle)),
sort_clique_procs_by_preferences(MaybeCurModuleName, ModuleQual, Prefs,
CliqueProcs0, CliqueProcs),
ProcRowLists0 = list.map(
clique_proc_to_table_rows(MaybeCurModuleName, ModuleQual, Prefs,
CliquePtr),
CliqueProcs),
ProcRowLists = list.map(add_front_separator_row, ProcRowLists0),
list.condense(ProcRowLists, ProcRows),
AllRows = AncestorRows ++
[table_separator_row, CliqueProcsHeaderRow] ++ ProcRows,
Table = table(table_class_box_if_pref, NumColumns, yes(Header), AllRows),
DisplayTable = display_table(Table),
% Build controls at the bottom of the page.
AncestorControls = ancestor_controls(Prefs, Cmd),
InactiveCallSiteControls = inactive_call_site_controls(Prefs, Cmd),
ModuleQualControls = module_qual_controls(Prefs, Cmd),
FieldControls = field_controls(Prefs, Cmd),
FormatControls = format_controls(Prefs, Cmd),
CliqueReportControls = clique_reports_controls(Prefs, CliquePtr, Cmd),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Display = display(yes(Title),
[DisplayTable,
display_paragraph_break, AncestorControls,
display_paragraph_break, InactiveCallSiteControls,
display_paragraph_break, ModuleQualControls,
display_paragraph_break, FieldControls,
display_paragraph_break, FormatControls,
display_paragraph_break, CliqueReportControls,
display_paragraph_break, MenuRestartQuitControls]).
:- func clique_proc_report_module_name(clique_proc_report) = string.
clique_proc_report_module_name(CliqueProc) =
CliqueProc ^ cpr_proc_summary ^ perf_row_subject ^ pdesc_module_name.
:- func add_front_separator_row(list(table_row)) = list(table_row).
add_front_separator_row(Rows) = [table_separator_row | Rows].
:- func clique_ancestor_to_row(maybe(string), module_qual, preferences,
perf_row_data(ancestor_desc)) = table_row.
clique_ancestor_to_row(MaybeCurModuleName, ModuleQual, Prefs, AncestorRowData)
= Row :-
AncestorDesc = AncestorRowData ^ perf_row_subject,
CallSiteDesc = AncestorDesc ^ ad_call_site_desc,
SourceCell = call_site_desc_source_cell(CallSiteDesc),
CliqueProcCell = call_site_desc_clique_proc_cell(MaybeCurModuleName,
ModuleQual, Prefs, AncestorDesc),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, AncestorRowData,
PerfCells),
AllCells = [SourceCell, CliqueProcCell] ++ PerfCells,
Row = table_row(AllCells).
:- func clique_proc_to_table_rows(maybe(string), module_qual, preferences,
clique_ptr, clique_proc_report) = list(table_row).
clique_proc_to_table_rows(MaybeCurModuleName, ModuleQual, Prefs, CliquePtr,
CliqueProcReport) = ProcRows :-
CliqueProcReport = clique_proc_report(SummaryRowData,
FirstPDReport, LaterPDReports),
(
LaterPDReports = [],
ProcRows = clique_proc_dynamic_to_table_rows(MaybeCurModuleName,
ModuleQual, Prefs, CliquePtr, FirstPDReport)
;
LaterPDReports = [_ | _],
AllPDReports = [FirstPDReport | LaterPDReports],
sort_clique_proc_dynamics_by_preferences(Prefs, AllPDReports,
SortedAllPDReports),
PDProcRowLists =
list.map(
clique_proc_dynamic_to_table_rows(MaybeCurModuleName,
ModuleQual, Prefs, CliquePtr),
SortedAllPDReports),
% Do we want separators between the rows of different proc dynamics?
list.condense(PDProcRowLists, PDProcRows),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, SummaryRowData,
SummaryPerfCells),
ProcDesc = SummaryRowData ^ perf_row_subject,
SourceCell = proc_desc_to_source_cell(ProcDesc),
ProcCell = proc_desc_to_prefix_proc_name_cell(no,
ModuleQual, Prefs, [attr_bold], ProcDesc, "summary "),
SummaryRowCells = [SourceCell, ProcCell] ++ SummaryPerfCells,
SummaryRow = table_row(SummaryRowCells),
ProcRows = [SummaryRow, table_separator_row] ++ PDProcRows
).
:- func clique_proc_dynamic_to_table_rows(maybe(string), module_qual,
preferences, clique_ptr, clique_proc_dynamic_report) = list(table_row).
clique_proc_dynamic_to_table_rows(MaybeCurModuleName, ModuleQual,
Prefs, CliquePtr, CliqueProcDynamicReport) = ProcRows :-
CliqueProcDynamicReport = clique_proc_dynamic_report(SummaryRowData,
CallSiteReports0),
ProcDesc = SummaryRowData ^ perf_row_subject,
ProcCell = proc_desc_to_proc_name_cell_span(no, ModuleQual, Prefs,
[attr_bold], ProcDesc, 2),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, SummaryRowData,
SummaryPerfCells),
SummaryRowCells = [ProcCell] ++ SummaryPerfCells,
SummaryRow = table_row(SummaryRowCells),
sort_clique_call_site_reports_by_preferences(MaybeCurModuleName,
ModuleQual, Prefs, CallSiteReports0, CallSiteReports),
CallSiteRowLists =
list.map(
clique_call_site_to_rows(MaybeCurModuleName, ModuleQual, Prefs,
CliquePtr),
CallSiteReports),
list.condense(CallSiteRowLists, CallSiteRows),
ProcRows = [SummaryRow, table_separator_row] ++ CallSiteRows.
:- func clique_call_site_to_rows(maybe(string), module_qual, preferences,
clique_ptr, clique_call_site_report) = list(table_row).
clique_call_site_to_rows(MaybeCurModuleName, ModuleQual, Prefs,
CliquePtr, CallSiteReport) = Rows :-
CallSiteReport = clique_call_site_report(CallSiteRowData, Kind,
CalleePerfs),
CallSiteDesc = CallSiteRowData ^ perf_row_subject,
SourceCell = call_site_desc_source_cell(CallSiteDesc),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, CallSiteRowData,
SummaryPerfCells),
(
Kind = normal_call_and_callee(CalleeProcDesc, _TypeSubst),
(
CalleePerfs = [],
Inactive = Prefs ^ pref_inactive,
Inactive = inactive_items(InactiveCallSites, _, _),
(
InactiveCallSites = inactive_show,
CalleeProcCell = proc_desc_to_prefix_proc_name_cell(
MaybeCurModuleName, ModuleQual, Prefs,
[], CalleeProcDesc, "no calls made to "),
RowCells = [SourceCell, CalleeProcCell] ++ SummaryPerfCells,
Row = table_row(RowCells),
Rows = [Row]
;
InactiveCallSites = inactive_hide,
Rows = []
)
;
CalleePerfs = [CalleePerf],
CalleeCliqueDesc = CalleePerf ^ perf_row_subject,
CalleeProcCell = clique_desc_to_non_self_link_proc_name_cell(
MaybeCurModuleName, ModuleQual, Prefs,
CalleeCliqueDesc, CliquePtr),
RowCells = [SourceCell, CalleeProcCell] ++ SummaryPerfCells,
Row = table_row(RowCells),
Rows = [Row]
;
CalleePerfs = [_, _ | _],
unexpected($module, $pred, "more than one callee at normal")
)
;
(
Kind = special_call_and_no_callee,
CalleeCellStr0 = "special call"
;
Kind = higher_order_call_and_no_callee,
CalleeCellStr0 = "higher order call"
;
Kind = method_call_and_no_callee,
CalleeCellStr0 = "method call"
;
Kind = callback_and_no_callee,
CalleeCellStr0 = "callback"
),
(
CalleePerfs = [],
CalleeCellStr = CalleeCellStr0 ++ " (no calls made)"
;
CalleePerfs = [_ | _],
CalleeCellStr = CalleeCellStr0 ++ " (summary)"
),
CalleeCell = table_cell(td_s(CalleeCellStr)),
SummaryRowCells = [SourceCell, CalleeCell] ++ SummaryPerfCells,
SummaryRow = table_row(SummaryRowCells),
Summarize = Prefs ^ pref_summarize,
(
Summarize = summarize_ho_call_sites,
Rows = [SummaryRow]
;
Summarize = do_not_summarize_ho_call_sites,
sort_clique_rows_by_preferences(Prefs, CalleePerfs,
SortedCalleePerfs),
CalleeRows =
list.map(
clique_call_site_callee_to_row(MaybeCurModuleName,
ModuleQual, Prefs, CliquePtr),
SortedCalleePerfs),
Rows = [SummaryRow] ++ CalleeRows
)
).
:- func clique_call_site_callee_to_row(maybe(string), module_qual,
preferences, clique_ptr, perf_row_data(clique_desc)) = table_row.
clique_call_site_callee_to_row(MaybeCurModuleName, ModuleQual, Prefs,
CliquePtr, CalleeRowData) = Row :-
CalleeCliqueDesc = CalleeRowData ^ perf_row_subject,
CalleeProcCell = clique_desc_to_non_self_link_proc_name_cell(
MaybeCurModuleName, ModuleQual, Prefs, CalleeCliqueDesc, CliquePtr),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, CalleeRowData, PerfCells),
EmptyCell = table_cell(td_s("")),
Cells = [EmptyCell, CalleeProcCell] ++ PerfCells,
Row = table_row(Cells).
%---------------------------------------------------------------------------%
%
% Code to display a clique recursion report.
%
:- pred display_report_clique_recursion(preferences::in,
clique_recursion_report::in, display::out) is det.
display_report_clique_recursion(Prefs, CliqueRecursionReport, Display) :-
CliqueRecursionReport = clique_recursion_report(CliquePtr, RecursionType,
_NumProcs),
Cmd = deep_cmd_clique_recursive_costs(CliquePtr),
CliquePtr = clique_ptr(CliqueNum),
Title = string.format("The recursion information for clique %d:",
[i(CliqueNum)]),
display_recursion_type(RecursionType, DisplayRecursionType),
CliqueReportsControls = clique_reports_controls(Prefs, CliquePtr, Cmd),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Display = display(yes(Title), DisplayRecursionType ++
[display_paragraph_break, CliqueReportsControls,
display_paragraph_break, MenuRestartQuitControls]).
:- pred display_recursion_type(recursion_type::in, list(display_item)::out)
is det.
display_recursion_type(RecursionType, Items) :-
(
(
RecursionType = rt_not_recursive,
Text = "Clique is non-recursive"
;
RecursionType = rt_mutual_recursion(NumProcs),
Text = format("Mutual recursion between %d procedures",
[i(NumProcs)])
),
Items = [display_text(Text)]
;
RecursionType = rt_errors(Errors),
ErrorItems = map((func(Text) = display_text(Text)), Errors),
Items = [display_list(list_class_vertical_no_bullets,
yes("Unknown, error(s) occured"), ErrorItems)]
;
(
RecursionType = rt_single(BaseLevel, RecLevel, AvgDepth,
AvgRecCost, AnyRecCost),
RowData = [
{"Base case", BaseLevel},
{"Recursive case", RecLevel}],
Text = "Single-recursion:",
MaxDepthI = round_to_int(AvgDepth),
ExtraTableRows0 =
[{"Average recursion depth:", AvgDepth},
{"Average recursive call cost (excluding the call itself):",
AvgRecCost}] ++
map(
(func(Level) =
{string.format("Cost at depth %d:", [i(Level)]),
AnyRecCost(Level)}),
[0, 1, 2, round_to_int(AvgDepth / 2.0),
MaxDepthI - 2, MaxDepthI - 1, MaxDepthI]),
ExtraTableRows = map((func({Label, Value}) = table_row(
[table_cell(td_s(Label)), table_cell(td_f(Value))])),
ExtraTableRows0)
;
RecursionType = rt_divide_and_conquer(BaseLevel, RecLevel),
RowData = [
{"Base case", BaseLevel},
{"Doubly-recursive case", RecLevel}],
Text = "Double-recursion (Probably Divide and Conquer):",
ExtraTableRows = []
;
RecursionType = rt_other(Levels),
RowData = map((func(Level) = {Label, Level} :-
Label = string.format("Case for %d recursive calls",
[i(Level ^ rlr_level)])
), Levels),
Text = "Unknown recursion type:",
ExtraTableRows = []
),
Rows = map(make_recursion_table_row, RowData),
ExtraTable = display_table(table(table_class_do_not_box, 2, no,
ExtraTableRows)),
Header = table_header(map(
(func({Name, Class}) =
table_header_group(table_header_group_single(td_s(Name)),
Class, column_do_not_colour)
),
[{"Recursion type", table_column_class_field_name},
{"Exec count", table_column_class_number},
{"Non recursive calls per-call cost",
table_column_class_callseqs},
{"Recursive calls per-call cost (ex children)",
table_column_class_callseqs}])),
Table = display_table(table(table_class_box_if_pref, 4, yes(Header),
Rows)),
Description = display_text(Text),
Items = [Description,
display_paragraph_break, Table,
display_paragraph_break, ExtraTable]
).
:- func make_recursion_table_row({string, recursion_level_report}) = table_row.
make_recursion_table_row({Label, Report}) =
table_row([table_cell(td_s(Label)),
table_cell(td_i(Report ^ rlr_calls)),
table_cell(td_f(Report ^ rlr_non_rec_calls_cost)),
table_cell(td_f(Report ^ rlr_rec_calls_ex_chld_cost))]).
:- pred display_report_recursion_types_frequency(preferences::in,
recursion_types_frequency_report::in, display::out) is det.
display_report_recursion_types_frequency(Prefs, Report, Display) :-
Cmd = deep_cmd_recursion_types_frequency,
Report = recursion_types_frequency_report(Histogram0),
Title = "Frequencies of recognized recursion types",
% Build the table.
RecursionTypeLink = deep_link(Cmd,
yes(Prefs ^ pref_criteria := by_context),
attr_str([], "Recursion Type"), link_class_link),
RecursionTypeHeaderGroup = make_single_table_header_group(
td_l(RecursionTypeLink), table_column_class_no_class,
column_do_not_colour),
FreqHeaderGroup = make_single_table_header_group(
td_s("Frequency"), table_column_class_no_class,
column_do_not_colour),
PercentageHeaderGroup = make_single_table_header_group(
td_s("Percentage"), table_column_class_no_class,
column_do_not_colour),
perf_table_header(total_columns_meaningful, Prefs,
override_order_criteria_header_data(Cmd), PerfHeaderGroups),
AllHeaderGroups = [RecursionTypeHeaderGroup, FreqHeaderGroup,
PercentageHeaderGroup] ++ PerfHeaderGroups,
header_groups_to_header(AllHeaderGroups, NumColumns, Header),
Histogram1 = map.to_assoc_list(Histogram0),
sort_recursion_types_by_preferences(Prefs, Histogram1, Histogram),
list.map(display_report_rec_type_freq_rows(Prefs, NumColumns),
Histogram, Rowss),
list.condense(Rowss, Rows),
RecursionTypesTable = display_table(table(table_class_box_if_pref,
NumColumns, yes(Header), Rows)),
ModuleQualControls = module_qual_controls(Prefs, Cmd),
FieldControls = field_controls(Prefs, Cmd),
FormatControls = format_controls(Prefs, Cmd),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Display = display(yes(Title), [RecursionTypesTable,
display_paragraph_break, ModuleQualControls,
display_paragraph_break, FieldControls,
display_paragraph_break, FormatControls,
display_paragraph_break, MenuRestartQuitControls]).
:- pred sort_recursion_types_by_preferences(preferences::in,
assoc_list(recursion_type_simple, recursion_type_freq_data)::in,
assoc_list(recursion_type_simple, recursion_type_freq_data)::out) is det.
sort_recursion_types_by_preferences(Prefs, !RecursionTypes) :-
OrderCriteria = Prefs ^ pref_criteria,
(
( OrderCriteria = by_context
; OrderCriteria = by_name
),
% Sort by the type of recursion.
list.sort(compare_recursion_type_row_by_rec_type, !RecursionTypes)
;
OrderCriteria = by_cost(CostKind, InclDesc, Scope),
list.sort(
compare_rec_type_row_datas_by_cost(CostKind, InclDesc, Scope),
!RecursionTypes),
% We want the most expensive rows to appear first.
list.reverse(!RecursionTypes)
).
:- pred sort_recursion_type_procs_by_preferences(preferences::in,
list(recursion_type_proc_freq_data)::in,
list(recursion_type_proc_freq_data)::out) is det.
sort_recursion_type_procs_by_preferences(Prefs, !RecursionTypeProcs) :-
OrderCriteria = Prefs ^ pref_criteria,
(
( OrderCriteria = by_context
; OrderCriteria = by_name
),
% Since in this case we sort recursion type rows by their recursion
% type It makes sense to sort the procs within each type by their
% frequency.
sort(compare_recursion_proc_row_by_frequency_rev, !RecursionTypeProcs)
;
OrderCriteria = by_cost(CostKind, InclDesc, Scope),
sort(compare_rec_proc_row_datas_by_cost(CostKind, InclDesc, Scope),
!RecursionTypeProcs),
% We want the most expensive rows to appear first.
reverse(!RecursionTypeProcs)
).
:- pred compare_recursion_type_row_by_rec_type(
pair(recursion_type_simple, T)::in,
pair(recursion_type_simple, T)::in, comparison_result::out) is det.
compare_recursion_type_row_by_rec_type(RTA - _, RTB - _, Result) :-
compare(Result, RTA, RTB).
:- pred compare_recursion_proc_row_by_frequency_rev(
recursion_type_proc_freq_data::in, recursion_type_proc_freq_data::in,
comparison_result::out) is det.
compare_recursion_proc_row_by_frequency_rev(
recursion_type_proc_freq_data(FreqA, _, _),
recursion_type_proc_freq_data(FreqB, _, _), Result) :-
% The reverse is so that entries with larger frequencies are listed first.
compare(Result, FreqB, FreqA).
:- pred compare_rec_type_row_datas_by_cost(cost_kind::in,
include_descendants::in, measurement_scope::in,
pair(T, recursion_type_freq_data)::in,
pair(T, recursion_type_freq_data)::in,
comparison_result::out) is det.
compare_rec_type_row_datas_by_cost(CostKind, IncDesc, Scope, _ - DataA,
_ - DataB, Result) :-
MaybePerfA = DataA ^ rtfd_maybe_summary,
MaybePerfB = DataB ^ rtfd_maybe_summary,
(
MaybePerfA = yes(PerfA),
MaybePerfB = yes(PerfB),
compare_perf_row_datas_by_cost(CostKind, IncDesc, Scope,
PerfA, PerfB, Result)
;
MaybePerfA = yes(_),
MaybePerfB = no,
Result = (>)
;
MaybePerfA = no,
MaybePerfB = yes(_),
Result = (=)
;
MaybePerfA = no,
MaybePerfB = no,
Result = (=)
).
:- pred compare_rec_proc_row_datas_by_cost(cost_kind::in,
include_descendants::in, measurement_scope::in,
recursion_type_proc_freq_data::in, recursion_type_proc_freq_data::in,
comparison_result::out) is det.
compare_rec_proc_row_datas_by_cost(CostKind, InclDesc, Scope,
recursion_type_proc_freq_data(_, _, PerfA),
recursion_type_proc_freq_data(_, _, PerfB), Result) :-
compare_perf_row_datas_by_cost(CostKind, InclDesc, Scope, PerfA, PerfB,
Result).
:- pred display_report_rec_type_freq_rows(preferences::in, int::in,
pair(recursion_type_simple, recursion_type_freq_data)::in,
list(table_row)::out) is det.
display_report_rec_type_freq_rows(Prefs, NumColumns, Type - FreqData, Rows) :-
FreqData = recursion_type_freq_data(Frequency, Percent, MaybeSummary,
ProcsMap),
% Make the header row.
display_report_recursion_type_simple(Type, TypeStr),
HeaderRow = table_section_header(td_s(TypeStr)),
% Make the row summarising the recursion type.
(
MaybeSummary = yes(Summary),
perf_table_row(total_columns_meaningful, Prefs ^ pref_fields, Summary,
SummaryCells)
;
MaybeSummary = no,
duplicate(NumColumns - 3, table_empty_cell, SummaryCells)
),
Row = table_row([table_cell(td_s("Totals")), table_cell(td_i(Frequency)),
table_cell(td_p(Percent))] ++ SummaryCells),
% Make rows for the top proc statics.
Procs0 = values(ProcsMap),
sort_recursion_type_procs_by_preferences(Prefs, Procs0, Procs1),
take_upto(Prefs ^ pref_proc_statics_per_rec_type, Procs1, Procs),
map(display_report_rec_type_proc_rows(Prefs), Procs, ProcRows),
Rows = [HeaderRow | [Row | ProcRows ++
[table_separator_row]]].
:- pred display_report_rec_type_proc_rows(preferences::in,
recursion_type_proc_freq_data::in, table_row::out) is det.
display_report_rec_type_proc_rows(Prefs,
recursion_type_proc_freq_data(Freq, Percent, Summary), Row) :-
perf_table_row(total_columns_meaningful, Prefs ^ pref_fields, Summary,
SummaryCells),
ProcDesc = Summary ^ perf_row_subject,
ProcCell = proc_desc_to_proc_name_cell(no, Prefs ^ pref_module_qual, Prefs,
ProcDesc),
Row = table_row([ProcCell, table_cell(td_i(Freq)),
table_cell(td_p(Percent))] ++ SummaryCells).
:- pred display_report_recursion_type_simple(recursion_type_simple::in,
string::out) is det.
display_report_recursion_type_simple(rts_not_recursive, "Not recursive").
display_report_recursion_type_simple(rts_single, "Single-recursion").
display_report_recursion_type_simple(rts_divide_and_conquer,
"Divide and conquer").
display_report_recursion_type_simple(rts_mutual_recursion(NumProcs), String) :-
format("Mutual recursion between %d procs", [i(NumProcs)], String).
display_report_recursion_type_simple(rts_other(Levels), String) :-
LevelsStr = join_list(", ", map(string, set.to_sorted_list(Levels))),
format("Other recursion with levels: %s", [s(LevelsStr)], String).
display_report_recursion_type_simple(rts_total_error_instances,
"Total errors").
display_report_recursion_type_simple(rts_error(Error), "Error: " ++ Error).
%---------------------------------------------------------------------------%
%
% Code to display a program_modules report.
%
% Create a display_report structure for a program_modules report.
%
:- pred display_report_program_modules(preferences::in,
program_modules_report::in, display::out) is det.
display_report_program_modules(Prefs, ProgramModulesReport, Display) :-
ProgramModulesReport = program_modules_report(ModuleRowDatas0),
Cmd = deep_cmd_program_modules,
Title = "The modules of the program:",
ShowInactiveModules = Prefs ^ pref_inactive ^ inactive_modules,
(
ShowInactiveModules = inactive_show,
ModuleRowDatas1 = ModuleRowDatas0
;
ShowInactiveModules = inactive_hide,
list.filter(active_module, ModuleRowDatas0, ModuleRowDatas1)
),
SortPrefs = avoid_sort_self_and_desc(Prefs),
sort_module_active_rows_by_preferences(SortPrefs,
ModuleRowDatas1, ModuleRowDatas),
% Build the table of all modules.
SortByNamePrefs = Prefs ^ pref_criteria := by_name,
ModuleHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "Module"), link_class_link)),
RankHeaderGroup =
make_single_table_header_group(td_s("Rank"),
table_column_class_ordinal_rank, column_do_not_colour),
ModuleHeaderGroup =
make_single_table_header_group(ModuleHeaderCell,
table_column_class_module_name, column_do_not_colour),
MakeHeaderData = override_order_criteria_header_data(Cmd),
perf_table_header(total_columns_not_meaningful, Prefs, MakeHeaderData,
PerfHeaderGroups),
AllHeaderGroups =
[RankHeaderGroup, ModuleHeaderGroup] ++ PerfHeaderGroups,
header_groups_to_header(AllHeaderGroups, NumColumns, Header),
list.map_foldl(
maybe_ranked_subject_perf_table_row(Prefs, ranked,
total_columns_not_meaningful, module_active_to_module_name_cell),
ModuleRowDatas, Rows, 1, _),
Table = table(table_class_box_if_pref, NumColumns, yes(Header), Rows),
DisplayTable = display_table(Table),
% Build controls at the bottom of the page.
InactiveControls = inactive_module_controls(Prefs, Cmd),
FieldControls = field_controls(Prefs, Cmd),
FormatControls = format_controls(Prefs, Cmd),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Display = display(yes(Title),
[DisplayTable,
display_paragraph_break, InactiveControls,
display_paragraph_break, FieldControls,
display_paragraph_break, FormatControls,
display_paragraph_break, MenuRestartQuitControls]).
:- pred active_module(perf_row_data(module_active)::in) is semidet.
active_module(ModuleRowData) :-
ModuleActive = ModuleRowData ^ perf_row_subject,
ModuleActive ^ ma_is_active = module_is_active.
:- func avoid_sort_self_and_desc(preferences) = preferences.
avoid_sort_self_and_desc(Prefs) = SortPrefs :-
( if Prefs ^ pref_criteria = by_cost(CostKind, self_and_desc, Scope) then
SortPrefs = Prefs ^ pref_criteria := by_cost(CostKind, self, Scope)
else
SortPrefs = Prefs
).
%---------------------------------------------------------------------------%
%
% Code to display a module report.
%
% Create a display_report structure for a module report.
%
:- pred display_report_module(preferences::in, module_report::in, display::out)
is det.
display_report_module(Prefs, ModuleReport, Display) :-
ModuleReport = module_report(ModuleName, HaveModuleRep, ProcRowDatas0),
Cmd = deep_cmd_module(ModuleName),
Title = string.format("The procedures of module %s:", [s(ModuleName)]),
ShowInactiveProcs = Prefs ^ pref_inactive ^ inactive_procs,
(
ShowInactiveProcs = inactive_show,
ProcRowDatas1 = ProcRowDatas0
;
ShowInactiveProcs = inactive_hide,
list.filter(active_proc, ProcRowDatas0, ProcRowDatas1)
),
MaybeCurModuleName = yes(ModuleName),
ModuleQual = Prefs ^ pref_module_qual,
sort_proc_active_rows_by_preferences(MaybeCurModuleName, ModuleQual,
Prefs, ProcRowDatas1, ProcRowDatas),
% Build the table of all modules.
SortByNamePrefs = Prefs ^ pref_criteria := by_name,
ProcHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "Procedure"), link_class_link)),
RankHeaderGroup =
make_single_table_header_group(td_s("Rank"),
table_column_class_ordinal_rank, column_do_not_colour),
ProcHeaderGroup =
make_single_table_header_group(ProcHeaderCell,
table_column_class_module_name, column_do_not_colour),
MakeHeaderData = override_order_criteria_header_data(Cmd),
perf_table_header(total_columns_meaningful, Prefs, MakeHeaderData,
PerfHeaderGroups),
AllHeaderGroups =
[RankHeaderGroup, ProcHeaderGroup] ++ PerfHeaderGroups,
header_groups_to_header(AllHeaderGroups, NumColumns, Header),
list.map_foldl(
maybe_ranked_subject_perf_table_row(Prefs, ranked,
total_columns_meaningful,
proc_active_to_proc_name_cell(MaybeCurModuleName, ModuleQual)),
ProcRowDatas, Rows, 1, _),
Table = table(table_class_box_if_pref, NumColumns, yes(Header), Rows),
DisplayTable = display_table(Table),
% Build controls at the bottom of the page.
GetterSetterCmd = deep_cmd_module_getter_setters(ModuleName),
GetterSetterControl = display_link(deep_link(GetterSetterCmd, yes(Prefs),
attr_str([], "Show field getters and setters"), link_class_link)),
(
HaveModuleRep = do_not_have_module_rep,
ModuleControls =
[display_paragraph_break, GetterSetterControl]
;
HaveModuleRep = have_module_rep,
RepCmd = deep_cmd_module_rep(ModuleName),
RepControl = display_link(deep_link(RepCmd, yes(Prefs),
attr_str([], "Show module representation"), link_class_link)),
ModuleControls =
[display_paragraph_break, GetterSetterControl,
display_paragraph_break, RepControl]
),
InactiveControls = inactive_proc_controls(Prefs, Cmd),
FieldControls = field_controls(Prefs, Cmd),
FormatControls = format_controls(Prefs, Cmd),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
GeneralControls =
[display_paragraph_break, InactiveControls,
display_paragraph_break, FieldControls,
display_paragraph_break, FormatControls,
display_paragraph_break, MenuRestartQuitControls],
Display = display(yes(Title),
[DisplayTable] ++ ModuleControls ++ GeneralControls).
:- pred active_proc(perf_row_data(proc_active)::in) is semidet.
active_proc(ProcRowData) :-
ProcActive = ProcRowData ^ perf_row_subject,
ProcActive ^ pa_is_active = proc_is_active.
%---------------------------------------------------------------------------%
%
% Code to display a module_getter_setters report.
%
% Create a display_report structure for a module_getter_setters report.
%
:- pred display_report_module_getter_setters(preferences::in,
module_getter_setters_report::in, display::out) is det.
display_report_module_getter_setters(Prefs, Report, Display) :-
Report = module_getter_setters_report(ModuleName, GSMap),
Title = string.format("The getters and setters of module %s:",
[s(ModuleName)]),
map.to_assoc_list(GSMap, GSPairs),
RowLists = list.map(display_data_struct_getter_setters(Prefs, ModuleName),
GSPairs),
list.condense(RowLists, Rows),
SortByNamePrefs = Prefs ^ pref_criteria := by_name,
FieldNameHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "FieldName"), link_class_link)),
RankHeaderGroup = make_single_table_header_group(td_s("Rank"),
table_column_class_ordinal_rank, column_do_not_colour),
FieldNameHeaderGroup = make_single_table_header_group(FieldNameHeaderCell,
table_column_class_field_name, column_do_not_colour),
Cmd = deep_cmd_module_getter_setters(ModuleName),
MakeHeaderData = override_order_criteria_header_data(Cmd),
perf_table_header(total_columns_meaningful, Prefs, MakeHeaderData,
PerfHeaderGroups),
header_groups_to_header([RankHeaderGroup, FieldNameHeaderGroup
| PerfHeaderGroups], NumColumns, Header),
Table = table(table_class_box_if_pref, NumColumns, yes(Header), Rows),
TableItem = display_table(Table),
ModuleCmd = deep_cmd_module(ModuleName),
ModuleControl = display_link(deep_link(ModuleCmd, yes(Prefs),
attr_str([], "Show all the procedures of the module"),
link_class_link)),
MenuResetQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Controls =
[display_paragraph_break, ModuleControl,
display_paragraph_break, MenuResetQuitControls],
Display = display(yes(Title), [TableItem] ++ Controls).
:- func display_data_struct_getter_setters(preferences, string,
pair(data_struct_name, gs_field_map)) = list(table_row).
display_data_struct_getter_setters(Prefs, ModuleName,
DataStructName - FieldMap) = Rows :-
DataStructName = data_struct_name(Name),
Title = string.format("The getters and setters of %s:", [s(Name)]),
TitleHeader = table_section_header(td_as(attr_str([attr_bold], Title))),
map.to_assoc_list(FieldMap, FieldPairs0),
sort_getter_setter_fields(Prefs, FieldPairs0, FieldPairs),
list.map_foldl(display_field_getter_setters(Prefs, ModuleName),
FieldPairs, DataRowLists, 1, _),
list.condense(DataRowLists, DataRows),
Rows = [table_separator_row, TitleHeader, table_separator_row | DataRows].
:- pred display_field_getter_setters(preferences::in, string::in,
pair(field_name, gs_field_info)::in, list(table_row)::out,
int::in, int::out) is det.
display_field_getter_setters(Prefs, ModuleName, FieldName - FieldInfo, Rows,
!Rank):-
Fields = Prefs ^ pref_fields,
FieldName = field_name(Name),
RankCell = table_cell(td_i(!.Rank)),
MaybeCurModuleName = yes(ModuleName),
ModuleQual = Prefs ^ pref_module_qual,
(
FieldInfo = gs_field_getter(GetterRowData),
perf_table_row(total_columns_meaningful, Fields, GetterRowData,
GetterPerfCells),
GetterProcDesc = GetterRowData ^ perf_row_subject,
GetterFieldNameCell = proc_desc_to_proc_name_cell(MaybeCurModuleName,
ModuleQual, Prefs, GetterProcDesc),
GetterRow =
table_row([RankCell, GetterFieldNameCell | GetterPerfCells]),
Rows = [table_separator_row, GetterRow]
;
FieldInfo = gs_field_setter(SetterRowData),
perf_table_row(total_columns_meaningful, Fields, SetterRowData,
SetterPerfCells),
SetterProcDesc = SetterRowData ^ perf_row_subject,
SetterFieldNameCell = proc_desc_to_proc_name_cell(MaybeCurModuleName,
ModuleQual, Prefs, SetterProcDesc),
SetterRow =
table_row([RankCell, SetterFieldNameCell | SetterPerfCells]),
Rows = [table_separator_row, SetterRow]
;
FieldInfo = gs_field_both(GetterRowData, SetterRowData, SumRowData),
EmptyCell = table_cell(td_s("")),
perf_table_row(total_columns_meaningful, Fields, SumRowData,
SumPerfCells),
SummaryName = string.format("%s summary", [s(Name)]),
SumFieldNameCell = table_cell(td_s(SummaryName)),
SumRow = table_row([RankCell, SumFieldNameCell | SumPerfCells]),
perf_table_row(total_columns_meaningful, Fields, GetterRowData,
GetterPerfCells),
GetterProcDesc = GetterRowData ^ perf_row_subject,
GetterFieldNameCell = proc_desc_to_proc_name_cell(MaybeCurModuleName,
ModuleQual, Prefs, GetterProcDesc),
GetterRow =
table_row([EmptyCell, GetterFieldNameCell | GetterPerfCells]),
perf_table_row(total_columns_meaningful, Fields, SetterRowData,
SetterPerfCells),
SetterProcDesc = SetterRowData ^ perf_row_subject,
SetterFieldNameCell = proc_desc_to_proc_name_cell(MaybeCurModuleName,
ModuleQual, Prefs, SetterProcDesc),
SetterRow =
table_row([EmptyCell, SetterFieldNameCell | SetterPerfCells]),
Rows = [table_separator_row, SumRow, GetterRow, SetterRow]
),
!:Rank = !.Rank + 1.
%---------------------------------------------------------------------------%
%
% Code to display a module_rep report.
%
% Create a display_report structure for a module_rep report.
%
:- pred display_report_module_rep(preferences::in, module_rep_report::in,
display::out) is det.
display_report_module_rep(Prefs, Report, Display) :-
Report = module_rep_report(ModuleName, ModuleRepStr),
Title = string.format("The representation of module %s:",
[s(ModuleName)]),
BodyItem = display_verbatim(ModuleRepStr),
ModuleCmd = deep_cmd_module(ModuleName),
ModuleControl = display_link(deep_link(ModuleCmd, yes(Prefs),
attr_str([], "Show all the procedures of the module"),
link_class_link)),
MenuResetQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Controls =
[display_paragraph_break, ModuleControl,
display_paragraph_break, MenuResetQuitControls],
Display = display(yes(Title), [BodyItem | Controls]).
%---------------------------------------------------------------------------%
%
% Code to display a top procedures report.
%
% Create a display_report structure for a top_procedures report.
%
:- pred display_report_top_procs(preferences::in, top_procs_report::in,
display::out) is det.
display_report_top_procs(Prefs, TopProcsReport, Display) :-
TopProcsReport = top_procs_report(Ordering, TopProcRowDatas),
Ordering = report_ordering(DisplayLimit, CostKind, InclDesc, Scope),
Desc = cost_criteria_to_description(CostKind, InclDesc, Scope),
Title = "Top procedures " ++ Desc,
% Build the table of the top procedures.
Cmd = deep_cmd_top_procs(DisplayLimit, CostKind, InclDesc, Scope),
MakeHeaderData = override_order_criteria_header_data(Cmd),
maybe_ranked_proc_table_header(Prefs, ranked, MakeHeaderData,
NumColumns, Header),
MaybeCurModuleName = no,
ModuleQual = Prefs ^ pref_module_qual,
sort_proc_desc_rows_by_preferences(MaybeCurModuleName, ModuleQual,
Prefs, TopProcRowDatas, OrderedTopProcRowDatas),
list.map_foldl(
maybe_ranked_subject_perf_table_row(Prefs, ranked,
total_columns_meaningful,
proc_desc_to_proc_name_cell(no, ModuleQual)),
OrderedTopProcRowDatas, Rows, 1, _),
Table = table(table_class_box_if_pref, NumColumns, yes(Header), Rows),
DisplayTable = display_table(Table),
% Build controls at the bottom of the page.
TopProcsControls = top_procs_controls(Prefs,
DisplayLimit, CostKind, InclDesc, Scope),
FieldControls = field_controls(Prefs, Cmd),
FormatControls = format_controls(Prefs, Cmd),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Display = display(yes(Title),
[DisplayTable,
display_paragraph_break, TopProcsControls,
display_paragraph_break, FieldControls,
display_paragraph_break, FormatControls,
display_paragraph_break, MenuRestartQuitControls]).
% Create a phrase describing how the top procedures may be sorted.
%
:- func cost_criteria_to_description(cost_kind, include_descendants,
measurement_scope) = string.
cost_criteria_to_description(CostKind, InclDesc, Scope) = Desc :-
Desc =
"ordered by " ++
incl_desc_to_description(InclDesc) ++ " " ++
cost_kind_to_description(CostKind) ++ " " ++
scope_to_description(Scope).
% Give the short name for what profiling data a field may be measuring.
%
:- func incl_desc_to_description(include_descendants) = string.
incl_desc_to_description(self) = "self".
incl_desc_to_description(self_and_desc) = "total".
% Describe the a measurement used by the deep profiler.
%
:- func cost_kind_to_description(cost_kind) = string.
cost_kind_to_description(cost_calls) = "number of calls".
cost_kind_to_description(cost_redos) = "number of redos".
cost_kind_to_description(cost_time) = "time".
cost_kind_to_description(cost_callseqs) = "call sequence numbers".
cost_kind_to_description(cost_allocs) = "memory allocations".
cost_kind_to_description(cost_words) = "words allocated".
% Describe a scope of profiling data.
%
:- func scope_to_description(measurement_scope) = string.
scope_to_description(per_call) = "per call".
scope_to_description(overall) = "overall".
%---------------------------------------------------------------------------%
%
% Code to display a procedure report.
%
% Create a display_report structure for a proc report.
%
:- pred display_report_proc(deep::in, preferences::in, proc_report::in,
display::out) is det.
display_report_proc(Deep, Prefs, ProcReport, Display) :-
ProcReport = proc_report(CallersSummaryRowData, ProcSummaryRowData,
CallSitePerfs0),
ProcDesc = ProcSummaryRowData ^ perf_row_subject,
RefinedName = ProcDesc ^ pdesc_q_refined_name,
Title = "Summary of procedure " ++ RefinedName,
PSPtr = ProcDesc ^ pdesc_ps_ptr,
Cmd = deep_cmd_proc(PSPtr),
SortByContextPrefs = Prefs ^ pref_criteria := by_context,
SourceHeaderCell = td_l(deep_link(Cmd, yes(SortByContextPrefs),
attr_str([], "Source"), link_class_link)),
SortByNamePrefs = Prefs ^ pref_criteria := by_name,
ProcHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "Procedure"), link_class_link)),
SourceHeaderGroup = make_single_table_header_group(SourceHeaderCell,
table_column_class_source_context, column_do_not_colour),
ProcHeaderGroup = make_single_table_header_group(ProcHeaderCell,
table_column_class_proc, column_do_not_colour),
MakeHeaderData = override_order_criteria_header_data(Cmd),
perf_table_header(total_columns_meaningful, Prefs, MakeHeaderData,
PerfHeaderGroups),
AllHeaderGroups =
[SourceHeaderGroup, ProcHeaderGroup] ++ PerfHeaderGroups,
header_groups_to_header(AllHeaderGroups, NumColumns, Header),
Fields = Prefs ^ pref_fields,
CallersCounts = CallersSummaryRowData ^ perf_row_subject,
CallersSummaryText = format("%d static & %d dynamic call sites",
[i(CallersCounts ^ cc_static), i(CallersCounts ^ cc_dynamic)]),
CallersSummaryCell = table_multi_cell(td_s(CallersSummaryText), 2),
perf_table_row(total_columns_meaningful, Fields, CallersSummaryRowData,
CallersPerfCells),
CallersCells = [CallersSummaryCell] ++ CallersPerfCells,
CallersRow = table_row(CallersCells),
% We could make SummaryProcCell a link, but the only link that would make
% sense (and the link that pre-display versions of the deep profiler
% generated) point back to this page itself, which is not useful and
% could be considered misleading.
%
% SummaryProcCell spans two columns: the ones that contain (1) the context
% and (2) the callee of each call site in the rows below.
SummaryProcCell = table_multi_cell(td_s(RefinedName), 2),
perf_table_row(total_columns_meaningful, Fields, ProcSummaryRowData,
SummaryPerfCells),
SummaryCells = [SummaryProcCell] ++ SummaryPerfCells,
SummaryRow = table_row(SummaryCells),
MaybeCurModuleName = yes(ProcDesc ^ pdesc_module_name),
ModuleQual = Prefs ^ pref_module_qual,
sort_call_sites_by_preferences(MaybeCurModuleName, ModuleQual, Prefs,
CallSitePerfs0, CallSitePerfs),
CallSiteRowLists = list.map(
report_proc_call_site(MaybeCurModuleName, ModuleQual, Prefs),
CallSitePerfs),
list.condense(CallSiteRowLists, CallSiteRows),
DeveloperRows = map(func(X) = table_developer_row(X),
[table_section_header(td_s(
"Callers excluding directly-recursive calls")),
CallersRow, table_separator_row]),
CommonRows = [SummaryRow, table_separator_row] ++ CallSiteRows,
AllRows = DeveloperRows ++ CommonRows,
Table = table(table_class_box_if_pref, NumColumns, yes(Header), AllRows),
DisplayTable = display_table(Table),
% Build the controls at the bottom of the page.
ProcCallersControls = proc_callers_group_controls(Deep, Prefs, Cmd,
PSPtr, group_by_call_site, default_callers_per_bunch,
Prefs ^ pref_contour),
SummarizeControls = summarize_controls(Prefs, Cmd),
InactiveCallSitesControls = inactive_call_site_controls(Prefs, Cmd),
ModuleQualControls = module_qual_controls(Prefs, Cmd),
SortControls = sort_controls(Prefs, Cmd),
FieldControls = field_controls(Prefs, Cmd),
FormatControls = format_controls(Prefs, Cmd),
ProcReportControls = proc_reports_controls(Prefs, PSPtr, Cmd),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Display = display(yes(Title),
[DisplayTable,
display_paragraph_break, ProcCallersControls,
display_paragraph_break, SummarizeControls,
display_paragraph_break, InactiveCallSitesControls,
display_paragraph_break, ModuleQualControls,
display_paragraph_break, SortControls,
display_paragraph_break, FieldControls,
display_paragraph_break, FormatControls,
display_paragraph_break, ProcReportControls,
display_paragraph_break, MenuRestartQuitControls]).
:- func default_callers_per_bunch = int.
default_callers_per_bunch = 20.
:- func report_proc_call_site(maybe(string), module_qual, preferences,
call_site_perf) = list(table_row).
report_proc_call_site(MaybeCurModuleName, ModuleQual, Prefs, CallSitePerf)
= Rows :-
CallSitePerf =
call_site_perf(KindAndCallee, SummaryPerfRowData, SubPerfs0),
CallSiteDesc = SummaryPerfRowData ^ perf_row_subject,
ContextCell = call_site_desc_source_cell(CallSiteDesc),
(
KindAndCallee = normal_call_and_info(NormalCalleeId),
NormalCalleeId = normal_callee_id(CalleeDesc, TypeSubstStr),
CalleeRefinedName = proc_desc_get_refined_id(MaybeCurModuleName,
ModuleQual, CalleeDesc),
( if TypeSubstStr = "" then
CallSiteStr = CalleeRefinedName
else
CallSiteStr = string.format("%s [%s]",
[s(CalleeRefinedName), s(TypeSubstStr)])
),
CalleePSPtr = CalleeDesc ^ pdesc_ps_ptr,
CallSiteLinkCmd = deep_cmd_proc(CalleePSPtr),
CallSiteLink = deep_link(CallSiteLinkCmd, yes(Prefs),
attr_str([], CallSiteStr), link_class_link),
CallSiteCell = table_cell(td_l(CallSiteLink)),
require(unify(SubPerfs0, []),
"report_proc_call_site: SubPerfs0 != [] for normal call site")
;
(
KindAndCallee = special_call_and_no_info,
CallSiteStr = "special call"
;
KindAndCallee = higher_order_call_and_no_info,
CallSiteStr = "higher order call"
;
KindAndCallee = method_call_and_no_info,
CallSiteStr = "method call"
;
KindAndCallee = callback_and_no_info,
CallSiteStr = "callback"
),
CallSiteCell = table_cell(td_s(CallSiteStr))
),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, SummaryPerfRowData,
SummaryPerfCells),
SummaryCells = [ContextCell, CallSiteCell] ++ SummaryPerfCells,
SummaryRow = table_row(SummaryCells),
Summarize = Prefs ^ pref_summarize,
(
Summarize = summarize_ho_call_sites,
Rows = [SummaryRow]
;
Summarize = do_not_summarize_ho_call_sites,
sort_proc_desc_rows_by_preferences(MaybeCurModuleName, ModuleQual,
Prefs, SubPerfs0, SubPerfs),
SubRows = list.map(
report_proc_call_site_callee(MaybeCurModuleName, ModuleQual,
Prefs),
SubPerfs),
Rows = [SummaryRow] ++ SubRows
).
:- func report_proc_call_site_callee(maybe(string), module_qual,
preferences, perf_row_data(proc_desc)) = table_row.
report_proc_call_site_callee(MaybeCurModuleName, ModuleQual,
Prefs, RowData) = Row :-
Fields = Prefs ^ pref_fields,
EmptyCell = table_empty_cell,
ProcDesc = RowData ^ perf_row_subject,
ProcCell = proc_desc_to_proc_name_cell(MaybeCurModuleName, ModuleQual,
Prefs, ProcDesc),
perf_table_row(total_columns_meaningful, Fields, RowData, PerfCells),
Cells = [EmptyCell, ProcCell] ++ PerfCells,
Row = table_row(Cells).
%---------------------------------------------------------------------------%
%
% Code to display a procedure callers report.
%
% Create a display_report structure for a proc_callers report.
%
:- pred display_report_proc_callers(deep::in, preferences::in,
proc_callers_report::in, display::out) is det.
display_report_proc_callers(Deep, Prefs0, ProcCallersReport, Display) :-
ProcCallersReport = proc_callers_report(ProcDesc, CallerRowDatas,
BunchNum, BunchSize, ContourExcl, MaybeContourWarnMessage),
(
MaybeContourWarnMessage = no,
WarnItems = []
;
MaybeContourWarnMessage = yes(ContourWarnMessage),
ContourWarnItem = display_text(ContourWarnMessage),
WarnItems = [display_paragraph_break, ContourWarnItem]
),
RefinedName = ProcDesc ^ pdesc_q_refined_name,
MaybeCurModuleName = yes(ProcDesc ^ pdesc_module_name),
ModuleQual = Prefs ^ pref_module_qual,
% Remember the selected value of contour exclusion.
Prefs = Prefs0 ^ pref_contour := ContourExcl,
PSPtr = ProcDesc ^ pdesc_ps_ptr,
(
CallerRowDatas = proc_caller_call_sites(CallSiteRowDatas),
CallerGroups = group_by_call_site,
Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, BunchSize,
ContourExcl),
Title = "The call sites calling " ++ RefinedName,
sort_call_site_desc_rows_by_preferences(MaybeCurModuleName, ModuleQual,
Prefs, CallSiteRowDatas, SortedCallSiteRowDatas),
select_displayed_rows(SortedCallSiteRowDatas, BunchNum, BunchSize,
DisplayedCallSiteRowDatas, TotalNumRows, FirstRowNum, LastRowNum,
DisplayedBunchNum, MaybeFirstAndLastBunchNum),
list.map_foldl(
display_caller_call_site(MaybeCurModuleName, ModuleQual, Prefs),
DisplayedCallSiteRowDatas, Rows, FirstRowNum, AfterLastRowNum),
SortByContextPrefs = Prefs ^ pref_criteria := by_context,
SourceHeaderCell = td_l(deep_link(Cmd, yes(SortByContextPrefs),
attr_str([], "Source"), link_class_link)),
SortByNamePrefs = Prefs ^ pref_criteria := by_context,
ProcHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "In procedure"), link_class_link)),
SourceHeaderGroup = make_single_table_header_group(SourceHeaderCell,
table_column_class_source_context, column_do_not_colour),
ProcHeaderGroup = make_single_table_header_group(ProcHeaderCell,
table_column_class_proc, column_do_not_colour),
IdHeaderGroups = [SourceHeaderGroup, ProcHeaderGroup]
;
CallerRowDatas = proc_caller_procedures(ProcRowDatas),
CallerGroups = group_by_proc,
Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, BunchSize,
ContourExcl),
Title = "The procedures calling " ++ RefinedName,
sort_proc_desc_rows_by_preferences(MaybeCurModuleName, ModuleQual,
Prefs, ProcRowDatas, SortedProcRowDatas),
select_displayed_rows(SortedProcRowDatas, BunchNum, BunchSize,
DisplayedProcRowDatas, TotalNumRows, FirstRowNum, LastRowNum,
DisplayedBunchNum, MaybeFirstAndLastBunchNum),
list.map_foldl(
display_caller_proc(MaybeCurModuleName, ModuleQual, Prefs),
DisplayedProcRowDatas, Rows, FirstRowNum, AfterLastRowNum),
SortByContextPrefs = Prefs ^ pref_criteria := by_context,
SourceHeaderCell = td_l(deep_link(Cmd, yes(SortByContextPrefs),
attr_str([], "Source"), link_class_link)),
SortByNamePrefs = Prefs ^ pref_criteria := by_context,
ProcHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "Procedure"), link_class_link)),
SourceHeaderGroup = make_single_table_header_group(SourceHeaderCell,
table_column_class_source_context, column_do_not_colour),
ProcHeaderGroup = make_single_table_header_group(ProcHeaderCell,
table_column_class_proc, column_do_not_colour),
IdHeaderGroups = [SourceHeaderGroup, ProcHeaderGroup]
;
CallerRowDatas = proc_caller_modules(ModuleRowDatas),
CallerGroups = group_by_module,
Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, BunchSize,
ContourExcl),
Title = "The modules calling " ++ RefinedName,
sort_module_name_rows_by_preferences(Prefs, ModuleRowDatas,
SortedModuleRowDatas),
select_displayed_rows(SortedModuleRowDatas, BunchNum, BunchSize,
DisplayedModuleRowDatas, TotalNumRows, FirstRowNum, LastRowNum,
DisplayedBunchNum, MaybeFirstAndLastBunchNum),
list.map_foldl(display_caller_module(Prefs),
DisplayedModuleRowDatas, Rows, FirstRowNum, AfterLastRowNum),
SortByNamePrefs = Prefs ^ pref_criteria := by_name,
ModuleHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "Module"), link_class_link)),
ModuleHeaderGroup = make_single_table_header_group(ModuleHeaderCell,
table_column_class_source_context, column_do_not_colour),
IdHeaderGroups = [ModuleHeaderGroup]
;
CallerRowDatas = proc_caller_cliques(CliqueRowDatas),
CallerGroups = group_by_clique,
Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, BunchSize,
ContourExcl),
Title = "The cliques calling " ++ RefinedName,
sort_clique_rows_by_preferences(Prefs, CliqueRowDatas,
SortedCliqueRowDatas),
select_displayed_rows(SortedCliqueRowDatas, BunchNum, BunchSize,
DisplayedCliqueRowDatas, TotalNumRows, FirstRowNum, LastRowNum,
DisplayedBunchNum, MaybeFirstAndLastBunchNum),
list.map_foldl(
display_caller_clique(MaybeCurModuleName, ModuleQual, Prefs),
DisplayedCliqueRowDatas, Rows, FirstRowNum, AfterLastRowNum),
SortByNamePrefs = Prefs ^ pref_criteria := by_name,
CliqueHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
attr_str([], "Clique"), link_class_link)),
CliqueHeaderGroup = make_single_table_header_group(CliqueHeaderCell,
table_column_class_clique, column_do_not_colour),
MembersHeaderGroup = make_single_table_header_group(td_s("Members"),
table_column_class_clique, column_do_not_colour),
IdHeaderGroups = [CliqueHeaderGroup, MembersHeaderGroup]
),
RankHeaderGroup = make_single_table_header_group(td_s("Rank"),
table_column_class_ordinal_rank, column_do_not_colour),
MakeHeaderData = override_order_criteria_header_data(Cmd),
perf_table_header(total_columns_meaningful, Prefs, MakeHeaderData,
PerfHeaderGroups),
AllHeaderGroups = [RankHeaderGroup] ++ IdHeaderGroups ++ PerfHeaderGroups,
header_groups_to_header(AllHeaderGroups, NumColumns, Header),
(
MaybeFirstAndLastBunchNum = no,
Message = "There are none.",
Display = display(yes(Title), [display_text(Message)])
;
MaybeFirstAndLastBunchNum = yes({FirstBunchNum, LastBunchNum}),
require(unify(LastRowNum + 1, AfterLastRowNum),
"display_report_proc_callers: row number mismatch"),
require((FirstBunchNum =< DisplayedBunchNum),
"display_report_proc_callers: display bunch number mismatch"),
require((DisplayedBunchNum =< LastBunchNum),
"display_report_proc_callers: display bunch number mismatch"),
( if FirstBunchNum = LastBunchNum then
Message = string.format("There are %d:",
[i(TotalNumRows)]),
BunchControls = []
else
Message = string.format("There are %d, showing %d to %d:",
[i(TotalNumRows), i(FirstRowNum), i(LastRowNum)]),
( if BunchNum > FirstBunchNum then
BunchControlsFirst = [make_proc_callers_link(Prefs,
"First group", PSPtr, CallerGroups, FirstBunchNum,
BunchSize, ContourExcl)]
else
BunchControlsFirst = []
),
( if BunchNum - 1 > FirstBunchNum then
BunchControlsPrev = [make_proc_callers_link(Prefs,
"Previous group", PSPtr, CallerGroups, BunchNum - 1,
BunchSize, ContourExcl)]
else
BunchControlsPrev = []
),
( if BunchNum + 1 < LastBunchNum then
BunchControlsNext = [make_proc_callers_link(Prefs,
"Next group", PSPtr, CallerGroups, BunchNum + 1,
BunchSize, ContourExcl)]
else
BunchControlsNext = []
),
( if BunchNum < LastBunchNum then
BunchControlsLast = [make_proc_callers_link(Prefs,
"Last group", PSPtr, CallerGroups, LastBunchNum,
BunchSize, ContourExcl)]
else
BunchControlsLast = []
),
BunchControlList = BunchControlsFirst ++ BunchControlsPrev ++
BunchControlsNext ++ BunchControlsLast,
BunchControls = [display_paragraph_break,
display_list(list_class_horizontal_except_title,
yes("Show other groups:"), BunchControlList)]
),
( if
BunchSize > 5,
HalfBunchSize = BunchSize / 2,
HalfBunchSize \= 10,
HalfBunchSize \= 20,
HalfBunchSize \= 50,
HalfBunchSize \= 100
then
BunchSizeControlPairsHalf = [(BunchSize / 2) -
make_proc_callers_link(Prefs,
"Halve group size", PSPtr, CallerGroups, BunchNum * 2,
BunchSize / 2, ContourExcl)]
else
BunchSizeControlPairsHalf = []
),
( if
DoubleBunchSize = BunchSize * 2,
DoubleBunchSize \= 10,
DoubleBunchSize \= 20,
DoubleBunchSize \= 50,
DoubleBunchSize \= 100
then
BunchSizeControlPairsDouble = [(BunchSize * 2) -
make_proc_callers_link(Prefs,
"Double group size", PSPtr, CallerGroups, BunchNum / 2,
BunchSize * 2, ContourExcl)]
else
BunchSizeControlPairsDouble = []
),
( if
TotalNumRows > 10,
BunchSize \= 10
then
BunchSizeControlPairs10 = [10 -
make_proc_callers_link(Prefs,
"Set group size to 10", PSPtr, CallerGroups,
(BunchNum * BunchSize) / 10, 10, ContourExcl)]
else
BunchSizeControlPairs10 = []
),
( if
TotalNumRows > 20,
BunchSize \= 20
then
BunchSizeControlPairs20 = [20 -
make_proc_callers_link(Prefs,
"Set group size to 20", PSPtr, CallerGroups,
(BunchNum * BunchSize) / 20, 20, ContourExcl)]
else
BunchSizeControlPairs20 = []
),
( if
TotalNumRows > 50,
BunchSize \= 50
then
BunchSizeControlPairs50 = [50 -
make_proc_callers_link(Prefs,
"Set group size to 50", PSPtr, CallerGroups,
(BunchNum * BunchSize) / 50, 50, ContourExcl)]
else
BunchSizeControlPairs50 = []
),
( if
TotalNumRows > 100,
BunchSize \= 100
then
BunchSizeControlPairs100 = [100 -
make_proc_callers_link(Prefs,
"Set group size to 100", PSPtr, CallerGroups,
(BunchNum * BunchSize) / 100, 100, ContourExcl)]
else
BunchSizeControlPairs100 = []
),
BunchSizeControlPairs =
BunchSizeControlPairsHalf ++ BunchSizeControlPairsDouble ++
BunchSizeControlPairs10 ++ BunchSizeControlPairs20 ++
BunchSizeControlPairs50 ++ BunchSizeControlPairs100,
list.sort(BunchSizeControlPairs, SortedBunchSizeControlPairs),
assoc_list.values(SortedBunchSizeControlPairs, BunchSizeControlList),
BunchSizeControls = [display_paragraph_break,
display_list(list_class_horizontal_except_title,
yes("Change group size:"), BunchSizeControlList)],
Table = table(table_class_box_if_pref, NumColumns, yes(Header), Rows),
DisplayTable = display_table(Table),
% Build the controls at the bottom of the page.
FirstCmd = deep_cmd_proc_callers(PSPtr, CallerGroups, 1, BunchSize,
ContourExcl),
CallerGroupControls = proc_callers_group_controls(Deep, Prefs,
FirstCmd, PSPtr, CallerGroups, BunchSize, ContourExcl),
FieldControls = field_controls(Prefs, Cmd),
FormatControls = format_controls(Prefs, Cmd),
MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Display = display(yes(Title),
[display_text(Message)] ++
WarnItems ++
[display_paragraph_break, DisplayTable] ++
BunchControls ++
BunchSizeControls ++
[display_paragraph_break, CallerGroupControls,
display_paragraph_break, FieldControls,
display_paragraph_break, FormatControls,
display_paragraph_break, MenuRestartQuitControls])
).
:- pred select_displayed_rows(list(perf_row_data(T))::in, int::in, int::in,
list(perf_row_data(T))::out, int::out, int::out, int::out,
int::out, maybe({int, int})::out) is det.
select_displayed_rows(RowDatas, BunchNum, BunchSize, DisplayRowDatas,
TotalNumRows, FirstRowNum, LastRowNum,
DisplayedBunchNum, MaybeFirstAndLastBunchNum) :-
list.length(RowDatas, TotalNumRows),
NumRowsToDelete = (BunchNum - 1) * BunchSize,
( if
list.drop(NumRowsToDelete, RowDatas, RemainingRowDatasPrime),
RemainingRowDatasPrime = [_ | _]
then
DisplayedBunchNum = BunchNum,
% We start counting rows at 1, not 0.
FirstRowNum = NumRowsToDelete + 1,
RemainingRowDatas = RemainingRowDatasPrime,
NumRemainingRows = TotalNumRows - NumRowsToDelete
else
DisplayedBunchNum = 1,
FirstRowNum = 1,
RemainingRowDatas = RowDatas,
NumRemainingRows = TotalNumRows
),
( if NumRemainingRows > BunchSize then
list.take_upto(BunchSize, RemainingRowDatas, DisplayRowDatas)
else
DisplayRowDatas = RemainingRowDatas
),
LastRowNum = FirstRowNum - 1 + list.length(DisplayRowDatas),
( if TotalNumRows > 0 then
FirstBunchNum = 1,
LastBunchNum = (TotalNumRows + BunchSize - 1) / BunchSize,
MaybeFirstAndLastBunchNum = yes({FirstBunchNum, LastBunchNum})
else
MaybeFirstAndLastBunchNum = no
).
:- pred display_caller_call_site(maybe(string)::in, module_qual::in,
preferences::in, perf_row_data(call_site_desc)::in, table_row::out,
int::in, int::out) is det.
display_caller_call_site(MaybeCurModuleName, ModuleQual, Prefs,
CallSiteRowData, Row, !RowNum) :-
RankCell = table_cell(td_i(!.RowNum)),
!:RowNum = !.RowNum + 1,
CallSiteDesc = CallSiteRowData ^ perf_row_subject,
SourceCell = call_site_desc_to_source_cell(CallSiteDesc),
ProcCell = call_site_desc_to_caller_proc_name_cell(MaybeCurModuleName,
ModuleQual, Prefs, CallSiteDesc),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, CallSiteRowData,
PerfCells),
Cells = [RankCell, SourceCell, ProcCell] ++ PerfCells,
Row = table_row(Cells).
:- pred display_caller_proc(maybe(string)::in, module_qual::in,
preferences::in, perf_row_data(proc_desc)::in, table_row::out,
int::in, int::out) is det.
display_caller_proc(MaybeCurModuleName, ModuleQual, Prefs, ProcRowData, Row,
!RowNum) :-
RankCell = table_cell(td_i(!.RowNum)),
!:RowNum = !.RowNum + 1,
ProcDesc = ProcRowData ^ perf_row_subject,
SourceCell = proc_desc_to_source_cell(ProcDesc),
ProcCell = proc_desc_to_proc_name_cell(MaybeCurModuleName, ModuleQual,
Prefs, ProcDesc),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, ProcRowData, PerfCells),
Cells = [RankCell, SourceCell, ProcCell] ++ PerfCells,
Row = table_row(Cells).
:- pred display_caller_module(preferences::in, perf_row_data(string)::in,
table_row::out, int::in, int::out) is det.
display_caller_module(Prefs, ModuleRowData, Row, !RowNum) :-
RankCell = table_cell(td_i(!.RowNum)),
!:RowNum = !.RowNum + 1,
ModuleName = ModuleRowData ^ perf_row_subject,
ModuleCell = table_cell(td_s(ModuleName)),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, ModuleRowData, PerfCells),
Cells = [RankCell, ModuleCell] ++ PerfCells,
Row = table_row(Cells).
:- pred display_caller_clique(maybe(string)::in, module_qual::in,
preferences::in, perf_row_data(clique_desc)::in, table_row::out,
int::in, int::out) is det.
display_caller_clique(MaybeCurModuleName, ModuleQual, Prefs,
CliqueRowData, Row, !RowNum) :-
RankCell = table_cell(td_i(!.RowNum)),
!:RowNum = !.RowNum + 1,
CliqueDesc = CliqueRowData ^ perf_row_subject,
CliqueDesc = clique_desc(CliquePtr, EntryProcDesc, OtherProcDescs),
CliquePtr = clique_ptr(CliqueNum),
CliqueLinkCmd = deep_cmd_clique(CliquePtr),
CliqueText = string.format("clique %d", [i(CliqueNum)]),
CliqueLink = deep_link(CliqueLinkCmd, yes(Prefs), attr_str([], CliqueText),
link_class_link),
CliqueCell = table_cell(td_l(CliqueLink)),
MembersStrs = list.map(
proc_desc_get_refined_id(MaybeCurModuleName, ModuleQual),
[EntryProcDesc | OtherProcDescs]),
MembersStr = string.join_list(", ", MembersStrs),
MembersCell = table_cell(td_s(MembersStr)),
Fields = Prefs ^ pref_fields,
perf_table_row(total_columns_meaningful, Fields, CliqueRowData, PerfCells),
Cells = [RankCell, CliqueCell, MembersCell] ++ PerfCells,
Row = table_row(Cells).
:- func make_proc_callers_link(preferences, string, proc_static_ptr,
caller_groups, int, int, contour_exclusion) = display_item.
make_proc_callers_link(Prefs, Label, PSPtr, CallerGroups, BunchNum, BunchSize,
ContourExcl) = Item :-
Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, BunchSize,
ContourExcl),
Link = deep_link(Cmd, yes(Prefs), attr_str([], Label), link_class_control),
Item = display_link(Link).
%---------------------------------------------------------------------------%
%
% Code to display procrep_coverage information.
%
:- pred display_report_procrep_coverage_info(preferences::in,
procrep_coverage_info::in, display::out) is det.
display_report_procrep_coverage_info(Prefs, ProcrepCoverageReport, Display) :-
ProcrepCoverageReport =
procrep_coverage_info(PSPtr, Procrep, CoverageArray),
print_proc_to_strings(get_goal_attribute_det(CoverageArray), Procrep,
ProcRepStrings),
string.append_list(list(ProcRepStrings), ProcRepString),
CoverageInfoItem = display_verbatim(ProcRepString),
Cmd = deep_cmd_static_procrep_coverage(PSPtr),
ProcReportControls = proc_reports_controls(Prefs, PSPtr, Cmd),
MenuResetQuitControls = cmds_menu_restart_quit(yes(Prefs)),
Controls =
[display_paragraph_break, ProcReportControls,
display_paragraph_break, MenuResetQuitControls],
Title = "Procedure coverage:",
Display = display(yes(Title), [CoverageInfoItem] ++ Controls).
:- instance goal_annotation(coverage_info) where [
pred(print_goal_annotation_to_strings/3) is coverage_to_cord_string
].
% Print the coverage information for a goal, this is used by
% print_proc_to_strings.
%
:- pred coverage_to_cord_string(var_name_table::in, coverage_info::in,
cord(cord(string))::out) is det.
coverage_to_cord_string(_, Coverage, singleton(singleton(String))) :-
(
Coverage = coverage_unknown,
String0 = "_ - _"
;
Coverage = coverage_known(Before, After),
String0 = string.format("%d - %d", [i(Before), i(After)])
;
(
Coverage = coverage_known_same(Count)
;
Coverage = coverage_known_zero,
Count = 0
),
String0 = string.format("%d - %d", [i(Count), i(Count)])
;
Coverage = coverage_known_before(Before),
String0 = string.format("%d - _", [i(Before)])
;
Coverage = coverage_known_after(After),
String0 = string.format("_ - %d", [i(After)])
),
String = "Coverage: " ++ String0.
%---------------------------------------------------------------------------%
%
% Code to display proc_static and proc_dynamic dumps.
%
% Create a display_report structure for a proc_static_dump report.
%
:- pred display_report_proc_static_dump(proc_static_dump_info::in,
display::out) is det.
display_report_proc_static_dump(ProcStaticDumpInfo, Display) :-
ProcStaticDumpInfo = proc_static_dump_info(PSPtr, RawName,
UnQualRefinedName, QualRefinedName, FileName, LineNumber,
NumCallSites, NumCoveragePoints),
PSPtr = proc_static_ptr(PSI),
string.format("Dump of proc_static %d", [i(PSI)], Title),
Values =
[("Raw name:" - td_s(RawName)),
("Unqualified refined name:" - td_s(UnQualRefinedName)),
("Qualified refined name:" - td_s(QualRefinedName)),
("File name:" - td_s(FileName)),
("Line number:" - td_i(LineNumber)),
("Number of call sites:" - td_i(NumCallSites)),
("Number of coverage points:" - td_i(NumCoveragePoints))],
Rows = list.map(make_labelled_table_row, Values),
Table = table(table_class_do_not_box, 2, no, Rows),
Display = display(yes(Title), [display_table(Table)]).
% Create a display_report structure for a proc_dynamic_dump report.
%
:- pred display_report_proc_dynamic_dump(deep::in, preferences::in,
proc_dynamic_dump_info::in, display::out) is det.
display_report_proc_dynamic_dump(_Deep, Prefs, ProcDynamicDumpInfo, Display) :-
ProcDynamicDumpInfo = proc_dynamic_dump_info(PDPtr, PSPtr, RawName,
ModuleName, UnQualRefinedName, QualRefinedName, CallSites,
MaybeCoveragePoints),
PDPtr = proc_dynamic_ptr(PDI),
PSPtr = proc_static_ptr(PSI),
string.format("Dump of proc_dynamic %d", [i(PDI)], Title),
ProcStaticLink = deep_link(deep_cmd_dump_proc_static(PSPtr), yes(Prefs),
attr_str([], string.int_to_string(PSI)), link_class_link),
MainValues =
[("Proc static:" - td_l(ProcStaticLink)),
("Raw name:" - td_s(RawName)),
("Module name:" - td_s(ModuleName)),
("Unqualified refined name:" - td_s(UnQualRefinedName)),
("Qualified refined name:" - td_s(QualRefinedName))],
MainRows = list.map(make_labelled_table_row, MainValues),
MainTable = table(table_class_do_not_box, 2, no, MainRows),
MainTableItem = display_table(MainTable),
CallSitesTitle = "Call site dynamics:",
CallSitesTitleItem = display_heading(CallSitesTitle),
list.map_foldl(dump_psd_call_site(Prefs), CallSites, CallSitesRowsList,
counter.init(1), _),
list.condense(CallSitesRowsList, CallSitesRows),
CallSitesTable = table(table_class_box_if_pref, 2, no, CallSitesRows),
CallSitesTableItem = display_table(CallSitesTable),
(
MaybeCoveragePoints = yes(CoveragePoints),
CoveragePointsTitle = "Coverage points:",
CoveragePointsTitleItem = display_heading(CoveragePointsTitle),
list.map(format_coverage_point_row, CoveragePoints,
CoveragePointsRows),
CoveragePointsTableHeader = table_header([
table_header_group(table_header_group_single(td_s("Goal Path")),
table_column_class_no_class, column_do_not_colour),
table_header_group(table_header_group_single(td_s("Type")),
table_column_class_no_class, column_do_not_colour),
table_header_group(table_header_group_single(td_s("Count")),
table_column_class_number, column_do_not_colour)]),
CoveragePointsTable = table(table_class_box_if_pref, 3,
yes(CoveragePointsTableHeader), CoveragePointsRows),
CoveragePointsTableItem = display_table(CoveragePointsTable),
CoveragePointsItems =
[CoveragePointsTitleItem, CoveragePointsTableItem]
;
MaybeCoveragePoints = no,
CoveragePointsItems = []
),
make_link(link_base(deep_cmd_dynamic_procrep_coverage(PDPtr), yes(Prefs),
"Dynamic coverage annotated procedure representation"),
CoverageAnnotatedProcrepItem),
RelatedReportsList = display_list(list_class_horizontal_except_title,
yes("Related reports:"), [CoverageAnnotatedProcrepItem]),
Display = display(yes(Title),
[MainTableItem, CallSitesTitleItem, CallSitesTableItem] ++
CoveragePointsItems ++
[display_paragraph_break, RelatedReportsList]).
:- pred dump_psd_call_site(preferences::in,
call_site_array_slot::in, list(table_row)::out,
counter::in, counter::out) is det.
dump_psd_call_site(Prefs, CallSite, Rows, !CallSiteCounter) :-
counter.allocate(CallSiteNum, !CallSiteCounter),
CallSiteNumCell = table_cell(td_i(CallSiteNum)),
(
CallSite = slot_normal(CSDPtr),
CSDPtr = call_site_dynamic_ptr(CSDI),
CSDLink = deep_link(deep_cmd_dump_call_site_dynamic(CSDPtr),
yes(Prefs), attr_str([], string.int_to_string(CSDI)),
link_class_link),
CSDCell = table_cell(td_l(CSDLink)),
FirstRow = table_row([CallSiteNumCell, CSDCell]),
Rows = [FirstRow]
;
CallSite = slot_multi(IsZeroed, CSDPtrArray),
(
IsZeroed = zeroed,
IsZeroedStr = "zeroed"
;
IsZeroed = not_zeroed,
IsZeroedStr = "not_zeroed"
),
array.to_list(CSDPtrArray, CSDPtrs),
NumCSDPtrs = list.length(CSDPtrs),
string.format("multi, %d csds (%s)", [i(NumCSDPtrs), s(IsZeroedStr)],
MultiCellStr),
MultiCell = table_cell(td_s(MultiCellStr)),
FirstRow = table_row([CallSiteNumCell, MultiCell]),
list.map(dump_psd_call_site_multi_entry(Prefs), CSDPtrs, LaterRows),
Rows = [FirstRow | LaterRows]
).
:- pred dump_psd_call_site_multi_entry(preferences::in,
call_site_dynamic_ptr::in, table_row::out) is det.
dump_psd_call_site_multi_entry(Prefs, CSDPtr, Row) :-
CSDPtr = call_site_dynamic_ptr(CSDI),
CSDLink = deep_link(deep_cmd_dump_call_site_dynamic(CSDPtr), yes(Prefs),
attr_str([], string.int_to_string(CSDI)), link_class_link),
CSDCell = table_cell(td_l(CSDLink)),
EmptyCell = table_cell(td_s("")),
Row = table_row([EmptyCell, CSDCell]).
:- pred format_coverage_point_row(coverage_point::in, table_row::out) is det.
format_coverage_point_row(CoveragePoint, Row) :-
CoveragePoint = coverage_point(Count, RevGoalPath, CPType),
GoalPathString = rev_goal_path_to_string(RevGoalPath),
GoalPathCell = table_cell(td_s(GoalPathString)),
TypeCell = table_cell(td_s(string(CPType))),
CountCell = table_cell(td_i(Count)),
Row = table_row([GoalPathCell, TypeCell, CountCell]).
% Create a display_report structure for a call_site_static_dump report.
%
:- pred display_report_call_site_static_dump(preferences::in,
call_site_static_dump_info::in, display::out) is det.
display_report_call_site_static_dump(Prefs, CallSiteStaticDumpInfo, Display) :-
CallSiteStaticDumpInfo = call_site_static_dump_info(CSSPtr,
ContainingPSPtr, SlotNumber, LineNumber, GoalPath, CallSiteKind),
CSSPtr = call_site_static_ptr(CSSI),
string.format("Dump of call_site_static %d", [i(CSSI)], Title),
ContainingPSPtr = proc_static_ptr(ContainingPSI),
ContainingProcStaticLink = deep_link(
deep_cmd_dump_proc_static(ContainingPSPtr), yes(Prefs),
attr_str([], string.int_to_string(ContainingPSI)), link_class_link),
(
CallSiteKind = normal_call_and_callee(CalleePSPtr, TypeSpecDesc),
CalleePSPtr = proc_static_ptr(CalleePSI),
CalleeDesc0 = "normal, callee " ++ string.int_to_string(CalleePSI),
( if TypeSpecDesc = "" then
CalleeDesc = CalleeDesc0
else
CalleeDesc = CalleeDesc0 ++ " typespec " ++ TypeSpecDesc
),
CalleeProcStaticLink = deep_link(
deep_cmd_dump_proc_static(CalleePSPtr), yes(Prefs),
attr_str([], CalleeDesc), link_class_link),
CallSiteKindData = td_l(CalleeProcStaticLink)
;
CallSiteKind = special_call_and_no_callee,
CallSiteKindData = td_s("special_call")
;
CallSiteKind = higher_order_call_and_no_callee,
CallSiteKindData = td_s("higher_order_call")
;
CallSiteKind = method_call_and_no_callee,
CallSiteKindData = td_s("method_call")
;
CallSiteKind = callback_and_no_callee,
CallSiteKindData = td_s("callback")
),
Values =
[("Containing proc_static:" - td_l(ContainingProcStaticLink)),
("Slot number:" - td_i(SlotNumber)),
("Line number:" - td_i(LineNumber)),
("Goal path:" - td_s(rev_goal_path_to_string(GoalPath))),
("Call site kind:" - CallSiteKindData)],
Rows = list.map(make_labelled_table_row, Values),
Table = table(table_class_do_not_box, 2, no, Rows),
Display = display(yes(Title), [display_table(Table)]).
% Create a display_report structure for a call_site_dynamic_dump report.
%
:- pred display_report_call_site_dynamic_dump(preferences::in,
call_site_dynamic_dump_info::in, display::out) is det.
display_report_call_site_dynamic_dump(Prefs, CallSiteDynamiccDumpInfo,
Display) :-
CallSiteDynamiccDumpInfo = call_site_dynamic_dump_info(CSDPtr,
CallerPDPtr, CalleePDPtr, RowData),
CSDPtr = call_site_dynamic_ptr(CSDI),
string.format("Dump of call_site_dynamic %d", [i(CSDI)], Title),
CallerPDPtr = proc_dynamic_ptr(CallerPDI),
CallerProcDynamicLink = deep_link(deep_cmd_dump_proc_dynamic(CallerPDPtr),
yes(Prefs), attr_str([], string.int_to_string(CallerPDI)),
link_class_link),
CalleePDPtr = proc_dynamic_ptr(CalleePDI),
CalleeProcDynamicLink = deep_link(deep_cmd_dump_proc_dynamic(CalleePDPtr),
yes(Prefs), attr_str([], string.int_to_string(CalleePDI)),
link_class_link),
FirstValues =
[("Caller proc_dynamic:" - td_l(CallerProcDynamicLink)),
("Callee proc_dynamic:" - td_l(CalleeProcDynamicLink))],
FirstRows = list.map(make_labelled_table_row, FirstValues),
FirstTable = table(table_class_do_not_box, 2, no, FirstRows),
MakeHeaderData = dummy_order_criteria_header_data,
maybe_ranked_proc_table_header(Prefs, non_ranked, MakeHeaderData,
NumColumns, Header),
maybe_ranked_subject_perf_table_row(Prefs, non_ranked,
total_columns_meaningful,
call_site_desc_to_name_path_slot_cell(no, module_qual_always),
RowData, PerfRow, 1, _),
PerfTable = table(table_class_box, NumColumns, yes(Header), [PerfRow]),
Display = display(yes(Title),
[display_table(FirstTable), display_table(PerfTable)]).
% Create a display_report structure for a clique_dump report.
%
:- pred display_report_clique_dump(preferences::in, clique_dump_info::in,
display::out) is det.
display_report_clique_dump(Prefs, CliqueDumpInfo, Display) :-
CliqueDumpInfo = clique_dump_info(CliqueDesc, EntryCSDPtr, MemberPDPtrs),
CliquePtr = CliqueDesc ^ cdesc_clique_ptr,
CliquePtr = clique_ptr(CliqueNum),
string.format("Dump of clique %d", [i(CliqueNum)], Title),
EntryCSDPtr = call_site_dynamic_ptr(EntryCSDI),
EntryLink = deep_link(deep_cmd_dump_call_site_dynamic(EntryCSDPtr),
yes(Prefs), attr_str([], string.int_to_string(EntryCSDI)),
link_class_link),
list.map_foldl(display_report_clique_dump_member(Prefs), MemberPDPtrs,
MemberPDLinks, "Member proc_dynamics:", _),
Values =
[("Caller call_site_dynamic:" - td_l(EntryLink))] ++
MemberPDLinks,
Rows = list.map(make_labelled_table_row, Values),
Table = table(table_class_do_not_box, 2, no, Rows),
Display = display(yes(Title), [display_table(Table)]).
:- pred display_report_clique_dump_member(preferences::in,
proc_dynamic_ptr::in, pair(string, table_data)::out,
string::in, string::out) is det.
display_report_clique_dump_member(Prefs, PDPtr, Pair, !Label) :-
PDLabel = !.Label,
!:Label = "",
PDPtr = proc_dynamic_ptr(PDI),
Link = deep_link(deep_cmd_dump_proc_dynamic(PDPtr),
yes(Prefs), attr_str([], string.int_to_string(PDI)),
link_class_link),
PDData = td_l(Link),
Pair = PDLabel - PDData.
:- pred display_report_call_site_dynamic_var_use(preferences::in,
call_site_dynamic_var_use_info::in, display::out) is det.
display_report_call_site_dynamic_var_use(_Prefs, CSDVarUseInfo, Display) :-
CSDVarUseInfo = call_site_dynamic_var_use_info(AverageCost, VarUses),
AverageCostItem = display_text(
format("Average Cost: %f", [f(AverageCost)])),
format_var_uses(VarUses, 1, VarUseRows),
Header = table_header(
map((func({Text, Class}) = table_header_group(
table_header_group_single(td_s(Text)),
Class, column_do_not_colour)
), [{"Argument", table_column_class_ordinal_rank},
{"Name", table_column_class_no_class},
{"Type", table_column_class_no_class},
{"Percent into proc", table_column_class_no_class},
{"Time into proc (Callseqs)", table_column_class_callseqs}])),
Table = table(table_class_box_if_pref, 5, yes(Header), VarUseRows),
Title = "Dump of var use info",
Display = display(yes(Title), [AverageCostItem, display_table(Table)]).
:- pred format_var_uses(list(var_use_and_name)::in, int::in,
list(table_row)::out) is det.
format_var_uses([], _, []).
format_var_uses([VarUse | VarUses], RowNum, [Row | Rows]) :-
HeaderCell = table_cell(td_s(format("Argument: %i", [i(RowNum)]))),
VarUse = var_use_and_name(Name,
var_use_info(CostUntilUse, ProcCost, UseType)),
NameCell = table_cell(td_s(Name)),
(
UseType = var_use_production,
TypeText = "production"
;
UseType = var_use_consumption,
TypeText = "consumption"
;
UseType = var_use_other,
TypeText = "other/unknown"
),
TypeCell = table_cell(td_s(TypeText)),
PercentCell = table_cell(td_p(percent(CostUntilUse / ProcCost))),
TimeCell = table_cell(td_f(CostUntilUse)),
Row = table_row([HeaderCell, NameCell, TypeCell, PercentCell, TimeCell]),
format_var_uses(VarUses, RowNum + 1, Rows).
%---------------------------------------------------------------------------%
%
% Common column header strings.
%
:- func percent_label = table_data.
percent_label = td_s("%").
:- func override_order_criteria_header_data(cmd, preferences, order_criteria,
string) = table_data.
override_order_criteria_header_data(Cmd, Prefs0, Criteria, Label)
= TableData :-
Criteria0 = Prefs0 ^ pref_criteria,
Prefs = Prefs0 ^ pref_criteria := Criteria,
( if Criteria = Criteria0 then
% Should we display a simple string to indicate that this link
% leads back to the same page, or would that be confusing?
Link = deep_link(Cmd, yes(Prefs), attr_str([], Label),
link_class_link),
TableData = td_l(Link)
else
Link = deep_link(Cmd, yes(Prefs), attr_str([], Label),
link_class_link),
TableData = td_l(Link)
).
:- func dummy_order_criteria_header_data(preferences, order_criteria, string)
= table_data.
dummy_order_criteria_header_data(_, _, Label) = td_s(Label).
%---------------------------------------------------------------------------%
%
% The predicates in this section build
%
% (a) the headers of table columns that describe each aspect of performance,
% and
% (b) the entries in those columns.
%
% Each pair of predicates should follow the exact same logic when selecting
% what columns to display, and in what order.
%
:- type total_columns_meaning
---> total_columns_meaningful
; total_columns_not_meaningful.
% Convert the performance information in a row data into the cells
% of a table row according to the preferences.
%
:- pred perf_table_row(total_columns_meaning::in, fields::in,
perf_row_data(Subject)::in, list(table_cell)::out) is det.
perf_table_row(TotalsMeaningful, Fields, RowData, PerfCells) :-
perf_table_row_ports(Fields, RowData, PortCells),
perf_table_row_time(TotalsMeaningful, Fields, RowData, TimeCells),
perf_table_row_callseqs(TotalsMeaningful, Fields, RowData, CallSeqsCells),
perf_table_row_allocs(TotalsMeaningful, Fields, RowData, AllocCells),
perf_table_row_memory(TotalsMeaningful, Fields, RowData, MemoryCells),
PerfCells =
PortCells ++ TimeCells ++ CallSeqsCells ++
AllocCells ++ MemoryCells.
% Build the performance group of table headers
% according to the preferences.
%
:- pred perf_table_header(total_columns_meaning::in, preferences::in,
(func(preferences, order_criteria, string) = table_data)::in,
list(table_header_group)::out) is det.
perf_table_header(TotalsMeaningful, Prefs, MakeHeaderData, HeaderGroups) :-
perf_table_header_ports(Prefs, MakeHeaderData, PortHeaderGroups),
perf_table_header_time(TotalsMeaningful, Prefs, MakeHeaderData,
TimeHeaderGroups),
perf_table_header_callseqs(TotalsMeaningful, Prefs, MakeHeaderData,
CallSeqsHeaderGroups),
perf_table_header_allocs(TotalsMeaningful, Prefs, MakeHeaderData,
AllocHeaderGroups),
perf_table_header_memory(TotalsMeaningful, Prefs, MakeHeaderData,
MemoryHeaderGroups),
HeaderGroups =
PortHeaderGroups ++ TimeHeaderGroups ++ CallSeqsHeaderGroups ++
AllocHeaderGroups ++ MemoryHeaderGroups.
% Convert the port information in a row data into the cells
% of a table row according to the preferences.
%
:- pred perf_table_row_ports(fields::in, perf_row_data(Subject)::in,
list(table_cell)::out) is det.
perf_table_row_ports(Fields, RowData, PortCells) :-
PortFields = Fields ^ port_fields,
(
PortFields = no_port,
PortCells = []
;
PortFields = port,
Calls = RowData ^ perf_row_calls,
Exits = RowData ^ perf_row_exits,
Fails = RowData ^ perf_row_fails,
Redos = RowData ^ perf_row_redos,
Excps = RowData ^ perf_row_excps,
CallsCell = table_cell(td_i(Calls)),
ExitsCell = table_cell(td_i(Exits)),
FailsCell = table_cell(td_i(Fails)),
RedosCell = table_cell(td_i(Redos)),
ExcpsCell = table_cell(td_i(Excps)),
PortCells = [CallsCell, ExitsCell, FailsCell, RedosCell, ExcpsCell]
).
% Build the ports group of table headers according to the preferences.
%
:- pred perf_table_header_ports(preferences::in,
(func(preferences, order_criteria, string) = table_data)::in,
list(table_header_group)::out) is det.
perf_table_header_ports(Prefs, MakeHeaderData, HeaderGroups) :-
Fields = Prefs ^ pref_fields,
PortFields = Fields ^ port_fields,
(
PortFields = no_port,
HeaderGroups = []
;
PortFields = port,
CallsCrit = by_cost(cost_calls, self, overall),
RedosCrit = by_cost(cost_redos, self, overall),
CallsData = MakeHeaderData(Prefs, CallsCrit, "Calls"),
ExitsData = td_s("Exits"),
FailsData = td_s("Fails"),
RedosData = MakeHeaderData(Prefs, RedosCrit, "Redos"),
ExcpsData = td_s("Excps"),
SubHeaders = [CallsData, ExitsData, FailsData, RedosData, ExcpsData],
Title = "Port counts",
HeaderGroup = make_multi_table_header_group(Title, SubHeaders,
table_column_class_port_counts, column_colour_if_pref),
HeaderGroups = [HeaderGroup]
).
% Convert the time information in a row data into the cells
% of a table row according to the preferences.
%
:- pred perf_table_row_time(total_columns_meaning::in, fields::in,
perf_row_data(Subject)::in, list(table_cell)::out) is det.
perf_table_row_time(TotalsMeaningful, Fields, RowData, TimeCells) :-
TimeFields = Fields ^ time_fields,
(
TimeFields = no_time,
TimeCells = []
;
( TimeFields = ticks
; TimeFields = time
; TimeFields = ticks_and_time
; TimeFields = time_and_percall
; TimeFields = ticks_and_time_and_percall
),
Self = RowData ^ perf_row_self,
SelfTicks = Self ^ perf_row_ticks,
SelfTime = Self ^ perf_row_time,
SelfTimePercent = Self ^ perf_row_time_percent,
SelfTimePerCall = Self ^ perf_row_time_percall,
SelfTicksCell = table_cell(td_i(SelfTicks)),
SelfTimeCell = table_cell(td_t(SelfTime)),
SelfTimePercentCell = table_cell(td_p(SelfTimePercent)),
SelfTimePerCallCell = table_cell(td_t(SelfTimePerCall)),
(
TotalsMeaningful = total_columns_not_meaningful,
(
TimeFields = ticks,
TimeCells =
[SelfTicksCell, SelfTimePercentCell]
;
TimeFields = time,
TimeCells =
[SelfTimeCell, SelfTimePercentCell]
;
TimeFields = ticks_and_time,
TotalsMeaningful = total_columns_not_meaningful,
TimeCells =
[SelfTicksCell, SelfTimeCell, SelfTimePercentCell]
;
TimeFields = time_and_percall,
TimeCells =
[SelfTimeCell, SelfTimePercentCell, SelfTimePerCallCell]
;
TimeFields = ticks_and_time_and_percall,
TimeCells =
[SelfTicksCell, SelfTimeCell,
SelfTimePercentCell, SelfTimePerCallCell]
)
;
TotalsMeaningful = total_columns_meaningful,
MaybeTotal = RowData ^ perf_row_maybe_total,
(
MaybeTotal = yes(Total)
;
MaybeTotal = no,
unexpected($module, $pred, "no total")
),
TotalTicks = Total ^ perf_row_ticks,
TotalTime = Total ^ perf_row_time,
TotalTimePercent = Total ^ perf_row_time_percent,
TotalTimePerCall = Total ^ perf_row_time_percall,
TotalTicksCell = table_cell(td_i(TotalTicks)),
TotalTimeCell = table_cell(td_t(TotalTime)),
TotalTimePercentCell = table_cell(td_p(TotalTimePercent)),
TotalTimePerCallCell = table_cell(td_t(TotalTimePerCall)),
(
TimeFields = ticks,
TimeCells =
[SelfTicksCell, SelfTimePercentCell,
TotalTicksCell, TotalTimePercentCell]
;
TimeFields = time,
TotalsMeaningful = total_columns_meaningful,