[m-rev.] diff: move deprecated deep profiler code to separate modules
Zoltan Somogyi
zs at csse.unimelb.edu.au
Thu Sep 25 17:32:51 AEST 2008
This diff has no algorithmic changes.
Zoltan.
deep_profiler/html_format.m:
deep_profiler/old_html_format.m:
deep_profiler/query.m:
deep_profiler/old_query.m:
Move old, now deprecated code from query.m and html_format.m to two new
modules: old_query.m and old_html_format.m. In each case, the leftover
module, whose cord works via reports, is significantly smaller.
deep_profiler/measurement_units.m:
Move some functions here from html_format.m, since they are needed
with both the old and the new approaches, and the functions belong
here.
cvs diff: Diffing .
Index: html_format.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/html_format.m,v
retrieving revision 1.32
diff -u -b -r1.32 html_format.m
--- html_format.m 25 Sep 2008 03:47:03 -0000 1.32
+++ html_format.m 25 Sep 2008 07:12:51 -0000
@@ -23,16 +23,11 @@
:- module html_format.
:- interface.
-:- import_module measurements.
:- import_module profile.
:- import_module query.
-:- import_module top_procs.
:- import_module display.
-:- import_module bool.
:- import_module cord.
-:- import_module list.
-:- import_module unit.
%-----------------------------------------------------------------------------%
@@ -52,110 +47,6 @@
%-----------------------------------------------------------------------------%
-:- func table_start(preferences) = string.
-:- func table_end(preferences) = string.
-
-:- func page_banner(cmd, preferences) = string.
-:- func page_footer(cmd, preferences, deep) = string.
-
-:- func toggle_cost_criteria_in_top_procs_cmd(preferences, deep, display_limit,
- cost_kind, include_descendants, measurement_scope) = string.
-
-:- func criteria_to_description(order_criteria) = string.
-:- func cost_criteria_to_description(cost_kind, include_descendants,
- measurement_scope) = string.
-
-:- type id_fields
- ---> source_proc
- ; rank_module
- ; rank_proc
- ; proc.
-
-:- type totals_disposition
- ---> totals_meaningful
- ; totals_not_meaningful.
-
-:- type header_wrap_func == (func(string, order_criteria) = string).
-
-:- func fields_header(preferences, id_fields, totals_disposition,
- header_wrap_func) = string.
-
-:- func header_row(string, preferences, id_fields, totals_disposition)
- = string.
-:- func separator_row(preferences, id_fields, totals_disposition)
- = string.
-
-:- type sub_lines(T)
- ---> sub_lines(
- sub_line_type :: T,
- sub_line_list :: list(line_group(T, unit))
- ).
-
-:- type one_id ---> one_id.
-:- type two_id ---> two_id.
-
-:- type one_id_sub_lines == sub_lines(one_id).
-:- type two_id_sub_lines == sub_lines(two_id).
-
-:- type one_id_line == line_group(one_id, unit).
-:- type two_id_line == line_group(two_id, unit).
-:- type one_id_line_group == line_group(one_id, one_id_sub_lines).
-:- type two_id_line_group == line_group(two_id, two_id_sub_lines).
-:- type one_two_id_line_group == line_group(one_id, two_id_sub_lines).
-
- % This function takes a context description (which may be empty) and a
- % HTML string describing all fields in a row but the first, and returns
- % the HTML for the full row.
- %
-:- func add_context(string, line_group(one_id, LL)) = line_group(two_id, LL).
-
- % This adds the context from the line group to the HTML as the first field
- % of the resulting line group.
- %
-:- func add_self_context(line_group(one_id, LL)) = line_group(two_id, LL).
-
-:- func add_ranks(list(line_group(one_id, LL))) = list(line_group(two_id, LL)).
-
-:- func line_to_one_id_subline_group(line_group(FL, unit))
- = line_group(FL, one_id_sub_lines).
-
-:- func line_to_two_id_subline_group(line_group(FL, unit))
- = line_group(FL, two_id_sub_lines).
-
-:- func one_id_line_to_html(preferences, deep, totals_disposition,
- one_id_line) = string.
-:- func one_id_line_group_to_html(preferences, deep, totals_disposition,
- one_id_line_group) = string.
-:- func two_id_line_to_html(preferences, deep, totals_disposition,
- two_id_line) = string.
-:- func two_id_line_group_to_html(preferences, deep, totals_disposition,
- two_id_line_group) = string.
-
-:- func own_and_desc_to_html(own_prof_info, inherit_prof_info,
- preferences, deep, totals_disposition) = string.
-
-:- pred lookup_ticks_per_sec(profile_stats::in, int::out, bool::out) is det.
-
-:- func proc_dynamic_name(deep, proc_dynamic_ptr) = string.
-:- func proc_static_name(deep, proc_static_ptr) = string.
-
-:- pred proc_dynamic_context(deep::in, proc_dynamic_ptr::in,
- string::out, int::out) is det.
-:- pred proc_static_context(deep::in, proc_static_ptr::in,
- string::out, int::out) is det.
-:- pred call_site_context(deep::in, call_site_static_ptr::in,
- string::out, int::out) is det.
-
-:- pred proc_static_to_line_group_info(preferences::in, deep::in,
- proc_static_ptr::in, string::out, int::out, string::out, string::out)
- is det.
-:- func proc_static_to_html_ref(preferences, deep, proc_static_ptr) = string.
-:- func module_name_to_html_ref(preferences, deep, string) = string.
-:- func clique_ptr_to_html_ref(preferences, deep, string, clique_ptr) = string.
-:- func deep_cmd_pref_to_url(preferences, deep, cmd) = string.
-
-:- func plural(int) = string.
-
% Convert any special characters in a string into appropriate HTML
% escapes.
%
@@ -179,6 +70,7 @@
:- import_module char.
:- import_module exception.
:- import_module float.
+:- import_module list.
:- import_module int.
:- import_module map.
:- import_module maybe.
@@ -1036,2094 +928,6 @@
!.ColumnNum, Tail, !HTML).
%-----------------------------------------------------------------------------%
-%
-% Deprecated html_format code.
-%
-
-page_banner(_Cmd, Pref) =
- "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01//EN""\n" ++
- """http://www.w3.org/TR/html4/strict.dtd"">\n" ++
- "<HTML>\n" ++
- "<HEAD>\n" ++
- "<TITLE>Page created by the Mercury Deep Profiler.</TITLE>\n" ++
- banner_style(Pref) ++
- "</HEAD>\n" ++
- "<BODY>\n".
-
-:- func banner_style(preferences) = string.
-
-banner_style(Pref) = HTML :-
- Fields = Pref ^ pref_fields,
-
- some [!GroupNum] (
- !:GroupNum = 0,
- IdStyle = string.format(" TD.id { %s }\n",
- [s(select_colgroup_background(Pref, !.GroupNum))]),
- !:GroupNum = !.GroupNum + 1,
- Fields = fields(PortFields, TimeFields, CallSeqsFields,
- AllocFields, MemoryFields),
- (
- PortFields = no_port,
- PortStyle = ""
- ;
- PortFields = port,
- PortStyle = string.format(" TD.port { %s }\n",
- [s(select_colgroup_background(Pref, !.GroupNum))]),
- !:GroupNum = !.GroupNum + 1
- ),
- (
- TimeFields = no_time,
- TimeStyle = ""
- ;
- ( TimeFields = ticks
- ; TimeFields = time
- ; TimeFields = ticks_and_time
- ; TimeFields = time_and_percall
- ; TimeFields = ticks_and_time_and_percall
- ),
- TimeStyle = string.format(" TD.time { %s }\n",
- [s(select_colgroup_background(Pref, !.GroupNum))]),
- !:GroupNum = !.GroupNum + 1
- ),
- (
- CallSeqsFields = no_callseqs,
- CallSeqsStyle = ""
- ;
- ( CallSeqsFields = callseqs
- ; CallSeqsFields = callseqs_and_percall
- ),
- CallSeqsStyle = string.format(" TD.callseqs { %s }\n",
- [s(select_colgroup_background(Pref, !.GroupNum))]),
- !:GroupNum = !.GroupNum + 1
- ),
- (
- AllocFields = no_alloc,
- AllocStyle = ""
- ;
- ( AllocFields = alloc
- ; AllocFields = alloc_and_percall
- ),
- AllocStyle = string.format(" TD.alloc { %s }\n",
- [s(select_colgroup_background(Pref, !.GroupNum))]),
- !:GroupNum = !.GroupNum + 1
- ),
- (
- MemoryFields = no_memory,
- MemoryStyle = ""
- ;
- ( MemoryFields = memory(_)
- ; MemoryFields = memory_and_percall(_)
- ),
- MemoryStyle = string.format(" TD.memory { %s }\n",
- [s(select_colgroup_background(Pref, !.GroupNum))])
- )
- ),
- ButtonStyle = " A.button { margin: 5px; text-decoration: none; }\n",
- HTML =
- "<STYLE TYPE=""text/css"">\n" ++
- IdStyle ++
- PortStyle ++
- TimeStyle ++
- CallSeqsStyle ++
- AllocStyle ++
- MemoryStyle ++
- ButtonStyle ++
- "</STYLE>\n".
-
-:- func select_colgroup_background(preferences, int) = string.
-
-select_colgroup_background(Pref, N) = HTML :-
- (
- Pref ^ pref_colour = colour_column_groups,
- ( N /\ 1 = 0 ->
- Background = even_background
- ;
- Background = odd_background
- ),
- string.format("background: %s", [s(Background)], HTML)
- ;
- Pref ^ pref_colour = do_not_colour_column_groups,
- HTML = ""
- ).
-
-:- func even_background = string.
-
-even_background = "rgb(255, 255, 240)".
-
-:- func odd_background = string.
-
-odd_background = "rgb(240, 240, 255)".
-
-%-----------------------------------------------------------------------------%
-
-table_start(Pref) = HTML :-
- (
- Pref ^ pref_box = do_not_box_tables,
- HTML = "\n<TABLE width=100%>\n"
- ;
- Pref ^ pref_box = box_tables,
- HTML = "\n<TABLE width=100% border=1>\n"
- ).
-
-table_end(_) = "</TABLE>\n".
-
-%-----------------------------------------------------------------------------%
-
-page_footer(Cmd, Pref, Deep) =
- "<p>\n" ++
- footer_pref_toggles(Cmd, Pref, Deep) ++
- "<br>\n" ++
- string.format("<A CLASS=""button"" HREF=""%s"">[Menu]</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_menu))]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">[Restart]</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_restart))]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">[Quit]</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_quit))]) ++
- "</BODY>\n" ++
- "</HTML>\n".
-
-:- func footer_pref_toggles(cmd, preferences, deep) = string.
-
-footer_pref_toggles(Cmd, Pref, Deep) = AllToggles :-
- RelevantToggles = command_relevant_toggles(Cmd),
- ( list.member(toggle_fields, RelevantToggles) ->
- FieldToggle = footer_field_toggle(Cmd, Pref, Deep)
- ;
- FieldToggle = ""
- ),
- ( list.member(toggle_ancestor_limit, RelevantToggles) ->
- AncestorToggle =
- footer_ancestor_toggle(Cmd, Pref, Deep) ++
- "<br>\n"
- ;
- AncestorToggle = ""
- ),
- ( list.member(toggle_order_criteria, RelevantToggles) ->
- OrderToggle =
- footer_order_criteria_toggle(Cmd, Pref, Deep) ++
- "<br>\n"
- ;
- OrderToggle = ""
- ),
- ( list.member(toggle_summarize, RelevantToggles) ->
- SummarizeToggle = footer_summarize_toggle(Cmd, Pref, Deep)
- ;
- SummarizeToggle = ""
- ),
- ( list.member(toggle_contour, RelevantToggles) ->
- ContourToggle = footer_contour_toggle(Cmd, Pref, Deep)
- ;
- ContourToggle = ""
- ),
- ( list.member(toggle_time_format, RelevantToggles) ->
- TimeFormatToggle = footer_time_format_toggle(Cmd, Pref, Deep)
- ;
- TimeFormatToggle = ""
- ),
- ( list.member(toggle_colour, RelevantToggles) ->
- ColourToggle = footer_colour_toggle(Cmd, Pref, Deep)
- ;
- ColourToggle = ""
- ),
- ( list.member(toggle_box, RelevantToggles) ->
- BoxToggle = footer_box_toggle(Cmd, Pref, Deep)
- ;
- BoxToggle = ""
- ),
- ( list.member(toggle_inactive_modules, RelevantToggles) ->
- InactiveModuleToggle = footer_inactive_modules_toggle(Cmd, Pref, Deep)
- ;
- InactiveModuleToggle = ""
- ),
- ( list.member(toggle_inactive_procs, RelevantToggles) ->
- InactiveProcsToggle = footer_inactive_procs_toggle(Cmd, Pref, Deep)
- ;
- InactiveProcsToggle = ""
- ),
- AllToggles =
- FieldToggle ++
- AncestorToggle ++
- OrderToggle ++
- SummarizeToggle ++
- ContourToggle ++
- TimeFormatToggle ++
- ColourToggle ++
- BoxToggle ++
- InactiveModuleToggle ++
- InactiveProcsToggle.
-
-%-----------------------------------------------------------------------------%
-
-:- type toggle_kind
- ---> toggle_fields
- ; toggle_box
- ; toggle_colour
- ; toggle_ancestor_limit
- ; toggle_summarize
- ; toggle_order_criteria
- ; toggle_contour
- ; toggle_time_format
- ; toggle_inactive_modules
- ; toggle_inactive_procs.
-
-:- func command_relevant_toggles(cmd) = list(toggle_kind).
-
-command_relevant_toggles(deep_cmd_quit) = [].
-command_relevant_toggles(deep_cmd_restart) = [].
-command_relevant_toggles(deep_cmd_timeout(_)) = [].
-command_relevant_toggles(deep_cmd_menu) = [].
-command_relevant_toggles(deep_cmd_root(_)) =
- % The clique_ptr doesn't matter.
- command_relevant_toggles(deep_cmd_clique(clique_ptr(1))).
-command_relevant_toggles(deep_cmd_clique(_)) =
- [toggle_fields, toggle_box, toggle_colour, toggle_ancestor_limit,
- toggle_summarize, toggle_order_criteria, toggle_time_format].
-command_relevant_toggles(deep_cmd_proc(_)) =
- [toggle_fields, toggle_box, toggle_colour, toggle_summarize,
- toggle_order_criteria, toggle_time_format].
-command_relevant_toggles(deep_cmd_proc_callers(_, _, _, _)) =
- [toggle_fields, toggle_box, toggle_colour, toggle_order_criteria,
- toggle_contour, toggle_time_format].
-command_relevant_toggles(deep_cmd_program_modules) =
- [toggle_fields, toggle_box, toggle_colour, toggle_order_criteria,
- toggle_time_format, toggle_inactive_modules].
-command_relevant_toggles(deep_cmd_module(_)) =
- [toggle_fields, toggle_box, toggle_colour, toggle_order_criteria,
- toggle_time_format, toggle_inactive_procs].
-command_relevant_toggles(deep_cmd_top_procs(_, _, _, _)) =
- [toggle_fields, toggle_box, toggle_colour, toggle_time_format].
-command_relevant_toggles(deep_cmd_procrep_coverage(_)) =
- [].
-command_relevant_toggles(deep_cmd_dump_proc_static(_)) = [].
-command_relevant_toggles(deep_cmd_dump_proc_dynamic(_)) = [].
-command_relevant_toggles(deep_cmd_dump_call_site_static(_)) = [].
-command_relevant_toggles(deep_cmd_dump_call_site_dynamic(_)) = [].
-command_relevant_toggles(deep_cmd_dump_clique(_)) = [].
-
-:- func footer_field_toggle(cmd, preferences, deep) = string.
-
-footer_field_toggle(Cmd, Pref, Deep) = HTML :-
- Fields = Pref ^ pref_fields,
- ( Fields ^ port_fields = no_port ->
- Port1Toggle = ""
- ;
- Port1Fields = Fields ^ port_fields := no_port,
- Port1Pref = Pref ^ pref_fields := Port1Fields,
- Port1Msg = "[No port counts]",
- Port1Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Port1Pref, Deep, Cmd)), s(Port1Msg)])
- ),
- ( Fields ^ port_fields = port ->
- Port2Toggle = ""
- ;
- Port2Fields = Fields ^ port_fields := port,
- Port2Pref = Pref ^ pref_fields := Port2Fields,
- Port2Msg = "[Port counts]",
- Port2Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Port2Pref, Deep, Cmd)), s(Port2Msg)])
- ),
- ( Fields ^ time_fields = no_time ->
- Time1Toggle = ""
- ;
- Time1Fields = Fields ^ time_fields := no_time,
- Time1Pref = Pref ^ pref_fields := Time1Fields,
- Time1Msg = "[No time info]",
- Time1Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Time1Pref, Deep, Cmd)), s(Time1Msg)])
- ),
- ( Fields ^ time_fields = ticks ->
- Time2Toggle = ""
- ;
- Time2Fields = Fields ^ time_fields := ticks,
- Time2Pref = Pref ^ pref_fields := Time2Fields,
- Time2Msg = "[Ticks]",
- Time2Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Time2Pref, Deep, Cmd)), s(Time2Msg)])
- ),
- ( Fields ^ time_fields = time ->
- Time3Toggle = ""
- ;
- Time3Fields = Fields ^ time_fields := time,
- Time3Pref = Pref ^ pref_fields := Time3Fields,
- Time3Msg = "[Times]",
- Time3Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Time3Pref, Deep, Cmd)), s(Time3Msg)])
- ),
- ( Fields ^ time_fields = ticks_and_time->
- Time4Toggle = ""
- ;
- Time4Fields = Fields ^ time_fields := ticks_and_time,
- Time4Pref = Pref ^ pref_fields := Time4Fields,
- Time4Msg = "[Ticks and times]",
- Time4Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Time4Pref, Deep, Cmd)), s(Time4Msg)])
- ),
- ( Fields ^ time_fields = time_and_percall ->
- Time5Toggle = ""
- ;
- Time5Fields = Fields ^ time_fields := time_and_percall,
- Time5Pref = Pref ^ pref_fields := Time5Fields,
- Time5Msg = "[Times and per-call times]",
- Time5Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Time5Pref, Deep, Cmd)), s(Time5Msg)])
- ),
- ( Fields ^ time_fields = ticks_and_time_and_percall ->
- Time6Toggle = ""
- ;
- Time6Fields = Fields ^ time_fields := ticks_and_time_and_percall,
- Time6Pref = Pref ^ pref_fields := Time6Fields,
- Time6Msg = "[Ticks and times and per-call times]",
- Time6Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Time6Pref, Deep, Cmd)), s(Time6Msg)])
- ),
- ( Fields ^ callseqs_fields = no_callseqs ->
- CallSeqs1Toggle = ""
- ;
- CallSeqs1Fields = Fields ^ callseqs_fields := no_callseqs,
- CallSeqs1Pref = Pref ^ pref_fields := CallSeqs1Fields,
- CallSeqs1Msg = "[No call sequence number info]",
- CallSeqs1Toggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(CallSeqs1Pref, Deep, Cmd)),
- s(CallSeqs1Msg)])
- ),
- ( Fields ^ callseqs_fields = callseqs ->
- CallSeqs2Toggle = ""
- ;
- CallSeqs2Fields = Fields ^ callseqs_fields := callseqs,
- CallSeqs2Pref = Pref ^ pref_fields := CallSeqs2Fields,
- CallSeqs2Msg = "[Call sequence numbers]",
- CallSeqs2Toggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(CallSeqs2Pref, Deep, Cmd)),
- s(CallSeqs2Msg)])
- ),
- ( Fields ^ callseqs_fields = callseqs_and_percall ->
- CallSeqs3Toggle = ""
- ;
- CallSeqs3Fields = Fields ^ callseqs_fields := callseqs_and_percall,
- CallSeqs3Pref = Pref ^ pref_fields := CallSeqs3Fields,
- CallSeqs3Msg = "[Call sequence numbers including per-call]",
- CallSeqs3Toggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(CallSeqs3Pref, Deep, Cmd)),
- s(CallSeqs3Msg)])
- ),
- ( Fields ^ alloc_fields = no_alloc ->
- Alloc1Toggle = ""
- ;
- Alloc1Fields = Fields ^ alloc_fields := no_alloc,
- Alloc1Pref = Pref ^ pref_fields := Alloc1Fields,
- Alloc1Msg = "[No allocations]",
- Alloc1Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Alloc1Pref, Deep, Cmd)), s(Alloc1Msg)])
- ),
- ( Fields ^ alloc_fields = alloc ->
- Alloc2Toggle = ""
- ;
- Alloc2Fields = Fields ^ alloc_fields := alloc,
- Alloc2Pref = Pref ^ pref_fields := Alloc2Fields,
- Alloc2Msg = "[Allocations]",
- Alloc2Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Alloc2Pref, Deep, Cmd)), s(Alloc2Msg)])
- ),
- ( Fields ^ alloc_fields = alloc_and_percall ->
- Alloc3Toggle = ""
- ;
- Alloc3Fields = Fields ^ alloc_fields := alloc_and_percall,
- Alloc3Pref = Pref ^ pref_fields := Alloc3Fields,
- Alloc3Msg = "[Allocations and per-call allocations]",
- Alloc3Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Alloc3Pref, Deep, Cmd)), s(Alloc3Msg)])
- ),
- ( Fields ^ memory_fields = no_memory ->
- Memory1Toggle = ""
- ;
- Memory1Fields = Fields ^ memory_fields := no_memory,
- Memory1Pref = Pref ^ pref_fields := Memory1Fields,
- Memory1Msg = "[No memory info]",
- Memory1Toggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Memory1Pref, Deep, Cmd)),
- s(Memory1Msg)])
- ),
- ( Fields ^ memory_fields = memory(units_words) ->
- Memory2Toggle = ""
- ;
- Memory2Fields = Fields ^ memory_fields := memory(units_words),
- Memory2Pref = Pref ^ pref_fields := Memory2Fields,
- Memory2Msg = "[Words]",
- Memory2Toggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Memory2Pref, Deep, Cmd)),
- s(Memory2Msg)])
- ),
- ( Fields ^ memory_fields = memory(units_bytes) ->
- Memory3Toggle = ""
- ;
- Memory3Fields = Fields ^ memory_fields := memory(units_bytes),
- Memory3Pref = Pref ^ pref_fields := Memory3Fields,
- Memory3Msg = "[Bytes]",
- Memory3Toggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Memory3Pref, Deep, Cmd)),
- s(Memory3Msg)])
- ),
- ( Fields ^ memory_fields = memory_and_percall(units_words) ->
- Memory4Toggle = ""
- ;
- Memory4Fields = Fields ^ memory_fields :=
- memory_and_percall(units_words),
- Memory4Pref = Pref ^ pref_fields := Memory4Fields,
- Memory4Msg = "[Words and per-call words]",
- Memory4Toggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Memory4Pref, Deep, Cmd)),
- s(Memory4Msg)])
- ),
- ( Fields ^ memory_fields = memory_and_percall(units_bytes) ->
- Memory5Toggle = ""
- ;
- Memory5Fields = Fields ^ memory_fields :=
- memory_and_percall(units_bytes),
- Memory5Pref = Pref ^ pref_fields := Memory5Fields,
- Memory5Msg = "[Bytes and per-call bytes]",
- Memory5Toggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Memory5Pref, Deep, Cmd)),
- s(Memory5Msg)])
- ),
- ( Fields = default_fields(Deep) ->
- DefaultToggle = ""
- ;
- DefaultMsg = "[Restore defaults]",
- DefaultPref = Pref ^ pref_fields := default_fields(Deep),
- DefaultToggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(DefaultPref, Deep, Cmd)),
- s(DefaultMsg)])
- ),
- HTML =
- "<strong>Toggle fields:</strong>\n" ++
- DefaultToggle ++
- "<br>\n" ++
- Port1Toggle ++ Port2Toggle ++
- "<br>\n" ++
- Time1Toggle ++ Time2Toggle ++ Time3Toggle ++
- Time4Toggle ++ Time5Toggle ++ Time6Toggle ++
- "<br>\n" ++
- CallSeqs1Toggle ++ CallSeqs2Toggle ++ CallSeqs3Toggle ++
- "<br>\n" ++
- Alloc1Toggle ++ Alloc2Toggle ++ Alloc3Toggle ++
- "<br>\n" ++
- Memory1Toggle ++ Memory2Toggle ++ Memory3Toggle ++
- Memory4Toggle ++ Memory5Toggle ++
- "<br>\n".
-
-:- func footer_ancestor_toggle(cmd, preferences, deep) = string.
-
-footer_ancestor_toggle(Cmd, Pref, Deep) = HTML :-
- (
- Pref ^ pref_anc = no,
- Display1 = yes,
- Display2 = yes,
- Msg1 = "[One ancestor]",
- Pref1 = Pref ^ pref_anc := yes(1),
- Msg2 = "[Two ancestors]",
- Pref2 = Pref ^ pref_anc := yes(2),
- Msg3 = "[Three ancestors]",
- Pref3 = Pref ^ pref_anc := yes(3),
- Msg4 = "[Five ancestors]",
- Pref4 = Pref ^ pref_anc := yes(5),
- Msg5 = "[Ten ancestors]",
- Pref5 = Pref ^ pref_anc := yes(10)
- ;
- Pref ^ pref_anc = yes(OldAncestorLimit),
- ( OldAncestorLimit > 2 ->
- Display1 = yes
- ;
- Display1 = no
- ),
- ( OldAncestorLimit > 1 ->
- Display2 = yes
- ;
- Display2 = no
- ),
- Msg1 = "[Halve ancestors]",
- Pref1 = Pref ^ pref_anc := yes(OldAncestorLimit // 2),
- Msg2 = "[Remove an ancestor]",
- Pref2 = Pref ^ pref_anc := yes(OldAncestorLimit - 1),
- Msg3 = "[Add an ancestor]",
- Pref3 = Pref ^ pref_anc := yes(OldAncestorLimit + 1),
- Msg4 = "[Double ancestors]",
- Pref4 = Pref ^ pref_anc := yes(OldAncestorLimit * 2),
- Msg5 = "[Unlimited ancestors]",
- Pref5 = Pref ^ pref_anc := no
- ),
- Toggle1 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]),
- Toggle2 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref2, Deep, Cmd)), s(Msg2)]),
- Toggle3 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref3, Deep, Cmd)), s(Msg3)]),
- Toggle4 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref4, Deep, Cmd)), s(Msg4)]),
- Toggle5 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref5, Deep, Cmd)), s(Msg5)]),
- (
- Display1 = yes,
- MaybeToggle1 = Toggle1
- ;
- Display1 = no,
- MaybeToggle1 = ""
- ),
- (
- Display2 = yes,
- MaybeToggle2 = Toggle2
- ;
- Display2 = no,
- MaybeToggle2 = ""
- ),
- HTML =
- "<strong>Toggle ancestors:</strong><br />\n" ++
- MaybeToggle1 ++ MaybeToggle2 ++ Toggle3 ++ Toggle4 ++ Toggle5.
-
-:- func footer_box_toggle(cmd, preferences, deep) = string.
-
-footer_box_toggle(Cmd, Pref, Deep) = HTML :-
- (
- Pref ^ pref_box = do_not_box_tables,
- Pref1 = Pref ^ pref_box := box_tables,
- Msg1 = "[Box]"
- ;
- Pref ^ pref_box = box_tables,
- Pref1 = Pref ^ pref_box := do_not_box_tables,
- Msg1 = "[Unbox]"
- ),
- HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]).
-
-:- func footer_colour_toggle(cmd, preferences, deep) = string.
-
-footer_colour_toggle(Cmd, Pref, Deep) = HTML :-
- (
- Pref ^ pref_colour = do_not_colour_column_groups,
- Pref1 = Pref ^ pref_colour := colour_column_groups,
- Msg1 = "[Colour column groups]"
- ;
- Pref ^ pref_colour = colour_column_groups,
- Pref1 = Pref ^ pref_colour := do_not_colour_column_groups,
- Msg1 = "[Fade column groups]"
- ),
- HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]).
-
-:- func footer_summarize_toggle(cmd, preferences, deep) = string.
-
-footer_summarize_toggle(Cmd, Pref, Deep) = HTML :-
- (
- Pref ^ pref_summarize = summarize,
- Pref1 = Pref ^ pref_summarize := do_not_summarize,
- Msg1 = "[Expand higher order calls]"
- ;
- Pref ^ pref_summarize = do_not_summarize,
- Pref1 = Pref ^ pref_summarize := summarize,
- Msg1 = "[Summarize higher order calls]"
- ),
- HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]).
-
-:- func footer_contour_toggle(cmd, preferences, deep) = string.
-
-footer_contour_toggle(Cmd, Pref, Deep) = HTML :-
- (
- Pref ^ pref_contour = do_not_apply_contour_exclusion,
- Pref1 = Pref ^ pref_contour := apply_contour_exclusion,
- Msg1 = "[Apply contour exclusion]"
- ;
- Pref ^ pref_contour = apply_contour_exclusion,
- Pref1 = Pref ^ pref_contour := do_not_apply_contour_exclusion,
- Msg1 = "[Don't apply contour exclusion]"
- ),
- HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]).
-
-:- func footer_time_format_toggle(cmd, preferences, deep) = string.
-
-footer_time_format_toggle(Cmd, Pref, Deep) = HTML :-
- TimeFields = Pref ^ pref_fields ^ time_fields,
- (
- ( TimeFields = no_time
- ; TimeFields = ticks
- ),
- ToggleTimeFormat = no
- ;
- ( TimeFields = time
- ; TimeFields = ticks_and_time
- ; TimeFields = time_and_percall
- ; TimeFields = ticks_and_time_and_percall
- ),
- ToggleTimeFormat = yes
- ),
- (
- ToggleTimeFormat = no,
- HTML = ""
- ;
- ToggleTimeFormat = yes,
- (
- Pref ^ pref_time = no_scale,
- Pref1 = Pref ^ pref_time := scale_by_millions,
- Msg1 = "[Time in s, us]",
- Pref2 = Pref ^ pref_time := scale_by_thousands,
- Msg2 = "[Time in s, ms, us, ns]"
- ;
- Pref ^ pref_time = scale_by_millions,
- Pref1 = Pref ^ pref_time := no_scale,
- Msg1 = "[Time in s]",
- Pref2 = Pref ^ pref_time := scale_by_thousands,
- Msg2 = "[Time in s, ms, us, ns]"
- ;
- Pref ^ pref_time = scale_by_thousands,
- Pref1 = Pref ^ pref_time := no_scale,
- Msg1 = "[Time in s]",
- Pref2 = Pref ^ pref_time := scale_by_millions,
- Msg2 = "[Time in s, us]"
- ),
- HTML =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref2, Deep, Cmd)), s(Msg2)])
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- func footer_order_criteria_toggle(cmd, preferences, deep) = string.
-
-footer_order_criteria_toggle(Cmd, Pref, Deep) =
- toggle_criteria(Pref ^ pref_criteria,
- update_criteria_in_prefs(Pref, Deep, Cmd),
- update_cost_criteria_in_prefs(Pref, Deep, Cmd)).
-
-toggle_cost_criteria_in_top_procs_cmd(Pref, Deep, Limit,
- CostKind, InclDesc, Scope) =
- toggle_cost_criteria(CostKind, InclDesc, Scope,
- update_cost_criteria_in_top_procs_cmd(Pref, Deep, Limit)).
-
-%-----------------------------------------------------------------------------%
-
-:- type update_criteria_func == (func(order_criteria) = string).
-
-:- type update_cost_criteria_func ==
- (func(cost_kind, include_descendants, measurement_scope) = string).
-
-:- func toggle_criteria(order_criteria,
- update_criteria_func, update_cost_criteria_func) = string.
-
-toggle_criteria(Criteria, UpdateCriteria, UpdateCostCriteria) = HTML :-
- (
- Criteria = by_context,
- Criteria1 = by_name,
- Msg1 = "[Sort by name]",
- Criteria2 =
- by_cost(default_cost_kind, default_incl_desc, default_scope),
- Msg2 = "[Sort by cost]"
- ;
- Criteria = by_name,
- Criteria1 = by_context,
- Msg1 = "[Sort by context]",
- Criteria2 =
- by_cost(default_cost_kind, default_incl_desc, default_scope),
- Msg2 = "[Sort by cost]"
- ;
- Criteria = by_cost(_, _, _),
- Criteria1 = by_context,
- Msg1 = "[Sort by context]",
- Criteria2 = by_name,
- Msg2 = "[Sort by name]"
- ),
- Toggle1 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(Criteria1)), s(Msg1)]),
- Toggle2 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(Criteria2)), s(Msg2)]),
- (
- Criteria = by_cost(CostKind, InclDesc, Scope),
- ToggleRest = toggle_cost_criteria(CostKind, InclDesc, Scope,
- UpdateCostCriteria)
- ;
- ( Criteria = by_context
- ; Criteria = by_name
- ),
- ToggleRest = ""
- ),
- HTML = "<strong>Toggle ordering criteria:</strong><br />\n" ++
- Toggle1 ++ Toggle2 ++ ToggleRest.
-
-:- func toggle_cost_criteria(cost_kind, include_descendants, measurement_scope,
- update_cost_criteria_func) = string.
-
-toggle_cost_criteria(CostKind, InclDesc, Scope, UpdateCriteria) = Toggles :-
- (
- ( CostKind = cost_redos
- ; CostKind = cost_time
- ; CostKind = cost_callseqs
- ; CostKind = cost_allocs
- ; CostKind = cost_words
- ),
- MsgCalls = "[Sort by calls]",
- ToggleCalls = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(cost_calls, InclDesc, Scope)), s(MsgCalls)])
- ;
- CostKind = cost_calls,
- ToggleCalls = ""
- ),
- (
- ( CostKind = cost_calls
- ; CostKind = cost_time
- ; CostKind = cost_callseqs
- ; CostKind = cost_allocs
- ; CostKind = cost_words
- ),
- MsgRedos = "[Sort by redos]",
- ToggleRedos = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(cost_redos, InclDesc, Scope)), s(MsgRedos)])
- ;
- CostKind = cost_redos,
- ToggleRedos = ""
- ),
- (
- ( CostKind = cost_calls
- ; CostKind = cost_redos
- ; CostKind = cost_callseqs
- ; CostKind = cost_allocs
- ; CostKind = cost_words
- ),
- MsgTime = "[Sort by time]",
- ToggleTime = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(cost_time, InclDesc, Scope)), s(MsgTime)])
- ;
- CostKind = cost_time,
- ToggleTime = ""
- ),
- (
- ( CostKind = cost_calls
- ; CostKind = cost_redos
- ; CostKind = cost_time
- ; CostKind = cost_allocs
- ; CostKind = cost_words
- ),
- MsgCallSeqs = "[Sort by call sequence numbers]",
- ToggleCallSeqs =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(cost_callseqs, InclDesc, Scope)),
- s(MsgCallSeqs)])
- ;
- CostKind = cost_callseqs,
- ToggleCallSeqs = ""
- ),
- (
- ( CostKind = cost_calls
- ; CostKind = cost_redos
- ; CostKind = cost_time
- ; CostKind = cost_callseqs
- ; CostKind = cost_words
- ),
- MsgAllocs = "[Sort by allocations]",
- ToggleAllocs =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(cost_allocs, InclDesc, Scope)),
- s(MsgAllocs)])
- ;
- CostKind = cost_allocs,
- ToggleAllocs = ""
- ),
- (
- ( CostKind = cost_calls
- ; CostKind = cost_redos
- ; CostKind = cost_time
- ; CostKind = cost_callseqs
- ; CostKind = cost_allocs
- ),
- MsgWords = "[Sort by words]",
- ToggleWords = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(cost_words, InclDesc, Scope)), s(MsgWords)])
- ;
- CostKind = cost_words,
- ToggleWords = ""
- ),
- (
- InclDesc = self,
- MsgDesc = "[Include descendants]",
- ToggleDesc = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(CostKind, self_and_desc, Scope)), s(MsgDesc)])
- ;
- InclDesc = self_and_desc,
- MsgDesc = "[Exclude descendants]",
- ToggleDesc = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(CostKind, self, Scope)), s(MsgDesc)])
- ),
- (
- Scope = per_call,
- MsgScope = "[Count overall cost]",
- ToggleScope = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(CostKind, InclDesc, overall)), s(MsgScope)])
- ;
- Scope = overall,
- MsgScope = "[Count per-call cost]",
- ToggleScope = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(UpdateCriteria(CostKind, InclDesc, per_call)), s(MsgScope)])
- ),
- Toggles = ToggleCalls ++ ToggleRedos ++ ToggleTime ++ ToggleCallSeqs ++
- ToggleAllocs ++ ToggleWords ++
- "\n<br>\n" ++ ToggleDesc ++ ToggleScope.
-
-%-----------------------------------------------------------------------------%
-%
-% Toggles to control showing/hiding inactive modules/procedures
-%
-
-:- func footer_inactive_modules_toggle(cmd, preferences, deep) = string.
-
-footer_inactive_modules_toggle(Cmd, Pref0, Deep) = HTML :-
- Pref0 ^ pref_inactive = inactive_items(Procs, Modules),
- (
- Modules = inactive_show,
- Msg = "[Hide inactive modules]",
- Pref = Pref0 ^ pref_inactive := inactive_items(Procs, inactive_hide)
- ;
- Modules = inactive_hide,
- Msg = "[Show inactive modules]",
- Pref = Pref0 ^ pref_inactive := inactive_items(Procs, inactive_show)
- ),
- HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, Cmd)), s(Msg)]).
-
-:- func footer_inactive_procs_toggle(cmd, preferences, deep) = string.
-
-footer_inactive_procs_toggle(Cmd, Pref0, Deep) = HTML :-
- Pref0 ^ pref_inactive = inactive_items(Procs, Modules),
- (
- Procs = inactive_show,
- Msg = "[Hide inactive procedures]",
- Pref = Pref0 ^ pref_inactive := inactive_items(inactive_hide, Modules)
- ;
- Procs = inactive_hide,
- Msg = "[Show inactive procedures]",
- Pref = Pref0 ^ pref_inactive := inactive_items(inactive_show, Modules)
- ),
- HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, Cmd)), s(Msg)]).
-
-%-----------------------------------------------------------------------------%
-
-:- func update_criteria_in_prefs(preferences, deep, cmd, order_criteria)
- = string.
-
-update_criteria_in_prefs(Pref0, Deep, Cmd, Criteria) = HTML :-
- Pref = Pref0 ^ pref_criteria := Criteria,
- HTML = deep_cmd_pref_to_url(Pref, Deep, Cmd).
-
-:- func update_cost_criteria_in_prefs(preferences, deep, cmd,
- cost_kind, include_descendants, measurement_scope) = string.
-
-update_cost_criteria_in_prefs(Pref0, Deep, Cmd, CostKind, InclDesc, Scope)
- = HTML :-
- Pref = Pref0 ^ pref_criteria := by_cost(CostKind, InclDesc, Scope),
- HTML = deep_cmd_pref_to_url(Pref, Deep, Cmd).
-
-:- func update_cost_criteria_in_top_procs_cmd(preferences, deep, display_limit,
- cost_kind, include_descendants, measurement_scope) = string.
-
-update_cost_criteria_in_top_procs_cmd(Pref, Deep, Limit,
- CostKind, InclDesc, Scope) = HTML :-
- Cmd = deep_cmd_top_procs(Limit, CostKind, InclDesc, Scope),
- HTML = deep_cmd_pref_to_url(Pref, Deep, Cmd).
-
-%-----------------------------------------------------------------------------%
-
-criteria_to_description(by_context) = "ordered by context".
-criteria_to_description(by_name) = "ordered by name".
-criteria_to_description(by_cost(CostKind, InclDesc, Scope)) =
- cost_criteria_to_description(CostKind, InclDesc, Scope).
-
-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).
-
-:- 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".
-
-:- func incl_desc_to_description(include_descendants) = string.
-
-incl_desc_to_description(self) = "self".
-incl_desc_to_description(self_and_desc) = "total".
-
-:- func scope_to_description(measurement_scope) = string.
-
-scope_to_description(per_call) = "per call".
-scope_to_description(overall) = "overall".
-
-%-----------------------------------------------------------------------------%
-
-% The predicates banner_style, fields_header, table_width and
-% own_and_desc_to_html all make decisions about what columns each row
-% in the table will have. They therefore have similar control structures,
-% and a change in one may require changes in the others as well.
-
-fields_header(Pref, IdFields, TotalsDisp, WrapFunc) = HTML :-
- Fields = Pref ^ pref_fields,
- ProcName = WrapFunc("Procedure", by_name),
- ModuleName = WrapFunc("Module", by_name),
-
- some [!FirstRow, !SecondRow] (
- (
- IdFields = source_proc,
- Source = WrapFunc("Source", by_context),
- !:FirstRow =
- "<TR>\n" ++
- string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(Source)]) ++
- string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(ProcName)])
- ;
- IdFields = rank_proc,
- !:FirstRow =
- "<TR>\n" ++
- "<TH ALIGN=LEFT ROWSPAN=2>Rank\n" ++
- string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(ProcName)])
- ;
- IdFields = rank_module,
- !:FirstRow =
- "<TR>\n" ++
- "<TH ALIGN=LEFT ROWSPAN=2>Rank\n" ++
- string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(ModuleName)])
- ;
- IdFields = proc,
- !:FirstRow =
- "<TR>\n" ++
- string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(ProcName)])
- ),
- !:SecondRow = "<TR>\n",
-
- ShowPortCounts = show_port_counts(Fields),
- (
- ShowPortCounts = yes,
- Calls = WrapFunc("Calls", by_cost(cost_calls, self, overall)),
- Redos = WrapFunc("Redos", by_cost(cost_redos, self, overall)),
- !:FirstRow = !.FirstRow ++
- "<TH COLSPAN=5>Port counts\n",
- !:SecondRow = !.SecondRow ++
- string.format("<TH ALIGN=RIGHT>%s\n", [s(Calls)]) ++
- "<TH ALIGN=RIGHT>Exits\n" ++
- "<TH ALIGN=RIGHT>Fails\n" ++
- string.format("<TH ALIGN=RIGHT>%s\n", [s(Redos)]) ++
- "<TH ALIGN=RIGHT>Excps\n"
- ;
- ShowPortCounts = no
- ),
-
- ShowQuanta = show_quanta(Fields),
- (
- ShowQuanta = yes,
- TicksSelfOverall = WrapFunc("Self",
- by_cost(cost_time, self, overall)),
- TicksSelfHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(TicksSelfOverall)]),
- TicksSelfFields = 1
- ;
- ShowQuanta = no,
- TicksSelfHeading = "",
- TicksSelfFields = 0
- ),
- ShowTimes = show_times(Fields),
- (
- ShowTimes = yes,
- ( show_quanta(Fields) = yes ->
- TimeSelfOverall = WrapFunc("Time",
- by_cost(cost_time, self, overall))
- ;
- TimeSelfOverall = WrapFunc("Self",
- by_cost(cost_time, self, overall))
- ),
- TimeSelfHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(TimeSelfOverall)]),
- TimeSelfFields = 1
- ;
- ShowTimes = no,
- TimeSelfHeading = "",
- TimeSelfFields = 0
- ),
- ( ( ShowQuanta = yes ; ShowTimes = yes ) ->
- TimeSelfPercentHeading = "<TH ALIGN=RIGHT>%\n",
- TimeSelfPercentFields = 1
- ;
- TimeSelfPercentHeading = "",
- TimeSelfPercentFields = 0
- ),
- ShowTimesPerCall = show_times_per_call(Fields),
- (
- ShowTimesPerCall = yes,
- TimeSelfPerCall = WrapFunc("/call",
- by_cost(cost_time, self, per_call)),
- TimeSelfPerCallHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(TimeSelfPerCall)]),
- TimeSelfPerCallFields = 1
- ;
- ShowTimesPerCall = no,
- TimeSelfPerCallHeading = "",
- TimeSelfPerCallFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowQuanta = yes ->
- TicksTotalOverall = WrapFunc("Total",
- by_cost(cost_time, self_and_desc, overall)),
- TicksTotalHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(TicksTotalOverall)]),
- TicksTotalFields = 1
- ;
- TicksTotalHeading = "",
- TicksTotalFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowTimes = yes ->
- ( show_quanta(Fields) = yes ->
- TimeTotalOverall = WrapFunc("Time",
- by_cost(cost_time, self_and_desc, overall))
- ;
- TimeTotalOverall = WrapFunc("Total",
- by_cost(cost_time, self_and_desc, overall))
- ),
- TimeTotalHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(TimeTotalOverall)]),
- TimeTotalFields = 1
- ;
- TimeTotalHeading = "",
- TimeTotalFields = 0
- ),
- (
- TotalsDisp = totals_meaningful,
- ( ShowQuanta = yes ; ShowTimes = yes )
- ->
- TimeTotalPercentHeading = "<TH ALIGN=RIGHT>%\n",
- TimeTotalPercentFields = 1
- ;
- TimeTotalPercentHeading = "",
- TimeTotalPercentFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowTimesPerCall = yes ->
- TimeTotalPerCall = WrapFunc("/call",
- by_cost(cost_time, self_and_desc, per_call)),
- TimeTotalPerCallHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(TimeTotalPerCall)]),
- TimeTotalPerCallFields = 1
- ;
- TimeTotalPerCallHeading = "",
- TimeTotalPerCallFields = 0
- ),
- TimeFields =
- TicksSelfFields + TimeSelfFields +
- TimeSelfPercentFields + TimeSelfPerCallFields +
- TicksTotalFields + TimeTotalFields +
- TimeTotalPercentFields + TimeTotalPerCallFields,
- !:SecondRow = !.SecondRow ++
- TicksSelfHeading ++ TimeSelfHeading ++
- TimeSelfPercentHeading ++ TimeSelfPerCallHeading ++
- TicksTotalHeading ++ TimeTotalHeading ++
- TimeTotalPercentHeading ++ TimeTotalPerCallHeading,
- (
- ShowQuanta = yes,
- ShowTimes = yes,
- !:FirstRow = !.FirstRow ++
- string.format("<TH COLSPAN=%d>Clock ticks and times\n",
- [i(TimeFields)])
- ;
- ShowQuanta = yes,
- ShowTimes = no,
- !:FirstRow = !.FirstRow ++
- string.format("<TH COLSPAN=%d>Clock ticks\n", [i(TimeFields)])
- ;
- ShowQuanta = no,
- ShowTimes = yes,
- !:FirstRow = !.FirstRow ++
- string.format("<TH COLSPAN=%d>Time\n", [i(TimeFields)])
- ;
- ShowQuanta = no,
- ShowTimes = no
- ),
-
- ShowCallSeqs = show_callseqs(Fields),
- (
- ShowCallSeqs = yes,
- CallSeqsSelfOverall = WrapFunc("Self",
- by_cost(cost_callseqs, self, overall)),
- CallSeqsSelfHeading =
- string.format("<TH ALIGN=RIGHT>%s\n",
- [s(CallSeqsSelfOverall)]) ++
- "<TH ALIGN=RIGHT>%\n",
- CallSeqsSelfFields = 2
- ;
- ShowCallSeqs = no,
- CallSeqsSelfHeading = "",
- CallSeqsSelfFields = 0
- ),
- ShowCallSeqsPerCall = show_callseqs_per_call(Fields),
- (
- ShowCallSeqsPerCall = yes,
- CallSeqsSelfPerCall = WrapFunc("/call",
- by_cost(cost_callseqs, self, per_call)),
- CallSeqsSelfPerCallHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(CallSeqsSelfPerCall)]),
- CallSeqsSelfPerCallFields = 1
- ;
- ShowCallSeqsPerCall = no,
- CallSeqsSelfPerCallHeading = "",
- CallSeqsSelfPerCallFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowCallSeqs = yes ->
- CallSeqsTotalOverall = WrapFunc("Total",
- by_cost(cost_callseqs, self_and_desc, overall)),
- CallSeqsTotalHeading =
- string.format("<TH ALIGN=RIGHT>%s\n",
- [s(CallSeqsTotalOverall)]) ++
- "<TH ALIGN=RIGHT>%\n",
- CallSeqsTotalFields = 2
- ;
- CallSeqsTotalHeading = "",
- CallSeqsTotalFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowCallSeqsPerCall = yes ->
- CallSeqsTotalPerCall = WrapFunc("/call",
- by_cost(cost_callseqs, self_and_desc, per_call)),
- CallSeqsTotalPerCallHeading =
- string.format("<TH ALIGN=RIGHT>%s\n",
- [s(CallSeqsTotalPerCall)]),
- CallSeqsTotalPerCallFields = 1
- ;
- CallSeqsTotalPerCallHeading = "",
- CallSeqsTotalPerCallFields = 0
- ),
- CallSeqsFields =
- CallSeqsSelfFields + CallSeqsSelfPerCallFields +
- CallSeqsTotalFields + CallSeqsTotalPerCallFields,
- !:SecondRow = !.SecondRow ++
- CallSeqsSelfHeading ++ CallSeqsSelfPerCallHeading ++
- CallSeqsTotalHeading ++ CallSeqsTotalPerCallHeading,
- (
- ShowCallSeqs = yes,
- !:FirstRow = !.FirstRow ++
- string.format("<TH COLSPAN=%d>Call sequence numbers\n",
- [i(CallSeqsFields)])
- ;
- ShowCallSeqs = no
- ),
-
- ShowAlloc = show_alloc(Fields),
- (
- ShowAlloc = yes,
- AllocsSelfOverall = WrapFunc("Self",
- by_cost(cost_allocs, self, overall)),
- AllocsSelfHeading =
- string.format("<TH ALIGN=RIGHT>%s\n",
- [s(AllocsSelfOverall)]) ++
- "<TH ALIGN=RIGHT>%\n",
- AllocsSelfFields = 2
- ;
- ShowAlloc = no,
- AllocsSelfHeading = "",
- AllocsSelfFields = 0
- ),
- ShowAllocPerCall = show_alloc_per_call(Fields),
- (
- ShowAllocPerCall = yes,
- AllocsSelfPerCall = WrapFunc("/call",
- by_cost(cost_allocs, self, per_call)),
- AllocsSelfPerCallHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(AllocsSelfPerCall)]),
- AllocsSelfPerCallFields = 1
- ;
- ShowAllocPerCall = no,
- AllocsSelfPerCallHeading = "",
- AllocsSelfPerCallFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowAlloc = yes ->
- AllocsTotalOverall = WrapFunc("Total",
- by_cost(cost_allocs, self_and_desc, overall)),
- AllocsTotalHeading =
- string.format("<TH ALIGN=RIGHT>%s\n",
- [s(AllocsTotalOverall)]) ++
- "<TH ALIGN=RIGHT>%\n",
- AllocsTotalFields = 2
- ;
- AllocsTotalHeading = "",
- AllocsTotalFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowAllocPerCall = yes ->
- AllocsTotalPerCall = WrapFunc("/call",
- by_cost(cost_allocs, self_and_desc, per_call)),
- AllocsTotalPerCallHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(AllocsTotalPerCall)]),
- AllocsTotalPerCallFields = 1
- ;
- AllocsTotalPerCallHeading = "",
- AllocsTotalPerCallFields = 0
- ),
- AllocsFields =
- AllocsSelfFields + AllocsSelfPerCallFields +
- AllocsTotalFields + AllocsTotalPerCallFields,
- !:SecondRow = !.SecondRow ++
- AllocsSelfHeading ++ AllocsSelfPerCallHeading ++
- AllocsTotalHeading ++ AllocsTotalPerCallHeading,
- (
- ShowAlloc = yes,
- !:FirstRow = !.FirstRow ++
- string.format("<TH COLSPAN=%d>Memory allocations\n",
- [i(AllocsFields)])
- ;
- ShowAlloc = no
- ),
-
- ShowMemory = show_memory(Fields),
- (
- ShowMemory = yes(_),
- MemorySelfOverall = WrapFunc("Self",
- by_cost(cost_words, self, overall)),
- MemorySelfHeading =
- string.format("<TH ALIGN=RIGHT>%s\n",
- [s(MemorySelfOverall)]) ++
- "<TH ALIGN=RIGHT>%\n",
- MemorySelfFields = 2
- ;
- ShowMemory = no,
- MemorySelfHeading = "",
- MemorySelfFields = 0
- ),
- ShowMemoryPerCall = show_memory_per_call(Fields),
- (
- ShowMemoryPerCall = yes(_),
- MemorySelfPerCall = WrapFunc("/call",
- by_cost(cost_words, self, per_call)),
- MemorySelfPerCallHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(MemorySelfPerCall)]),
- MemorySelfPerCallFields = 1
- ;
- ShowMemoryPerCall = no,
- MemorySelfPerCallHeading = "",
- MemorySelfPerCallFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowMemory = yes(_) ->
- MemoryTotalOverall = WrapFunc("Total",
- by_cost(cost_words, self_and_desc, overall)),
- MemoryTotalHeading =
- string.format("<TH ALIGN=RIGHT>%s\n",
- [s(MemoryTotalOverall)]) ++
- "<TH ALIGN=RIGHT>%\n",
- MemoryTotalFields = 2
- ;
- MemoryTotalHeading = "",
- MemoryTotalFields = 0
- ),
- ( TotalsDisp = totals_meaningful, ShowMemoryPerCall = yes(_) ->
- MemoryTotalPerCall = WrapFunc("/call",
- by_cost(cost_words, self_and_desc, per_call)),
- MemoryTotalPerCallHeading =
- string.format("<TH ALIGN=RIGHT>%s\n", [s(MemoryTotalPerCall)]),
- MemoryTotalPerCallFields = 1
- ;
- MemoryTotalPerCallHeading = "",
- MemoryTotalPerCallFields = 0
- ),
- MemoryFields =
- MemorySelfFields + MemorySelfPerCallFields +
- MemoryTotalFields + MemoryTotalPerCallFields,
- !:SecondRow = !.SecondRow ++
- MemorySelfHeading ++ MemorySelfPerCallHeading ++
- MemoryTotalHeading ++ MemoryTotalPerCallHeading,
- (
- ShowMemory = yes(Units),
- (
- Units = units_words,
- !:FirstRow = !.FirstRow ++
- string.format("<TH COLSPAN=%d>Memory words\n",
- [i(MemoryFields)])
- ;
- Units = units_bytes,
- !:FirstRow = !.FirstRow ++
- string.format("<TH COLSPAN=%d>Memory bytes\n",
- [i(MemoryFields)])
- )
- ;
- ShowMemory = no
- ),
- HTML =
- "<THEAD>\n" ++
- !.FirstRow ++
- !.SecondRow ++
- "<TBODY>\n" ++
- separator_row(Pref, IdFields, TotalsDisp)
- ).
-
-%-----------------------------------------------------------------------------%
-
-header_row(Heading, Pref, IdFields, TotalsDisp) = Separator :-
- Separator = string.format("<TR><TD COLSPAN=%d>%s</TD></TR>\n",
- [i(table_width(Pref, IdFields, TotalsDisp)), s(Heading)]).
-
-separator_row(Pref, IdFields, TotalsDisp) = Separator :-
- Separator = string.format("<TR><TD COLSPAN=%d></TD></TR>\n",
- [i(table_width(Pref, IdFields, TotalsDisp))]).
-
-:- func table_width(preferences, id_fields, totals_disposition) = int.
-
-table_width(Pref, IdFields, TotalsDisp) = Width :-
- Fields = Pref ^ pref_fields,
- (
- IdFields = source_proc,
- Id = 2
- ;
- IdFields = rank_module,
- Id = 2
- ;
- IdFields = rank_proc,
- Id = 2
- ;
- IdFields = proc,
- Id = 1
- ),
- (
- Fields ^ port_fields = no_port,
- Port = 0
- ;
- Fields ^ port_fields = port,
- Port = 5
- ),
- (
- Fields ^ time_fields = no_time,
- Time = 0
- ;
- Fields ^ time_fields = ticks,
- Time = 2
- ;
- Fields ^ time_fields = time,
- Time = 2
- ;
- Fields ^ time_fields = ticks_and_time,
- Time = 3
- ;
- Fields ^ time_fields = time_and_percall,
- Time = 3
- ;
- Fields ^ time_fields = ticks_and_time_and_percall,
- Time = 4
- ),
- (
- Fields ^ callseqs_fields = no_callseqs,
- CallSeqs = 0
- ;
- Fields ^ callseqs_fields = callseqs,
- CallSeqs = 2
- ;
- Fields ^ callseqs_fields = callseqs_and_percall,
- CallSeqs = 3
- ),
- (
- Fields ^ alloc_fields = no_alloc,
- Alloc = 0
- ;
- Fields ^ alloc_fields = alloc,
- Alloc = 2
- ;
- Fields ^ alloc_fields = alloc_and_percall,
- Alloc = 3
- ),
- (
- Fields ^ memory_fields = no_memory,
- Memory = 0
- ;
- Fields ^ memory_fields = memory(_),
- Memory = 2
- ;
- Fields ^ memory_fields = memory_and_percall(_),
- Memory = 3
- ),
- (
- TotalsDisp = totals_meaningful,
- Width = Id + Port + Time * 2 + CallSeqs * 2 + Alloc * 2 + Memory * 2
- ;
- TotalsDisp = totals_not_meaningful,
- Width = Id + Port + Time + CallSeqs + Alloc + Memory
- ).
-
-%-----------------------------------------------------------------------------%
-
-add_context(Context, LineGroup0) = LineGroup :-
- LineGroup0 =
- line_group(FileName, LineNumber, Name, Own, Desc, HTML0, LaterLines),
- HTML = string.format("<TD CLASS=id>%s</TD>%s",
- [s(Context), s(HTML0)]),
- LineGroup =
- line_group(FileName, LineNumber, Name, Own, Desc, HTML, LaterLines).
-
-add_self_context(LineGroup0) = LineGroup :-
- LineGroup0 =
- line_group(FileName, LineNumber, Name, Own, Desc, HTML0, LaterLines),
- HTML = string.format("<TD CLASS=id>%s:%d</TD>%s",
- [s(FileName), i(LineNumber), s(HTML0)]),
- LineGroup =
- line_group(FileName, LineNumber, Name, Own, Desc, HTML, LaterLines).
-
-add_ranks(LineGroups0) = add_ranks_2(1, LineGroups0).
-
-:- func add_ranks_2(int, list(line_group(one_id, LL)))
- = list(line_group(two_id, LL)).
-
-add_ranks_2(_Rank, []) = [].
-add_ranks_2(Rank, [LineGroup0 | LineGroups0]) = [LineGroup | LineGroups] :-
- LineGroup0 =
- line_group(FileName, LineNumber, Name, Own, Desc, HTML0, LaterLines),
- HTML = string.format("<TD CLASS=id>%d</TD>%s", [i(Rank), s(HTML0)]),
- LineGroup =
- line_group(FileName, LineNumber, Name, Own, Desc, HTML, LaterLines),
- LineGroups = add_ranks_2(Rank + 1, LineGroups0).
-
-line_to_one_id_subline_group(LineGroup0) = LineGroup :-
- LineGroup0 =
- line_group(FileName, LineNumber, Name, Own, Desc, HTML, unit),
- LineGroup =
- line_group(FileName, LineNumber, Name, Own, Desc, HTML,
- sub_lines(one_id, [])).
-
-line_to_two_id_subline_group(LineGroup0) = LineGroup :-
- LineGroup0 = line_group(FileName, LineNumber, Name, Own, Desc,
- HTML, unit),
- LineGroup = line_group(FileName, LineNumber, Name, Own, Desc,
- HTML, sub_lines(two_id, [])).
-
-%-----------------------------------------------------------------------------%
-
-one_id_line_to_html(Pref, Deep, TotalsDisp, LineGroup) =
- "<TR>\n" ++
- LineGroup ^ group_first_line_id ++
- own_and_desc_to_html(LineGroup ^ group_own, LineGroup ^ group_desc,
- Pref, Deep, TotalsDisp) ++
- "</TR>\n".
-
-one_id_line_group_to_html(Pref, Deep, TotalsDisp, LineGroup) =
- "<TR>\n" ++
- LineGroup ^ group_first_line_id ++
- own_and_desc_to_html(LineGroup ^ group_own, LineGroup ^ group_desc,
- Pref, Deep, TotalsDisp) ++
- "</TR>\n" ++
- string.append_list(
- list.map(one_id_line_to_html(Pref, Deep, TotalsDisp),
- LineGroup ^ group_later_lines ^ sub_line_list)).
-
-two_id_line_to_html(Pref, Deep, TotalsDisp, LineGroup) =
- "<TR>\n" ++
- LineGroup ^ group_first_line_id ++
- own_and_desc_to_html(LineGroup ^ group_own, LineGroup ^ group_desc,
- Pref, Deep, TotalsDisp) ++
- "</TR>\n".
-
-two_id_line_group_to_html(Pref, Deep, TotalsDisp, LineGroup) =
- "<TR>\n" ++
- LineGroup ^ group_first_line_id ++
- own_and_desc_to_html(LineGroup ^ group_own, LineGroup ^ group_desc,
- Pref, Deep, TotalsDisp) ++
- "</TR>\n" ++
- string.append_list(
- list.map(two_id_line_to_html(Pref, Deep, TotalsDisp),
- LineGroup ^ group_later_lines ^ sub_line_list)).
-
-%-----------------------------------------------------------------------------%
-
-own_and_desc_to_html(Own, Desc, Pref, Deep, TotalsDisp) = HTML :-
- add_own_to_inherit(Own, Desc) = OwnPlusDesc,
- Root = root_total_info(Deep),
- Calls = calls(Own),
- Exits = exits(Own),
- Fails = fails(Own),
- Redos = redos(Own),
- Excps = excps(Own),
-
- OwnQuanta = quanta(Own),
- TotalQuanta = inherit_quanta(OwnPlusDesc),
- RootQuanta = inherit_quanta(Root),
- OwnQuantaProp = percentage(OwnQuanta, RootQuanta),
- TotalQuantaProp = percentage(TotalQuanta, RootQuanta),
-
- OwnCallSeqs = callseqs(Own),
- TotalCallSeqs = inherit_callseqs(OwnPlusDesc),
- RootCallSeqs = inherit_callseqs(Root),
- OwnCallSeqsProp = percentage(OwnCallSeqs, RootCallSeqs),
- TotalCallSeqsProp = percentage(TotalCallSeqs, RootCallSeqs),
-
- OwnAllocs = allocs(Own),
- TotalAllocs = inherit_allocs(OwnPlusDesc),
- RootAllocs = inherit_allocs(Root),
- OwnAllocProp = percentage(OwnAllocs, RootAllocs),
- TotalAllocProp = percentage(TotalAllocs, RootAllocs),
-
- OwnWords = words(Own),
- TotalWords = inherit_words(OwnPlusDesc),
- RootWords = inherit_words(Root),
- OwnMemoryProp = percentage(OwnWords, RootWords),
- TotalMemoryProp = percentage(TotalWords, RootWords),
-
- Fields = Pref ^ pref_fields,
-
- ShowPortCounts = show_port_counts(Fields),
- (
- ShowPortCounts = yes,
- PortHTML =
- string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
- [s(commas(Calls))]) ++
- string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
- [s(commas(Exits))]) ++
- string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
- [s(commas(Fails))]) ++
- string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
- [s(commas(Redos))]) ++
- string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
- [s(commas(Excps))])
- ;
- ShowPortCounts = no,
- PortHTML = ""
- ),
-
- ShowQuanta = show_quanta(Fields),
- (
- ShowQuanta = yes,
- QuantaSelfHTML =
- string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
- [s(commas(OwnQuanta))]),
- QuantaTotalHTML =
- string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
- [s(commas(TotalQuanta))])
- ;
- ShowQuanta = no,
- QuantaSelfHTML = "",
- QuantaTotalHTML = ""
- ),
- ShowTimes = show_times(Fields),
- (
- ShowTimes = yes,
- TimeSelfHTML =
- string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
- [s(overall_time(Pref, Deep, OwnQuanta))]),
- TimeTotalHTML =
- string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
- [s(overall_time(Pref, Deep, TotalQuanta))])
- ;
- ShowTimes = no,
- TimeSelfHTML = "",
- TimeTotalHTML = ""
- ),
- ShowTimeFraction = bool.or(ShowQuanta, ShowTimes),
- (
- ShowTimeFraction = yes,
- QuantaPropSelfHTML =
- string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
- [s(OwnQuantaProp)]),
- QuantaPropTotalHTML =
- string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
- [s(TotalQuantaProp)])
- ;
- ShowTimeFraction = no,
- QuantaPropSelfHTML = "",
- QuantaPropTotalHTML = ""
- ),
- ShowTimesPerCall = show_times_per_call(Fields),
- (
- ShowTimesPerCall = yes,
- TimePerCallSelfHTML =
- string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
- [s(per_call_time(Pref, Deep, OwnQuanta, Calls))]),
- TimePerCallTotalHTML =
- string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
- [s(per_call_time(Pref, Deep, TotalQuanta, Calls))])
- ;
- ShowTimesPerCall = no,
- TimePerCallSelfHTML = "",
- TimePerCallTotalHTML = ""
- ),
-
- ShowCallSeqs = show_callseqs(Fields),
- (
- ShowCallSeqs = yes,
- CallSeqsSelfHTML =
- string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
- [s(commas(OwnCallSeqs))]),
- CallSeqsTotalHTML =
- string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
- [s(commas(TotalCallSeqs))]),
- CallSeqsPropSelfHTML =
- string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
- [s(OwnCallSeqsProp)]),
- CallSeqsPropTotalHTML =
- string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
- [s(TotalCallSeqsProp)])
- ;
- ShowCallSeqs = no,
- CallSeqsSelfHTML = "",
- CallSeqsTotalHTML = "",
- CallSeqsPropSelfHTML = "",
- CallSeqsPropTotalHTML = ""
- ),
- ShowCallSeqsPerCall = show_callseqs_per_call(Fields),
- (
- ShowCallSeqsPerCall = yes,
- ( Calls = 0 ->
- OwnCallSeqsPerCall = "N/A",
- TotalCallSeqsPerCall = "N/A"
- ;
- OwnCallSeqsPerCall =
- one_decimal_fraction(float(OwnCallSeqs) / float(Calls)),
- TotalCallSeqsPerCall =
- one_decimal_fraction(float(TotalCallSeqs) / float(Calls))
- ),
- CallSeqsPerCallSelfHTML =
- string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
- [s(OwnCallSeqsPerCall)]),
- CallSeqsPerCallTotalHTML =
- string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
- [s(TotalCallSeqsPerCall)])
- ;
- ShowCallSeqsPerCall = no,
- CallSeqsPerCallSelfHTML = "",
- CallSeqsPerCallTotalHTML = ""
- ),
-
- ShowAlloc = show_alloc(Fields),
- (
- ShowAlloc = yes,
- AllocSelfHTML =
- string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
- [s(commas(OwnAllocs))]) ++
- string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
- [s(OwnAllocProp)]),
- AllocTotalHTML =
- string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
- [s(commas(TotalAllocs))]) ++
- string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
- [s(TotalAllocProp)])
- ;
- ShowAlloc = no,
- AllocSelfHTML = "",
- AllocTotalHTML = ""
- ),
- ShowAllocPerCall = show_alloc_per_call(Fields),
- (
- ShowAllocPerCall = yes,
- AllocPerCallSelfHTML =
- string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
- [s(count_per_call(OwnAllocs, Calls))]),
- AllocPerCallTotalHTML =
- string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
- [s(count_per_call(TotalAllocs, Calls))])
- ;
- ShowAllocPerCall = no,
- AllocPerCallSelfHTML = "",
- AllocPerCallTotalHTML = ""
- ),
-
- ShowMemory = show_memory(Fields),
- (
- ShowMemory = yes(Unit),
- (
- Unit = units_words,
- OwnMemory = OwnWords,
- TotalMemory = TotalWords
- ;
- Unit = units_bytes,
- WordSize = Deep ^ profile_stats ^ word_size,
- OwnMemory = OwnWords * WordSize,
- TotalMemory = TotalWords * WordSize
- )
- ;
- ShowMemory = no,
- % These values won't be used.
- OwnMemory = 0,
- TotalMemory = 0
- ),
- (
- ShowMemory = yes(_),
- MemorySelfHTML =
- string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
- [s(commas(OwnMemory))]) ++
- string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
- [s(OwnMemoryProp)]),
- MemoryTotalHTML =
- string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
- [s(commas(TotalMemory))]) ++
- string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
- [s(TotalMemoryProp)])
- ;
- ShowMemory = no,
- MemorySelfHTML = "",
- MemoryTotalHTML = ""
- ),
- ShowMemoryPerCall = show_memory_per_call(Fields),
- (
- ShowMemoryPerCall = yes(_),
- MemoryPerCallSelfHTML =
- string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
- [s(count_per_call(OwnMemory, Calls))]),
- MemoryPerCallTotalHTML =
- string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
- [s(count_per_call(TotalMemory, Calls))])
- ;
- ShowMemoryPerCall = no,
- MemoryPerCallSelfHTML = "",
- MemoryPerCallTotalHTML = ""
- ),
-
- (
- TotalsDisp = totals_meaningful,
- HTML =
- PortHTML ++
-
- QuantaSelfHTML ++
- TimeSelfHTML ++
- QuantaPropSelfHTML ++
- TimePerCallSelfHTML ++
- QuantaTotalHTML ++
- TimeTotalHTML ++
- QuantaPropTotalHTML ++
- TimePerCallTotalHTML ++
-
- CallSeqsSelfHTML ++
- CallSeqsPropSelfHTML ++
- CallSeqsPerCallSelfHTML ++
- CallSeqsTotalHTML ++
- CallSeqsPropTotalHTML ++
- CallSeqsPerCallTotalHTML ++
-
- AllocSelfHTML ++
- AllocPerCallSelfHTML ++
- AllocTotalHTML ++
- AllocPerCallTotalHTML ++
-
- MemorySelfHTML ++
- MemoryPerCallSelfHTML ++
- MemoryTotalHTML ++
- MemoryPerCallTotalHTML
- ;
- TotalsDisp = totals_not_meaningful,
- HTML =
- PortHTML ++
-
- QuantaSelfHTML ++
- TimeSelfHTML ++
- QuantaPropSelfHTML ++
- TimePerCallSelfHTML ++
-
- CallSeqsSelfHTML ++
- CallSeqsPropSelfHTML ++
- CallSeqsPerCallSelfHTML ++
-
- AllocSelfHTML ++
- AllocPerCallSelfHTML ++
-
- MemorySelfHTML ++
- MemoryPerCallSelfHTML
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- func overall_time(preferences, deep, int) = string.
-
-overall_time(Pref, Deep, Quanta) = TimeStr :-
- lookup_ticks_per_sec(Deep ^ profile_stats, TicksPerSec, _Assumed),
- % We display Time as seconds, with two digits after the decimal point.
- % This is the most we can do, given clock granularity.
- Time = float(Quanta) / float(TicksPerSec),
- TimeStr = format_time(Pref, Time).
-
-:- func per_call_time(preferences, deep, int, int) = string.
-
-per_call_time(Pref, Deep, Quanta, Calls) = TimeStr :-
- lookup_ticks_per_sec(Deep ^ profile_stats, TicksPerSec, _Assumed),
- % We display Time as seconds, with two digits after the decimal point.
- % This is the most we can do, given clock granularity.
- Time = float(Quanta) / float(TicksPerSec),
- ( Calls \= 0 ->
- TimePerCall = Time / float(Calls)
- ;
- TimePerCall = 0.0
- ),
- TimeStr = format_time(Pref, TimePerCall).
-
-:- func format_time(preferences, float) = string.
-
-format_time(Pref, Time) = TimeStr :-
- (
- Pref ^ pref_time = no_scale,
- TimeStr0 = four_decimal_fraction(Time),
- Unit = "s"
- ;
- Pref ^ pref_time = scale_by_millions,
- ( Time >= 0.001 ->
- ScaledTime = Time,
- Unit = "s"
- ;
- ScaledTime = 1000000.0 * Time,
- Unit = "us"
- ),
- TimeStr0 = four_decimal_fraction(ScaledTime)
- ;
- Pref ^ pref_time = scale_by_thousands,
- ( Time >= 1.0 ->
- ScaledTime = Time,
- Unit = "s"
- ; Time >= 0.001 ->
- ScaledTime = 1000.0 * Time,
- Unit = "ms"
- ; Time >= 0.000001 ->
- ScaledTime = 1000000.0 * Time,
- Unit = "us"
- ;
- ScaledTime = 1000000000.0 * Time,
- Unit = "ns"
- ),
- TimeStr0 = two_decimal_fraction(ScaledTime)
- ),
- TimeStr = TimeStr0 ++ Unit.
-
-:- func one_decimal_fraction(float) = string.
-
-one_decimal_fraction(Measure) = decimal_fraction("%.1f", Measure).
-
-:- func two_decimal_fraction(float) = string.
-
-two_decimal_fraction(Measure) = decimal_fraction("%.2f", Measure).
-
-:- func four_decimal_fraction(float) = string.
-
-four_decimal_fraction(Measure) = decimal_fraction("%.4f", Measure).
-
-:- func percentage(int, int) = string.
-
-percentage(Fraction, Whole) = PercentageStr :-
- ( Whole = 0 ->
- PercentageStr = "N/A"
- ;
- Percentage = 100.0 * float(Fraction) / float(Whole),
- PercentageStr = string.format("%5.2f", [f(Percentage)])
- ).
-
-lookup_ticks_per_sec(Stats, TicksPerSec, Assumed) :-
- TicksPerSec0 = Stats ^ ticks_per_sec,
- ( TicksPerSec0 = 0 ->
- TicksPerSec = default_ticks_per_sec,
- Assumed = yes
- ;
- TicksPerSec = TicksPerSec0,
- Assumed = no
- ).
-
- % The number of ticks per sec to assume if the profiling data file does
- % not record the actual tick rate.
- %
-:- func default_ticks_per_sec = int.
-
-default_ticks_per_sec = 100.
-
-%-----------------------------------------------------------------------------%
-
-:- func count_per_call(int, int) = string.
-
-count_per_call(Count, Calls) =
- ( Calls = 0 ->
- two_decimal_fraction(0.0)
- ;
- two_decimal_fraction(float(Count) / float(Calls))
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- func show_port_counts(fields) = bool.
-
-show_port_counts(Fields) = ShowPorts :-
- PortFields = Fields ^ port_fields,
- ( PortFields = no_port, ShowPorts = no
- ; PortFields = port, ShowPorts = yes
- ).
-
-:- func show_quanta(fields) = bool.
-
-show_quanta(Fields) = ShowQuanta :-
- TimeFields = Fields ^ time_fields,
- ( TimeFields = no_time, ShowQuanta = no
- ; TimeFields = ticks, ShowQuanta = yes
- ; TimeFields = time, ShowQuanta = no
- ; TimeFields = ticks_and_time, ShowQuanta = yes
- ; TimeFields = time_and_percall, ShowQuanta = no
- ; TimeFields = ticks_and_time_and_percall, ShowQuanta = yes
- ).
-
-:- func show_times(fields) = bool.
-
-show_times(Fields) = ShowTimes :-
- TimeFields = Fields ^ time_fields,
- ( TimeFields = no_time, ShowTimes = no
- ; TimeFields = ticks, ShowTimes = no
- ; TimeFields = time, ShowTimes = yes
- ; TimeFields = ticks_and_time, ShowTimes = yes
- ; TimeFields = time_and_percall, ShowTimes = yes
- ; TimeFields = ticks_and_time_and_percall, ShowTimes = yes
- ).
-
-:- func show_times_per_call(fields) = bool.
-
-show_times_per_call(Fields) = ShowTimesPerCall :-
- TimeFields = Fields ^ time_fields,
- ( TimeFields = no_time, ShowTimesPerCall = no
- ; TimeFields = ticks, ShowTimesPerCall = no
- ; TimeFields = time, ShowTimesPerCall = no
- ; TimeFields = ticks_and_time, ShowTimesPerCall = no
- ; TimeFields = time_and_percall, ShowTimesPerCall = yes
- ; TimeFields = ticks_and_time_and_percall, ShowTimesPerCall = yes
- ).
-
-:- func show_callseqs(fields) = bool.
-
-show_callseqs(Fields) = ShowCallSeqs :-
- CallSeqsField = Fields ^ callseqs_fields,
- ( CallSeqsField = no_callseqs, ShowCallSeqs = no
- ; CallSeqsField = callseqs, ShowCallSeqs = yes
- ; CallSeqsField = callseqs_and_percall, ShowCallSeqs = yes
- ).
-
-:- func show_callseqs_per_call(fields) = bool.
-
-show_callseqs_per_call(Fields) = ShowCallSeqsPerCall :-
- CallSeqsField = Fields ^ callseqs_fields,
- ( CallSeqsField = no_callseqs, ShowCallSeqsPerCall = no
- ; CallSeqsField = callseqs, ShowCallSeqsPerCall = no
- ; CallSeqsField = callseqs_and_percall, ShowCallSeqsPerCall = yes
- ).
-
-:- func show_alloc(fields) = bool.
-
-show_alloc(Fields) = ShowAlloc :-
- AllocFields = Fields ^ alloc_fields,
- ( AllocFields = no_alloc, ShowAlloc = no
- ; AllocFields = alloc, ShowAlloc = yes
- ; AllocFields = alloc_and_percall, ShowAlloc = yes
- ).
-
-:- func show_alloc_per_call(fields) = bool.
-
-show_alloc_per_call(Fields) = ShowPerAlloc :-
- AllocFields = Fields ^ alloc_fields,
- ( AllocFields = no_alloc, ShowPerAlloc = no
- ; AllocFields = alloc, ShowPerAlloc = no
- ; AllocFields = alloc_and_percall, ShowPerAlloc = yes
- ).
-
-:- func show_memory(fields) = maybe(memory_units).
-
-show_memory(Fields) = ShowMemory :-
- MemoryFields = Fields ^ memory_fields,
- ( MemoryFields = no_memory, ShowMemory = no
- ; MemoryFields = memory(Unit), ShowMemory = yes(Unit)
- ; MemoryFields = memory_and_percall(Unit), ShowMemory = yes(Unit)
- ).
-
-:- func show_memory_per_call(fields) = maybe(memory_units).
-
-show_memory_per_call(Fields) = ShowPerMemory :-
- MemoryFields = Fields ^ memory_fields,
- ( MemoryFields = no_memory, ShowPerMemory = no
- ; MemoryFields = memory(_Unit), ShowPerMemory = no
- ; MemoryFields = memory_and_percall(Unit), ShowPerMemory = yes(Unit)
- ).
-
-%-----------------------------------------------------------------------------%
-
-proc_dynamic_name(Deep, PDPtr) = Name :-
- deep_lookup_proc_dynamics(Deep, PDPtr, PD),
- PSPtr = PD ^ pd_proc_static,
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- Name = PS ^ ps_refined_id.
-
-proc_static_name(Deep, PSPtr) = Name :-
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- Name = PS ^ ps_refined_id.
-
-%-----------------------------------------------------------------------------%
-
-proc_dynamic_context(Deep, PDPtr, FileName, LineNumber) :-
- deep_lookup_proc_dynamics(Deep, PDPtr, PD),
- PSPtr = PD ^ pd_proc_static,
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- FileName = PS ^ ps_file_name,
- LineNumber = PS ^ ps_line_number.
-
-proc_static_context(Deep, PSPtr, FileName, LineNumber) :-
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- FileName = PS ^ ps_file_name,
- LineNumber = PS ^ ps_line_number.
-
-call_site_context(Deep, CSSPtr, FileName, LineNumber) :-
- deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
- CSS = call_site_static(PSPtr, _SlotNum, _Kind, LineNumber, _GoalPath),
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- FileName = PS ^ ps_file_name.
-
-%-----------------------------------------------------------------------------%
-
-proc_static_to_line_group_info(Pref, Deep, PSPtr, FileName, LineNumber,
- Name, HTML) :-
- ( valid_proc_static_ptr(Deep, PSPtr) ->
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- FileName = PS ^ ps_file_name,
- LineNumber = PS ^ ps_line_number,
- Name = PS ^ ps_refined_id,
- HTML = proc_static_to_html_ref(Pref, Deep, PSPtr)
- ;
- FileName = "",
- LineNumber = 0,
- Name = "mercury_runtime",
- HTML = Name
- ).
-
-proc_static_to_html_ref(Pref, Deep, PSPtr) = HTML :-
- URL = deep_cmd_pref_to_url(Pref, Deep, deep_cmd_proc(PSPtr)),
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- ProcName = PS ^ ps_refined_id,
- HTML = string.format("<A HREF=""%s"">%s</A>",
- [s(URL), s(escape_break_html_string(ProcName))]).
-
-module_name_to_html_ref(Pref, Deep, ModuleName) = HTML :-
- URL = deep_cmd_pref_to_url(Pref, Deep, deep_cmd_module(ModuleName)),
- HTML = string.format("<A HREF=""%s"">%s</A>",
- [s(URL), s(escape_break_html_string(ModuleName))]).
-
-clique_ptr_to_html_ref(Pref, Deep, ProcName, CliquePtr) = HTML :-
- URL = deep_cmd_pref_to_url(Pref, Deep, deep_cmd_clique(CliquePtr)),
- HTML = string.format("<A HREF=""%s"">%s</A>",
- [s(URL), s(escape_break_html_string(ProcName))]).
-
-deep_cmd_pref_to_url(Pref, Deep, Cmd) =
- machine_datafile_cmd_pref_to_url(Deep ^ server_name_port,
- Deep ^ script_name, Deep ^ data_file_name, Cmd, Pref).
-
-%-----------------------------------------------------------------------------%
-
-plural(N) = Plural :-
- ( N = 1 ->
- Plural = ""
- ;
- Plural = "s"
- ).
-
-%-----------------------------------------------------------------------------%
escape_html_string(String) =
replace_special_chars(special_html_char, String).
@@ -3208,16 +1012,6 @@
% zero_width_space = "".
zero_width_space = "<wbr />".
-:- func machine_datafile_cmd_pref_to_url(string, string, string, cmd,
- preferences) = string.
-
-machine_datafile_cmd_pref_to_url(Machine, ScriptName, DeepFileName, Cmd,
- Preferences) =
- "http://" ++
- Machine ++
- ScriptName ++ "?" ++
- query_to_string(deep_query(yes(Cmd), DeepFileName, yes(Preferences))).
-
%-----------------------------------------------------------------------------%
:- end_module html_format.
%-----------------------------------------------------------------------------%
Index: measurement_units.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/measurement_units.m,v
retrieving revision 1.4
diff -u -b -r1.4 measurement_units.m
--- measurement_units.m 25 Sep 2008 03:47:03 -0000 1.4
+++ measurement_units.m 25 Sep 2008 07:04:29 -0000
@@ -119,10 +119,14 @@
:- func commas(int) = string.
% Format a floating point number, placing commas between groups of three
- % digits in the integer part.
+ % digits in the integer part. The first argument is a format string.
%
:- func decimal_fraction(string, float) = string.
+:- func one_decimal_fraction(float) = string.
+:- func two_decimal_fraction(float) = string.
+:- func four_decimal_fraction(float) = string.
+
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -279,6 +283,12 @@
error("decimal_fraction: Didn't split on decimal point properly")
).
+one_decimal_fraction(Measure) = decimal_fraction("%.1f", Measure).
+
+two_decimal_fraction(Measure) = decimal_fraction("%.2f", Measure).
+
+four_decimal_fraction(Measure) = decimal_fraction("%.4f", Measure).
+
%-----------------------------------------------------------------------------%
:- pred add_commas_intstr(string::in, string::out) is det.
Index: old_html_format.m
===================================================================
RCS file: old_html_format.m
diff -N old_html_format.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ old_html_format.m 25 Sep 2008 07:12:55 -0000
@@ -0,0 +1,2237 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2001-2002, 2004-2008 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: old_html_format.m.
+%
+% This module contains code that helps old_query.m generate HTML.
+% The approach whose implementation it forms a part of has been superseded,
+% so it shouldn't be actively modified in the future.
+%
+%-----------------------------------------------------------------------------%
+
+:- module old_html_format.
+:- interface.
+
+:- import_module measurements.
+:- import_module profile.
+:- import_module query.
+:- import_module top_procs.
+
+:- import_module bool.
+:- import_module list.
+:- import_module unit.
+
+%-----------------------------------------------------------------------------%
+
+:- func table_start(preferences) = string.
+:- func table_end(preferences) = string.
+
+:- func page_banner(cmd, preferences) = string.
+:- func page_footer(cmd, preferences, deep) = string.
+
+:- func toggle_cost_criteria_in_top_procs_cmd(preferences, deep, display_limit,
+ cost_kind, include_descendants, measurement_scope) = string.
+
+:- func criteria_to_description(order_criteria) = string.
+:- func cost_criteria_to_description(cost_kind, include_descendants,
+ measurement_scope) = string.
+
+:- type id_fields
+ ---> source_proc
+ ; rank_module
+ ; rank_proc
+ ; proc.
+
+:- type totals_disposition
+ ---> totals_meaningful
+ ; totals_not_meaningful.
+
+:- type header_wrap_func == (func(string, order_criteria) = string).
+
+:- func fields_header(preferences, id_fields, totals_disposition,
+ header_wrap_func) = string.
+
+:- func header_row(string, preferences, id_fields, totals_disposition)
+ = string.
+:- func separator_row(preferences, id_fields, totals_disposition)
+ = string.
+
+:- type sub_lines(T)
+ ---> sub_lines(
+ sub_line_type :: T,
+ sub_line_list :: list(line_group(T, unit))
+ ).
+
+:- type one_id ---> one_id.
+:- type two_id ---> two_id.
+
+:- type one_id_sub_lines == sub_lines(one_id).
+:- type two_id_sub_lines == sub_lines(two_id).
+
+:- type one_id_line == line_group(one_id, unit).
+:- type two_id_line == line_group(two_id, unit).
+:- type one_id_line_group == line_group(one_id, one_id_sub_lines).
+:- type two_id_line_group == line_group(two_id, two_id_sub_lines).
+:- type one_two_id_line_group == line_group(one_id, two_id_sub_lines).
+
+ % This function takes a context description (which may be empty) and a
+ % HTML string describing all fields in a row but the first, and returns
+ % the HTML for the full row.
+ %
+:- func add_context(string, line_group(one_id, LL)) = line_group(two_id, LL).
+
+ % This adds the context from the line group to the HTML as the first field
+ % of the resulting line group.
+ %
+:- func add_self_context(line_group(one_id, LL)) = line_group(two_id, LL).
+
+:- func add_ranks(list(line_group(one_id, LL))) = list(line_group(two_id, LL)).
+
+:- func line_to_one_id_subline_group(line_group(FL, unit))
+ = line_group(FL, one_id_sub_lines).
+
+:- func line_to_two_id_subline_group(line_group(FL, unit))
+ = line_group(FL, two_id_sub_lines).
+
+:- func one_id_line_to_html(preferences, deep, totals_disposition,
+ one_id_line) = string.
+:- func one_id_line_group_to_html(preferences, deep, totals_disposition,
+ one_id_line_group) = string.
+:- func two_id_line_to_html(preferences, deep, totals_disposition,
+ two_id_line) = string.
+:- func two_id_line_group_to_html(preferences, deep, totals_disposition,
+ two_id_line_group) = string.
+
+:- func own_and_desc_to_html(own_prof_info, inherit_prof_info,
+ preferences, deep, totals_disposition) = string.
+
+:- pred lookup_ticks_per_sec(profile_stats::in, int::out, bool::out) is det.
+
+:- func proc_dynamic_name(deep, proc_dynamic_ptr) = string.
+:- func proc_static_name(deep, proc_static_ptr) = string.
+
+:- pred proc_dynamic_context(deep::in, proc_dynamic_ptr::in,
+ string::out, int::out) is det.
+:- pred proc_static_context(deep::in, proc_static_ptr::in,
+ string::out, int::out) is det.
+:- pred call_site_context(deep::in, call_site_static_ptr::in,
+ string::out, int::out) is det.
+
+:- pred proc_static_to_line_group_info(preferences::in, deep::in,
+ proc_static_ptr::in, string::out, int::out, string::out, string::out)
+ is det.
+:- func proc_static_to_html_ref(preferences, deep, proc_static_ptr) = string.
+:- func module_name_to_html_ref(preferences, deep, string) = string.
+:- func clique_ptr_to_html_ref(preferences, deep, string, clique_ptr) = string.
+:- func deep_cmd_pref_to_url(preferences, deep, cmd) = string.
+
+:- func plural(int) = string.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module measurement_units.
+:- import_module html_format. % for escape_break_html_string
+
+:- import_module float.
+:- import_module int.
+:- import_module maybe.
+:- import_module string.
+
+%-----------------------------------------------------------------------------%
+%
+% Deprecated html_format code.
+%
+
+page_banner(_Cmd, Pref) =
+ "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01//EN""\n" ++
+ """http://www.w3.org/TR/html4/strict.dtd"">\n" ++
+ "<HTML>\n" ++
+ "<HEAD>\n" ++
+ "<TITLE>Page created by the Mercury Deep Profiler.</TITLE>\n" ++
+ banner_style(Pref) ++
+ "</HEAD>\n" ++
+ "<BODY>\n".
+
+:- func banner_style(preferences) = string.
+
+banner_style(Pref) = HTML :-
+ Fields = Pref ^ pref_fields,
+
+ some [!GroupNum] (
+ !:GroupNum = 0,
+ IdStyle = string.format(" TD.id { %s }\n",
+ [s(select_colgroup_background(Pref, !.GroupNum))]),
+ !:GroupNum = !.GroupNum + 1,
+ Fields = fields(PortFields, TimeFields, CallSeqsFields,
+ AllocFields, MemoryFields),
+ (
+ PortFields = no_port,
+ PortStyle = ""
+ ;
+ PortFields = port,
+ PortStyle = string.format(" TD.port { %s }\n",
+ [s(select_colgroup_background(Pref, !.GroupNum))]),
+ !:GroupNum = !.GroupNum + 1
+ ),
+ (
+ TimeFields = no_time,
+ TimeStyle = ""
+ ;
+ ( TimeFields = ticks
+ ; TimeFields = time
+ ; TimeFields = ticks_and_time
+ ; TimeFields = time_and_percall
+ ; TimeFields = ticks_and_time_and_percall
+ ),
+ TimeStyle = string.format(" TD.time { %s }\n",
+ [s(select_colgroup_background(Pref, !.GroupNum))]),
+ !:GroupNum = !.GroupNum + 1
+ ),
+ (
+ CallSeqsFields = no_callseqs,
+ CallSeqsStyle = ""
+ ;
+ ( CallSeqsFields = callseqs
+ ; CallSeqsFields = callseqs_and_percall
+ ),
+ CallSeqsStyle = string.format(" TD.callseqs { %s }\n",
+ [s(select_colgroup_background(Pref, !.GroupNum))]),
+ !:GroupNum = !.GroupNum + 1
+ ),
+ (
+ AllocFields = no_alloc,
+ AllocStyle = ""
+ ;
+ ( AllocFields = alloc
+ ; AllocFields = alloc_and_percall
+ ),
+ AllocStyle = string.format(" TD.alloc { %s }\n",
+ [s(select_colgroup_background(Pref, !.GroupNum))]),
+ !:GroupNum = !.GroupNum + 1
+ ),
+ (
+ MemoryFields = no_memory,
+ MemoryStyle = ""
+ ;
+ ( MemoryFields = memory(_)
+ ; MemoryFields = memory_and_percall(_)
+ ),
+ MemoryStyle = string.format(" TD.memory { %s }\n",
+ [s(select_colgroup_background(Pref, !.GroupNum))])
+ )
+ ),
+ ButtonStyle = " A.button { margin: 5px; text-decoration: none; }\n",
+ HTML =
+ "<STYLE TYPE=""text/css"">\n" ++
+ IdStyle ++
+ PortStyle ++
+ TimeStyle ++
+ CallSeqsStyle ++
+ AllocStyle ++
+ MemoryStyle ++
+ ButtonStyle ++
+ "</STYLE>\n".
+
+:- func select_colgroup_background(preferences, int) = string.
+
+select_colgroup_background(Pref, N) = HTML :-
+ (
+ Pref ^ pref_colour = colour_column_groups,
+ ( N /\ 1 = 0 ->
+ Background = even_background
+ ;
+ Background = odd_background
+ ),
+ string.format("background: %s", [s(Background)], HTML)
+ ;
+ Pref ^ pref_colour = do_not_colour_column_groups,
+ HTML = ""
+ ).
+
+:- func even_background = string.
+
+even_background = "rgb(255, 255, 240)".
+
+:- func odd_background = string.
+
+odd_background = "rgb(240, 240, 255)".
+
+%-----------------------------------------------------------------------------%
+
+table_start(Pref) = HTML :-
+ (
+ Pref ^ pref_box = do_not_box_tables,
+ HTML = "\n<TABLE width=100%>\n"
+ ;
+ Pref ^ pref_box = box_tables,
+ HTML = "\n<TABLE width=100% border=1>\n"
+ ).
+
+table_end(_) = "</TABLE>\n".
+
+%-----------------------------------------------------------------------------%
+
+page_footer(Cmd, Pref, Deep) =
+ "<p>\n" ++
+ footer_pref_toggles(Cmd, Pref, Deep) ++
+ "<br>\n" ++
+ string.format("<A CLASS=""button"" HREF=""%s"">[Menu]</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_menu))]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">[Restart]</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_restart))]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">[Quit]</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_quit))]) ++
+ "</BODY>\n" ++
+ "</HTML>\n".
+
+:- func footer_pref_toggles(cmd, preferences, deep) = string.
+
+footer_pref_toggles(Cmd, Pref, Deep) = AllToggles :-
+ RelevantToggles = command_relevant_toggles(Cmd),
+ ( list.member(toggle_fields, RelevantToggles) ->
+ FieldToggle = footer_field_toggle(Cmd, Pref, Deep)
+ ;
+ FieldToggle = ""
+ ),
+ ( list.member(toggle_ancestor_limit, RelevantToggles) ->
+ AncestorToggle =
+ footer_ancestor_toggle(Cmd, Pref, Deep) ++
+ "<br>\n"
+ ;
+ AncestorToggle = ""
+ ),
+ ( list.member(toggle_order_criteria, RelevantToggles) ->
+ OrderToggle =
+ footer_order_criteria_toggle(Cmd, Pref, Deep) ++
+ "<br>\n"
+ ;
+ OrderToggle = ""
+ ),
+ ( list.member(toggle_summarize, RelevantToggles) ->
+ SummarizeToggle = footer_summarize_toggle(Cmd, Pref, Deep)
+ ;
+ SummarizeToggle = ""
+ ),
+ ( list.member(toggle_contour, RelevantToggles) ->
+ ContourToggle = footer_contour_toggle(Cmd, Pref, Deep)
+ ;
+ ContourToggle = ""
+ ),
+ ( list.member(toggle_time_format, RelevantToggles) ->
+ TimeFormatToggle = footer_time_format_toggle(Cmd, Pref, Deep)
+ ;
+ TimeFormatToggle = ""
+ ),
+ ( list.member(toggle_colour, RelevantToggles) ->
+ ColourToggle = footer_colour_toggle(Cmd, Pref, Deep)
+ ;
+ ColourToggle = ""
+ ),
+ ( list.member(toggle_box, RelevantToggles) ->
+ BoxToggle = footer_box_toggle(Cmd, Pref, Deep)
+ ;
+ BoxToggle = ""
+ ),
+ ( list.member(toggle_inactive_modules, RelevantToggles) ->
+ InactiveModuleToggle = footer_inactive_modules_toggle(Cmd, Pref, Deep)
+ ;
+ InactiveModuleToggle = ""
+ ),
+ ( list.member(toggle_inactive_procs, RelevantToggles) ->
+ InactiveProcsToggle = footer_inactive_procs_toggle(Cmd, Pref, Deep)
+ ;
+ InactiveProcsToggle = ""
+ ),
+ AllToggles =
+ FieldToggle ++
+ AncestorToggle ++
+ OrderToggle ++
+ SummarizeToggle ++
+ ContourToggle ++
+ TimeFormatToggle ++
+ ColourToggle ++
+ BoxToggle ++
+ InactiveModuleToggle ++
+ InactiveProcsToggle.
+
+%-----------------------------------------------------------------------------%
+
+:- type toggle_kind
+ ---> toggle_fields
+ ; toggle_box
+ ; toggle_colour
+ ; toggle_ancestor_limit
+ ; toggle_summarize
+ ; toggle_order_criteria
+ ; toggle_contour
+ ; toggle_time_format
+ ; toggle_inactive_modules
+ ; toggle_inactive_procs.
+
+:- func command_relevant_toggles(cmd) = list(toggle_kind).
+
+command_relevant_toggles(deep_cmd_quit) = [].
+command_relevant_toggles(deep_cmd_restart) = [].
+command_relevant_toggles(deep_cmd_timeout(_)) = [].
+command_relevant_toggles(deep_cmd_menu) = [].
+command_relevant_toggles(deep_cmd_root(_)) =
+ % The clique_ptr doesn't matter.
+ command_relevant_toggles(deep_cmd_clique(clique_ptr(1))).
+command_relevant_toggles(deep_cmd_clique(_)) =
+ [toggle_fields, toggle_box, toggle_colour, toggle_ancestor_limit,
+ toggle_summarize, toggle_order_criteria, toggle_time_format].
+command_relevant_toggles(deep_cmd_proc(_)) =
+ [toggle_fields, toggle_box, toggle_colour, toggle_summarize,
+ toggle_order_criteria, toggle_time_format].
+command_relevant_toggles(deep_cmd_proc_callers(_, _, _, _)) =
+ [toggle_fields, toggle_box, toggle_colour, toggle_order_criteria,
+ toggle_contour, toggle_time_format].
+command_relevant_toggles(deep_cmd_program_modules) =
+ [toggle_fields, toggle_box, toggle_colour, toggle_order_criteria,
+ toggle_time_format, toggle_inactive_modules].
+command_relevant_toggles(deep_cmd_module(_)) =
+ [toggle_fields, toggle_box, toggle_colour, toggle_order_criteria,
+ toggle_time_format, toggle_inactive_procs].
+command_relevant_toggles(deep_cmd_top_procs(_, _, _, _)) =
+ [toggle_fields, toggle_box, toggle_colour, toggle_time_format].
+command_relevant_toggles(deep_cmd_procrep_coverage(_)) = [].
+command_relevant_toggles(deep_cmd_dump_proc_static(_)) = [].
+command_relevant_toggles(deep_cmd_dump_proc_dynamic(_)) = [].
+command_relevant_toggles(deep_cmd_dump_call_site_static(_)) = [].
+command_relevant_toggles(deep_cmd_dump_call_site_dynamic(_)) = [].
+command_relevant_toggles(deep_cmd_dump_clique(_)) = [].
+
+:- func footer_field_toggle(cmd, preferences, deep) = string.
+
+footer_field_toggle(Cmd, Pref, Deep) = HTML :-
+ Fields = Pref ^ pref_fields,
+ ( Fields ^ port_fields = no_port ->
+ Port1Toggle = ""
+ ;
+ Port1Fields = Fields ^ port_fields := no_port,
+ Port1Pref = Pref ^ pref_fields := Port1Fields,
+ Port1Msg = "[No port counts]",
+ Port1Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Port1Pref, Deep, Cmd)), s(Port1Msg)])
+ ),
+ ( Fields ^ port_fields = port ->
+ Port2Toggle = ""
+ ;
+ Port2Fields = Fields ^ port_fields := port,
+ Port2Pref = Pref ^ pref_fields := Port2Fields,
+ Port2Msg = "[Port counts]",
+ Port2Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Port2Pref, Deep, Cmd)), s(Port2Msg)])
+ ),
+ ( Fields ^ time_fields = no_time ->
+ Time1Toggle = ""
+ ;
+ Time1Fields = Fields ^ time_fields := no_time,
+ Time1Pref = Pref ^ pref_fields := Time1Fields,
+ Time1Msg = "[No time info]",
+ Time1Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Time1Pref, Deep, Cmd)), s(Time1Msg)])
+ ),
+ ( Fields ^ time_fields = ticks ->
+ Time2Toggle = ""
+ ;
+ Time2Fields = Fields ^ time_fields := ticks,
+ Time2Pref = Pref ^ pref_fields := Time2Fields,
+ Time2Msg = "[Ticks]",
+ Time2Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Time2Pref, Deep, Cmd)), s(Time2Msg)])
+ ),
+ ( Fields ^ time_fields = time ->
+ Time3Toggle = ""
+ ;
+ Time3Fields = Fields ^ time_fields := time,
+ Time3Pref = Pref ^ pref_fields := Time3Fields,
+ Time3Msg = "[Times]",
+ Time3Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Time3Pref, Deep, Cmd)), s(Time3Msg)])
+ ),
+ ( Fields ^ time_fields = ticks_and_time->
+ Time4Toggle = ""
+ ;
+ Time4Fields = Fields ^ time_fields := ticks_and_time,
+ Time4Pref = Pref ^ pref_fields := Time4Fields,
+ Time4Msg = "[Ticks and times]",
+ Time4Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Time4Pref, Deep, Cmd)), s(Time4Msg)])
+ ),
+ ( Fields ^ time_fields = time_and_percall ->
+ Time5Toggle = ""
+ ;
+ Time5Fields = Fields ^ time_fields := time_and_percall,
+ Time5Pref = Pref ^ pref_fields := Time5Fields,
+ Time5Msg = "[Times and per-call times]",
+ Time5Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Time5Pref, Deep, Cmd)), s(Time5Msg)])
+ ),
+ ( Fields ^ time_fields = ticks_and_time_and_percall ->
+ Time6Toggle = ""
+ ;
+ Time6Fields = Fields ^ time_fields := ticks_and_time_and_percall,
+ Time6Pref = Pref ^ pref_fields := Time6Fields,
+ Time6Msg = "[Ticks and times and per-call times]",
+ Time6Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Time6Pref, Deep, Cmd)), s(Time6Msg)])
+ ),
+ ( Fields ^ callseqs_fields = no_callseqs ->
+ CallSeqs1Toggle = ""
+ ;
+ CallSeqs1Fields = Fields ^ callseqs_fields := no_callseqs,
+ CallSeqs1Pref = Pref ^ pref_fields := CallSeqs1Fields,
+ CallSeqs1Msg = "[No call sequence number info]",
+ CallSeqs1Toggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(CallSeqs1Pref, Deep, Cmd)),
+ s(CallSeqs1Msg)])
+ ),
+ ( Fields ^ callseqs_fields = callseqs ->
+ CallSeqs2Toggle = ""
+ ;
+ CallSeqs2Fields = Fields ^ callseqs_fields := callseqs,
+ CallSeqs2Pref = Pref ^ pref_fields := CallSeqs2Fields,
+ CallSeqs2Msg = "[Call sequence numbers]",
+ CallSeqs2Toggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(CallSeqs2Pref, Deep, Cmd)),
+ s(CallSeqs2Msg)])
+ ),
+ ( Fields ^ callseqs_fields = callseqs_and_percall ->
+ CallSeqs3Toggle = ""
+ ;
+ CallSeqs3Fields = Fields ^ callseqs_fields := callseqs_and_percall,
+ CallSeqs3Pref = Pref ^ pref_fields := CallSeqs3Fields,
+ CallSeqs3Msg = "[Call sequence numbers including per-call]",
+ CallSeqs3Toggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(CallSeqs3Pref, Deep, Cmd)),
+ s(CallSeqs3Msg)])
+ ),
+ ( Fields ^ alloc_fields = no_alloc ->
+ Alloc1Toggle = ""
+ ;
+ Alloc1Fields = Fields ^ alloc_fields := no_alloc,
+ Alloc1Pref = Pref ^ pref_fields := Alloc1Fields,
+ Alloc1Msg = "[No allocations]",
+ Alloc1Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Alloc1Pref, Deep, Cmd)), s(Alloc1Msg)])
+ ),
+ ( Fields ^ alloc_fields = alloc ->
+ Alloc2Toggle = ""
+ ;
+ Alloc2Fields = Fields ^ alloc_fields := alloc,
+ Alloc2Pref = Pref ^ pref_fields := Alloc2Fields,
+ Alloc2Msg = "[Allocations]",
+ Alloc2Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Alloc2Pref, Deep, Cmd)), s(Alloc2Msg)])
+ ),
+ ( Fields ^ alloc_fields = alloc_and_percall ->
+ Alloc3Toggle = ""
+ ;
+ Alloc3Fields = Fields ^ alloc_fields := alloc_and_percall,
+ Alloc3Pref = Pref ^ pref_fields := Alloc3Fields,
+ Alloc3Msg = "[Allocations and per-call allocations]",
+ Alloc3Toggle = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Alloc3Pref, Deep, Cmd)), s(Alloc3Msg)])
+ ),
+ ( Fields ^ memory_fields = no_memory ->
+ Memory1Toggle = ""
+ ;
+ Memory1Fields = Fields ^ memory_fields := no_memory,
+ Memory1Pref = Pref ^ pref_fields := Memory1Fields,
+ Memory1Msg = "[No memory info]",
+ Memory1Toggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Memory1Pref, Deep, Cmd)),
+ s(Memory1Msg)])
+ ),
+ ( Fields ^ memory_fields = memory(units_words) ->
+ Memory2Toggle = ""
+ ;
+ Memory2Fields = Fields ^ memory_fields := memory(units_words),
+ Memory2Pref = Pref ^ pref_fields := Memory2Fields,
+ Memory2Msg = "[Words]",
+ Memory2Toggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Memory2Pref, Deep, Cmd)),
+ s(Memory2Msg)])
+ ),
+ ( Fields ^ memory_fields = memory(units_bytes) ->
+ Memory3Toggle = ""
+ ;
+ Memory3Fields = Fields ^ memory_fields := memory(units_bytes),
+ Memory3Pref = Pref ^ pref_fields := Memory3Fields,
+ Memory3Msg = "[Bytes]",
+ Memory3Toggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Memory3Pref, Deep, Cmd)),
+ s(Memory3Msg)])
+ ),
+ ( Fields ^ memory_fields = memory_and_percall(units_words) ->
+ Memory4Toggle = ""
+ ;
+ Memory4Fields = Fields ^ memory_fields :=
+ memory_and_percall(units_words),
+ Memory4Pref = Pref ^ pref_fields := Memory4Fields,
+ Memory4Msg = "[Words and per-call words]",
+ Memory4Toggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Memory4Pref, Deep, Cmd)),
+ s(Memory4Msg)])
+ ),
+ ( Fields ^ memory_fields = memory_and_percall(units_bytes) ->
+ Memory5Toggle = ""
+ ;
+ Memory5Fields = Fields ^ memory_fields :=
+ memory_and_percall(units_bytes),
+ Memory5Pref = Pref ^ pref_fields := Memory5Fields,
+ Memory5Msg = "[Bytes and per-call bytes]",
+ Memory5Toggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Memory5Pref, Deep, Cmd)),
+ s(Memory5Msg)])
+ ),
+ ( Fields = default_fields(Deep) ->
+ DefaultToggle = ""
+ ;
+ DefaultMsg = "[Restore defaults]",
+ DefaultPref = Pref ^ pref_fields := default_fields(Deep),
+ DefaultToggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(DefaultPref, Deep, Cmd)),
+ s(DefaultMsg)])
+ ),
+ HTML =
+ "<strong>Toggle fields:</strong>\n" ++
+ DefaultToggle ++
+ "<br>\n" ++
+ Port1Toggle ++ Port2Toggle ++
+ "<br>\n" ++
+ Time1Toggle ++ Time2Toggle ++ Time3Toggle ++
+ Time4Toggle ++ Time5Toggle ++ Time6Toggle ++
+ "<br>\n" ++
+ CallSeqs1Toggle ++ CallSeqs2Toggle ++ CallSeqs3Toggle ++
+ "<br>\n" ++
+ Alloc1Toggle ++ Alloc2Toggle ++ Alloc3Toggle ++
+ "<br>\n" ++
+ Memory1Toggle ++ Memory2Toggle ++ Memory3Toggle ++
+ Memory4Toggle ++ Memory5Toggle ++
+ "<br>\n".
+
+:- func footer_ancestor_toggle(cmd, preferences, deep) = string.
+
+footer_ancestor_toggle(Cmd, Pref, Deep) = HTML :-
+ (
+ Pref ^ pref_anc = no,
+ Display1 = yes,
+ Display2 = yes,
+ Msg1 = "[One ancestor]",
+ Pref1 = Pref ^ pref_anc := yes(1),
+ Msg2 = "[Two ancestors]",
+ Pref2 = Pref ^ pref_anc := yes(2),
+ Msg3 = "[Three ancestors]",
+ Pref3 = Pref ^ pref_anc := yes(3),
+ Msg4 = "[Five ancestors]",
+ Pref4 = Pref ^ pref_anc := yes(5),
+ Msg5 = "[Ten ancestors]",
+ Pref5 = Pref ^ pref_anc := yes(10)
+ ;
+ Pref ^ pref_anc = yes(OldAncestorLimit),
+ ( OldAncestorLimit > 2 ->
+ Display1 = yes
+ ;
+ Display1 = no
+ ),
+ ( OldAncestorLimit > 1 ->
+ Display2 = yes
+ ;
+ Display2 = no
+ ),
+ Msg1 = "[Halve ancestors]",
+ Pref1 = Pref ^ pref_anc := yes(OldAncestorLimit // 2),
+ Msg2 = "[Remove an ancestor]",
+ Pref2 = Pref ^ pref_anc := yes(OldAncestorLimit - 1),
+ Msg3 = "[Add an ancestor]",
+ Pref3 = Pref ^ pref_anc := yes(OldAncestorLimit + 1),
+ Msg4 = "[Double ancestors]",
+ Pref4 = Pref ^ pref_anc := yes(OldAncestorLimit * 2),
+ Msg5 = "[Unlimited ancestors]",
+ Pref5 = Pref ^ pref_anc := no
+ ),
+ Toggle1 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]),
+ Toggle2 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref2, Deep, Cmd)), s(Msg2)]),
+ Toggle3 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref3, Deep, Cmd)), s(Msg3)]),
+ Toggle4 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref4, Deep, Cmd)), s(Msg4)]),
+ Toggle5 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref5, Deep, Cmd)), s(Msg5)]),
+ (
+ Display1 = yes,
+ MaybeToggle1 = Toggle1
+ ;
+ Display1 = no,
+ MaybeToggle1 = ""
+ ),
+ (
+ Display2 = yes,
+ MaybeToggle2 = Toggle2
+ ;
+ Display2 = no,
+ MaybeToggle2 = ""
+ ),
+ HTML =
+ "<strong>Toggle ancestors:</strong><br />\n" ++
+ MaybeToggle1 ++ MaybeToggle2 ++ Toggle3 ++ Toggle4 ++ Toggle5.
+
+:- func footer_box_toggle(cmd, preferences, deep) = string.
+
+footer_box_toggle(Cmd, Pref, Deep) = HTML :-
+ (
+ Pref ^ pref_box = do_not_box_tables,
+ Pref1 = Pref ^ pref_box := box_tables,
+ Msg1 = "[Box]"
+ ;
+ Pref ^ pref_box = box_tables,
+ Pref1 = Pref ^ pref_box := do_not_box_tables,
+ Msg1 = "[Unbox]"
+ ),
+ HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]).
+
+:- func footer_colour_toggle(cmd, preferences, deep) = string.
+
+footer_colour_toggle(Cmd, Pref, Deep) = HTML :-
+ (
+ Pref ^ pref_colour = do_not_colour_column_groups,
+ Pref1 = Pref ^ pref_colour := colour_column_groups,
+ Msg1 = "[Colour column groups]"
+ ;
+ Pref ^ pref_colour = colour_column_groups,
+ Pref1 = Pref ^ pref_colour := do_not_colour_column_groups,
+ Msg1 = "[Fade column groups]"
+ ),
+ HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]).
+
+:- func footer_summarize_toggle(cmd, preferences, deep) = string.
+
+footer_summarize_toggle(Cmd, Pref, Deep) = HTML :-
+ (
+ Pref ^ pref_summarize = summarize,
+ Pref1 = Pref ^ pref_summarize := do_not_summarize,
+ Msg1 = "[Expand higher order calls]"
+ ;
+ Pref ^ pref_summarize = do_not_summarize,
+ Pref1 = Pref ^ pref_summarize := summarize,
+ Msg1 = "[Summarize higher order calls]"
+ ),
+ HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]).
+
+:- func footer_contour_toggle(cmd, preferences, deep) = string.
+
+footer_contour_toggle(Cmd, Pref, Deep) = HTML :-
+ (
+ Pref ^ pref_contour = do_not_apply_contour_exclusion,
+ Pref1 = Pref ^ pref_contour := apply_contour_exclusion,
+ Msg1 = "[Apply contour exclusion]"
+ ;
+ Pref ^ pref_contour = apply_contour_exclusion,
+ Pref1 = Pref ^ pref_contour := do_not_apply_contour_exclusion,
+ Msg1 = "[Don't apply contour exclusion]"
+ ),
+ HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]).
+
+:- func footer_time_format_toggle(cmd, preferences, deep) = string.
+
+footer_time_format_toggle(Cmd, Pref, Deep) = HTML :-
+ TimeFields = Pref ^ pref_fields ^ time_fields,
+ (
+ ( TimeFields = no_time
+ ; TimeFields = ticks
+ ),
+ ToggleTimeFormat = no
+ ;
+ ( TimeFields = time
+ ; TimeFields = ticks_and_time
+ ; TimeFields = time_and_percall
+ ; TimeFields = ticks_and_time_and_percall
+ ),
+ ToggleTimeFormat = yes
+ ),
+ (
+ ToggleTimeFormat = no,
+ HTML = ""
+ ;
+ ToggleTimeFormat = yes,
+ (
+ Pref ^ pref_time = no_scale,
+ Pref1 = Pref ^ pref_time := scale_by_millions,
+ Msg1 = "[Time in s, us]",
+ Pref2 = Pref ^ pref_time := scale_by_thousands,
+ Msg2 = "[Time in s, ms, us, ns]"
+ ;
+ Pref ^ pref_time = scale_by_millions,
+ Pref1 = Pref ^ pref_time := no_scale,
+ Msg1 = "[Time in s]",
+ Pref2 = Pref ^ pref_time := scale_by_thousands,
+ Msg2 = "[Time in s, ms, us, ns]"
+ ;
+ Pref ^ pref_time = scale_by_thousands,
+ Pref1 = Pref ^ pref_time := no_scale,
+ Msg1 = "[Time in s]",
+ Pref2 = Pref ^ pref_time := scale_by_millions,
+ Msg2 = "[Time in s, us]"
+ ),
+ HTML =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref1, Deep, Cmd)), s(Msg1)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref2, Deep, Cmd)), s(Msg2)])
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- func footer_order_criteria_toggle(cmd, preferences, deep) = string.
+
+footer_order_criteria_toggle(Cmd, Pref, Deep) =
+ toggle_criteria(Pref ^ pref_criteria,
+ update_criteria_in_prefs(Pref, Deep, Cmd),
+ update_cost_criteria_in_prefs(Pref, Deep, Cmd)).
+
+toggle_cost_criteria_in_top_procs_cmd(Pref, Deep, Limit,
+ CostKind, InclDesc, Scope) =
+ toggle_cost_criteria(CostKind, InclDesc, Scope,
+ update_cost_criteria_in_top_procs_cmd(Pref, Deep, Limit)).
+
+%-----------------------------------------------------------------------------%
+
+:- type update_criteria_func == (func(order_criteria) = string).
+
+:- type update_cost_criteria_func ==
+ (func(cost_kind, include_descendants, measurement_scope) = string).
+
+:- func toggle_criteria(order_criteria,
+ update_criteria_func, update_cost_criteria_func) = string.
+
+toggle_criteria(Criteria, UpdateCriteria, UpdateCostCriteria) = HTML :-
+ (
+ Criteria = by_context,
+ Criteria1 = by_name,
+ Msg1 = "[Sort by name]",
+ Criteria2 =
+ by_cost(default_cost_kind, default_incl_desc, default_scope),
+ Msg2 = "[Sort by cost]"
+ ;
+ Criteria = by_name,
+ Criteria1 = by_context,
+ Msg1 = "[Sort by context]",
+ Criteria2 =
+ by_cost(default_cost_kind, default_incl_desc, default_scope),
+ Msg2 = "[Sort by cost]"
+ ;
+ Criteria = by_cost(_, _, _),
+ Criteria1 = by_context,
+ Msg1 = "[Sort by context]",
+ Criteria2 = by_name,
+ Msg2 = "[Sort by name]"
+ ),
+ Toggle1 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(Criteria1)), s(Msg1)]),
+ Toggle2 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(Criteria2)), s(Msg2)]),
+ (
+ Criteria = by_cost(CostKind, InclDesc, Scope),
+ ToggleRest = toggle_cost_criteria(CostKind, InclDesc, Scope,
+ UpdateCostCriteria)
+ ;
+ ( Criteria = by_context
+ ; Criteria = by_name
+ ),
+ ToggleRest = ""
+ ),
+ HTML = "<strong>Toggle ordering criteria:</strong><br />\n" ++
+ Toggle1 ++ Toggle2 ++ ToggleRest.
+
+:- func toggle_cost_criteria(cost_kind, include_descendants, measurement_scope,
+ update_cost_criteria_func) = string.
+
+toggle_cost_criteria(CostKind, InclDesc, Scope, UpdateCriteria) = Toggles :-
+ (
+ ( CostKind = cost_redos
+ ; CostKind = cost_time
+ ; CostKind = cost_callseqs
+ ; CostKind = cost_allocs
+ ; CostKind = cost_words
+ ),
+ MsgCalls = "[Sort by calls]",
+ ToggleCalls = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(cost_calls, InclDesc, Scope)), s(MsgCalls)])
+ ;
+ CostKind = cost_calls,
+ ToggleCalls = ""
+ ),
+ (
+ ( CostKind = cost_calls
+ ; CostKind = cost_time
+ ; CostKind = cost_callseqs
+ ; CostKind = cost_allocs
+ ; CostKind = cost_words
+ ),
+ MsgRedos = "[Sort by redos]",
+ ToggleRedos = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(cost_redos, InclDesc, Scope)), s(MsgRedos)])
+ ;
+ CostKind = cost_redos,
+ ToggleRedos = ""
+ ),
+ (
+ ( CostKind = cost_calls
+ ; CostKind = cost_redos
+ ; CostKind = cost_callseqs
+ ; CostKind = cost_allocs
+ ; CostKind = cost_words
+ ),
+ MsgTime = "[Sort by time]",
+ ToggleTime = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(cost_time, InclDesc, Scope)), s(MsgTime)])
+ ;
+ CostKind = cost_time,
+ ToggleTime = ""
+ ),
+ (
+ ( CostKind = cost_calls
+ ; CostKind = cost_redos
+ ; CostKind = cost_time
+ ; CostKind = cost_allocs
+ ; CostKind = cost_words
+ ),
+ MsgCallSeqs = "[Sort by call sequence numbers]",
+ ToggleCallSeqs =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(cost_callseqs, InclDesc, Scope)),
+ s(MsgCallSeqs)])
+ ;
+ CostKind = cost_callseqs,
+ ToggleCallSeqs = ""
+ ),
+ (
+ ( CostKind = cost_calls
+ ; CostKind = cost_redos
+ ; CostKind = cost_time
+ ; CostKind = cost_callseqs
+ ; CostKind = cost_words
+ ),
+ MsgAllocs = "[Sort by allocations]",
+ ToggleAllocs =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(cost_allocs, InclDesc, Scope)),
+ s(MsgAllocs)])
+ ;
+ CostKind = cost_allocs,
+ ToggleAllocs = ""
+ ),
+ (
+ ( CostKind = cost_calls
+ ; CostKind = cost_redos
+ ; CostKind = cost_time
+ ; CostKind = cost_callseqs
+ ; CostKind = cost_allocs
+ ),
+ MsgWords = "[Sort by words]",
+ ToggleWords = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(cost_words, InclDesc, Scope)), s(MsgWords)])
+ ;
+ CostKind = cost_words,
+ ToggleWords = ""
+ ),
+ (
+ InclDesc = self,
+ MsgDesc = "[Include descendants]",
+ ToggleDesc = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(CostKind, self_and_desc, Scope)), s(MsgDesc)])
+ ;
+ InclDesc = self_and_desc,
+ MsgDesc = "[Exclude descendants]",
+ ToggleDesc = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(CostKind, self, Scope)), s(MsgDesc)])
+ ),
+ (
+ Scope = per_call,
+ MsgScope = "[Count overall cost]",
+ ToggleScope = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(CostKind, InclDesc, overall)), s(MsgScope)])
+ ;
+ Scope = overall,
+ MsgScope = "[Count per-call cost]",
+ ToggleScope = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(UpdateCriteria(CostKind, InclDesc, per_call)), s(MsgScope)])
+ ),
+ Toggles = ToggleCalls ++ ToggleRedos ++ ToggleTime ++ ToggleCallSeqs ++
+ ToggleAllocs ++ ToggleWords ++
+ "\n<br>\n" ++ ToggleDesc ++ ToggleScope.
+
+%-----------------------------------------------------------------------------%
+%
+% Toggles to control showing/hiding inactive modules/procedures
+%
+
+:- func footer_inactive_modules_toggle(cmd, preferences, deep) = string.
+
+footer_inactive_modules_toggle(Cmd, Pref0, Deep) = HTML :-
+ Pref0 ^ pref_inactive = inactive_items(Procs, Modules),
+ (
+ Modules = inactive_show,
+ Msg = "[Hide inactive modules]",
+ Pref = Pref0 ^ pref_inactive := inactive_items(Procs, inactive_hide)
+ ;
+ Modules = inactive_hide,
+ Msg = "[Show inactive modules]",
+ Pref = Pref0 ^ pref_inactive := inactive_items(Procs, inactive_show)
+ ),
+ HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, Cmd)), s(Msg)]).
+
+:- func footer_inactive_procs_toggle(cmd, preferences, deep) = string.
+
+footer_inactive_procs_toggle(Cmd, Pref0, Deep) = HTML :-
+ Pref0 ^ pref_inactive = inactive_items(Procs, Modules),
+ (
+ Procs = inactive_show,
+ Msg = "[Hide inactive procedures]",
+ Pref = Pref0 ^ pref_inactive := inactive_items(inactive_hide, Modules)
+ ;
+ Procs = inactive_hide,
+ Msg = "[Show inactive procedures]",
+ Pref = Pref0 ^ pref_inactive := inactive_items(inactive_show, Modules)
+ ),
+ HTML = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, Cmd)), s(Msg)]).
+
+%-----------------------------------------------------------------------------%
+
+:- func update_criteria_in_prefs(preferences, deep, cmd, order_criteria)
+ = string.
+
+update_criteria_in_prefs(Pref0, Deep, Cmd, Criteria) = HTML :-
+ Pref = Pref0 ^ pref_criteria := Criteria,
+ HTML = deep_cmd_pref_to_url(Pref, Deep, Cmd).
+
+:- func update_cost_criteria_in_prefs(preferences, deep, cmd,
+ cost_kind, include_descendants, measurement_scope) = string.
+
+update_cost_criteria_in_prefs(Pref0, Deep, Cmd, CostKind, InclDesc, Scope)
+ = HTML :-
+ Pref = Pref0 ^ pref_criteria := by_cost(CostKind, InclDesc, Scope),
+ HTML = deep_cmd_pref_to_url(Pref, Deep, Cmd).
+
+:- func update_cost_criteria_in_top_procs_cmd(preferences, deep, display_limit,
+ cost_kind, include_descendants, measurement_scope) = string.
+
+update_cost_criteria_in_top_procs_cmd(Pref, Deep, Limit,
+ CostKind, InclDesc, Scope) = HTML :-
+ Cmd = deep_cmd_top_procs(Limit, CostKind, InclDesc, Scope),
+ HTML = deep_cmd_pref_to_url(Pref, Deep, Cmd).
+
+%-----------------------------------------------------------------------------%
+
+criteria_to_description(by_context) = "ordered by context".
+criteria_to_description(by_name) = "ordered by name".
+criteria_to_description(by_cost(CostKind, InclDesc, Scope)) =
+ cost_criteria_to_description(CostKind, InclDesc, Scope).
+
+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).
+
+:- 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".
+
+:- func incl_desc_to_description(include_descendants) = string.
+
+incl_desc_to_description(self) = "self".
+incl_desc_to_description(self_and_desc) = "total".
+
+:- func scope_to_description(measurement_scope) = string.
+
+scope_to_description(per_call) = "per call".
+scope_to_description(overall) = "overall".
+
+%-----------------------------------------------------------------------------%
+
+% The predicates banner_style, fields_header, table_width and
+% own_and_desc_to_html all make decisions about what columns each row
+% in the table will have. They therefore have similar control structures,
+% and a change in one may require changes in the others as well.
+
+fields_header(Pref, IdFields, TotalsDisp, WrapFunc) = HTML :-
+ Fields = Pref ^ pref_fields,
+ ProcName = WrapFunc("Procedure", by_name),
+ ModuleName = WrapFunc("Module", by_name),
+
+ some [!FirstRow, !SecondRow] (
+ (
+ IdFields = source_proc,
+ Source = WrapFunc("Source", by_context),
+ !:FirstRow =
+ "<TR>\n" ++
+ string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(Source)]) ++
+ string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(ProcName)])
+ ;
+ IdFields = rank_proc,
+ !:FirstRow =
+ "<TR>\n" ++
+ "<TH ALIGN=LEFT ROWSPAN=2>Rank\n" ++
+ string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(ProcName)])
+ ;
+ IdFields = rank_module,
+ !:FirstRow =
+ "<TR>\n" ++
+ "<TH ALIGN=LEFT ROWSPAN=2>Rank\n" ++
+ string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(ModuleName)])
+ ;
+ IdFields = proc,
+ !:FirstRow =
+ "<TR>\n" ++
+ string.format("<TH ALIGN=LEFT ROWSPAN=2>%s\n", [s(ProcName)])
+ ),
+ !:SecondRow = "<TR>\n",
+
+ ShowPortCounts = show_port_counts(Fields),
+ (
+ ShowPortCounts = yes,
+ Calls = WrapFunc("Calls", by_cost(cost_calls, self, overall)),
+ Redos = WrapFunc("Redos", by_cost(cost_redos, self, overall)),
+ !:FirstRow = !.FirstRow ++
+ "<TH COLSPAN=5>Port counts\n",
+ !:SecondRow = !.SecondRow ++
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(Calls)]) ++
+ "<TH ALIGN=RIGHT>Exits\n" ++
+ "<TH ALIGN=RIGHT>Fails\n" ++
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(Redos)]) ++
+ "<TH ALIGN=RIGHT>Excps\n"
+ ;
+ ShowPortCounts = no
+ ),
+
+ ShowQuanta = show_quanta(Fields),
+ (
+ ShowQuanta = yes,
+ TicksSelfOverall = WrapFunc("Self",
+ by_cost(cost_time, self, overall)),
+ TicksSelfHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(TicksSelfOverall)]),
+ TicksSelfFields = 1
+ ;
+ ShowQuanta = no,
+ TicksSelfHeading = "",
+ TicksSelfFields = 0
+ ),
+ ShowTimes = show_times(Fields),
+ (
+ ShowTimes = yes,
+ ( show_quanta(Fields) = yes ->
+ TimeSelfOverall = WrapFunc("Time",
+ by_cost(cost_time, self, overall))
+ ;
+ TimeSelfOverall = WrapFunc("Self",
+ by_cost(cost_time, self, overall))
+ ),
+ TimeSelfHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(TimeSelfOverall)]),
+ TimeSelfFields = 1
+ ;
+ ShowTimes = no,
+ TimeSelfHeading = "",
+ TimeSelfFields = 0
+ ),
+ ( ( ShowQuanta = yes ; ShowTimes = yes ) ->
+ TimeSelfPercentHeading = "<TH ALIGN=RIGHT>%\n",
+ TimeSelfPercentFields = 1
+ ;
+ TimeSelfPercentHeading = "",
+ TimeSelfPercentFields = 0
+ ),
+ ShowTimesPerCall = show_times_per_call(Fields),
+ (
+ ShowTimesPerCall = yes,
+ TimeSelfPerCall = WrapFunc("/call",
+ by_cost(cost_time, self, per_call)),
+ TimeSelfPerCallHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(TimeSelfPerCall)]),
+ TimeSelfPerCallFields = 1
+ ;
+ ShowTimesPerCall = no,
+ TimeSelfPerCallHeading = "",
+ TimeSelfPerCallFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowQuanta = yes ->
+ TicksTotalOverall = WrapFunc("Total",
+ by_cost(cost_time, self_and_desc, overall)),
+ TicksTotalHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(TicksTotalOverall)]),
+ TicksTotalFields = 1
+ ;
+ TicksTotalHeading = "",
+ TicksTotalFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowTimes = yes ->
+ ( show_quanta(Fields) = yes ->
+ TimeTotalOverall = WrapFunc("Time",
+ by_cost(cost_time, self_and_desc, overall))
+ ;
+ TimeTotalOverall = WrapFunc("Total",
+ by_cost(cost_time, self_and_desc, overall))
+ ),
+ TimeTotalHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(TimeTotalOverall)]),
+ TimeTotalFields = 1
+ ;
+ TimeTotalHeading = "",
+ TimeTotalFields = 0
+ ),
+ (
+ TotalsDisp = totals_meaningful,
+ ( ShowQuanta = yes ; ShowTimes = yes )
+ ->
+ TimeTotalPercentHeading = "<TH ALIGN=RIGHT>%\n",
+ TimeTotalPercentFields = 1
+ ;
+ TimeTotalPercentHeading = "",
+ TimeTotalPercentFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowTimesPerCall = yes ->
+ TimeTotalPerCall = WrapFunc("/call",
+ by_cost(cost_time, self_and_desc, per_call)),
+ TimeTotalPerCallHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(TimeTotalPerCall)]),
+ TimeTotalPerCallFields = 1
+ ;
+ TimeTotalPerCallHeading = "",
+ TimeTotalPerCallFields = 0
+ ),
+ TimeFields =
+ TicksSelfFields + TimeSelfFields +
+ TimeSelfPercentFields + TimeSelfPerCallFields +
+ TicksTotalFields + TimeTotalFields +
+ TimeTotalPercentFields + TimeTotalPerCallFields,
+ !:SecondRow = !.SecondRow ++
+ TicksSelfHeading ++ TimeSelfHeading ++
+ TimeSelfPercentHeading ++ TimeSelfPerCallHeading ++
+ TicksTotalHeading ++ TimeTotalHeading ++
+ TimeTotalPercentHeading ++ TimeTotalPerCallHeading,
+ (
+ ShowQuanta = yes,
+ ShowTimes = yes,
+ !:FirstRow = !.FirstRow ++
+ string.format("<TH COLSPAN=%d>Clock ticks and times\n",
+ [i(TimeFields)])
+ ;
+ ShowQuanta = yes,
+ ShowTimes = no,
+ !:FirstRow = !.FirstRow ++
+ string.format("<TH COLSPAN=%d>Clock ticks\n", [i(TimeFields)])
+ ;
+ ShowQuanta = no,
+ ShowTimes = yes,
+ !:FirstRow = !.FirstRow ++
+ string.format("<TH COLSPAN=%d>Time\n", [i(TimeFields)])
+ ;
+ ShowQuanta = no,
+ ShowTimes = no
+ ),
+
+ ShowCallSeqs = show_callseqs(Fields),
+ (
+ ShowCallSeqs = yes,
+ CallSeqsSelfOverall = WrapFunc("Self",
+ by_cost(cost_callseqs, self, overall)),
+ CallSeqsSelfHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n",
+ [s(CallSeqsSelfOverall)]) ++
+ "<TH ALIGN=RIGHT>%\n",
+ CallSeqsSelfFields = 2
+ ;
+ ShowCallSeqs = no,
+ CallSeqsSelfHeading = "",
+ CallSeqsSelfFields = 0
+ ),
+ ShowCallSeqsPerCall = show_callseqs_per_call(Fields),
+ (
+ ShowCallSeqsPerCall = yes,
+ CallSeqsSelfPerCall = WrapFunc("/call",
+ by_cost(cost_callseqs, self, per_call)),
+ CallSeqsSelfPerCallHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(CallSeqsSelfPerCall)]),
+ CallSeqsSelfPerCallFields = 1
+ ;
+ ShowCallSeqsPerCall = no,
+ CallSeqsSelfPerCallHeading = "",
+ CallSeqsSelfPerCallFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowCallSeqs = yes ->
+ CallSeqsTotalOverall = WrapFunc("Total",
+ by_cost(cost_callseqs, self_and_desc, overall)),
+ CallSeqsTotalHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n",
+ [s(CallSeqsTotalOverall)]) ++
+ "<TH ALIGN=RIGHT>%\n",
+ CallSeqsTotalFields = 2
+ ;
+ CallSeqsTotalHeading = "",
+ CallSeqsTotalFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowCallSeqsPerCall = yes ->
+ CallSeqsTotalPerCall = WrapFunc("/call",
+ by_cost(cost_callseqs, self_and_desc, per_call)),
+ CallSeqsTotalPerCallHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n",
+ [s(CallSeqsTotalPerCall)]),
+ CallSeqsTotalPerCallFields = 1
+ ;
+ CallSeqsTotalPerCallHeading = "",
+ CallSeqsTotalPerCallFields = 0
+ ),
+ CallSeqsFields =
+ CallSeqsSelfFields + CallSeqsSelfPerCallFields +
+ CallSeqsTotalFields + CallSeqsTotalPerCallFields,
+ !:SecondRow = !.SecondRow ++
+ CallSeqsSelfHeading ++ CallSeqsSelfPerCallHeading ++
+ CallSeqsTotalHeading ++ CallSeqsTotalPerCallHeading,
+ (
+ ShowCallSeqs = yes,
+ !:FirstRow = !.FirstRow ++
+ string.format("<TH COLSPAN=%d>Call sequence numbers\n",
+ [i(CallSeqsFields)])
+ ;
+ ShowCallSeqs = no
+ ),
+
+ ShowAlloc = show_alloc(Fields),
+ (
+ ShowAlloc = yes,
+ AllocsSelfOverall = WrapFunc("Self",
+ by_cost(cost_allocs, self, overall)),
+ AllocsSelfHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n",
+ [s(AllocsSelfOverall)]) ++
+ "<TH ALIGN=RIGHT>%\n",
+ AllocsSelfFields = 2
+ ;
+ ShowAlloc = no,
+ AllocsSelfHeading = "",
+ AllocsSelfFields = 0
+ ),
+ ShowAllocPerCall = show_alloc_per_call(Fields),
+ (
+ ShowAllocPerCall = yes,
+ AllocsSelfPerCall = WrapFunc("/call",
+ by_cost(cost_allocs, self, per_call)),
+ AllocsSelfPerCallHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(AllocsSelfPerCall)]),
+ AllocsSelfPerCallFields = 1
+ ;
+ ShowAllocPerCall = no,
+ AllocsSelfPerCallHeading = "",
+ AllocsSelfPerCallFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowAlloc = yes ->
+ AllocsTotalOverall = WrapFunc("Total",
+ by_cost(cost_allocs, self_and_desc, overall)),
+ AllocsTotalHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n",
+ [s(AllocsTotalOverall)]) ++
+ "<TH ALIGN=RIGHT>%\n",
+ AllocsTotalFields = 2
+ ;
+ AllocsTotalHeading = "",
+ AllocsTotalFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowAllocPerCall = yes ->
+ AllocsTotalPerCall = WrapFunc("/call",
+ by_cost(cost_allocs, self_and_desc, per_call)),
+ AllocsTotalPerCallHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(AllocsTotalPerCall)]),
+ AllocsTotalPerCallFields = 1
+ ;
+ AllocsTotalPerCallHeading = "",
+ AllocsTotalPerCallFields = 0
+ ),
+ AllocsFields =
+ AllocsSelfFields + AllocsSelfPerCallFields +
+ AllocsTotalFields + AllocsTotalPerCallFields,
+ !:SecondRow = !.SecondRow ++
+ AllocsSelfHeading ++ AllocsSelfPerCallHeading ++
+ AllocsTotalHeading ++ AllocsTotalPerCallHeading,
+ (
+ ShowAlloc = yes,
+ !:FirstRow = !.FirstRow ++
+ string.format("<TH COLSPAN=%d>Memory allocations\n",
+ [i(AllocsFields)])
+ ;
+ ShowAlloc = no
+ ),
+
+ ShowMemory = show_memory(Fields),
+ (
+ ShowMemory = yes(_),
+ MemorySelfOverall = WrapFunc("Self",
+ by_cost(cost_words, self, overall)),
+ MemorySelfHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n",
+ [s(MemorySelfOverall)]) ++
+ "<TH ALIGN=RIGHT>%\n",
+ MemorySelfFields = 2
+ ;
+ ShowMemory = no,
+ MemorySelfHeading = "",
+ MemorySelfFields = 0
+ ),
+ ShowMemoryPerCall = show_memory_per_call(Fields),
+ (
+ ShowMemoryPerCall = yes(_),
+ MemorySelfPerCall = WrapFunc("/call",
+ by_cost(cost_words, self, per_call)),
+ MemorySelfPerCallHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(MemorySelfPerCall)]),
+ MemorySelfPerCallFields = 1
+ ;
+ ShowMemoryPerCall = no,
+ MemorySelfPerCallHeading = "",
+ MemorySelfPerCallFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowMemory = yes(_) ->
+ MemoryTotalOverall = WrapFunc("Total",
+ by_cost(cost_words, self_and_desc, overall)),
+ MemoryTotalHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n",
+ [s(MemoryTotalOverall)]) ++
+ "<TH ALIGN=RIGHT>%\n",
+ MemoryTotalFields = 2
+ ;
+ MemoryTotalHeading = "",
+ MemoryTotalFields = 0
+ ),
+ ( TotalsDisp = totals_meaningful, ShowMemoryPerCall = yes(_) ->
+ MemoryTotalPerCall = WrapFunc("/call",
+ by_cost(cost_words, self_and_desc, per_call)),
+ MemoryTotalPerCallHeading =
+ string.format("<TH ALIGN=RIGHT>%s\n", [s(MemoryTotalPerCall)]),
+ MemoryTotalPerCallFields = 1
+ ;
+ MemoryTotalPerCallHeading = "",
+ MemoryTotalPerCallFields = 0
+ ),
+ MemoryFields =
+ MemorySelfFields + MemorySelfPerCallFields +
+ MemoryTotalFields + MemoryTotalPerCallFields,
+ !:SecondRow = !.SecondRow ++
+ MemorySelfHeading ++ MemorySelfPerCallHeading ++
+ MemoryTotalHeading ++ MemoryTotalPerCallHeading,
+ (
+ ShowMemory = yes(Units),
+ (
+ Units = units_words,
+ !:FirstRow = !.FirstRow ++
+ string.format("<TH COLSPAN=%d>Memory words\n",
+ [i(MemoryFields)])
+ ;
+ Units = units_bytes,
+ !:FirstRow = !.FirstRow ++
+ string.format("<TH COLSPAN=%d>Memory bytes\n",
+ [i(MemoryFields)])
+ )
+ ;
+ ShowMemory = no
+ ),
+ HTML =
+ "<THEAD>\n" ++
+ !.FirstRow ++
+ !.SecondRow ++
+ "<TBODY>\n" ++
+ separator_row(Pref, IdFields, TotalsDisp)
+ ).
+
+%-----------------------------------------------------------------------------%
+
+header_row(Heading, Pref, IdFields, TotalsDisp) = Separator :-
+ Separator = string.format("<TR><TD COLSPAN=%d>%s</TD></TR>\n",
+ [i(table_width(Pref, IdFields, TotalsDisp)), s(Heading)]).
+
+separator_row(Pref, IdFields, TotalsDisp) = Separator :-
+ Separator = string.format("<TR><TD COLSPAN=%d></TD></TR>\n",
+ [i(table_width(Pref, IdFields, TotalsDisp))]).
+
+:- func table_width(preferences, id_fields, totals_disposition) = int.
+
+table_width(Pref, IdFields, TotalsDisp) = Width :-
+ Fields = Pref ^ pref_fields,
+ (
+ IdFields = source_proc,
+ Id = 2
+ ;
+ IdFields = rank_module,
+ Id = 2
+ ;
+ IdFields = rank_proc,
+ Id = 2
+ ;
+ IdFields = proc,
+ Id = 1
+ ),
+ (
+ Fields ^ port_fields = no_port,
+ Port = 0
+ ;
+ Fields ^ port_fields = port,
+ Port = 5
+ ),
+ (
+ Fields ^ time_fields = no_time,
+ Time = 0
+ ;
+ Fields ^ time_fields = ticks,
+ Time = 2
+ ;
+ Fields ^ time_fields = time,
+ Time = 2
+ ;
+ Fields ^ time_fields = ticks_and_time,
+ Time = 3
+ ;
+ Fields ^ time_fields = time_and_percall,
+ Time = 3
+ ;
+ Fields ^ time_fields = ticks_and_time_and_percall,
+ Time = 4
+ ),
+ (
+ Fields ^ callseqs_fields = no_callseqs,
+ CallSeqs = 0
+ ;
+ Fields ^ callseqs_fields = callseqs,
+ CallSeqs = 2
+ ;
+ Fields ^ callseqs_fields = callseqs_and_percall,
+ CallSeqs = 3
+ ),
+ (
+ Fields ^ alloc_fields = no_alloc,
+ Alloc = 0
+ ;
+ Fields ^ alloc_fields = alloc,
+ Alloc = 2
+ ;
+ Fields ^ alloc_fields = alloc_and_percall,
+ Alloc = 3
+ ),
+ (
+ Fields ^ memory_fields = no_memory,
+ Memory = 0
+ ;
+ Fields ^ memory_fields = memory(_),
+ Memory = 2
+ ;
+ Fields ^ memory_fields = memory_and_percall(_),
+ Memory = 3
+ ),
+ (
+ TotalsDisp = totals_meaningful,
+ Width = Id + Port + Time * 2 + CallSeqs * 2 + Alloc * 2 + Memory * 2
+ ;
+ TotalsDisp = totals_not_meaningful,
+ Width = Id + Port + Time + CallSeqs + Alloc + Memory
+ ).
+
+%-----------------------------------------------------------------------------%
+
+add_context(Context, LineGroup0) = LineGroup :-
+ LineGroup0 =
+ line_group(FileName, LineNumber, Name, Own, Desc, HTML0, LaterLines),
+ HTML = string.format("<TD CLASS=id>%s</TD>%s",
+ [s(Context), s(HTML0)]),
+ LineGroup =
+ line_group(FileName, LineNumber, Name, Own, Desc, HTML, LaterLines).
+
+add_self_context(LineGroup0) = LineGroup :-
+ LineGroup0 =
+ line_group(FileName, LineNumber, Name, Own, Desc, HTML0, LaterLines),
+ HTML = string.format("<TD CLASS=id>%s:%d</TD>%s",
+ [s(FileName), i(LineNumber), s(HTML0)]),
+ LineGroup =
+ line_group(FileName, LineNumber, Name, Own, Desc, HTML, LaterLines).
+
+add_ranks(LineGroups0) = add_ranks_2(1, LineGroups0).
+
+:- func add_ranks_2(int, list(line_group(one_id, LL)))
+ = list(line_group(two_id, LL)).
+
+add_ranks_2(_Rank, []) = [].
+add_ranks_2(Rank, [LineGroup0 | LineGroups0]) = [LineGroup | LineGroups] :-
+ LineGroup0 =
+ line_group(FileName, LineNumber, Name, Own, Desc, HTML0, LaterLines),
+ HTML = string.format("<TD CLASS=id>%d</TD>%s", [i(Rank), s(HTML0)]),
+ LineGroup =
+ line_group(FileName, LineNumber, Name, Own, Desc, HTML, LaterLines),
+ LineGroups = add_ranks_2(Rank + 1, LineGroups0).
+
+line_to_one_id_subline_group(LineGroup0) = LineGroup :-
+ LineGroup0 =
+ line_group(FileName, LineNumber, Name, Own, Desc, HTML, unit),
+ LineGroup =
+ line_group(FileName, LineNumber, Name, Own, Desc, HTML,
+ sub_lines(one_id, [])).
+
+line_to_two_id_subline_group(LineGroup0) = LineGroup :-
+ LineGroup0 = line_group(FileName, LineNumber, Name, Own, Desc,
+ HTML, unit),
+ LineGroup = line_group(FileName, LineNumber, Name, Own, Desc,
+ HTML, sub_lines(two_id, [])).
+
+%-----------------------------------------------------------------------------%
+
+one_id_line_to_html(Pref, Deep, TotalsDisp, LineGroup) =
+ "<TR>\n" ++
+ LineGroup ^ group_first_line_id ++
+ own_and_desc_to_html(LineGroup ^ group_own, LineGroup ^ group_desc,
+ Pref, Deep, TotalsDisp) ++
+ "</TR>\n".
+
+one_id_line_group_to_html(Pref, Deep, TotalsDisp, LineGroup) =
+ "<TR>\n" ++
+ LineGroup ^ group_first_line_id ++
+ own_and_desc_to_html(LineGroup ^ group_own, LineGroup ^ group_desc,
+ Pref, Deep, TotalsDisp) ++
+ "</TR>\n" ++
+ string.append_list(
+ list.map(one_id_line_to_html(Pref, Deep, TotalsDisp),
+ LineGroup ^ group_later_lines ^ sub_line_list)).
+
+two_id_line_to_html(Pref, Deep, TotalsDisp, LineGroup) =
+ "<TR>\n" ++
+ LineGroup ^ group_first_line_id ++
+ own_and_desc_to_html(LineGroup ^ group_own, LineGroup ^ group_desc,
+ Pref, Deep, TotalsDisp) ++
+ "</TR>\n".
+
+two_id_line_group_to_html(Pref, Deep, TotalsDisp, LineGroup) =
+ "<TR>\n" ++
+ LineGroup ^ group_first_line_id ++
+ own_and_desc_to_html(LineGroup ^ group_own, LineGroup ^ group_desc,
+ Pref, Deep, TotalsDisp) ++
+ "</TR>\n" ++
+ string.append_list(
+ list.map(two_id_line_to_html(Pref, Deep, TotalsDisp),
+ LineGroup ^ group_later_lines ^ sub_line_list)).
+
+%-----------------------------------------------------------------------------%
+
+own_and_desc_to_html(Own, Desc, Pref, Deep, TotalsDisp) = HTML :-
+ add_own_to_inherit(Own, Desc) = OwnPlusDesc,
+ Root = root_total_info(Deep),
+ Calls = calls(Own),
+ Exits = exits(Own),
+ Fails = fails(Own),
+ Redos = redos(Own),
+ Excps = excps(Own),
+
+ OwnQuanta = quanta(Own),
+ TotalQuanta = inherit_quanta(OwnPlusDesc),
+ RootQuanta = inherit_quanta(Root),
+ OwnQuantaProp = percentage(OwnQuanta, RootQuanta),
+ TotalQuantaProp = percentage(TotalQuanta, RootQuanta),
+
+ OwnCallSeqs = callseqs(Own),
+ TotalCallSeqs = inherit_callseqs(OwnPlusDesc),
+ RootCallSeqs = inherit_callseqs(Root),
+ OwnCallSeqsProp = percentage(OwnCallSeqs, RootCallSeqs),
+ TotalCallSeqsProp = percentage(TotalCallSeqs, RootCallSeqs),
+
+ OwnAllocs = allocs(Own),
+ TotalAllocs = inherit_allocs(OwnPlusDesc),
+ RootAllocs = inherit_allocs(Root),
+ OwnAllocProp = percentage(OwnAllocs, RootAllocs),
+ TotalAllocProp = percentage(TotalAllocs, RootAllocs),
+
+ OwnWords = words(Own),
+ TotalWords = inherit_words(OwnPlusDesc),
+ RootWords = inherit_words(Root),
+ OwnMemoryProp = percentage(OwnWords, RootWords),
+ TotalMemoryProp = percentage(TotalWords, RootWords),
+
+ Fields = Pref ^ pref_fields,
+
+ ShowPortCounts = show_port_counts(Fields),
+ (
+ ShowPortCounts = yes,
+ PortHTML =
+ string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(Calls))]) ++
+ string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(Exits))]) ++
+ string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(Fails))]) ++
+ string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(Redos))]) ++
+ string.format("<TD CLASS=port ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(Excps))])
+ ;
+ ShowPortCounts = no,
+ PortHTML = ""
+ ),
+
+ ShowQuanta = show_quanta(Fields),
+ (
+ ShowQuanta = yes,
+ QuantaSelfHTML =
+ string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(OwnQuanta))]),
+ QuantaTotalHTML =
+ string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(TotalQuanta))])
+ ;
+ ShowQuanta = no,
+ QuantaSelfHTML = "",
+ QuantaTotalHTML = ""
+ ),
+ ShowTimes = show_times(Fields),
+ (
+ ShowTimes = yes,
+ TimeSelfHTML =
+ string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
+ [s(overall_time(Pref, Deep, OwnQuanta))]),
+ TimeTotalHTML =
+ string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
+ [s(overall_time(Pref, Deep, TotalQuanta))])
+ ;
+ ShowTimes = no,
+ TimeSelfHTML = "",
+ TimeTotalHTML = ""
+ ),
+ ShowTimeFraction = bool.or(ShowQuanta, ShowTimes),
+ (
+ ShowTimeFraction = yes,
+ QuantaPropSelfHTML =
+ string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
+ [s(OwnQuantaProp)]),
+ QuantaPropTotalHTML =
+ string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
+ [s(TotalQuantaProp)])
+ ;
+ ShowTimeFraction = no,
+ QuantaPropSelfHTML = "",
+ QuantaPropTotalHTML = ""
+ ),
+ ShowTimesPerCall = show_times_per_call(Fields),
+ (
+ ShowTimesPerCall = yes,
+ TimePerCallSelfHTML =
+ string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
+ [s(per_call_time(Pref, Deep, OwnQuanta, Calls))]),
+ TimePerCallTotalHTML =
+ string.format("<TD CLASS=time ALIGN=RIGHT>%s</TD>\n",
+ [s(per_call_time(Pref, Deep, TotalQuanta, Calls))])
+ ;
+ ShowTimesPerCall = no,
+ TimePerCallSelfHTML = "",
+ TimePerCallTotalHTML = ""
+ ),
+
+ ShowCallSeqs = show_callseqs(Fields),
+ (
+ ShowCallSeqs = yes,
+ CallSeqsSelfHTML =
+ string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(OwnCallSeqs))]),
+ CallSeqsTotalHTML =
+ string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(TotalCallSeqs))]),
+ CallSeqsPropSelfHTML =
+ string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
+ [s(OwnCallSeqsProp)]),
+ CallSeqsPropTotalHTML =
+ string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
+ [s(TotalCallSeqsProp)])
+ ;
+ ShowCallSeqs = no,
+ CallSeqsSelfHTML = "",
+ CallSeqsTotalHTML = "",
+ CallSeqsPropSelfHTML = "",
+ CallSeqsPropTotalHTML = ""
+ ),
+ ShowCallSeqsPerCall = show_callseqs_per_call(Fields),
+ (
+ ShowCallSeqsPerCall = yes,
+ ( Calls = 0 ->
+ OwnCallSeqsPerCall = "N/A",
+ TotalCallSeqsPerCall = "N/A"
+ ;
+ OwnCallSeqsPerCall =
+ one_decimal_fraction(float(OwnCallSeqs) / float(Calls)),
+ TotalCallSeqsPerCall =
+ one_decimal_fraction(float(TotalCallSeqs) / float(Calls))
+ ),
+ CallSeqsPerCallSelfHTML =
+ string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
+ [s(OwnCallSeqsPerCall)]),
+ CallSeqsPerCallTotalHTML =
+ string.format("<TD CLASS=callseqs ALIGN=RIGHT>%s</TD>\n",
+ [s(TotalCallSeqsPerCall)])
+ ;
+ ShowCallSeqsPerCall = no,
+ CallSeqsPerCallSelfHTML = "",
+ CallSeqsPerCallTotalHTML = ""
+ ),
+
+ ShowAlloc = show_alloc(Fields),
+ (
+ ShowAlloc = yes,
+ AllocSelfHTML =
+ string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(OwnAllocs))]) ++
+ string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
+ [s(OwnAllocProp)]),
+ AllocTotalHTML =
+ string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(TotalAllocs))]) ++
+ string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
+ [s(TotalAllocProp)])
+ ;
+ ShowAlloc = no,
+ AllocSelfHTML = "",
+ AllocTotalHTML = ""
+ ),
+ ShowAllocPerCall = show_alloc_per_call(Fields),
+ (
+ ShowAllocPerCall = yes,
+ AllocPerCallSelfHTML =
+ string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
+ [s(count_per_call(OwnAllocs, Calls))]),
+ AllocPerCallTotalHTML =
+ string.format("<TD CLASS=alloc ALIGN=RIGHT>%s</TD>\n",
+ [s(count_per_call(TotalAllocs, Calls))])
+ ;
+ ShowAllocPerCall = no,
+ AllocPerCallSelfHTML = "",
+ AllocPerCallTotalHTML = ""
+ ),
+
+ ShowMemory = show_memory(Fields),
+ (
+ ShowMemory = yes(Unit),
+ (
+ Unit = units_words,
+ OwnMemory = OwnWords,
+ TotalMemory = TotalWords
+ ;
+ Unit = units_bytes,
+ WordSize = Deep ^ profile_stats ^ word_size,
+ OwnMemory = OwnWords * WordSize,
+ TotalMemory = TotalWords * WordSize
+ )
+ ;
+ ShowMemory = no,
+ % These values won't be used.
+ OwnMemory = 0,
+ TotalMemory = 0
+ ),
+ (
+ ShowMemory = yes(_),
+ MemorySelfHTML =
+ string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(OwnMemory))]) ++
+ string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
+ [s(OwnMemoryProp)]),
+ MemoryTotalHTML =
+ string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
+ [s(commas(TotalMemory))]) ++
+ string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
+ [s(TotalMemoryProp)])
+ ;
+ ShowMemory = no,
+ MemorySelfHTML = "",
+ MemoryTotalHTML = ""
+ ),
+ ShowMemoryPerCall = show_memory_per_call(Fields),
+ (
+ ShowMemoryPerCall = yes(_),
+ MemoryPerCallSelfHTML =
+ string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
+ [s(count_per_call(OwnMemory, Calls))]),
+ MemoryPerCallTotalHTML =
+ string.format("<TD CLASS=memory ALIGN=RIGHT>%s</TD>\n",
+ [s(count_per_call(TotalMemory, Calls))])
+ ;
+ ShowMemoryPerCall = no,
+ MemoryPerCallSelfHTML = "",
+ MemoryPerCallTotalHTML = ""
+ ),
+
+ (
+ TotalsDisp = totals_meaningful,
+ HTML =
+ PortHTML ++
+
+ QuantaSelfHTML ++
+ TimeSelfHTML ++
+ QuantaPropSelfHTML ++
+ TimePerCallSelfHTML ++
+ QuantaTotalHTML ++
+ TimeTotalHTML ++
+ QuantaPropTotalHTML ++
+ TimePerCallTotalHTML ++
+
+ CallSeqsSelfHTML ++
+ CallSeqsPropSelfHTML ++
+ CallSeqsPerCallSelfHTML ++
+ CallSeqsTotalHTML ++
+ CallSeqsPropTotalHTML ++
+ CallSeqsPerCallTotalHTML ++
+
+ AllocSelfHTML ++
+ AllocPerCallSelfHTML ++
+ AllocTotalHTML ++
+ AllocPerCallTotalHTML ++
+
+ MemorySelfHTML ++
+ MemoryPerCallSelfHTML ++
+ MemoryTotalHTML ++
+ MemoryPerCallTotalHTML
+ ;
+ TotalsDisp = totals_not_meaningful,
+ HTML =
+ PortHTML ++
+
+ QuantaSelfHTML ++
+ TimeSelfHTML ++
+ QuantaPropSelfHTML ++
+ TimePerCallSelfHTML ++
+
+ CallSeqsSelfHTML ++
+ CallSeqsPropSelfHTML ++
+ CallSeqsPerCallSelfHTML ++
+
+ AllocSelfHTML ++
+ AllocPerCallSelfHTML ++
+
+ MemorySelfHTML ++
+ MemoryPerCallSelfHTML
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- func overall_time(preferences, deep, int) = string.
+
+overall_time(Pref, Deep, Quanta) = TimeStr :-
+ lookup_ticks_per_sec(Deep ^ profile_stats, TicksPerSec, _Assumed),
+ % We display Time as seconds, with two digits after the decimal point.
+ % This is the most we can do, given clock granularity.
+ Time = float(Quanta) / float(TicksPerSec),
+ TimeStr = format_time(Pref, Time).
+
+:- func per_call_time(preferences, deep, int, int) = string.
+
+per_call_time(Pref, Deep, Quanta, Calls) = TimeStr :-
+ lookup_ticks_per_sec(Deep ^ profile_stats, TicksPerSec, _Assumed),
+ % We display Time as seconds, with two digits after the decimal point.
+ % This is the most we can do, given clock granularity.
+ Time = float(Quanta) / float(TicksPerSec),
+ ( Calls \= 0 ->
+ TimePerCall = Time / float(Calls)
+ ;
+ TimePerCall = 0.0
+ ),
+ TimeStr = format_time(Pref, TimePerCall).
+
+:- func format_time(preferences, float) = string.
+
+format_time(Pref, Time) = TimeStr :-
+ (
+ Pref ^ pref_time = no_scale,
+ TimeStr0 = four_decimal_fraction(Time),
+ Unit = "s"
+ ;
+ Pref ^ pref_time = scale_by_millions,
+ ( Time >= 0.001 ->
+ ScaledTime = Time,
+ Unit = "s"
+ ;
+ ScaledTime = 1000000.0 * Time,
+ Unit = "us"
+ ),
+ TimeStr0 = four_decimal_fraction(ScaledTime)
+ ;
+ Pref ^ pref_time = scale_by_thousands,
+ ( Time >= 1.0 ->
+ ScaledTime = Time,
+ Unit = "s"
+ ; Time >= 0.001 ->
+ ScaledTime = 1000.0 * Time,
+ Unit = "ms"
+ ; Time >= 0.000001 ->
+ ScaledTime = 1000000.0 * Time,
+ Unit = "us"
+ ;
+ ScaledTime = 1000000000.0 * Time,
+ Unit = "ns"
+ ),
+ TimeStr0 = two_decimal_fraction(ScaledTime)
+ ),
+ TimeStr = TimeStr0 ++ Unit.
+
+:- func percentage(int, int) = string.
+
+percentage(Fraction, Whole) = PercentageStr :-
+ ( Whole = 0 ->
+ PercentageStr = "N/A"
+ ;
+ Percentage = 100.0 * float(Fraction) / float(Whole),
+ PercentageStr = string.format("%5.2f", [f(Percentage)])
+ ).
+
+lookup_ticks_per_sec(Stats, TicksPerSec, Assumed) :-
+ TicksPerSec0 = Stats ^ ticks_per_sec,
+ ( TicksPerSec0 = 0 ->
+ TicksPerSec = default_ticks_per_sec,
+ Assumed = yes
+ ;
+ TicksPerSec = TicksPerSec0,
+ Assumed = no
+ ).
+
+ % The number of ticks per sec to assume if the profiling data file does
+ % not record the actual tick rate.
+ %
+:- func default_ticks_per_sec = int.
+
+default_ticks_per_sec = 100.
+
+%-----------------------------------------------------------------------------%
+
+:- func count_per_call(int, int) = string.
+
+count_per_call(Count, Calls) =
+ ( Calls = 0 ->
+ two_decimal_fraction(0.0)
+ ;
+ two_decimal_fraction(float(Count) / float(Calls))
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- func show_port_counts(fields) = bool.
+
+show_port_counts(Fields) = ShowPorts :-
+ PortFields = Fields ^ port_fields,
+ ( PortFields = no_port, ShowPorts = no
+ ; PortFields = port, ShowPorts = yes
+ ).
+
+:- func show_quanta(fields) = bool.
+
+show_quanta(Fields) = ShowQuanta :-
+ TimeFields = Fields ^ time_fields,
+ ( TimeFields = no_time, ShowQuanta = no
+ ; TimeFields = ticks, ShowQuanta = yes
+ ; TimeFields = time, ShowQuanta = no
+ ; TimeFields = ticks_and_time, ShowQuanta = yes
+ ; TimeFields = time_and_percall, ShowQuanta = no
+ ; TimeFields = ticks_and_time_and_percall, ShowQuanta = yes
+ ).
+
+:- func show_times(fields) = bool.
+
+show_times(Fields) = ShowTimes :-
+ TimeFields = Fields ^ time_fields,
+ ( TimeFields = no_time, ShowTimes = no
+ ; TimeFields = ticks, ShowTimes = no
+ ; TimeFields = time, ShowTimes = yes
+ ; TimeFields = ticks_and_time, ShowTimes = yes
+ ; TimeFields = time_and_percall, ShowTimes = yes
+ ; TimeFields = ticks_and_time_and_percall, ShowTimes = yes
+ ).
+
+:- func show_times_per_call(fields) = bool.
+
+show_times_per_call(Fields) = ShowTimesPerCall :-
+ TimeFields = Fields ^ time_fields,
+ ( TimeFields = no_time, ShowTimesPerCall = no
+ ; TimeFields = ticks, ShowTimesPerCall = no
+ ; TimeFields = time, ShowTimesPerCall = no
+ ; TimeFields = ticks_and_time, ShowTimesPerCall = no
+ ; TimeFields = time_and_percall, ShowTimesPerCall = yes
+ ; TimeFields = ticks_and_time_and_percall, ShowTimesPerCall = yes
+ ).
+
+:- func show_callseqs(fields) = bool.
+
+show_callseqs(Fields) = ShowCallSeqs :-
+ CallSeqsField = Fields ^ callseqs_fields,
+ ( CallSeqsField = no_callseqs, ShowCallSeqs = no
+ ; CallSeqsField = callseqs, ShowCallSeqs = yes
+ ; CallSeqsField = callseqs_and_percall, ShowCallSeqs = yes
+ ).
+
+:- func show_callseqs_per_call(fields) = bool.
+
+show_callseqs_per_call(Fields) = ShowCallSeqsPerCall :-
+ CallSeqsField = Fields ^ callseqs_fields,
+ ( CallSeqsField = no_callseqs, ShowCallSeqsPerCall = no
+ ; CallSeqsField = callseqs, ShowCallSeqsPerCall = no
+ ; CallSeqsField = callseqs_and_percall, ShowCallSeqsPerCall = yes
+ ).
+
+:- func show_alloc(fields) = bool.
+
+show_alloc(Fields) = ShowAlloc :-
+ AllocFields = Fields ^ alloc_fields,
+ ( AllocFields = no_alloc, ShowAlloc = no
+ ; AllocFields = alloc, ShowAlloc = yes
+ ; AllocFields = alloc_and_percall, ShowAlloc = yes
+ ).
+
+:- func show_alloc_per_call(fields) = bool.
+
+show_alloc_per_call(Fields) = ShowPerAlloc :-
+ AllocFields = Fields ^ alloc_fields,
+ ( AllocFields = no_alloc, ShowPerAlloc = no
+ ; AllocFields = alloc, ShowPerAlloc = no
+ ; AllocFields = alloc_and_percall, ShowPerAlloc = yes
+ ).
+
+:- func show_memory(fields) = maybe(memory_units).
+
+show_memory(Fields) = ShowMemory :-
+ MemoryFields = Fields ^ memory_fields,
+ ( MemoryFields = no_memory, ShowMemory = no
+ ; MemoryFields = memory(Unit), ShowMemory = yes(Unit)
+ ; MemoryFields = memory_and_percall(Unit), ShowMemory = yes(Unit)
+ ).
+
+:- func show_memory_per_call(fields) = maybe(memory_units).
+
+show_memory_per_call(Fields) = ShowPerMemory :-
+ MemoryFields = Fields ^ memory_fields,
+ ( MemoryFields = no_memory, ShowPerMemory = no
+ ; MemoryFields = memory(_Unit), ShowPerMemory = no
+ ; MemoryFields = memory_and_percall(Unit), ShowPerMemory = yes(Unit)
+ ).
+
+%-----------------------------------------------------------------------------%
+
+proc_dynamic_name(Deep, PDPtr) = Name :-
+ deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+ PSPtr = PD ^ pd_proc_static,
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ Name = PS ^ ps_refined_id.
+
+proc_static_name(Deep, PSPtr) = Name :-
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ Name = PS ^ ps_refined_id.
+
+%-----------------------------------------------------------------------------%
+
+proc_dynamic_context(Deep, PDPtr, FileName, LineNumber) :-
+ deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+ PSPtr = PD ^ pd_proc_static,
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ FileName = PS ^ ps_file_name,
+ LineNumber = PS ^ ps_line_number.
+
+proc_static_context(Deep, PSPtr, FileName, LineNumber) :-
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ FileName = PS ^ ps_file_name,
+ LineNumber = PS ^ ps_line_number.
+
+call_site_context(Deep, CSSPtr, FileName, LineNumber) :-
+ deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
+ CSS = call_site_static(PSPtr, _SlotNum, _Kind, LineNumber, _GoalPath),
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ FileName = PS ^ ps_file_name.
+
+%-----------------------------------------------------------------------------%
+
+proc_static_to_line_group_info(Pref, Deep, PSPtr, FileName, LineNumber,
+ Name, HTML) :-
+ ( valid_proc_static_ptr(Deep, PSPtr) ->
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ FileName = PS ^ ps_file_name,
+ LineNumber = PS ^ ps_line_number,
+ Name = PS ^ ps_refined_id,
+ HTML = proc_static_to_html_ref(Pref, Deep, PSPtr)
+ ;
+ FileName = "",
+ LineNumber = 0,
+ Name = "mercury_runtime",
+ HTML = Name
+ ).
+
+proc_static_to_html_ref(Pref, Deep, PSPtr) = HTML :-
+ URL = deep_cmd_pref_to_url(Pref, Deep, deep_cmd_proc(PSPtr)),
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ ProcName = PS ^ ps_refined_id,
+ HTML = string.format("<A HREF=""%s"">%s</A>",
+ [s(URL), s(escape_break_html_string(ProcName))]).
+
+module_name_to_html_ref(Pref, Deep, ModuleName) = HTML :-
+ URL = deep_cmd_pref_to_url(Pref, Deep, deep_cmd_module(ModuleName)),
+ HTML = string.format("<A HREF=""%s"">%s</A>",
+ [s(URL), s(escape_break_html_string(ModuleName))]).
+
+clique_ptr_to_html_ref(Pref, Deep, ProcName, CliquePtr) = HTML :-
+ URL = deep_cmd_pref_to_url(Pref, Deep, deep_cmd_clique(CliquePtr)),
+ HTML = string.format("<A HREF=""%s"">%s</A>",
+ [s(URL), s(escape_break_html_string(ProcName))]).
+
+deep_cmd_pref_to_url(Pref, Deep, Cmd) =
+ machine_datafile_cmd_pref_to_url(Deep ^ server_name_port,
+ Deep ^ script_name, Deep ^ data_file_name, Cmd, Pref).
+
+%-----------------------------------------------------------------------------%
+
+plural(N) = Plural :-
+ ( N = 1 ->
+ Plural = ""
+ ;
+ Plural = "s"
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- func machine_datafile_cmd_pref_to_url(string, string, string, cmd,
+ preferences) = string.
+
+machine_datafile_cmd_pref_to_url(Machine, ScriptName, DeepFileName, Cmd,
+ Preferences) =
+ "http://" ++
+ Machine ++
+ ScriptName ++ "?" ++
+ query_to_string(deep_query(yes(Cmd), DeepFileName, yes(Preferences))).
+
+%-----------------------------------------------------------------------------%
+:- end_module old_html_format.
+%-----------------------------------------------------------------------------%
Index: old_query.m
===================================================================
RCS file: old_query.m
diff -N old_query.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ old_query.m 25 Sep 2008 07:06:59 -0000
@@ -0,0 +1,1874 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2001-2003, 2005-2008 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: query.m.
+% Authors: conway, zs.
+%
+% This module contains code to answer deep profiler queries by directly
+% generating HTML. This approach has been superseded by another (implemented in
+% create_report.m and display_report.m) that answers queries by first creating
+% a high level report, and then converting that report to a display structure
+% and finally to HTML. The code in this module is therefore present only as a
+% backup; it should not be actively modified.
+%
+%-----------------------------------------------------------------------------%
+
+:- module old_query.
+
+:- interface.
+
+:- import_module profile.
+:- import_module query.
+
+:- import_module io.
+
+ % Old deep profiler cgi code. This should remain supported until all cmds
+ % have been updated to use the data structures in report.m.
+ %
+:- pred old_exec(cmd::in, preferences::in, deep::in, string::out,
+ io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module apply_exclusion.
+:- import_module html_format. % for escape_break_html_string
+:- import_module measurements.
+:- import_module old_html_format.
+:- import_module top_procs.
+
+:- import_module array.
+:- import_module assoc_list.
+:- import_module bool.
+:- import_module float.
+:- import_module int.
+:- import_module list.
+:- import_module map.
+:- import_module maybe.
+:- import_module pair.
+:- import_module require.
+:- import_module string.
+:- import_module unit.
+
+old_exec(deep_cmd_restart, _Pref, _Deep, _HTML, !IO) :-
+ % Our caller is supposed to filter out restart commands.
+ error("exec: found restart command").
+old_exec(deep_cmd_quit, _Pref, Deep, HTML, !IO) :-
+ HTML = string.format(
+ "<H3>Shutting down deep profile server for %s.</H3>\n",
+ [s(Deep ^ data_file_name)]).
+old_exec(deep_cmd_timeout(TimeOut), _Pref, _Deep, HTML, !IO) :-
+ HTML = string.format("<H3>Timeout set to %d minutes</H3>\n", [i(TimeOut)]).
+old_exec(Cmd, Pref, Deep, HTML, !IO) :-
+ Cmd = deep_cmd_menu,
+ HTML = generate_menu_page(Cmd, Pref, Deep).
+old_exec(Cmd, Pref, Deep, HTML, !IO) :-
+ Cmd = deep_cmd_top_procs(Limit, CostKind, InclDesc, Scope),
+ HTML = generate_top_procs_page(Cmd, Limit, CostKind, InclDesc, Scope,
+ Pref, Deep).
+old_exec(deep_cmd_dump_proc_static(PSPtr), _Pref, Deep, HTML, !IO) :-
+ HTML = generate_proc_static_debug_page(PSPtr, Deep).
+old_exec(deep_cmd_dump_proc_dynamic(PDPtr), _Pref, Deep, HTML, !IO) :-
+ HTML = generate_proc_dynamic_debug_page(PDPtr, Deep).
+old_exec(deep_cmd_dump_call_site_static(CSSPtr), _Pref, Deep, HTML, !IO) :-
+ HTML = generate_call_site_static_debug_page(CSSPtr, Deep).
+old_exec(deep_cmd_dump_call_site_dynamic(CSDPtr), _Pref, Deep, HTML, !IO) :-
+ HTML = generate_call_site_dynamic_debug_page(CSDPtr, Deep).
+old_exec(Cmd, Pref, Deep, HTML, !IO) :-
+ Cmd = deep_cmd_proc(PSPtr),
+ ( valid_proc_static_ptr(Deep, PSPtr) ->
+ HTML = generate_proc_page(Cmd, PSPtr, Pref, Deep)
+ ;
+ HTML =
+ page_banner(Cmd, Pref) ++
+ "There is no procedure with that number.\n" ++
+ page_footer(Cmd, Pref, Deep)
+ ).
+old_exec(Cmd, Pref, Deep, HTML, !IO) :-
+ Cmd = deep_cmd_root(MaybePercent),
+ deep_lookup_clique_index(Deep, Deep ^ root, RootCliquePtr),
+ (
+ MaybePercent = yes(Percent),
+ HTML = chase_the_action(Cmd, RootCliquePtr, Pref, Deep, Percent)
+ ;
+ MaybePercent = no,
+ generate_clique_page(Cmd, RootCliquePtr, Pref, Deep, HTML, 100, _)
+ ).
+old_exec(Cmd, Pref, Deep, HTML, !IO) :-
+ Cmd = deep_cmd_clique(CliquePtr),
+ ( valid_clique_ptr(Deep, CliquePtr) ->
+ generate_clique_page(Cmd, CliquePtr, Pref, Deep, HTML, 100, _)
+ ;
+ HTML =
+ page_banner(Cmd, Pref) ++
+ "There is no clique with that number.\n" ++
+ page_footer(Cmd, Pref, Deep)
+ ).
+old_exec(Cmd, Pref0, Deep, HTML, !IO) :-
+ Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, Contour),
+ Pref = Pref0 ^ pref_contour := Contour,
+ ( valid_proc_static_ptr(Deep, PSPtr) ->
+ generate_proc_callers_page(Cmd, PSPtr, CallerGroups, BunchNum,
+ Pref, Deep, HTML, !IO)
+ ;
+ HTML =
+ page_banner(Cmd, Pref) ++
+ "There is no procedure with that number.\n" ++
+ page_footer(Cmd, Pref, Deep)
+ ).
+old_exec(Cmd, Pref, Deep, HTML, !IO) :-
+ Cmd = deep_cmd_program_modules,
+ HTML = generate_modules_page(Cmd, Pref, Deep).
+old_exec(Cmd, Pref, Deep, HTML, !IO) :-
+ Cmd = deep_cmd_module(ModuleName),
+ ( map.search(Deep ^ module_data, ModuleName, ModuleData) ->
+ HTML = generate_module_page(Cmd, ModuleName, ModuleData, Pref, Deep)
+ ;
+ HTML =
+ page_banner(Cmd, Pref) ++
+ "There is no procedure with that number.\n" ++
+ page_footer(Cmd, Pref, Deep)
+ ).
+old_exec(deep_cmd_dump_clique(CliquePtr), _Pref, Deep, HTML, !IO) :-
+ HTML = generate_clique_debug_page(CliquePtr, Deep).
+old_exec(deep_cmd_procrep_coverage(_), _, _, HTML, !IO) :-
+ HTML = "query.m: deep_cmd_procrep_coverage is unsupported by old_exec\n".
+
+%-----------------------------------------------------------------------------%
+
+:- func generate_proc_static_debug_page(proc_static_ptr, deep) = string.
+
+generate_proc_static_debug_page(PSPtr, Deep) = HTML :-
+ ( valid_proc_static_ptr(Deep, PSPtr) ->
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ Refined = PS ^ ps_refined_id,
+ Raw = PS ^ ps_raw_id,
+ FileName = PS ^ ps_file_name,
+ HTML =
+ "<HTML>\n" ++
+ Refined ++ " " ++ Raw ++ " " ++ FileName ++ " " ++
+ string.int_to_string(array.max(PS ^ ps_sites)) ++
+ "</HTML>\n"
+ ;
+ HTML =
+ "<HTML>\n" ++
+ "Invalid proc_static_ptr" ++
+ "</HTML>\n"
+ ).
+
+:- func generate_proc_dynamic_debug_page(proc_dynamic_ptr, deep) = string.
+
+generate_proc_dynamic_debug_page(PDPtr, Deep) = HTML :-
+ ( valid_proc_dynamic_ptr(Deep, PDPtr) ->
+ deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+ PSPtr = PD ^ pd_proc_static,
+ PSPtr = proc_static_ptr(PSI),
+ HTML =
+ "<HTML>\n" ++
+ string.format("proc_static %d, ", [i(PSI)]) ++
+ array_slots_to_html(PD ^ pd_sites) ++
+ "</HTML>\n"
+ ;
+ HTML =
+ "<HTML>\n" ++
+ "Invalid proc_dynamic_ptr" ++
+ "</HTML>\n"
+ ).
+
+:- func generate_call_site_static_debug_page(call_site_static_ptr, deep)
+ = string.
+
+generate_call_site_static_debug_page(CSSPtr, Deep) = HTML :-
+ ( valid_call_site_static_ptr(Deep, CSSPtr) ->
+ deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
+ ContainerPtr = CSS ^ css_container,
+ ContainerPtr = proc_static_ptr(Container),
+ HTML =
+ "<HTML>\n" ++
+ string.int_to_string(Container) ++ " " ++
+ string.int_to_string(CSS ^ css_slot_num) ++ " " ++
+ string.int_to_string(CSS ^ css_line_num) ++ " " ++
+ kind_and_callee_to_string(CSS ^ css_kind) ++ " " ++
+ CSS ^ css_goal_path ++
+ "</HTML>\n"
+ ;
+ HTML =
+ "<HTML>\n" ++
+ "Invalid call_site_static_ptr" ++
+ "</HTML>\n"
+ ).
+
+:- func generate_call_site_dynamic_debug_page(call_site_dynamic_ptr, deep)
+ = string.
+
+generate_call_site_dynamic_debug_page(CSDPtr, Deep) = HTML :-
+ ( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
+ deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
+ CSD ^ csd_caller = proc_dynamic_ptr(CallerPDI),
+ CSD ^ csd_callee = proc_dynamic_ptr(CalleePDI),
+ HTML =
+ "<HTML>\n" ++
+ string.int_to_string(CallerPDI) ++ " -> " ++
+ string.int_to_string(CalleePDI) ++ ": " ++
+ own_to_string(CSD ^ csd_own_prof) ++
+ "</HTML>\n"
+ ;
+ HTML =
+ "<HTML>\n" ++
+ "Invalid call_site_dynamic_ptr" ++
+ "</HTML>\n"
+ ).
+
+:- func generate_clique_debug_page(clique_ptr, deep) = string.
+
+generate_clique_debug_page(CliquePtr, Deep) = HTML :-
+ ( valid_clique_ptr(Deep, CliquePtr) ->
+ deep_lookup_clique_parents(Deep, CliquePtr, ParentCSDPtr),
+ ParentCSDPtr = call_site_dynamic_ptr(ParentCSDI),
+ ParentStr = string.format("%d ->", [i(ParentCSDI)]),
+ deep_lookup_clique_members(Deep, CliquePtr, Members),
+ HTML =
+ "<HTML>\n" ++
+ ParentStr ++
+ list.foldl(append_pdi_to_string, Members, "") ++
+ "</HTML>\n"
+ ;
+ HTML =
+ "<HTML>\n" ++
+ "Invalid call_site_dynamic_ptr" ++
+ "</HTML>\n"
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- func array_slots_to_html(array(call_site_array_slot)) = string.
+
+array_slots_to_html(SlotArray) = HTML :-
+ array.to_list(SlotArray, SlotList),
+ list.foldl(append_slot_to_string, SlotList, "multi", HTML).
+
+:- pred append_slot_to_string(call_site_array_slot::in,
+ string::in, string::out) is det.
+
+append_slot_to_string(Slot, Str0, Str) :-
+ Str = Str0 ++ " " ++ array_slot_to_html(Slot).
+
+:- func array_slot_to_html(call_site_array_slot) = string.
+
+array_slot_to_html(slot_normal(CSDPtr)) = HTML :-
+ CSDPtr = call_site_dynamic_ptr(CSDI),
+ HTML = "normal " ++ string.int_to_string(CSDI).
+array_slot_to_html(slot_multi(_, CSDPtrArray)) = HTML :-
+ array.to_list(CSDPtrArray, CSDPtrs),
+ list.foldl(append_csdi_to_string, CSDPtrs, "", CSDI_HTML),
+ list.length(CSDPtrs, CSDPtrCount),
+ HTML = string.format("multi(%d): [", [i(CSDPtrCount)]) ++ CSDI_HTML ++ "]".
+
+:- pred append_csdi_to_string(call_site_dynamic_ptr::in,
+ string::in, string::out) is det.
+
+append_csdi_to_string(call_site_dynamic_ptr(CSDI), Str0, Str) :-
+ Str = Str0 ++ " " ++ string.int_to_string(CSDI).
+
+:- func append_pdi_to_string(proc_dynamic_ptr, string) = string.
+
+append_pdi_to_string(proc_dynamic_ptr(PDI), Str0) =
+ Str0 ++ " " ++ string.int_to_string(PDI).
+
+:- func kind_and_callee_to_string(call_site_kind_and_callee) = string.
+
+kind_and_callee_to_string(normal_call_and_callee(proc_static_ptr(PSI),
+ TypeSpec)) =
+ "normal " ++ string.int_to_string(PSI) ++ " " ++ TypeSpec.
+kind_and_callee_to_string(special_call_and_no_callee) = "special_call".
+kind_and_callee_to_string(higher_order_call_and_no_callee) =
+ "higher_order_call".
+kind_and_callee_to_string(method_call_and_no_callee) = "method_call".
+kind_and_callee_to_string(callback_and_no_callee) = "callback".
+
+%-----------------------------------------------------------------------------%
+
+:- func call_site_kind_and_callee_to_html(call_site_kind_and_callee) = string.
+
+call_site_kind_and_callee_to_html(normal_call_and_callee(_, _)) =
+ "normal_call".
+call_site_kind_and_callee_to_html(special_call_and_no_callee) =
+ "special_call".
+call_site_kind_and_callee_to_html(higher_order_call_and_no_callee) =
+ "higher_order_call".
+call_site_kind_and_callee_to_html(method_call_and_no_callee) =
+ "method_call".
+call_site_kind_and_callee_to_html(callback_and_no_callee) =
+ "callback".
+
+%-----------------------------------------------------------------------------%
+
+:- func generate_menu_page(cmd, preferences, deep) = string.
+
+generate_menu_page(Cmd, Pref, Deep) = HTML :-
+ ShouldDisplayTimes = should_display_times(Deep),
+ HTML =
+ page_banner(Cmd, Pref) ++
+ "<p>\n" ++
+ menu_text ++
+ "<ul>\n" ++
+ "<li>\n" ++
+ menu_item(Deep, Pref, deep_cmd_root(no),
+ "Exploring the call graph, starting at the root.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref, deep_cmd_root(yes(90)),
+ "Exploring the call graph, starting at the action.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref, deep_cmd_program_modules,
+ "Exploring the program module by module.") ++
+ ( ShouldDisplayTimes = yes ->
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(rank_range(1, 100), cost_time,
+ self, overall),
+ "Top 100 most expensive procedures: time, self.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(rank_range(1, 100), cost_time,
+ self_and_desc, overall),
+ "Top 100 most expensive procedures: time, self+descendants.")
+ ;
+ ""
+ ) ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(rank_range(1, 100), cost_callseqs,
+ self, overall),
+ "Top 100 most expensive procedures: callseqs, self.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(rank_range(1, 100), cost_callseqs,
+ self_and_desc, overall),
+ "Top 100 most expensive procedures: callseqs, self+descendants.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(rank_range(1, 100), cost_words, self, overall),
+ "Top 100 most expensive procedures: words, self.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(rank_range(1, 100), cost_words, self_and_desc,
+ overall),
+ "Top 100 most expensive procedures: words, self+descendants.")
+ ++
+ ( ShouldDisplayTimes = yes ->
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_percent(0.1), cost_time, self,
+ overall),
+ "Procedures above 0.1% threshold: time, self.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_percent(1.0), cost_time,
+ self_and_desc, overall),
+ "Procedures above 1% threshold: time, self+descendants.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_value(100.0), cost_time,
+ self_and_desc, overall),
+ "Procedures above 1 second threshold: " ++
+ "time, self+descendants.")
+ ;
+ ""
+ ) ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_percent(0.1), cost_callseqs, self,
+ overall),
+ "Procedures above 0.1% threshold: callseqs, self.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_percent(1.0), cost_callseqs,
+ self_and_desc, overall),
+ "Procedures above 1% threshold: callseqs, self+descendants.")
+ ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_value(1000000.0), cost_callseqs,
+ self_and_desc, overall),
+ "Procedures above 1,000,000 callseqs threshold: callseqs, " ++
+ "self+descendants.")
+ ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_percent(0.1), cost_words, self,
+ overall),
+ "Procedures above 0.1% threshold: words, self.") ++
+ "<li>\n" ++
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_percent(1.0), cost_words,
+ self_and_desc, overall),
+ "Procedures above 1% threshold: words, self+descendants.")
+ ++
+ "<li>\n" ++
+ % 2M words is chosen because it is 8MB on ia32
+ menu_item(Deep, Pref,
+ deep_cmd_top_procs(threshold_value(float(1024 * 1024 * 2)),
+ cost_words, self_and_desc, overall),
+ "Procedures above 2M words threshold: words, self+descendants.")
+ ++
+ "</ul>\n" ++
+ "<p>\n" ++
+ present_stats(Deep) ++
+ page_footer(Cmd, Pref, Deep).
+
+:- func menu_text = string.
+
+menu_text =
+ "You can start exploring the deep profile at the following points.\n".
+
+:- func menu_item(deep, preferences, cmd, string) = string.
+
+menu_item(Deep, Pref, Cmd, Text) =
+ string.format("<A HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, Cmd)), s(Text)]).
+
+:- func present_stats(deep) = string.
+
+present_stats(Deep) = HTML :-
+ Stats = Deep ^ profile_stats,
+ lookup_ticks_per_sec(Stats, TicksPerSec, Assumed),
+ (
+ Assumed = yes,
+ AssumedStr = " (assumed)"
+ ;
+ Assumed = no,
+ AssumedStr = ""
+ ),
+ HTML =
+ "<TABLE>\n" ++
+ "<TR><TD ALIGN=left>Quanta per second:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d%s</TD></TR>\n",
+ [i(TicksPerSec), s(AssumedStr)]) ++
+ "<TR><TD ALIGN=left>Quanta in user code:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d</TD></TR>\n",
+ [i(Stats ^ user_quanta)]) ++
+ "<TR><TD ALIGN=left>Quanta in instrumentation:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d</TD></TR>\n",
+ [i(Stats ^ instrument_quanta)]) ++
+ "<TR><TD ALIGN=left>Call sequence numbers:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d</TD></TR>\n",
+ [i(Stats ^ num_callseqs)]) ++
+ "<TR><TD ALIGN=left>CallSiteDynamic structures:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d</TD></TR>\n",
+ [i(Stats ^ num_csd)]) ++
+ "<TR><TD ALIGN=left>ProcDynamic structures:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d</TD></TR>\n",
+ [i(Stats ^ num_pd)]) ++
+ "<TR><TD ALIGN=left>CallSiteStatic structures:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d</TD></TR>\n",
+ [i(Stats ^ num_css)]) ++
+ "<TR><TD ALIGN=left>ProcStatic structures:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d</TD></TR>\n",
+ [i(Stats ^ num_ps)]) ++
+ "<TR><TD ALIGN=left>Cliques:</TD>\n" ++
+ string.format("<TD ALIGN=right>%d</TD></TR>\n",
+ [i(array.max(Deep ^ clique_members))]) ++
+ "</TABLE>\n".
+
+%-----------------------------------------------------------------------------%
+
+:- func chase_the_action(cmd, clique_ptr, preferences, deep, int) = string.
+
+chase_the_action(Cmd, CliquePtr, Pref, Deep, Percent) = HTML :-
+ generate_clique_page(Cmd, CliquePtr, Pref, Deep, HTML0,
+ Percent, ActionPtrs),
+ ( ActionPtrs = [ActionCliquePtr] ->
+ HTML = chase_the_action(Cmd, ActionCliquePtr, Pref, Deep, Percent)
+ ;
+ HTML = HTML0
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred generate_clique_page(cmd::in, clique_ptr::in, preferences::in,
+ deep::in, string::out, int::in, list(clique_ptr)::out) is det.
+
+generate_clique_page(Cmd, CliquePtr, Pref, Deep, HTML, Percent, ActionPtrs) :-
+ clique_to_html(Pref, Deep, CliquePtr, CliqueHTML, Percent, ActionPtrs),
+ CliquePtr = clique_ptr(CliqueNum),
+ HTML =
+ page_banner(Cmd, Pref) ++
+ string.format("<H3>Clique %d:</H3>\n", [i(CliqueNum)]) ++
+ table_start(Pref) ++
+ fields_header(Pref, source_proc, totals_meaningful,
+ wrap_clique_links(CliquePtr, Pref, Deep)) ++
+ CliqueHTML ++
+ table_end(Pref) ++
+ page_footer(Cmd, Pref, Deep).
+
+:- func generate_proc_page(cmd, proc_static_ptr, preferences, deep) = string.
+
+generate_proc_page(Cmd, PSPtr, Pref, Deep) =
+ page_banner(Cmd, Pref) ++
+ string.format("<H3>Summary of procedure %s:</H3>\n",
+ [s(escape_html_string(proc_static_name(Deep, PSPtr)))]) ++
+ table_start(Pref) ++
+ fields_header(Pref, source_proc, totals_meaningful,
+ wrap_proc_links(PSPtr, Pref, Deep)) ++
+ proc_summary_to_html(Pref, Deep, PSPtr) ++
+ table_end(Pref) ++
+ "<p>\n" ++
+ proc_summary_toggles_to_html(Pref, Deep, PSPtr) ++
+ page_footer(Cmd, Pref, Deep).
+
+:- pred generate_proc_callers_page(cmd::in, proc_static_ptr::in,
+ caller_groups::in, int::in, preferences::in, deep::in, string::out,
+ io::di, io::uo) is det.
+
+generate_proc_callers_page(Cmd, PSPtr, CallerGroups, BunchNum, Pref, Deep,
+ HTML, !IO) :-
+ proc_callers_to_html(Pref, Deep, PSPtr, CallerGroups, BunchNum,
+ MaybePage, !IO),
+ (
+ MaybePage = ok({IdFields, Heading, CallersHTML, Toggles}),
+ HTML =
+ page_banner(Cmd, Pref) ++
+ Heading ++
+ ( CallersHTML = "" ->
+ ""
+ ;
+ table_start(Pref) ++
+ fields_header(Pref, IdFields, totals_meaningful,
+ wrap_proc_callers_links(PSPtr, CallerGroups, 1,
+ Pref, Deep)) ++
+ CallersHTML ++
+ table_end(Pref) ++
+ "<p>\n"
+ ) ++
+ Toggles ++
+ page_footer(Cmd, Pref, Deep)
+ ;
+ MaybePage = error(Msg),
+ HTML =
+ string.format("<H3>%s</H3>\n", [s(Msg)])
+ ).
+
+:- func generate_modules_page(cmd, preferences, deep) = string.
+
+generate_modules_page(Cmd, Pref, Deep) =
+ page_banner(Cmd, Pref) ++
+ "<H3>The modules of the program:</H3>\n" ++
+ table_start(Pref) ++
+ fields_header(Pref, rank_module, totals_not_meaningful,
+ wrap_modules_links(Pref, Deep)) ++
+ modules_to_html(Pref, Deep) ++
+ table_end(Pref) ++
+ page_footer(Cmd, Pref, Deep).
+
+:- func generate_module_page(cmd, string, module_data, preferences, deep)
+ = string.
+
+generate_module_page(Cmd, ModuleName, ModuleData, Pref, Deep) = HTML :-
+ module_to_html(Pref, Deep, ModuleName, ModuleData,
+ IdFields, ModulesHTML),
+ HTML =
+ page_banner(Cmd, Pref) ++
+ string.format("<H3>The procedures of module %s:</H3>\n",
+ [s(ModuleName)]) ++
+ table_start(Pref) ++
+ fields_header(Pref, IdFields, totals_meaningful,
+ wrap_module_links(ModuleName, Pref, Deep)) ++
+ ModulesHTML ++
+ table_end(Pref) ++
+ page_footer(Cmd, Pref, Deep).
+
+:- func generate_top_procs_page(cmd, display_limit,
+ cost_kind, include_descendants, measurement_scope,
+ preferences, deep) = string.
+
+generate_top_procs_page(Cmd, Limit, CostKind, InclDesc0, Scope0, Pref, Deep)
+ = HTML :-
+ (
+ CostKind = cost_calls,
+ % Counting calls is incompatible both with self_and_desc
+ % and per_call.
+ InclDesc = self,
+ Scope = overall
+ ;
+ ( CostKind = cost_redos
+ ; CostKind = cost_time
+ ; CostKind = cost_callseqs
+ ; CostKind = cost_allocs
+ ; CostKind = cost_words
+ ),
+ InclDesc = InclDesc0,
+ Scope = Scope0
+ ),
+ MaybeTopPSIs = find_top_procs(CostKind, InclDesc, Scope, Limit, Deep),
+ (
+ MaybeTopPSIs = error(ErrorMessage),
+ HTML =
+ page_banner(Cmd, Pref) ++
+ ErrorMessage ++ "\n" ++
+ page_footer(Cmd, Pref, Deep)
+ ;
+ MaybeTopPSIs = ok(TopPSIs),
+ ToggleLimitHTML = "",
+ ToggleCostHTML = toggle_cost_criteria_in_top_procs_cmd(
+ Pref, Deep, Limit, CostKind, InclDesc, Scope),
+ Desc = cost_criteria_to_description(CostKind, InclDesc, Scope),
+ Heading = string.format("<H3>Top procedures %s</H3>\n",
+ [s(Desc)]),
+ (
+ TopPSIs = [],
+ HTML =
+ page_banner(Cmd, Pref) ++
+ Heading ++ "<p>\n" ++
+ "No procedures match the specification.\n" ++
+ "<p>\n" ++
+ ToggleLimitHTML ++
+ ToggleCostHTML ++
+ page_footer(Cmd, Pref, Deep)
+ ;
+ TopPSIs = [_ | _],
+ TopProcs = list.filter_map(
+ lookup_proc_total_to_html(Pref, Deep, no, ""),
+ list.map(wrap_proc_static_ptr, TopPSIs)),
+ RankedTopProcs = add_ranks(TopProcs),
+ SummaryHTMLs = list.map(
+ two_id_line_to_html(Pref, Deep, totals_meaningful),
+ RankedTopProcs),
+ HTML =
+ page_banner(Cmd, Pref) ++
+ Heading ++ "<p>\n" ++
+ table_start(Pref) ++
+ fields_header(Pref, rank_proc, totals_meaningful,
+ wrap_top_procs_links(Limit, Pref, Deep)) ++
+ string.append_list(SummaryHTMLs) ++
+ table_end(Pref) ++
+ "<p>\n" ++
+ ToggleLimitHTML ++
+ ToggleCostHTML ++
+ page_footer(Cmd, Pref, Deep)
+ )
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- func modules_to_html(preferences, deep) = string.
+
+modules_to_html(Pref, Deep) = HTML :-
+ map.to_assoc_list(Deep ^ module_data, ModulePairs0),
+ list.filter(not_mercury_runtime, ModulePairs0, ModulePairs),
+ ModuleLines = list.filter_map(module_summary_to_html(Pref, Deep),
+ ModulePairs),
+ SortedModuleLines = sort_line_groups(Pref ^ pref_criteria,
+ ModuleLines),
+ RankedModuleLines = add_ranks(SortedModuleLines),
+ ModuleHTMLs = list.map(
+ two_id_line_to_html(Pref, Deep, totals_not_meaningful),
+ RankedModuleLines),
+ HTML =
+ separator_row(Pref, rank_module, totals_not_meaningful) ++
+ string.append_list(ModuleHTMLs).
+
+:- pred not_mercury_runtime(pair(string, module_data)::in) is semidet.
+
+not_mercury_runtime(ModuleName - _) :-
+ ModuleName \= "Mercury runtime".
+
+:- func module_summary_to_html(preferences, deep, pair(string, module_data))
+ = one_id_line is semidet.
+
+module_summary_to_html(Pref, Deep, ModuleName - ModuleData) = LineGroup :-
+ ModuleData = module_data(Own, Desc, _),
+ not (
+ Pref ^ pref_inactive ^ inactive_modules = inactive_hide,
+ compute_is_active(Own) = is_not_active
+ ),
+ HTML = string.format("<TD><A HREF=""%s"">%s</A></TD>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_module(ModuleName))),
+ s(ModuleName)]),
+ LineGroup = line_group(ModuleName, 0, ModuleName, Own, Desc, HTML, unit).
+
+%-----------------------------------------------------------------------------%
+
+:- pred module_to_html(preferences::in, deep::in, string::in, module_data::in,
+ id_fields::out, string::out) is det.
+
+module_to_html(Pref, Deep, _ModuleName, ModuleData, IdHeaders, HTML) :-
+ ModuleData = module_data(_Own, _Desc, PSPtrs),
+ ProcLines = list.filter_map(lookup_proc_total_to_html(Pref, Deep, yes, ""),
+ PSPtrs),
+ Criteria = Pref ^ pref_criteria,
+ SortedProcLines = sort_line_groups(Criteria, ProcLines),
+ (
+ Criteria = by_cost(_, _, _),
+ IdHeaders = rank_proc,
+ RankedProcLines = add_ranks(SortedProcLines)
+ ;
+ ( Criteria = by_name
+ ; Criteria = by_context
+ ),
+ IdHeaders = source_proc,
+ RankedProcLines = list.map(add_self_context, SortedProcLines)
+ ),
+ ProcHTMLs = list.map(two_id_line_to_html(Pref, Deep, totals_meaningful),
+ RankedProcLines),
+ HTML =
+ separator_row(Pref, IdHeaders, totals_meaningful) ++
+ string.append_list(ProcHTMLs).
+
+%-----------------------------------------------------------------------------%
+
+:- pred clique_to_html(preferences::in, deep::in, clique_ptr::in,
+ string::out, int::in, list(clique_ptr)::out) is det.
+
+clique_to_html(Pref, Deep, CliquePtr, HTML, PerCent, ActionPtrs) :-
+ (
+ Pref ^ pref_anc = yes(AncestorLimit),
+ RespectLimit = yes
+ ;
+ Pref ^ pref_anc = no,
+ AncestorLimit = 0, % the value doesn't matter
+ RespectLimit = no
+ ),
+ clique_ancestors_to_html(Pref, Deep,
+ AncestorLimit, RespectLimit, CliquePtr, Ancestors, Cutoff),
+ deep_lookup_clique_members(Deep, CliquePtr, PDPtrs),
+ list.foldl(group_proc_dynamics_by_proc_static(Deep), PDPtrs,
+ map.init, PStoPDsMap),
+ map.to_assoc_list(PStoPDsMap, PStoPDsList0),
+
+ deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
+ ( valid_call_site_dynamic_ptr(Deep, EntryCSDPtr) ->
+ deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
+ EntryPDPtr = EntryCSD ^ csd_callee,
+ list.filter(proc_group_contains(EntryPDPtr), PStoPDsList0,
+ EntryGroup, RestGroup),
+ list.append(EntryGroup, RestGroup, PStoPDsList)
+ ;
+ PStoPDsList = PStoPDsList0
+ ),
+
+ list.map2(procs_in_clique_to_html(Pref, Deep, CliquePtr, PerCent),
+ PStoPDsList, PDsStrs, ActionPtrLists),
+ list.condense(ActionPtrLists, ActionPtrs),
+ string.append_list(PDsStrs, ProcGroups),
+ (
+ Cutoff = yes,
+ Heading = string.format("The %d closest ancestors:",
+ [i(AncestorLimit)])
+ ;
+ Cutoff = no,
+ Heading = "Ancestors:"
+ ),
+ HTML =
+ header_row(Heading, Pref, source_proc, totals_meaningful) ++
+ separator_row(Pref, source_proc, totals_meaningful) ++
+ Ancestors ++
+ separator_row(Pref, source_proc, totals_meaningful) ++
+ header_row("Procedures of the clique:", Pref, source_proc,
+ totals_meaningful) ++
+ separator_row(Pref, source_proc, totals_meaningful) ++
+ ProcGroups.
+
+:- pred proc_group_contains(proc_dynamic_ptr::in,
+ pair(proc_static_ptr, list(proc_dynamic_ptr))::in) is semidet.
+
+proc_group_contains(EntryPDPtr, _ - PDPtrs) :-
+ list.member(EntryPDPtr, PDPtrs).
+
+:- pred clique_ancestors_to_html(preferences::in, deep::in, int::in, bool::in,
+ clique_ptr::in, string::out, bool::out) is det.
+
+clique_ancestors_to_html(Pref, Deep, AncestorLimit, RespectLimit, CliquePtr,
+ HTML, Cutoff) :-
+ deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
+ ( valid_call_site_dynamic_ptr(Deep, EntryCSDPtr) ->
+ deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
+ EntryPDPtr = EntryCSD ^ csd_caller,
+ ( EntryPDPtr = Deep ^ root ->
+ % We have reached the root.
+ HTML = "",
+ Cutoff = no
+ ; RespectLimit = yes, AncestorLimit =< 0 ->
+ HTML = "",
+ Cutoff = yes
+ ;
+ deep_lookup_clique_index(Deep, EntryPDPtr, EntryCliquePtr),
+ ThisLine = call_site_dynamic_to_html(Pref, Deep,
+ ancestor_display, yes(EntryCliquePtr), EntryCSDPtr),
+ ThisHTML = two_id_line_to_html(Pref, Deep, totals_meaningful,
+ ThisLine),
+ clique_ancestors_to_html(Pref, Deep, AncestorLimit - 1,
+ RespectLimit, EntryCliquePtr, AncestorHTML, Cutoff),
+ HTML = AncestorHTML ++ ThisHTML
+ )
+ ;
+ % We have reached the parent of root.
+ HTML = "",
+ Cutoff = no
+ ).
+
+:- pred group_proc_dynamics_by_proc_static(deep::in, proc_dynamic_ptr::in,
+ map(proc_static_ptr, list(proc_dynamic_ptr))::in,
+ map(proc_static_ptr, list(proc_dynamic_ptr))::out) is det.
+
+group_proc_dynamics_by_proc_static(Deep, PDPtr, PStoPDsMap0, PStoPDsMap) :-
+ require(valid_proc_dynamic_ptr(Deep, PDPtr),
+ "group_proc_dynamics_by_proc_static: invalid PDPtr"),
+ deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+ PSPtr = PD ^ pd_proc_static,
+ ( map.search(PStoPDsMap0, PSPtr, PSPDs0) ->
+ PSPDs = [PDPtr | PSPDs0],
+ map.det_update(PStoPDsMap0, PSPtr, PSPDs, PStoPDsMap)
+ ;
+ map.det_insert(PStoPDsMap0, PSPtr, [PDPtr], PStoPDsMap)
+ ).
+
+:- pred procs_in_clique_to_html(preferences::in, deep::in, clique_ptr::in,
+ int::in, pair(proc_static_ptr, list(proc_dynamic_ptr))::in,
+ string::out, list(clique_ptr)::out) is det.
+
+procs_in_clique_to_html(Pref, Deep, CliquePtr, Percent, PSPtr - PDPtrs,
+ HTML, ActionPtrs) :-
+ (
+ PDPtrs = [],
+ HTML = "",
+ ActionPtrs = []
+ ;
+ PDPtrs = [PDPtr],
+ proc_in_clique_to_html(Pref, Deep, CliquePtr, Percent, PDPtr,
+ HTML, ActionPtrs)
+ ;
+ PDPtrs = [_, _ | _],
+ list.map(deep_lookup_pd_own(Deep), PDPtrs, ProcOwns),
+ list.map(deep_lookup_pd_desc(Deep), PDPtrs, ProcDescs),
+ ProcOwn = sum_own_infos(ProcOwns),
+ ProcDesc = sum_inherit_infos(ProcDescs),
+ ProcTotal = proc_total_to_two_id_line(Pref, Deep, yes, "summary ",
+ PSPtr, ProcOwn, ProcDesc),
+ list.map2(proc_in_clique_to_html(Pref, Deep, CliquePtr, Percent),
+ PDPtrs, ComponentHTMLs, ActionPtrLists),
+ list.condense(ActionPtrLists, ActionPtrs),
+ string.append_list(ComponentHTMLs, ComponentHTML),
+ HTML =
+ separator_row(Pref, source_proc, totals_meaningful) ++
+ two_id_line_to_html(Pref, Deep, totals_meaningful, ProcTotal) ++
+ separator_row(Pref, source_proc, totals_meaningful) ++
+ ComponentHTML
+ ).
+
+:- pred proc_in_clique_to_html(preferences::in, deep::in, clique_ptr::in,
+ int::in, proc_dynamic_ptr::in, string::out, list(clique_ptr)::out) is det.
+
+proc_in_clique_to_html(Pref, Deep, CliquePtr, Percent, PDPtr,
+ HTML, ActionPtrs) :-
+ ( valid_proc_dynamic_ptr(Deep, PDPtr) ->
+ deep_lookup_pd_own(Deep, PDPtr, ProcOwn),
+ deep_lookup_pd_desc(Deep, PDPtr, ProcDesc),
+ deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+ PSPtr = PD ^ pd_proc_static,
+ ProcTotal = proc_total_to_two_id_line(Pref, Deep, yes, "",
+ PSPtr, ProcOwn, ProcDesc),
+ child_call_sites(Deep ^ proc_dynamics, Deep ^ proc_statics,
+ PDPtr, GroupPairs),
+ ProcHTML =
+ separator_row(Pref, source_proc, totals_meaningful) ++
+ two_id_line_to_html(Pref, Deep, totals_meaningful, ProcTotal),
+ (
+ GroupPairs = [],
+ HTML = ProcHTML,
+ ActionPtrs = []
+ ;
+ GroupPairs = [_ | _],
+ list.map2(call_site_clique_to_html(Pref, Deep, CliquePtr, Percent),
+ GroupPairs, CallSiteLists, ActionPtrLists),
+ list.condense(CallSiteLists, CallSites),
+ list.condense(ActionPtrLists, ActionPtrs),
+ SortedCallSites = sort_line_groups(Pref ^ pref_criteria,
+ CallSites),
+ BodyHTMLs = list.map(
+ two_id_line_group_to_html(Pref, Deep, totals_meaningful),
+ SortedCallSites),
+ HTML = ProcHTML ++
+ separator_row(Pref, source_proc, totals_meaningful) ++
+ string.append_list(BodyHTMLs)
+ )
+ ;
+ HTML = "",
+ ActionPtrs = []
+ ).
+
+:- pred child_call_sites(proc_dynamics::in, proc_statics::in,
+ proc_dynamic_ptr::in,
+ assoc_list(call_site_static_ptr, call_site_array_slot)::out) is det.
+
+child_call_sites(ProcDynamics, ProcStatics, PDPtr, PairedSlots) :-
+ lookup_proc_dynamics(ProcDynamics, PDPtr, PD),
+ PSPtr = PD ^ pd_proc_static,
+ CSDArray = PD ^ pd_sites,
+ lookup_proc_statics(ProcStatics, PSPtr, PS),
+ CSSArray = PS ^ ps_sites,
+ array.to_list(CSDArray, CSDSlots),
+ array.to_list(CSSArray, CSSSlots),
+ assoc_list.from_corresponding_lists(CSSSlots, CSDSlots, PairedSlots).
+
+%-----------------------------------------------------------------------------%
+
+ % Fails if the procedure is inactive and the preferences say to
+ % hide inactive procedures.
+ %
+:- func lookup_proc_total_to_html(preferences, deep, bool, string,
+ proc_static_ptr) = one_id_line is semidet.
+
+lookup_proc_total_to_html(Pref, Deep, Bold, Prefix, PSPtr) = LineGroup :-
+ deep_lookup_ps_own(Deep, PSPtr, Own),
+ not (
+ Pref ^ pref_inactive ^ inactive_procs = inactive_hide,
+ compute_is_active(Own) = is_not_active
+ ),
+ deep_lookup_ps_desc(Deep, PSPtr, Desc),
+ LineGroup = proc_total_to_html(Pref, Deep, Bold, Prefix, PSPtr, Own, Desc).
+
+:- func lookup_proc_total_to_two_id_line(preferences, deep, bool, string,
+ proc_static_ptr) = two_id_line.
+
+lookup_proc_total_to_two_id_line(Pref, Deep, Bold, Prefix, PSPtr)
+ = LineGroup :-
+ deep_lookup_ps_own(Deep, PSPtr, Own),
+ deep_lookup_ps_desc(Deep, PSPtr, Desc),
+ LineGroup = proc_total_to_two_id_line(Pref, Deep, Bold, Prefix,
+ PSPtr, Own, Desc).
+
+:- func proc_total_to_html(preferences, deep, bool, string,
+ proc_static_ptr, own_prof_info, inherit_prof_info) = one_id_line.
+
+proc_total_to_html(Pref, Deep, Bold, Prefix, PSPtr, Own, Desc)
+ = LineGroup :-
+ proc_total_to_html_base(Pref, Deep, 1, Bold, Prefix, PSPtr,
+ FileName, LineNumber, ProcName, HTML),
+ LineGroup = line_group(FileName, LineNumber, ProcName, Own, Desc, HTML,
+ unit).
+
+:- func proc_total_to_two_id_line(preferences, deep, bool, string,
+ proc_static_ptr, own_prof_info, inherit_prof_info) = two_id_line.
+
+proc_total_to_two_id_line(Pref, Deep, Bold, Prefix, PSPtr, Own, Desc)
+ = LineGroup :-
+ proc_total_to_html_base(Pref, Deep, 2, Bold, Prefix, PSPtr,
+ FileName, LineNumber, ProcName, HTML),
+ LineGroup = line_group(FileName, LineNumber, ProcName, Own, Desc, HTML,
+ unit).
+
+:- pred proc_total_to_html_base(preferences::in, deep::in,
+ int::in, bool::in, string::in, proc_static_ptr::in,
+ string::out, int::out, string::out, string::out) is det.
+
+proc_total_to_html_base(Pref, Deep, Span, Bold, Prefix, PSPtr,
+ FileName, LineNumber, ProcName, HTML) :-
+ proc_static_to_line_group_info(Pref, Deep, PSPtr, FileName, LineNumber,
+ ProcName, WrappedProcName),
+ (
+ Bold = no,
+ BoldStart = "",
+ BoldEnd = ""
+ ;
+ Bold = yes,
+ BoldStart = "<B>",
+ BoldEnd = "</B>"
+ ),
+ HTML = string.format("<TD CLASS=id COLSPAN=%d>%s%s%s%s</TD>\n",
+ [i(Span), s(BoldStart), s(Prefix), s(WrappedProcName), s(BoldEnd)]).
+
+%-----------------------------------------------------------------------------%
+
+:- pred call_site_clique_to_html(preferences::in, deep::in,
+ clique_ptr::in, int::in,
+ pair(call_site_static_ptr, call_site_array_slot)::in,
+ list(two_id_line_group)::out, list(clique_ptr)::out) is det.
+
+call_site_clique_to_html(Pref, Deep, CallerCliquePtr, Percent, Pair,
+ LineGroups, ActionPtrs) :-
+ Pair = CSSPtr - CallSiteArraySlot,
+ deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
+ Kind = CSS ^ css_kind,
+ ( Kind = normal_call_and_callee(_CalleePSPtr, _) ->
+ (
+ CallSiteArraySlot = slot_normal(CSDPtr0),
+ CSDPtr = CSDPtr0
+ ;
+ CallSiteArraySlot = slot_multi(_, _),
+ error("call_site_clique_to_html: normal_call error")
+ ),
+ normal_call_site_clique_to_html(Pref, Deep, CallerCliquePtr,
+ CSDPtr, LineGroups, Percent, ActionPtrs)
+ ;
+ (
+ CallSiteArraySlot = slot_multi(_, CSDPtrs0),
+ array.to_list(CSDPtrs0, CSDPtrs)
+ ;
+ CallSiteArraySlot = slot_normal(_),
+ error("call_site_clique_to_html: non-normal_call error")
+ ),
+ call_site_context(Deep, CSSPtr, FileName, LineNumber),
+ multi_call_site_clique_to_html(Pref, Deep, FileName, LineNumber,
+ Kind, CallerCliquePtr, CSDPtrs, LineGroups, Percent, ActionPtrs)
+ ).
+
+:- func maybe_extract_action_clique(deep, clique_ptr, int,
+ call_site_dynamic_ptr) = list(clique_ptr).
+
+maybe_extract_action_clique(Deep, CallerCliquePtr, Percent, CSDPtr)
+ = ActionPtrs :-
+ ( Percent > 100 ->
+ ActionPtrs = []
+ ;
+ deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
+ deep_lookup_clique_index(Deep, CSD ^ csd_callee, CalleeCliquePtr),
+ ( CalleeCliquePtr = CallerCliquePtr ->
+ ActionPtrs = []
+ ;
+ deep_lookup_csd_desc(Deep, CSDPtr, CSDDesc),
+ CSDOwn = CSD ^ csd_own_prof,
+ CSDTotal = add_own_to_inherit(CSDOwn, CSDDesc),
+ RootTotal = root_total_info(Deep),
+ CSDCallSeqs = inherit_callseqs(CSDTotal),
+ RootCallSeqs = inherit_callseqs(RootTotal),
+ ( CSDCallSeqs * 100 > RootCallSeqs * Percent ->
+ ActionPtrs = [CalleeCliquePtr]
+ ;
+ ActionPtrs = []
+ )
+ )
+ ).
+
+:- pred normal_call_site_clique_to_html(preferences::in, deep::in,
+ clique_ptr::in, call_site_dynamic_ptr::in,
+ list(two_id_line_group)::out, int::in, list(clique_ptr)::out) is det.
+
+normal_call_site_clique_to_html(Pref, Deep, CallerCliquePtr, CSDPtr,
+ LineGroups, Percent, ActionPtrs) :-
+ ( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
+ LineGroup = call_site_dynamic_to_html(Pref, Deep,
+ downward_display, yes(CallerCliquePtr), CSDPtr),
+ LineGroups = [line_to_two_id_subline_group(LineGroup)],
+ ActionPtrs = maybe_extract_action_clique(Deep, CallerCliquePtr,
+ Percent, CSDPtr)
+ ;
+ LineGroups = [],
+ ActionPtrs = []
+ ).
+
+:- pred multi_call_site_clique_to_html(preferences::in, deep::in,
+ string::in, int::in, call_site_kind_and_callee::in, clique_ptr::in,
+ list(call_site_dynamic_ptr)::in, list(two_id_line_group)::out,
+ int::in, list(clique_ptr)::out) is det.
+
+multi_call_site_clique_to_html(Pref, Deep, FileName, LineNumber, Kind,
+ CallerCliquePtr, CSDPtrs, LineGroups, Percent, ActionPtrs) :-
+ ValidCSDPtrs = CSDPtrs,
+ RawCallSiteName = call_site_kind_and_callee_to_html(Kind),
+ CallSiteName = multi_call_site_add_suffix(Pref, RawCallSiteName,
+ ValidCSDPtrs),
+ SubLines = list.map(call_site_dynamic_to_html(Pref, Deep,
+ downward_summary_display, yes(CallerCliquePtr)),
+ ValidCSDPtrs),
+ ActionPtrLists = list.map(
+ maybe_extract_action_clique(Deep, CallerCliquePtr, Percent),
+ ValidCSDPtrs),
+ list.condense(ActionPtrLists, ActionPtrs),
+ sum_line_group_measurements(SubLines, Own, Desc),
+ SummaryHTML =
+ string.format("<TD CLASS=id>%s:%d</TD>\n",
+ [s(escape_break_html_string(FileName)), i(LineNumber)]) ++
+
+ % NOTE: we don't escape HTML special characters for
+ % 'CallSiteName' because it has already been done.
+ string.format("<TD CLASS=id>%s</TD>\n", [s(CallSiteName)]),
+ (
+ Pref ^ pref_summarize = summarize,
+ LineGroup = line_group(FileName, LineNumber, RawCallSiteName,
+ Own, Desc, SummaryHTML, sub_lines(two_id, []))
+ ;
+ Pref ^ pref_summarize = do_not_summarize,
+ LineGroup = line_group(FileName, LineNumber, RawCallSiteName,
+ Own, Desc, SummaryHTML, sub_lines(two_id, SubLines))
+ ),
+ LineGroups = [LineGroup].
+
+%-----------------------------------------------------------------------------%
+
+:- func call_site_summary_to_html(preferences, deep,
+ call_site_static_ptr) = two_id_line_group.
+
+call_site_summary_to_html(Pref, Deep, CSSPtr) = LineGroup :-
+ deep_lookup_call_site_calls(Deep, CSSPtr, CallSiteCallMap),
+ map.to_assoc_list(CallSiteCallMap, CallSiteCallList),
+ deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
+ Kind = CSS ^ css_kind,
+ CallerPSPtr = CSS ^ css_container,
+ call_site_context(Deep, CSSPtr, FileName, LineNumber),
+ ( Kind = normal_call_and_callee(CalleePSPtr, _) ->
+ LineGroup0 = normal_call_site_summary_to_html(Pref, Deep,
+ FileName, LineNumber, CallerPSPtr, CalleePSPtr, CallSiteCallList)
+ ;
+ LineGroup0 = multi_call_site_summary_to_html(Pref, Deep,
+ FileName, LineNumber, Kind, CallerPSPtr, CallSiteCallList)
+ ),
+ CSSContext = string.format("%s:%d",
+ [s(escape_break_html_string(FileName)), i(LineNumber)]),
+ LineGroup = add_context(CSSContext, LineGroup0).
+
+:- func normal_call_site_summary_to_html(preferences, deep, string, int,
+ proc_static_ptr, proc_static_ptr,
+ assoc_list(proc_static_ptr, list(call_site_dynamic_ptr))) =
+ one_two_id_line_group.
+
+normal_call_site_summary_to_html(Pref, Deep, FileName, LineNumber,
+ CallerPSPtr, CalleePSPtr, CallSiteCallList) = LineGroup :-
+ deep_lookup_proc_statics(Deep, CalleePSPtr, CalleePS),
+ ProcName = CalleePS ^ ps_refined_id,
+ (
+ CallSiteCallList = [],
+ Own = zero_own_prof_info,
+ Desc = zero_inherit_prof_info,
+ SummaryHTML =
+ string.format("<TD CLASS=id>%s</TD>\n",
+ [s(proc_static_to_html_ref(Pref, Deep, CalleePSPtr))]),
+ LineGroup = line_group(FileName, LineNumber,
+ ProcName, Own, Desc, SummaryHTML,
+ sub_lines(two_id, []))
+ ;
+ CallSiteCallList = [CallSiteCall],
+ CallSiteCall = CalleePSPtrFromCall - _,
+ require(unify(CalleePSPtr, CalleePSPtrFromCall),
+ "call_site_summary_to_html: callee mismatch"),
+ LineGroup0 = call_site_summary_group_to_html(Pref, Deep,
+ FileName, LineNumber, ProcName, CallerPSPtr, CallSiteCall),
+ LineGroup = line_to_two_id_subline_group(LineGroup0)
+ ;
+ CallSiteCallList = [_, _ | _],
+ error("normal_call_site_summary_to_html: too many procedures")
+ ).
+
+:- func multi_call_site_summary_to_html(preferences, deep, string, int,
+ call_site_kind_and_callee, proc_static_ptr,
+ assoc_list(proc_static_ptr, list(call_site_dynamic_ptr))) =
+ one_two_id_line_group.
+
+multi_call_site_summary_to_html(Pref, Deep, FileName, LineNumber, Kind,
+ CallerPSPtr, CallSiteCallList) = LineGroup :-
+ RawCallSiteName = call_site_kind_and_callee_to_html(Kind),
+ CallSiteName = multi_call_site_add_suffix(Pref, RawCallSiteName,
+ CallSiteCallList),
+ SubLines = list.map(call_site_summary_group_to_html(Pref, Deep,
+ FileName, LineNumber, RawCallSiteName, CallerPSPtr),
+ CallSiteCallList),
+ sum_line_group_measurements(SubLines, Own, Desc),
+
+ % NOTE: we don't escape HTML special characters for
+ % 'CallSiteName' because it has already been done.
+ SummaryHTML =
+ string.format("<TD CLASS=id>%s</TD>\n", [s(CallSiteName)]),
+ (
+ Pref ^ pref_summarize = summarize,
+ LineGroup = line_group(FileName, LineNumber, RawCallSiteName,
+ Own, Desc, SummaryHTML, sub_lines(two_id, []))
+ ;
+ Pref ^ pref_summarize = do_not_summarize,
+ ContextSubLines = list.map(add_context(""), SubLines),
+ LineGroup = line_group(FileName, LineNumber, RawCallSiteName,
+ Own, Desc, SummaryHTML, sub_lines(two_id, ContextSubLines))
+ ).
+
+:- func call_site_summary_group_to_html(preferences, deep,
+ string, int, string, proc_static_ptr,
+ pair(proc_static_ptr, list(call_site_dynamic_ptr))) = one_id_line.
+
+call_site_summary_group_to_html(Pref, Deep, FileName, LineNumber, ProcName,
+ CallerPSPtr, PSPtr - CSDPtrs) = LineGroup :-
+ list.foldl2(accumulate_csd_prof_info(Deep, CallerPSPtr), CSDPtrs,
+ zero_own_prof_info, Own, zero_inherit_prof_info, Desc),
+ HTML =
+ string.format("<TD CLASS=id>%s</TD>\n",
+ [s(proc_static_to_html_ref(Pref, Deep, PSPtr))]),
+ LineGroup = line_group(FileName, LineNumber, ProcName,
+ Own, Desc, HTML, unit).
+
+%-----------------------------------------------------------------------------%
+
+:- func multi_call_site_add_suffix(preferences, string, list(T)) = string.
+
+multi_call_site_add_suffix(Pref, RawCallSiteName, CallList) = CallSiteName :-
+ (
+ CallList = [],
+ CallSiteName = RawCallSiteName ++ " (no calls made)"
+ ;
+ CallList = [_ | _],
+ Summarize = Pref ^ pref_summarize,
+ (
+ Summarize = summarize,
+ CallSiteName = RawCallSiteName ++ " (summary)"
+ ;
+ Summarize = do_not_summarize,
+ CallSiteName = RawCallSiteName
+ )
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred process_call_site_dynamics_group(list(call_site_dynamic_ptr)::in,
+ deep::in, proc_static_ptr::in,
+ maybe(clique_ptr)::in, maybe(clique_ptr)::out,
+ own_prof_info::in, own_prof_info::out,
+ inherit_prof_info::in, inherit_prof_info::out) is det.
+
+process_call_site_dynamics_group([], _, _,
+ MaybeCalleeCliquePtr, MaybeCalleeCliquePtr, Own, Own, Desc, Desc).
+process_call_site_dynamics_group([CSDPtr | CSDPtrs], Deep, CalleePSPtr,
+ MaybeCalleeCliquePtr0, MaybeCalleeCliquePtr, Own0, Own, Desc0, Desc) :-
+ deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
+ PDPtr = CSD ^ csd_callee,
+ deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+ PSPtr = PD ^ pd_proc_static,
+ require(unify(CalleePSPtr, PSPtr),
+ "process_call_site_dynamics_group: callee mismatch"),
+ deep_lookup_clique_index(Deep, PDPtr, CalleeCliquePtr),
+ (
+ MaybeCalleeCliquePtr0 = no,
+ MaybeCalleeCliquePtr1 = yes(CalleeCliquePtr)
+ ;
+ MaybeCalleeCliquePtr0 = yes(PrevCalleeCliquePtr),
+ MaybeCalleeCliquePtr1 = MaybeCalleeCliquePtr0,
+ require(unify(PrevCalleeCliquePtr, CalleeCliquePtr),
+ "process_call_site_dynamics_group: clique mismatch")
+ ),
+ deep_lookup_csd_own(Deep, CSDPtr, CSDOwn),
+ deep_lookup_csd_desc(Deep, CSDPtr, CSDDesc),
+ Own1 = add_own_to_own(Own0, CSDOwn),
+ Desc1 = add_inherit_to_inherit(Desc0, CSDDesc),
+ process_call_site_dynamics_group(CSDPtrs, Deep, CalleePSPtr,
+ MaybeCalleeCliquePtr1, MaybeCalleeCliquePtr, Own1, Own, Desc1, Desc).
+
+:- pred accumulate_csd_prof_info(deep::in, proc_static_ptr::in,
+ call_site_dynamic_ptr::in,
+ own_prof_info::in, own_prof_info::out,
+ inherit_prof_info::in, inherit_prof_info::out) is det.
+
+accumulate_csd_prof_info(Deep, CallerPSPtr, CSDPtr, Own0, Own, Desc0, Desc) :-
+ deep_lookup_csd_own(Deep, CSDPtr, CSDOwn),
+ deep_lookup_csd_desc(Deep, CSDPtr, CSDDesc),
+ add_own_to_own(Own0, CSDOwn) = Own,
+ add_inherit_to_inherit(Desc0, CSDDesc) = Desc1,
+ deep_lookup_csd_comp_table(Deep, CSDPtr, CompTableArray),
+ ( map.search(CompTableArray, CallerPSPtr, InnerTotal) ->
+ Desc = subtract_inherit_from_inherit(InnerTotal, Desc1)
+ ;
+ Desc = Desc1
+ ).
+
+:- func call_site_dynamic_to_html_with_caller(preferences, deep,
+ call_site_display, call_site_dynamic_ptr) = two_id_line.
+
+call_site_dynamic_to_html_with_caller(Pref, Deep, Display, CSDPtr)
+ = LineGroup :-
+ deep_extract_csdptr_caller(Deep, CSDPtr, CallerPDPtr),
+ deep_lookup_clique_index(Deep, CallerPDPtr, CallerClique),
+ LineGroup = call_site_dynamic_to_html(Pref, Deep, Display,
+ yes(CallerClique), CSDPtr).
+
+:- func call_site_dynamic_to_html(preferences, deep, call_site_display,
+ maybe(clique_ptr), call_site_dynamic_ptr) = two_id_line.
+
+call_site_dynamic_to_html(Pref, Deep, CallSiteDisplay, MaybeCallerCliquePtr,
+ CSDPtr) = LineGroup :-
+ require(valid_call_site_dynamic_ptr(Deep, CSDPtr),
+ "call_site_dynamic_to_html: invalid call_site_dynamic_ptr"),
+ deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
+ CallerPDPtr = CSD ^ csd_caller,
+ CalleePDPtr = CSD ^ csd_callee,
+ CallSiteOwn = CSD ^ csd_own_prof,
+ deep_lookup_csd_desc(Deep, CSDPtr, CallSiteDesc),
+ deep_lookup_clique_index(Deep, CalleePDPtr, CalleeCliquePtr),
+ call_site_dynamic_context(Deep, CSDPtr, FileName, LineNumber),
+ Context = string.format("%s:%d",
+ [s(escape_break_html_string(FileName)), i(LineNumber)]),
+ HTML = call_to_html(Pref, Deep, CallSiteDisplay, Context,
+ CallerPDPtr, CalleePDPtr, MaybeCallerCliquePtr, CalleeCliquePtr),
+ ProcName = escape_break_html_string(proc_dynamic_name(Deep, CalleePDPtr)),
+ LineGroup = line_group(FileName, LineNumber, ProcName,
+ CallSiteOwn, CallSiteDesc, HTML, unit).
+
+%-----------------------------------------------------------------------------%
+
+:- type call_site_display
+ ---> call_site_display(
+ display_context :: call_site_context,
+ display_proc_name :: call_site_proc_name,
+ display_url :: url_with_proc_name,
+ display_wrap :: wrap_with_url
+ ).
+
+:- type call_site_context
+ ---> call_context
+ ; empty_context.
+
+:- type call_site_proc_name
+ ---> caller_proc_name
+ ; callee_proc_name.
+
+:- type url_with_proc_name
+ ---> caller_clique
+ ; callee_clique.
+
+:- type wrap_with_url
+ ---> wrap_url_always
+ ; wrap_url_if_cross_clique(assume_cross_clique)
+ ; wrap_url_never.
+
+:- type assume_cross_clique
+ ---> assume_cross_clique
+ ; assume_within_clique.
+
+:- func ancestor_display = call_site_display.
+:- func downward_display = call_site_display.
+:- func downward_summary_display = call_site_display.
+
+ancestor_display =
+ call_site_display(call_context, caller_proc_name, caller_clique,
+ wrap_url_always).
+
+downward_display =
+ call_site_display(call_context, callee_proc_name, callee_clique,
+ wrap_url_if_cross_clique(assume_within_clique)).
+
+downward_summary_display =
+ call_site_display(empty_context, callee_proc_name, callee_clique,
+ wrap_url_if_cross_clique(assume_within_clique)).
+
+%-----------------------------------------------------------------------------%
+
+:- func call_to_html(preferences, deep, call_site_display, string,
+ proc_dynamic_ptr, proc_dynamic_ptr, maybe(clique_ptr), clique_ptr)
+ = string.
+
+call_to_html(Pref, Deep, CallSiteDisplay, CallContext,
+ CallerPDPtr, CalleePDPtr,
+ MaybeCallerCliquePtr, CalleeCliquePtr) = HTML :-
+ (
+ MaybeCallerCliquePtr = yes(CallerCliquePtr0),
+ CallerCliquePtr = CallerCliquePtr0
+ ;
+ MaybeCallerCliquePtr = no,
+ CallerCliquePtr = dummy_clique_ptr
+ ),
+ (
+ CallSiteDisplay ^ display_context = call_context,
+ Context = CallContext
+ ;
+ CallSiteDisplay ^ display_context = empty_context,
+ Context = ""
+ ),
+ (
+ CallSiteDisplay ^ display_proc_name = caller_proc_name,
+ ProcName = proc_dynamic_name(Deep, CallerPDPtr)
+ ;
+ CallSiteDisplay ^ display_proc_name = callee_proc_name,
+ ProcName = proc_dynamic_name(Deep, CalleePDPtr)
+ ),
+ (
+ CallSiteDisplay ^ display_url = caller_clique,
+ ChosenCliquePtr = CallerCliquePtr
+ ;
+ CallSiteDisplay ^ display_url = callee_clique,
+ ChosenCliquePtr = CalleeCliquePtr
+ ),
+ WrappedProcName = string.format("<A HREF=""%s"">%s</A>",
+ [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_clique(ChosenCliquePtr))),
+ s(escape_break_html_string(ProcName))]),
+ (
+ CallSiteDisplay ^ display_wrap = wrap_url_always,
+ UsedProcName0 = WrappedProcName
+ ;
+ CallSiteDisplay ^ display_wrap = wrap_url_if_cross_clique(Assume),
+ (
+ MaybeCallerCliquePtr = yes(_),
+ ( CallerCliquePtr \= CalleeCliquePtr ->
+ UsedProcName0 = WrappedProcName
+ ;
+ UsedProcName0 = escape_break_html_string(ProcName)
+ )
+ ;
+ MaybeCallerCliquePtr = no,
+ (
+ Assume = assume_cross_clique,
+ UsedProcName0 = WrappedProcName
+ ;
+ Assume = assume_within_clique,
+ UsedProcName0 = escape_break_html_string(ProcName)
+ )
+ )
+ ;
+ CallSiteDisplay ^ display_wrap = wrap_url_never,
+ UsedProcName0 = escape_break_html_string(ProcName)
+ ),
+ (
+ UsedProcName0 = WrappedProcName,
+ valid_clique_ptr(Deep, ChosenCliquePtr)
+ ->
+ UsedProcName = UsedProcName0
+ ;
+ UsedProcName = escape_break_html_string(ProcName)
+ ),
+ HTML =
+ string.format("<TD CLASS=id>%s</TD>\n", [s(Context)]) ++
+ string.format("<TD CLASS=id>%s</TD>\n", [s(UsedProcName)]).
+
+%-----------------------------------------------------------------------------%
+
+:- pred call_site_dynamic_context(deep::in, call_site_dynamic_ptr::in,
+ string::out, int::out) is det.
+
+call_site_dynamic_context(Deep, CSDPtr, FileName, LineNumber) :-
+ deep_lookup_call_site_static_map(Deep, CSDPtr, CSSPtr),
+ deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
+ PSPtr = CSS ^ css_container,
+ LineNumber = CSS ^ css_line_num,
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ FileName = PS ^ ps_file_name.
+
+%-----------------------------------------------------------------------------%
+
+:- pred proc_callers_to_html(preferences::in, deep::in, proc_static_ptr::in,
+ caller_groups::in, int::in,
+ maybe_error({id_fields, string, string, string})::out,
+ io::di, io::uo) is det.
+
+proc_callers_to_html(Pref, Deep, PSPtr, CallerGroups, BunchNum0, MaybePage,
+ !IO) :-
+ deep_lookup_proc_callers(Deep, PSPtr, CallerCSDPtrs),
+ PrefContour = Pref ^ pref_contour,
+ (
+ PrefContour = do_not_apply_contour_exclusion,
+ CallerCSDPtrPairs = list.map(pair_self, CallerCSDPtrs),
+ MaybeErrorMsg = no
+ ;
+ PrefContour = apply_contour_exclusion,
+ MaybeMaybeExcludeFile = Deep ^ exclude_contour_file,
+ (
+ MaybeMaybeExcludeFile = no,
+ % There is no contour exclusion file, so do the same as for
+ % do_not_apply_contour_exclusion.
+ CallerCSDPtrPairs = list.map(pair_self, CallerCSDPtrs),
+ MaybeErrorMsg = no
+ ;
+ MaybeMaybeExcludeFile = yes(MaybeExcludeFile),
+ (
+ MaybeExcludeFile = ok(ExcludeSpec),
+ CallerCSDPtrPairs = list.map(pair_contour(Deep, ExcludeSpec),
+ CallerCSDPtrs),
+ MaybeErrorMsg = no
+ ;
+ MaybeExcludeFile = error(ErrorMsg),
+ MaybeErrorMsg = yes(ErrorMsg ++ "\n<br>"),
+ CallerCSDPtrPairs = list.map(pair_self, CallerCSDPtrs)
+ )
+ )
+ ),
+ ProcName = proc_static_name(Deep, PSPtr),
+ CmdSite = deep_cmd_proc_callers(PSPtr, group_by_call_site, 1,
+ PrefContour),
+ CmdProc = deep_cmd_proc_callers(PSPtr, group_by_proc, 1,
+ PrefContour),
+ CmdModule = deep_cmd_proc_callers(PSPtr, group_by_module, 1,
+ PrefContour),
+ CmdClique = deep_cmd_proc_callers(PSPtr, group_by_clique, 1,
+ PrefContour),
+ LinkSite = "[Group callers by call site]",
+ LinkProc = "[Group callers by procedure]",
+ LinkModule = "[Group callers by module]",
+ LinkClique = "[Group callers by clique]",
+ % Don't display more lines than BunchSize, to avoid quadratic behaviour
+ % in Netscape.
+ BunchSize = 100,
+ (
+ CallerGroups = group_by_call_site,
+ GroupList = group_csds_by_call_site(Deep, CallerCSDPtrPairs),
+ Lines = list.map(proc_callers_call_site_to_html(Pref, Deep, PSPtr),
+ GroupList),
+ SortedLines = sort_line_groups(Pref ^ pref_criteria, Lines),
+ IdFields = source_proc,
+ Entity = "call site",
+ GroupToggles =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdProc)),
+ s(LinkProc)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdModule)),
+ s(LinkModule)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdClique)),
+ s(LinkClique)])
+ ;
+ CallerGroups = group_by_proc,
+ GroupList = group_csds_by_procedure(Deep, CallerCSDPtrPairs),
+ Lines = list.map(proc_callers_proc_to_html(Pref, Deep, PSPtr),
+ GroupList),
+ SortedLines = sort_line_groups(Pref ^ pref_criteria, Lines),
+ IdFields = source_proc,
+ Entity = "procedure",
+ GroupToggles =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdSite)),
+ s(LinkSite)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdModule)),
+ s(LinkModule)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdClique)),
+ s(LinkClique)])
+ ;
+ CallerGroups = group_by_module,
+ GroupList = group_csds_by_module(Deep, CallerCSDPtrPairs),
+ RawLines = list.map(proc_callers_module_to_html(Pref, Deep, PSPtr),
+ GroupList),
+ SortedRawLines = sort_line_groups(Pref ^ pref_criteria, RawLines),
+ SortedLines = add_ranks(SortedRawLines),
+ IdFields = rank_module,
+ Entity = "module",
+ GroupToggles =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdSite)),
+ s(LinkSite)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdProc)),
+ s(LinkProc)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdClique)),
+ s(LinkClique)])
+ ;
+ CallerGroups = group_by_clique,
+ GroupList = group_csds_by_clique(Deep, CallerCSDPtrPairs),
+ RawLines = list.map(proc_callers_clique_to_html(Pref, Deep, PSPtr),
+ GroupList),
+ SortedRawLines = sort_line_groups(Pref ^ pref_criteria, RawLines),
+ SortedLines = add_ranks(SortedRawLines),
+ IdFields = source_proc,
+ Entity = "clique",
+ GroupToggles =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdSite)),
+ s(LinkSite)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdProc)),
+ s(LinkProc)]) ++
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, CmdModule)),
+ s(LinkModule)])
+ ),
+ % SortedLines may contain many thousand elements, and Netscape
+ % chokes on the output unless we filter them or break them into chunks.
+ % This simple limit device is temporary until we decide what filtering
+ % and/or chunking mechanism we want to use.
+ list.length(SortedLines, NumLines),
+ select_line_bunch(NumLines, BunchNum0, BunchNum, BunchSize,
+ SortedLines, DisplayedLines),
+ Banner = proc_callers_banner(PSPtr, ProcName, Pref, Deep,
+ NumLines, BunchSize, BunchNum, Entity),
+ DisplayedHTMLs = list.map(
+ two_id_line_to_html(Pref, Deep, totals_meaningful),
+ DisplayedLines),
+ HTML = string.append_list(DisplayedHTMLs),
+ ( BunchNum > 1 ->
+ FirstCmd = deep_cmd_proc_callers(PSPtr, CallerGroups, 1, PrefContour),
+ FirstLink = "First group",
+ FirstToggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, FirstCmd)), s(FirstLink)])
+ ;
+ FirstToggle = ""
+ ),
+ ( BunchNum > 2 ->
+ PrevCmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum - 1,
+ PrefContour),
+ PrevLink = "Previous group",
+ PrevToggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, PrevCmd)), s(PrevLink)])
+ ;
+ PrevToggle = ""
+ ),
+ ( NumLines > BunchNum * BunchSize ->
+ NextCmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum + 1,
+ PrefContour),
+ NextLink = "Next group",
+ NextToggle =
+ string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, NextCmd)), s(NextLink)])
+ ;
+ NextToggle = ""
+ ),
+ Toggles = GroupToggles ++ FirstToggle ++ PrevToggle ++ NextToggle,
+ (
+ MaybeErrorMsg = no,
+ MaybePage = ok({IdFields, Banner, HTML, Toggles})
+ ;
+ MaybeErrorMsg = yes(Msg),
+ MaybePage = error(Msg)
+ ).
+
+:- pred select_line_bunch(int::in, int::in, int::out, int::in, list(T)::in,
+ list(T)::out) is det.
+
+select_line_bunch(NumLines, BunchNum0, BunchNum, BunchSize,
+ Lines, DisplayedLines) :-
+ ToDelete = (BunchNum0 - 1) * BunchSize,
+ (
+ list.drop(ToDelete, Lines, RemainingLines0),
+ RemainingLines0 = [_ | _]
+ ->
+ BunchNum = BunchNum0,
+ RemainingLines = RemainingLines0,
+ RemainingNumLines = NumLines - ToDelete
+ ;
+ BunchNum = 1,
+ RemainingLines = Lines,
+ RemainingNumLines = NumLines
+ ),
+ ( RemainingNumLines > BunchSize ->
+ list.take_upto(BunchSize, RemainingLines, DisplayedLines)
+ ;
+ DisplayedLines = RemainingLines
+ ).
+
+:- func proc_callers_banner(proc_static_ptr, string, preferences, deep,
+ int, int, int, string) = string.
+
+proc_callers_banner(PSPtr, ProcName, Pref, Deep, NumLines, BunchSize, BunchNum,
+ Parent) = HTML :-
+ Cmd = deep_cmd_proc(PSPtr),
+ WrappedProcName = string.format("<A HREF=""%s"">%s</A>",
+ [s(deep_cmd_pref_to_url(Pref, Deep, Cmd)),
+ s(escape_break_html_string(ProcName))]),
+ ( NumLines = 0 ->
+ HTML = string.format("<H3>There are no %ss calling %s</H3>",
+ [s(Parent), s(WrappedProcName)])
+ ; NumLines = 1 ->
+ HTML = string.format("<H3>There is one %s calling %s:</H3>\n",
+ [s(Parent), s(WrappedProcName)])
+ ; NumLines =< BunchSize ->
+ HTML = string.format("<H3>The %d %ss calling %s:</H3>",
+ [i(NumLines), s(Parent), s(WrappedProcName)])
+ ; BunchNum = 1 ->
+ HTML = string.format(
+ "<H3>There are %d %ss calling %s, showing first %d:</H3>",
+ [i(NumLines), s(Parent), s(WrappedProcName), i(BunchSize)])
+ ;
+ First = (BunchNum - 1) * BunchSize + 1,
+ Last0 = (BunchNum) * BunchSize,
+ ( Last0 > NumLines ->
+ Last = NumLines
+ ;
+ Last = Last0
+ ),
+ HTML = string.format(
+ "<H3>There are %d %ss calling %s, showing %d to %d:</H3>",
+ [i(NumLines), s(Parent), s(WrappedProcName), i(First), i(Last)])
+ ).
+
+:- func proc_callers_call_site_to_html(preferences, deep, proc_static_ptr,
+ pair(call_site_static_ptr, list(call_site_dynamic_ptr))) = two_id_line.
+
+proc_callers_call_site_to_html(Pref, Deep, CalleePSPtr, CSSPtr - CSDPtrs)
+ = LineGroup :-
+ call_site_context(Deep, CSSPtr, FileName, LineNumber),
+ deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
+ CallerPSPtr = CSS ^ css_container,
+ deep_lookup_proc_statics(Deep, CallerPSPtr, CallerPS),
+ CallerProcName = CallerPS ^ ps_refined_id,
+ compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
+ HTML =
+ string.format("<TD CLASS=id>%s:%d</TD>\n",
+ [s(escape_break_html_string(FileName)), i(LineNumber)]) ++
+ string.format("<TD CLASS=id>%s</TD>\n",
+ [s(proc_static_to_html_ref(Pref, Deep, CallerPSPtr))]),
+ LineGroup = line_group(FileName, LineNumber, CallerProcName,
+ Own, Desc, HTML, unit).
+
+:- func proc_callers_proc_to_html(preferences, deep, proc_static_ptr,
+ pair(proc_static_ptr, list(call_site_dynamic_ptr))) = two_id_line.
+
+proc_callers_proc_to_html(Pref, Deep, CalleePSPtr, CallerPSPtr - CSDPtrs)
+ = LineGroup :-
+ proc_static_context(Deep, CallerPSPtr, FileName, LineNumber),
+ deep_lookup_proc_statics(Deep, CallerPSPtr, CallerPS),
+ CallerProcName = CallerPS ^ ps_refined_id,
+ compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
+ HTML =
+ string.format("<TD CLASS=id>%s:%d</TD>\n",
+ [s(escape_break_html_string(FileName)), i(LineNumber)]) ++
+ string.format("<TD CLASS=id>%s</TD>\n",
+ [s(proc_static_to_html_ref(Pref, Deep, CallerPSPtr))]),
+ LineGroup = line_group(FileName, LineNumber, CallerProcName,
+ Own, Desc, HTML, unit).
+
+:- func proc_callers_module_to_html(preferences, deep, proc_static_ptr,
+ pair(string, list(call_site_dynamic_ptr))) = one_id_line.
+
+proc_callers_module_to_html(Pref, Deep, CalleePSPtr, ModuleName - CSDPtrs)
+ = LineGroup :-
+ compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
+ HTML = string.format("<TD CLASS=id>%s</TD>\n",
+ [s(module_name_to_html_ref(Pref, Deep, ModuleName))]),
+ % We don't have filename information for modules, and line numbers
+ % are not meaningful for modules.
+ LineGroup = line_group(ModuleName, 0, ModuleName,
+ Own, Desc, HTML, unit).
+
+:- func proc_callers_clique_to_html(preferences, deep, proc_static_ptr,
+ pair(clique_ptr, list(call_site_dynamic_ptr))) = one_id_line.
+
+proc_callers_clique_to_html(Pref, Deep, CalleePSPtr, CliquePtr - CSDPtrs)
+ = LineGroup :-
+ compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
+ deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
+ deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
+ EntryPDPtr = EntryCSD ^ csd_callee,
+ proc_dynamic_context(Deep, EntryPDPtr, FileName, LineNumber),
+ ProcName = proc_dynamic_name(Deep, EntryPDPtr),
+ HTML = string.format("<TD CLASS=id>%s</TD>\n",
+ [s(clique_ptr_to_html_ref(Pref, Deep, ProcName, CliquePtr))]),
+ LineGroup = line_group(FileName, LineNumber, ProcName,
+ Own, Desc, HTML, unit).
+
+%-----------------------------------------------------------------------------%
+
+:- func proc_summary_to_html(preferences, deep, proc_static_ptr) = string.
+
+proc_summary_to_html(Pref, Deep, PSPtr) = HTML :-
+ SumHTML = two_id_line_to_html(Pref, Deep, totals_meaningful,
+ lookup_proc_total_to_two_id_line(Pref, Deep, yes, "", PSPtr)),
+ deep_lookup_proc_statics(Deep, PSPtr, PS),
+ CSSPtrsArray = PS ^ ps_sites,
+ array.to_list(CSSPtrsArray, CSSPtrs),
+ CallSiteGroups = list.map(call_site_summary_to_html(Pref, Deep), CSSPtrs),
+ SortedCallSiteGroups = sort_line_groups(Pref ^ pref_criteria,
+ CallSiteGroups),
+ BodyHTMLs = list.map(
+ two_id_line_group_to_html(Pref, Deep, totals_meaningful),
+ SortedCallSiteGroups),
+ string.append_list(BodyHTMLs, BodyHTML0),
+ (
+ SortedCallSiteGroups = [],
+ BodyHTML = BodyHTML0
+ ;
+ SortedCallSiteGroups = [_ | _],
+ BodyHTML =
+ BodyHTML0 ++
+ separator_row(Pref, source_proc, totals_meaningful)
+ ),
+ HTML =
+ SumHTML ++
+ separator_row(Pref, source_proc, totals_meaningful) ++
+ BodyHTML.
+
+:- func proc_summary_toggles_to_html(preferences, deep, proc_static_ptr)
+ = string.
+
+proc_summary_toggles_to_html(Pref, Deep, PSPtr) = HTML :-
+ PrefContour = Pref ^ pref_contour,
+ Msg1 = "[Parent call sites]",
+ Cmd1 = deep_cmd_proc_callers(PSPtr, group_by_call_site, 1, PrefContour),
+ Msg2 = "[Parent procedures]",
+ Cmd2 = deep_cmd_proc_callers(PSPtr, group_by_proc, 1, PrefContour),
+ Msg3 = "[Parent modules]",
+ Cmd3 = deep_cmd_proc_callers(PSPtr, group_by_module, 1, PrefContour),
+ Msg4 = "[Parent cliques]",
+ Cmd4 = deep_cmd_proc_callers(PSPtr, group_by_clique, 1, PrefContour),
+ Link1 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, Cmd1)), s(Msg1)]),
+ Link2 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, Cmd2)), s(Msg2)]),
+ Link3 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, Cmd3)), s(Msg3)]),
+ Link4 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
+ [s(deep_cmd_pref_to_url(Pref, Deep, Cmd4)), s(Msg4)]),
+ HTML =
+ Link1 ++
+ Link2 ++
+ Link3 ++
+ Link4.
+
+%-----------------------------------------------------------------------------%
+
+:- func wrap_clique_links(clique_ptr, preferences, deep, string,
+ order_criteria) = string.
+
+wrap_clique_links(CliquePtr, Pref0, Deep, Str0, Criteria) = Str :-
+ Cmd = deep_cmd_clique(CliquePtr),
+ Pref = Pref0 ^ pref_criteria := Criteria,
+ URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
+ Str = string.format("<A HREF=%s>%s</A>",
+ [s(URL), s(escape_break_html_string(Str0))]).
+
+:- func wrap_proc_links(proc_static_ptr, preferences, deep, string,
+ order_criteria) = string.
+
+wrap_proc_links(PSPtr, Pref0, Deep, Str0, Criteria) = Str :-
+ Cmd = deep_cmd_proc(PSPtr),
+ Pref = Pref0 ^ pref_criteria := Criteria,
+ URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
+ Str = string.format("<A HREF=%s>%s</A>",
+ [s(URL), s(escape_break_html_string(Str0))]).
+
+:- func wrap_proc_callers_links(proc_static_ptr, caller_groups, int,
+ preferences, deep, string, order_criteria) = string.
+
+wrap_proc_callers_links(PSPtr, CallerGroups, BunchNum, Pref0, Deep,
+ Str0, Criteria) = Str :-
+ PrefContour = Pref0 ^ pref_contour,
+ Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, PrefContour),
+ Pref = Pref0 ^ pref_criteria := Criteria,
+ URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
+ Str = string.format("<A HREF=%s>%s</A>",
+ [s(URL), s(escape_break_html_string(Str0))]).
+
+:- func wrap_module_links(string, preferences, deep, string,
+ order_criteria) = string.
+
+wrap_module_links(ModuleName, Pref0, Deep, Str0, Criteria) = Str :-
+ Cmd = deep_cmd_module(ModuleName),
+ Pref = Pref0 ^ pref_criteria := Criteria,
+ URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
+ Str = string.format("<A HREF=%s>%s</A>",
+ [s(URL), s(escape_break_html_string(Str0))]).
+
+:- func wrap_modules_links(preferences, deep, string, order_criteria) = string.
+
+wrap_modules_links(Pref0, Deep, Str0, Criteria) = Str :-
+ Cmd = deep_cmd_program_modules,
+ Pref = Pref0 ^ pref_criteria := Criteria,
+ URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
+ Str = string.format("<A HREF=%s>%s</A>",
+ [s(URL), s(escape_break_html_string(Str0))]).
+
+:- func wrap_top_procs_links(display_limit, preferences, deep, string,
+ order_criteria) = string.
+
+wrap_top_procs_links(Limit, Pref, Deep, Str0, Criteria) = Str :-
+ (
+ Criteria = by_context,
+ Str = Str0
+ ;
+ Criteria = by_name,
+ Str = Str0
+ ;
+ Criteria = by_cost(CostKind, InclDesc, Scope),
+ Cmd = deep_cmd_top_procs(Limit, CostKind, InclDesc, Scope),
+ URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
+ Str = string.format("<A HREF=%s>%s</A>",
+ [s(URL), s(escape_break_html_string(Str0))])
+ ).
Index: query.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/query.m,v
retrieving revision 1.29
diff -u -b -r1.29 query.m
--- query.m 25 Sep 2008 03:47:03 -0000 1.29
+++ query.m 25 Sep 2008 04:01:33 -0000
@@ -323,28 +323,20 @@
:- import_module apply_exclusion.
:- import_module create_report.
:- import_module display_report.
-:- import_module exclude.
:- import_module html_format.
:- import_module measurements.
+:- import_module old_query.
:- import_module report.
-:- import_module top_procs.
:- import_module util.
-:- import_module array.
-:- import_module assoc_list.
-:- import_module bool.
:- import_module char.
:- import_module exception.
-:- import_module float.
:- import_module int.
:- import_module list.
-:- import_module map.
:- import_module math.
:- import_module maybe.
-:- import_module pair.
:- import_module require.
:- import_module string.
-:- import_module unit.
:- import_module univ.
%-----------------------------------------------------------------------------%
@@ -438,1828 +430,6 @@
HTML = htmlize_display(Deep, Prefs, Display),
HTMLStr = html_to_string(HTML).
- % Old deep profiler cgi code. This should remain supported until all cmds
- % have been updated to use the data structures in report.m.
- %
-:- pred old_exec(cmd::in, preferences::in, deep::in, string::out,
- io::di, io::uo) is det.
-
-old_exec(deep_cmd_restart, _Pref, _Deep, _HTML, !IO) :-
- % Our caller is supposed to filter out restart commands.
- error("exec: found restart command").
-old_exec(deep_cmd_quit, _Pref, Deep, HTML, !IO) :-
- HTML = string.format(
- "<H3>Shutting down deep profile server for %s.</H3>\n",
- [s(Deep ^ data_file_name)]).
-old_exec(deep_cmd_timeout(TimeOut), _Pref, _Deep, HTML, !IO) :-
- HTML = string.format("<H3>Timeout set to %d minutes</H3>\n", [i(TimeOut)]).
-old_exec(Cmd, Pref, Deep, HTML, !IO) :-
- Cmd = deep_cmd_menu,
- HTML = generate_menu_page(Cmd, Pref, Deep).
-old_exec(Cmd, Pref, Deep, HTML, !IO) :-
- Cmd = deep_cmd_top_procs(Limit, CostKind, InclDesc, Scope),
- HTML = generate_top_procs_page(Cmd, Limit, CostKind, InclDesc, Scope,
- Pref, Deep).
-old_exec(deep_cmd_dump_proc_static(PSPtr), _Pref, Deep, HTML, !IO) :-
- HTML = generate_proc_static_debug_page(PSPtr, Deep).
-old_exec(deep_cmd_dump_proc_dynamic(PDPtr), _Pref, Deep, HTML, !IO) :-
- HTML = generate_proc_dynamic_debug_page(PDPtr, Deep).
-old_exec(deep_cmd_dump_call_site_static(CSSPtr), _Pref, Deep, HTML, !IO) :-
- HTML = generate_call_site_static_debug_page(CSSPtr, Deep).
-old_exec(deep_cmd_dump_call_site_dynamic(CSDPtr), _Pref, Deep, HTML, !IO) :-
- HTML = generate_call_site_dynamic_debug_page(CSDPtr, Deep).
-old_exec(Cmd, Pref, Deep, HTML, !IO) :-
- Cmd = deep_cmd_proc(PSPtr),
- ( valid_proc_static_ptr(Deep, PSPtr) ->
- HTML = generate_proc_page(Cmd, PSPtr, Pref, Deep)
- ;
- HTML =
- page_banner(Cmd, Pref) ++
- "There is no procedure with that number.\n" ++
- page_footer(Cmd, Pref, Deep)
- ).
-old_exec(Cmd, Pref, Deep, HTML, !IO) :-
- Cmd = deep_cmd_root(MaybePercent),
- deep_lookup_clique_index(Deep, Deep ^ root, RootCliquePtr),
- (
- MaybePercent = yes(Percent),
- HTML = chase_the_action(Cmd, RootCliquePtr, Pref, Deep, Percent)
- ;
- MaybePercent = no,
- generate_clique_page(Cmd, RootCliquePtr, Pref, Deep, HTML, 100, _)
- ).
-old_exec(Cmd, Pref, Deep, HTML, !IO) :-
- Cmd = deep_cmd_clique(CliquePtr),
- ( valid_clique_ptr(Deep, CliquePtr) ->
- generate_clique_page(Cmd, CliquePtr, Pref, Deep, HTML, 100, _)
- ;
- HTML =
- page_banner(Cmd, Pref) ++
- "There is no clique with that number.\n" ++
- page_footer(Cmd, Pref, Deep)
- ).
-old_exec(Cmd, Pref0, Deep, HTML, !IO) :-
- Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, Contour),
- Pref = Pref0 ^ pref_contour := Contour,
- ( valid_proc_static_ptr(Deep, PSPtr) ->
- generate_proc_callers_page(Cmd, PSPtr, CallerGroups, BunchNum,
- Pref, Deep, HTML, !IO)
- ;
- HTML =
- page_banner(Cmd, Pref) ++
- "There is no procedure with that number.\n" ++
- page_footer(Cmd, Pref, Deep)
- ).
-old_exec(Cmd, Pref, Deep, HTML, !IO) :-
- Cmd = deep_cmd_program_modules,
- HTML = generate_modules_page(Cmd, Pref, Deep).
-old_exec(Cmd, Pref, Deep, HTML, !IO) :-
- Cmd = deep_cmd_module(ModuleName),
- ( map.search(Deep ^ module_data, ModuleName, ModuleData) ->
- HTML = generate_module_page(Cmd, ModuleName, ModuleData, Pref, Deep)
- ;
- HTML =
- page_banner(Cmd, Pref) ++
- "There is no procedure with that number.\n" ++
- page_footer(Cmd, Pref, Deep)
- ).
-old_exec(deep_cmd_dump_clique(CliquePtr), _Pref, Deep, HTML, !IO) :-
- HTML = generate_clique_debug_page(CliquePtr, Deep).
-old_exec(deep_cmd_procrep_coverage(_), _, _, HTML, !IO) :-
- HTML = "query.m: deep_cmd_procrep_coverage is unsupported by old_exec\n".
-
-%-----------------------------------------------------------------------------%
-
-:- func generate_proc_static_debug_page(proc_static_ptr, deep) = string.
-
-generate_proc_static_debug_page(PSPtr, Deep) = HTML :-
- ( valid_proc_static_ptr(Deep, PSPtr) ->
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- Refined = PS ^ ps_refined_id,
- Raw = PS ^ ps_raw_id,
- FileName = PS ^ ps_file_name,
- HTML =
- "<HTML>\n" ++
- Refined ++ " " ++ Raw ++ " " ++ FileName ++ " " ++
- string.int_to_string(array.max(PS ^ ps_sites)) ++
- "</HTML>\n"
- ;
- HTML =
- "<HTML>\n" ++
- "Invalid proc_static_ptr" ++
- "</HTML>\n"
- ).
-
-:- func generate_proc_dynamic_debug_page(proc_dynamic_ptr, deep) = string.
-
-generate_proc_dynamic_debug_page(PDPtr, Deep) = HTML :-
- ( valid_proc_dynamic_ptr(Deep, PDPtr) ->
- deep_lookup_proc_dynamics(Deep, PDPtr, PD),
- PSPtr = PD ^ pd_proc_static,
- PSPtr = proc_static_ptr(PSI),
- HTML =
- "<HTML>\n" ++
- string.format("proc_static %d, ", [i(PSI)]) ++
- array_slots_to_html(PD ^ pd_sites) ++
- "</HTML>\n"
- ;
- HTML =
- "<HTML>\n" ++
- "Invalid proc_dynamic_ptr" ++
- "</HTML>\n"
- ).
-
-:- func generate_call_site_static_debug_page(call_site_static_ptr, deep)
- = string.
-
-generate_call_site_static_debug_page(CSSPtr, Deep) = HTML :-
- ( valid_call_site_static_ptr(Deep, CSSPtr) ->
- deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
- ContainerPtr = CSS ^ css_container,
- ContainerPtr = proc_static_ptr(Container),
- HTML =
- "<HTML>\n" ++
- string.int_to_string(Container) ++ " " ++
- string.int_to_string(CSS ^ css_slot_num) ++ " " ++
- string.int_to_string(CSS ^ css_line_num) ++ " " ++
- kind_and_callee_to_string(CSS ^ css_kind) ++ " " ++
- CSS ^ css_goal_path ++
- "</HTML>\n"
- ;
- HTML =
- "<HTML>\n" ++
- "Invalid call_site_static_ptr" ++
- "</HTML>\n"
- ).
-
-:- func generate_call_site_dynamic_debug_page(call_site_dynamic_ptr, deep)
- = string.
-
-generate_call_site_dynamic_debug_page(CSDPtr, Deep) = HTML :-
- ( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
- deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
- CSD ^ csd_caller = proc_dynamic_ptr(CallerPDI),
- CSD ^ csd_callee = proc_dynamic_ptr(CalleePDI),
- HTML =
- "<HTML>\n" ++
- string.int_to_string(CallerPDI) ++ " -> " ++
- string.int_to_string(CalleePDI) ++ ": " ++
- own_to_string(CSD ^ csd_own_prof) ++
- "</HTML>\n"
- ;
- HTML =
- "<HTML>\n" ++
- "Invalid call_site_dynamic_ptr" ++
- "</HTML>\n"
- ).
-
-:- func generate_clique_debug_page(clique_ptr, deep) = string.
-
-generate_clique_debug_page(CliquePtr, Deep) = HTML :-
- ( valid_clique_ptr(Deep, CliquePtr) ->
- deep_lookup_clique_parents(Deep, CliquePtr, ParentCSDPtr),
- ParentCSDPtr = call_site_dynamic_ptr(ParentCSDI),
- ParentStr = string.format("%d ->", [i(ParentCSDI)]),
- deep_lookup_clique_members(Deep, CliquePtr, Members),
- HTML =
- "<HTML>\n" ++
- ParentStr ++
- list.foldl(append_pdi_to_string, Members, "") ++
- "</HTML>\n"
- ;
- HTML =
- "<HTML>\n" ++
- "Invalid call_site_dynamic_ptr" ++
- "</HTML>\n"
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- func array_slots_to_html(array(call_site_array_slot)) = string.
-
-array_slots_to_html(SlotArray) = HTML :-
- array.to_list(SlotArray, SlotList),
- list.foldl(append_slot_to_string, SlotList, "multi", HTML).
-
-:- pred append_slot_to_string(call_site_array_slot::in,
- string::in, string::out) is det.
-
-append_slot_to_string(Slot, Str0, Str) :-
- Str = Str0 ++ " " ++ array_slot_to_html(Slot).
-
-:- func array_slot_to_html(call_site_array_slot) = string.
-
-array_slot_to_html(slot_normal(CSDPtr)) = HTML :-
- CSDPtr = call_site_dynamic_ptr(CSDI),
- HTML = "normal " ++ string.int_to_string(CSDI).
-array_slot_to_html(slot_multi(_, CSDPtrArray)) = HTML :-
- array.to_list(CSDPtrArray, CSDPtrs),
- list.foldl(append_csdi_to_string, CSDPtrs, "", CSDI_HTML),
- list.length(CSDPtrs, CSDPtrCount),
- HTML = string.format("multi(%d): [", [i(CSDPtrCount)]) ++ CSDI_HTML ++ "]".
-
-:- pred append_csdi_to_string(call_site_dynamic_ptr::in,
- string::in, string::out) is det.
-
-append_csdi_to_string(call_site_dynamic_ptr(CSDI), Str0, Str) :-
- Str = Str0 ++ " " ++ string.int_to_string(CSDI).
-
-:- func append_pdi_to_string(proc_dynamic_ptr, string) = string.
-
-append_pdi_to_string(proc_dynamic_ptr(PDI), Str0) =
- Str0 ++ " " ++ string.int_to_string(PDI).
-
-:- func kind_and_callee_to_string(call_site_kind_and_callee) = string.
-
-kind_and_callee_to_string(normal_call_and_callee(proc_static_ptr(PSI),
- TypeSpec)) =
- "normal " ++ string.int_to_string(PSI) ++ " " ++ TypeSpec.
-kind_and_callee_to_string(special_call_and_no_callee) = "special_call".
-kind_and_callee_to_string(higher_order_call_and_no_callee) =
- "higher_order_call".
-kind_and_callee_to_string(method_call_and_no_callee) = "method_call".
-kind_and_callee_to_string(callback_and_no_callee) = "callback".
-
-%-----------------------------------------------------------------------------%
-
-:- func call_site_kind_and_callee_to_html(call_site_kind_and_callee) = string.
-
-call_site_kind_and_callee_to_html(normal_call_and_callee(_, _)) =
- "normal_call".
-call_site_kind_and_callee_to_html(special_call_and_no_callee) =
- "special_call".
-call_site_kind_and_callee_to_html(higher_order_call_and_no_callee) =
- "higher_order_call".
-call_site_kind_and_callee_to_html(method_call_and_no_callee) =
- "method_call".
-call_site_kind_and_callee_to_html(callback_and_no_callee) =
- "callback".
-
-%-----------------------------------------------------------------------------%
-
-:- func generate_menu_page(cmd, preferences, deep) = string.
-
-generate_menu_page(Cmd, Pref, Deep) = HTML :-
- ShouldDisplayTimes = should_display_times(Deep),
- HTML =
- page_banner(Cmd, Pref) ++
- "<p>\n" ++
- menu_text ++
- "<ul>\n" ++
- "<li>\n" ++
- menu_item(Deep, Pref, deep_cmd_root(no),
- "Exploring the call graph, starting at the root.") ++
- "<li>\n" ++
- menu_item(Deep, Pref, deep_cmd_root(yes(90)),
- "Exploring the call graph, starting at the action.") ++
- "<li>\n" ++
- menu_item(Deep, Pref, deep_cmd_program_modules,
- "Exploring the program module by module.") ++
- ( ShouldDisplayTimes = yes ->
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(rank_range(1, 100), cost_time,
- self, overall),
- "Top 100 most expensive procedures: time, self.") ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(rank_range(1, 100), cost_time,
- self_and_desc, overall),
- "Top 100 most expensive procedures: time, self+descendants.")
- ;
- ""
- ) ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(rank_range(1, 100), cost_callseqs,
- self, overall),
- "Top 100 most expensive procedures: callseqs, self.") ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(rank_range(1, 100), cost_callseqs,
- self_and_desc, overall),
- "Top 100 most expensive procedures: callseqs, self+descendants.") ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(rank_range(1, 100), cost_words, self, overall),
- "Top 100 most expensive procedures: words, self.") ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(rank_range(1, 100), cost_words, self_and_desc,
- overall),
- "Top 100 most expensive procedures: words, self+descendants.")
- ++
- ( ShouldDisplayTimes = yes ->
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_percent(0.1), cost_time, self,
- overall),
- "Procedures above 0.1% threshold: time, self.") ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_percent(1.0), cost_time,
- self_and_desc, overall),
- "Procedures above 1% threshold: time, self+descendants.") ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_value(100.0), cost_time,
- self_and_desc, overall),
- "Procedures above 1 second threshold: " ++
- "time, self+descendants.")
- ;
- ""
- ) ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_percent(0.1), cost_callseqs, self,
- overall),
- "Procedures above 0.1% threshold: callseqs, self.") ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_percent(1.0), cost_callseqs,
- self_and_desc, overall),
- "Procedures above 1% threshold: callseqs, self+descendants.")
- ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_value(1000000.0), cost_callseqs,
- self_and_desc, overall),
- "Procedures above 1,000,000 callseqs threshold: callseqs, " ++
- "self+descendants.")
- ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_percent(0.1), cost_words, self,
- overall),
- "Procedures above 0.1% threshold: words, self.") ++
- "<li>\n" ++
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_percent(1.0), cost_words,
- self_and_desc, overall),
- "Procedures above 1% threshold: words, self+descendants.")
- ++
- "<li>\n" ++
- % 2M words is chosen because it is 8MB on ia32
- menu_item(Deep, Pref,
- deep_cmd_top_procs(threshold_value(float(1024 * 1024 * 2)),
- cost_words, self_and_desc, overall),
- "Procedures above 2M words threshold: words, self+descendants.")
- ++
- "</ul>\n" ++
- "<p>\n" ++
- present_stats(Deep) ++
- page_footer(Cmd, Pref, Deep).
-
-:- func menu_text = string.
-
-menu_text =
- "You can start exploring the deep profile at the following points.\n".
-
-:- func menu_item(deep, preferences, cmd, string) = string.
-
-menu_item(Deep, Pref, Cmd, Text) =
- string.format("<A HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, Cmd)), s(Text)]).
-
-:- func present_stats(deep) = string.
-
-present_stats(Deep) = HTML :-
- Stats = Deep ^ profile_stats,
- lookup_ticks_per_sec(Stats, TicksPerSec, Assumed),
- (
- Assumed = yes,
- AssumedStr = " (assumed)"
- ;
- Assumed = no,
- AssumedStr = ""
- ),
- HTML =
- "<TABLE>\n" ++
- "<TR><TD ALIGN=left>Quanta per second:</TD>\n" ++
- string.format("<TD ALIGN=right>%d%s</TD></TR>\n",
- [i(TicksPerSec), s(AssumedStr)]) ++
- "<TR><TD ALIGN=left>Quanta in user code:</TD>\n" ++
- string.format("<TD ALIGN=right>%d</TD></TR>\n",
- [i(Stats ^ user_quanta)]) ++
- "<TR><TD ALIGN=left>Quanta in instrumentation:</TD>\n" ++
- string.format("<TD ALIGN=right>%d</TD></TR>\n",
- [i(Stats ^ instrument_quanta)]) ++
- "<TR><TD ALIGN=left>Call sequence numbers:</TD>\n" ++
- string.format("<TD ALIGN=right>%d</TD></TR>\n",
- [i(Stats ^ num_callseqs)]) ++
- "<TR><TD ALIGN=left>CallSiteDynamic structures:</TD>\n" ++
- string.format("<TD ALIGN=right>%d</TD></TR>\n",
- [i(Stats ^ num_csd)]) ++
- "<TR><TD ALIGN=left>ProcDynamic structures:</TD>\n" ++
- string.format("<TD ALIGN=right>%d</TD></TR>\n",
- [i(Stats ^ num_pd)]) ++
- "<TR><TD ALIGN=left>CallSiteStatic structures:</TD>\n" ++
- string.format("<TD ALIGN=right>%d</TD></TR>\n",
- [i(Stats ^ num_css)]) ++
- "<TR><TD ALIGN=left>ProcStatic structures:</TD>\n" ++
- string.format("<TD ALIGN=right>%d</TD></TR>\n",
- [i(Stats ^ num_ps)]) ++
- "<TR><TD ALIGN=left>Cliques:</TD>\n" ++
- string.format("<TD ALIGN=right>%d</TD></TR>\n",
- [i(array.max(Deep ^ clique_members))]) ++
- "</TABLE>\n".
-
-%-----------------------------------------------------------------------------%
-
-:- func chase_the_action(cmd, clique_ptr, preferences, deep, int) = string.
-
-chase_the_action(Cmd, CliquePtr, Pref, Deep, Percent) = HTML :-
- generate_clique_page(Cmd, CliquePtr, Pref, Deep, HTML0,
- Percent, ActionPtrs),
- ( ActionPtrs = [ActionCliquePtr] ->
- HTML = chase_the_action(Cmd, ActionCliquePtr, Pref, Deep, Percent)
- ;
- HTML = HTML0
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- pred generate_clique_page(cmd::in, clique_ptr::in, preferences::in,
- deep::in, string::out, int::in, list(clique_ptr)::out) is det.
-
-generate_clique_page(Cmd, CliquePtr, Pref, Deep, HTML, Percent, ActionPtrs) :-
- clique_to_html(Pref, Deep, CliquePtr, CliqueHTML, Percent, ActionPtrs),
- CliquePtr = clique_ptr(CliqueNum),
- HTML =
- page_banner(Cmd, Pref) ++
- string.format("<H3>Clique %d:</H3>\n", [i(CliqueNum)]) ++
- table_start(Pref) ++
- fields_header(Pref, source_proc, totals_meaningful,
- wrap_clique_links(CliquePtr, Pref, Deep)) ++
- CliqueHTML ++
- table_end(Pref) ++
- page_footer(Cmd, Pref, Deep).
-
-:- func generate_proc_page(cmd, proc_static_ptr, preferences, deep) = string.
-
-generate_proc_page(Cmd, PSPtr, Pref, Deep) =
- page_banner(Cmd, Pref) ++
- string.format("<H3>Summary of procedure %s:</H3>\n",
- [s(escape_html_string(proc_static_name(Deep, PSPtr)))]) ++
- table_start(Pref) ++
- fields_header(Pref, source_proc, totals_meaningful,
- wrap_proc_links(PSPtr, Pref, Deep)) ++
- proc_summary_to_html(Pref, Deep, PSPtr) ++
- table_end(Pref) ++
- "<p>\n" ++
- proc_summary_toggles_to_html(Pref, Deep, PSPtr) ++
- page_footer(Cmd, Pref, Deep).
-
-:- pred generate_proc_callers_page(cmd::in, proc_static_ptr::in,
- caller_groups::in, int::in, preferences::in, deep::in, string::out,
- io::di, io::uo) is det.
-
-generate_proc_callers_page(Cmd, PSPtr, CallerGroups, BunchNum, Pref, Deep,
- HTML, !IO) :-
- proc_callers_to_html(Pref, Deep, PSPtr, CallerGroups, BunchNum,
- MaybePage, !IO),
- (
- MaybePage = ok({IdFields, Heading, CallersHTML, Toggles}),
- HTML =
- page_banner(Cmd, Pref) ++
- Heading ++
- ( CallersHTML = "" ->
- ""
- ;
- table_start(Pref) ++
- fields_header(Pref, IdFields, totals_meaningful,
- wrap_proc_callers_links(PSPtr, CallerGroups, 1,
- Pref, Deep)) ++
- CallersHTML ++
- table_end(Pref) ++
- "<p>\n"
- ) ++
- Toggles ++
- page_footer(Cmd, Pref, Deep)
- ;
- MaybePage = error(Msg),
- HTML =
- string.format("<H3>%s</H3>\n", [s(Msg)])
- ).
-
-:- func generate_modules_page(cmd, preferences, deep) = string.
-
-generate_modules_page(Cmd, Pref, Deep) =
- page_banner(Cmd, Pref) ++
- "<H3>The modules of the program:</H3>\n" ++
- table_start(Pref) ++
- fields_header(Pref, rank_module, totals_not_meaningful,
- wrap_modules_links(Pref, Deep)) ++
- modules_to_html(Pref, Deep) ++
- table_end(Pref) ++
- page_footer(Cmd, Pref, Deep).
-
-:- func generate_module_page(cmd, string, module_data, preferences, deep)
- = string.
-
-generate_module_page(Cmd, ModuleName, ModuleData, Pref, Deep) = HTML :-
- module_to_html(Pref, Deep, ModuleName, ModuleData,
- IdFields, ModulesHTML),
- HTML =
- page_banner(Cmd, Pref) ++
- string.format("<H3>The procedures of module %s:</H3>\n",
- [s(ModuleName)]) ++
- table_start(Pref) ++
- fields_header(Pref, IdFields, totals_meaningful,
- wrap_module_links(ModuleName, Pref, Deep)) ++
- ModulesHTML ++
- table_end(Pref) ++
- page_footer(Cmd, Pref, Deep).
-
-:- func generate_top_procs_page(cmd, display_limit,
- cost_kind, include_descendants, measurement_scope,
- preferences, deep) = string.
-
-generate_top_procs_page(Cmd, Limit, CostKind, InclDesc0, Scope0, Pref, Deep)
- = HTML :-
- (
- CostKind = cost_calls,
- % Counting calls is incompatible both with self_and_desc
- % and per_call.
- InclDesc = self,
- Scope = overall
- ;
- ( CostKind = cost_redos
- ; CostKind = cost_time
- ; CostKind = cost_callseqs
- ; CostKind = cost_allocs
- ; CostKind = cost_words
- ),
- InclDesc = InclDesc0,
- Scope = Scope0
- ),
- MaybeTopPSIs = find_top_procs(CostKind, InclDesc, Scope, Limit, Deep),
- (
- MaybeTopPSIs = error(ErrorMessage),
- HTML =
- page_banner(Cmd, Pref) ++
- ErrorMessage ++ "\n" ++
- page_footer(Cmd, Pref, Deep)
- ;
- MaybeTopPSIs = ok(TopPSIs),
- ToggleLimitHTML = "",
- ToggleCostHTML = toggle_cost_criteria_in_top_procs_cmd(
- Pref, Deep, Limit, CostKind, InclDesc, Scope),
- Desc = cost_criteria_to_description(CostKind, InclDesc, Scope),
- Heading = string.format("<H3>Top procedures %s</H3>\n",
- [s(Desc)]),
- (
- TopPSIs = [],
- HTML =
- page_banner(Cmd, Pref) ++
- Heading ++ "<p>\n" ++
- "No procedures match the specification.\n" ++
- "<p>\n" ++
- ToggleLimitHTML ++
- ToggleCostHTML ++
- page_footer(Cmd, Pref, Deep)
- ;
- TopPSIs = [_ | _],
- TopProcs = list.filter_map(
- lookup_proc_total_to_html(Pref, Deep, no, ""),
- list.map(wrap_proc_static_ptr, TopPSIs)),
- RankedTopProcs = add_ranks(TopProcs),
- SummaryHTMLs = list.map(
- two_id_line_to_html(Pref, Deep, totals_meaningful),
- RankedTopProcs),
- HTML =
- page_banner(Cmd, Pref) ++
- Heading ++ "<p>\n" ++
- table_start(Pref) ++
- fields_header(Pref, rank_proc, totals_meaningful,
- wrap_top_procs_links(Limit, Pref, Deep)) ++
- string.append_list(SummaryHTMLs) ++
- table_end(Pref) ++
- "<p>\n" ++
- ToggleLimitHTML ++
- ToggleCostHTML ++
- page_footer(Cmd, Pref, Deep)
- )
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- func modules_to_html(preferences, deep) = string.
-
-modules_to_html(Pref, Deep) = HTML :-
- map.to_assoc_list(Deep ^ module_data, ModulePairs0),
- list.filter(not_mercury_runtime, ModulePairs0, ModulePairs),
- ModuleLines = list.filter_map(module_summary_to_html(Pref, Deep),
- ModulePairs),
- SortedModuleLines = sort_line_groups(Pref ^ pref_criteria,
- ModuleLines),
- RankedModuleLines = add_ranks(SortedModuleLines),
- ModuleHTMLs = list.map(
- two_id_line_to_html(Pref, Deep, totals_not_meaningful),
- RankedModuleLines),
- HTML =
- separator_row(Pref, rank_module, totals_not_meaningful) ++
- string.append_list(ModuleHTMLs).
-
-:- pred not_mercury_runtime(pair(string, module_data)::in) is semidet.
-
-not_mercury_runtime(ModuleName - _) :-
- ModuleName \= "Mercury runtime".
-
-:- func module_summary_to_html(preferences, deep, pair(string, module_data))
- = one_id_line is semidet.
-
-module_summary_to_html(Pref, Deep, ModuleName - ModuleData) = LineGroup :-
- ModuleData = module_data(Own, Desc, _),
- not (
- Pref ^ pref_inactive ^ inactive_modules = inactive_hide,
- compute_is_active(Own) = is_not_active
- ),
- HTML = string.format("<TD><A HREF=""%s"">%s</A></TD>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_module(ModuleName))),
- s(ModuleName)]),
- LineGroup = line_group(ModuleName, 0, ModuleName, Own, Desc, HTML, unit).
-
-%-----------------------------------------------------------------------------%
-
-:- pred module_to_html(preferences::in, deep::in, string::in, module_data::in,
- id_fields::out, string::out) is det.
-
-module_to_html(Pref, Deep, _ModuleName, ModuleData, IdHeaders, HTML) :-
- ModuleData = module_data(_Own, _Desc, PSPtrs),
- ProcLines = list.filter_map(lookup_proc_total_to_html(Pref, Deep, yes, ""),
- PSPtrs),
- Criteria = Pref ^ pref_criteria,
- SortedProcLines = sort_line_groups(Criteria, ProcLines),
- (
- Criteria = by_cost(_, _, _),
- IdHeaders = rank_proc,
- RankedProcLines = add_ranks(SortedProcLines)
- ;
- ( Criteria = by_name
- ; Criteria = by_context
- ),
- IdHeaders = source_proc,
- RankedProcLines = list.map(add_self_context, SortedProcLines)
- ),
- ProcHTMLs = list.map(two_id_line_to_html(Pref, Deep, totals_meaningful),
- RankedProcLines),
- HTML =
- separator_row(Pref, IdHeaders, totals_meaningful) ++
- string.append_list(ProcHTMLs).
-
-%-----------------------------------------------------------------------------%
-
-:- pred clique_to_html(preferences::in, deep::in, clique_ptr::in,
- string::out, int::in, list(clique_ptr)::out) is det.
-
-clique_to_html(Pref, Deep, CliquePtr, HTML, PerCent, ActionPtrs) :-
- (
- Pref ^ pref_anc = yes(AncestorLimit),
- RespectLimit = yes
- ;
- Pref ^ pref_anc = no,
- AncestorLimit = 0, % the value doesn't matter
- RespectLimit = no
- ),
- clique_ancestors_to_html(Pref, Deep,
- AncestorLimit, RespectLimit, CliquePtr, Ancestors, Cutoff),
- deep_lookup_clique_members(Deep, CliquePtr, PDPtrs),
- list.foldl(group_proc_dynamics_by_proc_static(Deep), PDPtrs,
- map.init, PStoPDsMap),
- map.to_assoc_list(PStoPDsMap, PStoPDsList0),
-
- deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
- ( valid_call_site_dynamic_ptr(Deep, EntryCSDPtr) ->
- deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
- EntryPDPtr = EntryCSD ^ csd_callee,
- list.filter(proc_group_contains(EntryPDPtr), PStoPDsList0,
- EntryGroup, RestGroup),
- list.append(EntryGroup, RestGroup, PStoPDsList)
- ;
- PStoPDsList = PStoPDsList0
- ),
-
- list.map2(procs_in_clique_to_html(Pref, Deep, CliquePtr, PerCent),
- PStoPDsList, PDsStrs, ActionPtrLists),
- list.condense(ActionPtrLists, ActionPtrs),
- string.append_list(PDsStrs, ProcGroups),
- (
- Cutoff = yes,
- Heading = string.format("The %d closest ancestors:",
- [i(AncestorLimit)])
- ;
- Cutoff = no,
- Heading = "Ancestors:"
- ),
- HTML =
- header_row(Heading, Pref, source_proc, totals_meaningful) ++
- separator_row(Pref, source_proc, totals_meaningful) ++
- Ancestors ++
- separator_row(Pref, source_proc, totals_meaningful) ++
- header_row("Procedures of the clique:", Pref, source_proc,
- totals_meaningful) ++
- separator_row(Pref, source_proc, totals_meaningful) ++
- ProcGroups.
-
-:- pred proc_group_contains(proc_dynamic_ptr::in,
- pair(proc_static_ptr, list(proc_dynamic_ptr))::in) is semidet.
-
-proc_group_contains(EntryPDPtr, _ - PDPtrs) :-
- list.member(EntryPDPtr, PDPtrs).
-
-:- pred clique_ancestors_to_html(preferences::in, deep::in, int::in, bool::in,
- clique_ptr::in, string::out, bool::out) is det.
-
-clique_ancestors_to_html(Pref, Deep, AncestorLimit, RespectLimit, CliquePtr,
- HTML, Cutoff) :-
- deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
- ( valid_call_site_dynamic_ptr(Deep, EntryCSDPtr) ->
- deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
- EntryPDPtr = EntryCSD ^ csd_caller,
- ( EntryPDPtr = Deep ^ root ->
- % We have reached the root.
- HTML = "",
- Cutoff = no
- ; RespectLimit = yes, AncestorLimit =< 0 ->
- HTML = "",
- Cutoff = yes
- ;
- deep_lookup_clique_index(Deep, EntryPDPtr, EntryCliquePtr),
- ThisLine = call_site_dynamic_to_html(Pref, Deep,
- ancestor_display, yes(EntryCliquePtr), EntryCSDPtr),
- ThisHTML = two_id_line_to_html(Pref, Deep, totals_meaningful,
- ThisLine),
- clique_ancestors_to_html(Pref, Deep, AncestorLimit - 1,
- RespectLimit, EntryCliquePtr, AncestorHTML, Cutoff),
- HTML = AncestorHTML ++ ThisHTML
- )
- ;
- % We have reached the parent of root.
- HTML = "",
- Cutoff = no
- ).
-
-:- pred group_proc_dynamics_by_proc_static(deep::in, proc_dynamic_ptr::in,
- map(proc_static_ptr, list(proc_dynamic_ptr))::in,
- map(proc_static_ptr, list(proc_dynamic_ptr))::out) is det.
-
-group_proc_dynamics_by_proc_static(Deep, PDPtr, PStoPDsMap0, PStoPDsMap) :-
- require(valid_proc_dynamic_ptr(Deep, PDPtr),
- "group_proc_dynamics_by_proc_static: invalid PDPtr"),
- deep_lookup_proc_dynamics(Deep, PDPtr, PD),
- PSPtr = PD ^ pd_proc_static,
- ( map.search(PStoPDsMap0, PSPtr, PSPDs0) ->
- PSPDs = [PDPtr | PSPDs0],
- map.det_update(PStoPDsMap0, PSPtr, PSPDs, PStoPDsMap)
- ;
- map.det_insert(PStoPDsMap0, PSPtr, [PDPtr], PStoPDsMap)
- ).
-
-:- pred procs_in_clique_to_html(preferences::in, deep::in, clique_ptr::in,
- int::in, pair(proc_static_ptr, list(proc_dynamic_ptr))::in,
- string::out, list(clique_ptr)::out) is det.
-
-procs_in_clique_to_html(Pref, Deep, CliquePtr, Percent, PSPtr - PDPtrs,
- HTML, ActionPtrs) :-
- (
- PDPtrs = [],
- HTML = "",
- ActionPtrs = []
- ;
- PDPtrs = [PDPtr],
- proc_in_clique_to_html(Pref, Deep, CliquePtr, Percent, PDPtr,
- HTML, ActionPtrs)
- ;
- PDPtrs = [_, _ | _],
- list.map(deep_lookup_pd_own(Deep), PDPtrs, ProcOwns),
- list.map(deep_lookup_pd_desc(Deep), PDPtrs, ProcDescs),
- ProcOwn = sum_own_infos(ProcOwns),
- ProcDesc = sum_inherit_infos(ProcDescs),
- ProcTotal = proc_total_to_two_id_line(Pref, Deep, yes, "summary ",
- PSPtr, ProcOwn, ProcDesc),
- list.map2(proc_in_clique_to_html(Pref, Deep, CliquePtr, Percent),
- PDPtrs, ComponentHTMLs, ActionPtrLists),
- list.condense(ActionPtrLists, ActionPtrs),
- string.append_list(ComponentHTMLs, ComponentHTML),
- HTML =
- separator_row(Pref, source_proc, totals_meaningful) ++
- two_id_line_to_html(Pref, Deep, totals_meaningful, ProcTotal) ++
- separator_row(Pref, source_proc, totals_meaningful) ++
- ComponentHTML
- ).
-
-:- pred proc_in_clique_to_html(preferences::in, deep::in, clique_ptr::in,
- int::in, proc_dynamic_ptr::in, string::out, list(clique_ptr)::out) is det.
-
-proc_in_clique_to_html(Pref, Deep, CliquePtr, Percent, PDPtr,
- HTML, ActionPtrs) :-
- ( valid_proc_dynamic_ptr(Deep, PDPtr) ->
- deep_lookup_pd_own(Deep, PDPtr, ProcOwn),
- deep_lookup_pd_desc(Deep, PDPtr, ProcDesc),
- deep_lookup_proc_dynamics(Deep, PDPtr, PD),
- PSPtr = PD ^ pd_proc_static,
- ProcTotal = proc_total_to_two_id_line(Pref, Deep, yes, "",
- PSPtr, ProcOwn, ProcDesc),
- child_call_sites(Deep ^ proc_dynamics, Deep ^ proc_statics,
- PDPtr, GroupPairs),
- ProcHTML =
- separator_row(Pref, source_proc, totals_meaningful) ++
- two_id_line_to_html(Pref, Deep, totals_meaningful, ProcTotal),
- (
- GroupPairs = [],
- HTML = ProcHTML,
- ActionPtrs = []
- ;
- GroupPairs = [_ | _],
- list.map2(call_site_clique_to_html(Pref, Deep, CliquePtr, Percent),
- GroupPairs, CallSiteLists, ActionPtrLists),
- list.condense(CallSiteLists, CallSites),
- list.condense(ActionPtrLists, ActionPtrs),
- SortedCallSites = sort_line_groups(Pref ^ pref_criteria,
- CallSites),
- BodyHTMLs = list.map(
- two_id_line_group_to_html(Pref, Deep, totals_meaningful),
- SortedCallSites),
- HTML = ProcHTML ++
- separator_row(Pref, source_proc, totals_meaningful) ++
- string.append_list(BodyHTMLs)
- )
- ;
- HTML = "",
- ActionPtrs = []
- ).
-
-:- pred child_call_sites(proc_dynamics::in, proc_statics::in,
- proc_dynamic_ptr::in,
- assoc_list(call_site_static_ptr, call_site_array_slot)::out) is det.
-
-child_call_sites(ProcDynamics, ProcStatics, PDPtr, PairedSlots) :-
- lookup_proc_dynamics(ProcDynamics, PDPtr, PD),
- PSPtr = PD ^ pd_proc_static,
- CSDArray = PD ^ pd_sites,
- lookup_proc_statics(ProcStatics, PSPtr, PS),
- CSSArray = PS ^ ps_sites,
- array.to_list(CSDArray, CSDSlots),
- array.to_list(CSSArray, CSSSlots),
- assoc_list.from_corresponding_lists(CSSSlots, CSDSlots, PairedSlots).
-
-%-----------------------------------------------------------------------------%
-
- % Fails if the procedure is inactive and the preferences say to
- % hide inactive procedures.
- %
-:- func lookup_proc_total_to_html(preferences, deep, bool, string,
- proc_static_ptr) = one_id_line is semidet.
-
-lookup_proc_total_to_html(Pref, Deep, Bold, Prefix, PSPtr) = LineGroup :-
- deep_lookup_ps_own(Deep, PSPtr, Own),
- not (
- Pref ^ pref_inactive ^ inactive_procs = inactive_hide,
- compute_is_active(Own) = is_not_active
- ),
- deep_lookup_ps_desc(Deep, PSPtr, Desc),
- LineGroup = proc_total_to_html(Pref, Deep, Bold, Prefix, PSPtr, Own, Desc).
-
-:- func lookup_proc_total_to_two_id_line(preferences, deep, bool, string,
- proc_static_ptr) = two_id_line.
-
-lookup_proc_total_to_two_id_line(Pref, Deep, Bold, Prefix, PSPtr)
- = LineGroup :-
- deep_lookup_ps_own(Deep, PSPtr, Own),
- deep_lookup_ps_desc(Deep, PSPtr, Desc),
- LineGroup = proc_total_to_two_id_line(Pref, Deep, Bold, Prefix,
- PSPtr, Own, Desc).
-
-:- func proc_total_to_html(preferences, deep, bool, string,
- proc_static_ptr, own_prof_info, inherit_prof_info) = one_id_line.
-
-proc_total_to_html(Pref, Deep, Bold, Prefix, PSPtr, Own, Desc)
- = LineGroup :-
- proc_total_to_html_base(Pref, Deep, 1, Bold, Prefix, PSPtr,
- FileName, LineNumber, ProcName, HTML),
- LineGroup = line_group(FileName, LineNumber, ProcName, Own, Desc, HTML,
- unit).
-
-:- func proc_total_to_two_id_line(preferences, deep, bool, string,
- proc_static_ptr, own_prof_info, inherit_prof_info) = two_id_line.
-
-proc_total_to_two_id_line(Pref, Deep, Bold, Prefix, PSPtr, Own, Desc)
- = LineGroup :-
- proc_total_to_html_base(Pref, Deep, 2, Bold, Prefix, PSPtr,
- FileName, LineNumber, ProcName, HTML),
- LineGroup = line_group(FileName, LineNumber, ProcName, Own, Desc, HTML,
- unit).
-
-:- pred proc_total_to_html_base(preferences::in, deep::in,
- int::in, bool::in, string::in, proc_static_ptr::in,
- string::out, int::out, string::out, string::out) is det.
-
-proc_total_to_html_base(Pref, Deep, Span, Bold, Prefix, PSPtr,
- FileName, LineNumber, ProcName, HTML) :-
- proc_static_to_line_group_info(Pref, Deep, PSPtr, FileName, LineNumber,
- ProcName, WrappedProcName),
- (
- Bold = no,
- BoldStart = "",
- BoldEnd = ""
- ;
- Bold = yes,
- BoldStart = "<B>",
- BoldEnd = "</B>"
- ),
- HTML = string.format("<TD CLASS=id COLSPAN=%d>%s%s%s%s</TD>\n",
- [i(Span), s(BoldStart), s(Prefix), s(WrappedProcName), s(BoldEnd)]).
-
-%-----------------------------------------------------------------------------%
-
-:- pred call_site_clique_to_html(preferences::in, deep::in,
- clique_ptr::in, int::in,
- pair(call_site_static_ptr, call_site_array_slot)::in,
- list(two_id_line_group)::out, list(clique_ptr)::out) is det.
-
-call_site_clique_to_html(Pref, Deep, CallerCliquePtr, Percent, Pair,
- LineGroups, ActionPtrs) :-
- Pair = CSSPtr - CallSiteArraySlot,
- deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
- Kind = CSS ^ css_kind,
- ( Kind = normal_call_and_callee(_CalleePSPtr, _) ->
- (
- CallSiteArraySlot = slot_normal(CSDPtr0),
- CSDPtr = CSDPtr0
- ;
- CallSiteArraySlot = slot_multi(_, _),
- error("call_site_clique_to_html: normal_call error")
- ),
- normal_call_site_clique_to_html(Pref, Deep, CallerCliquePtr,
- CSDPtr, LineGroups, Percent, ActionPtrs)
- ;
- (
- CallSiteArraySlot = slot_multi(_, CSDPtrs0),
- array.to_list(CSDPtrs0, CSDPtrs)
- ;
- CallSiteArraySlot = slot_normal(_),
- error("call_site_clique_to_html: non-normal_call error")
- ),
- call_site_context(Deep, CSSPtr, FileName, LineNumber),
- multi_call_site_clique_to_html(Pref, Deep, FileName, LineNumber,
- Kind, CallerCliquePtr, CSDPtrs, LineGroups, Percent, ActionPtrs)
- ).
-
-:- func maybe_extract_action_clique(deep, clique_ptr, int,
- call_site_dynamic_ptr) = list(clique_ptr).
-
-maybe_extract_action_clique(Deep, CallerCliquePtr, Percent, CSDPtr)
- = ActionPtrs :-
- ( Percent > 100 ->
- ActionPtrs = []
- ;
- deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
- deep_lookup_clique_index(Deep, CSD ^ csd_callee, CalleeCliquePtr),
- ( CalleeCliquePtr = CallerCliquePtr ->
- ActionPtrs = []
- ;
- deep_lookup_csd_desc(Deep, CSDPtr, CSDDesc),
- CSDOwn = CSD ^ csd_own_prof,
- CSDTotal = add_own_to_inherit(CSDOwn, CSDDesc),
- RootTotal = root_total_info(Deep),
- CSDCallSeqs = inherit_callseqs(CSDTotal),
- RootCallSeqs = inherit_callseqs(RootTotal),
- ( CSDCallSeqs * 100 > RootCallSeqs * Percent ->
- ActionPtrs = [CalleeCliquePtr]
- ;
- ActionPtrs = []
- )
- )
- ).
-
-:- pred normal_call_site_clique_to_html(preferences::in, deep::in,
- clique_ptr::in, call_site_dynamic_ptr::in,
- list(two_id_line_group)::out, int::in, list(clique_ptr)::out) is det.
-
-normal_call_site_clique_to_html(Pref, Deep, CallerCliquePtr, CSDPtr,
- LineGroups, Percent, ActionPtrs) :-
- ( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
- LineGroup = call_site_dynamic_to_html(Pref, Deep,
- downward_display, yes(CallerCliquePtr), CSDPtr),
- LineGroups = [line_to_two_id_subline_group(LineGroup)],
- ActionPtrs = maybe_extract_action_clique(Deep, CallerCliquePtr,
- Percent, CSDPtr)
- ;
- LineGroups = [],
- ActionPtrs = []
- ).
-
-:- pred multi_call_site_clique_to_html(preferences::in, deep::in,
- string::in, int::in, call_site_kind_and_callee::in, clique_ptr::in,
- list(call_site_dynamic_ptr)::in, list(two_id_line_group)::out,
- int::in, list(clique_ptr)::out) is det.
-
-multi_call_site_clique_to_html(Pref, Deep, FileName, LineNumber, Kind,
- CallerCliquePtr, CSDPtrs, LineGroups, Percent, ActionPtrs) :-
- ValidCSDPtrs = CSDPtrs,
- RawCallSiteName = call_site_kind_and_callee_to_html(Kind),
- CallSiteName = multi_call_site_add_suffix(Pref, RawCallSiteName,
- ValidCSDPtrs),
- SubLines = list.map(call_site_dynamic_to_html(Pref, Deep,
- downward_summary_display, yes(CallerCliquePtr)),
- ValidCSDPtrs),
- ActionPtrLists = list.map(
- maybe_extract_action_clique(Deep, CallerCliquePtr, Percent),
- ValidCSDPtrs),
- list.condense(ActionPtrLists, ActionPtrs),
- sum_line_group_measurements(SubLines, Own, Desc),
- SummaryHTML =
- string.format("<TD CLASS=id>%s:%d</TD>\n",
- [s(escape_break_html_string(FileName)), i(LineNumber)]) ++
-
- % NOTE: we don't escape HTML special characters for
- % 'CallSiteName' because it has already been done.
- string.format("<TD CLASS=id>%s</TD>\n", [s(CallSiteName)]),
- (
- Pref ^ pref_summarize = summarize,
- LineGroup = line_group(FileName, LineNumber, RawCallSiteName,
- Own, Desc, SummaryHTML, sub_lines(two_id, []))
- ;
- Pref ^ pref_summarize = do_not_summarize,
- LineGroup = line_group(FileName, LineNumber, RawCallSiteName,
- Own, Desc, SummaryHTML, sub_lines(two_id, SubLines))
- ),
- LineGroups = [LineGroup].
-
-%-----------------------------------------------------------------------------%
-
-:- func call_site_summary_to_html(preferences, deep,
- call_site_static_ptr) = two_id_line_group.
-
-call_site_summary_to_html(Pref, Deep, CSSPtr) = LineGroup :-
- deep_lookup_call_site_calls(Deep, CSSPtr, CallSiteCallMap),
- map.to_assoc_list(CallSiteCallMap, CallSiteCallList),
- deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
- Kind = CSS ^ css_kind,
- CallerPSPtr = CSS ^ css_container,
- call_site_context(Deep, CSSPtr, FileName, LineNumber),
- ( Kind = normal_call_and_callee(CalleePSPtr, _) ->
- LineGroup0 = normal_call_site_summary_to_html(Pref, Deep,
- FileName, LineNumber, CallerPSPtr, CalleePSPtr, CallSiteCallList)
- ;
- LineGroup0 = multi_call_site_summary_to_html(Pref, Deep,
- FileName, LineNumber, Kind, CallerPSPtr, CallSiteCallList)
- ),
- CSSContext = string.format("%s:%d",
- [s(escape_break_html_string(FileName)), i(LineNumber)]),
- LineGroup = add_context(CSSContext, LineGroup0).
-
-:- func normal_call_site_summary_to_html(preferences, deep, string, int,
- proc_static_ptr, proc_static_ptr,
- assoc_list(proc_static_ptr, list(call_site_dynamic_ptr))) =
- one_two_id_line_group.
-
-normal_call_site_summary_to_html(Pref, Deep, FileName, LineNumber,
- CallerPSPtr, CalleePSPtr, CallSiteCallList) = LineGroup :-
- deep_lookup_proc_statics(Deep, CalleePSPtr, CalleePS),
- ProcName = CalleePS ^ ps_refined_id,
- (
- CallSiteCallList = [],
- Own = zero_own_prof_info,
- Desc = zero_inherit_prof_info,
- SummaryHTML =
- string.format("<TD CLASS=id>%s</TD>\n",
- [s(proc_static_to_html_ref(Pref, Deep, CalleePSPtr))]),
- LineGroup = line_group(FileName, LineNumber,
- ProcName, Own, Desc, SummaryHTML,
- sub_lines(two_id, []))
- ;
- CallSiteCallList = [CallSiteCall],
- CallSiteCall = CalleePSPtrFromCall - _,
- require(unify(CalleePSPtr, CalleePSPtrFromCall),
- "call_site_summary_to_html: callee mismatch"),
- LineGroup0 = call_site_summary_group_to_html(Pref, Deep,
- FileName, LineNumber, ProcName, CallerPSPtr, CallSiteCall),
- LineGroup = line_to_two_id_subline_group(LineGroup0)
- ;
- CallSiteCallList = [_, _ | _],
- error("normal_call_site_summary_to_html: too many procedures")
- ).
-
-:- func multi_call_site_summary_to_html(preferences, deep, string, int,
- call_site_kind_and_callee, proc_static_ptr,
- assoc_list(proc_static_ptr, list(call_site_dynamic_ptr))) =
- one_two_id_line_group.
-
-multi_call_site_summary_to_html(Pref, Deep, FileName, LineNumber, Kind,
- CallerPSPtr, CallSiteCallList) = LineGroup :-
- RawCallSiteName = call_site_kind_and_callee_to_html(Kind),
- CallSiteName = multi_call_site_add_suffix(Pref, RawCallSiteName,
- CallSiteCallList),
- SubLines = list.map(call_site_summary_group_to_html(Pref, Deep,
- FileName, LineNumber, RawCallSiteName, CallerPSPtr),
- CallSiteCallList),
- sum_line_group_measurements(SubLines, Own, Desc),
-
- % NOTE: we don't escape HTML special characters for
- % 'CallSiteName' because it has already been done.
- SummaryHTML =
- string.format("<TD CLASS=id>%s</TD>\n", [s(CallSiteName)]),
- (
- Pref ^ pref_summarize = summarize,
- LineGroup = line_group(FileName, LineNumber, RawCallSiteName,
- Own, Desc, SummaryHTML, sub_lines(two_id, []))
- ;
- Pref ^ pref_summarize = do_not_summarize,
- ContextSubLines = list.map(add_context(""), SubLines),
- LineGroup = line_group(FileName, LineNumber, RawCallSiteName,
- Own, Desc, SummaryHTML, sub_lines(two_id, ContextSubLines))
- ).
-
-:- func call_site_summary_group_to_html(preferences, deep,
- string, int, string, proc_static_ptr,
- pair(proc_static_ptr, list(call_site_dynamic_ptr))) = one_id_line.
-
-call_site_summary_group_to_html(Pref, Deep, FileName, LineNumber, ProcName,
- CallerPSPtr, PSPtr - CSDPtrs) = LineGroup :-
- list.foldl2(accumulate_csd_prof_info(Deep, CallerPSPtr), CSDPtrs,
- zero_own_prof_info, Own, zero_inherit_prof_info, Desc),
- HTML =
- string.format("<TD CLASS=id>%s</TD>\n",
- [s(proc_static_to_html_ref(Pref, Deep, PSPtr))]),
- LineGroup = line_group(FileName, LineNumber, ProcName,
- Own, Desc, HTML, unit).
-
-%-----------------------------------------------------------------------------%
-
-:- func multi_call_site_add_suffix(preferences, string, list(T)) = string.
-
-multi_call_site_add_suffix(Pref, RawCallSiteName, CallList) = CallSiteName :-
- (
- CallList = [],
- CallSiteName = RawCallSiteName ++ " (no calls made)"
- ;
- CallList = [_ | _],
- Summarize = Pref ^ pref_summarize,
- (
- Summarize = summarize,
- CallSiteName = RawCallSiteName ++ " (summary)"
- ;
- Summarize = do_not_summarize,
- CallSiteName = RawCallSiteName
- )
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- pred process_call_site_dynamics_group(list(call_site_dynamic_ptr)::in,
- deep::in, proc_static_ptr::in,
- maybe(clique_ptr)::in, maybe(clique_ptr)::out,
- own_prof_info::in, own_prof_info::out,
- inherit_prof_info::in, inherit_prof_info::out) is det.
-
-process_call_site_dynamics_group([], _, _,
- MaybeCalleeCliquePtr, MaybeCalleeCliquePtr, Own, Own, Desc, Desc).
-process_call_site_dynamics_group([CSDPtr | CSDPtrs], Deep, CalleePSPtr,
- MaybeCalleeCliquePtr0, MaybeCalleeCliquePtr, Own0, Own, Desc0, Desc) :-
- deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
- PDPtr = CSD ^ csd_callee,
- deep_lookup_proc_dynamics(Deep, PDPtr, PD),
- PSPtr = PD ^ pd_proc_static,
- require(unify(CalleePSPtr, PSPtr),
- "process_call_site_dynamics_group: callee mismatch"),
- deep_lookup_clique_index(Deep, PDPtr, CalleeCliquePtr),
- (
- MaybeCalleeCliquePtr0 = no,
- MaybeCalleeCliquePtr1 = yes(CalleeCliquePtr)
- ;
- MaybeCalleeCliquePtr0 = yes(PrevCalleeCliquePtr),
- MaybeCalleeCliquePtr1 = MaybeCalleeCliquePtr0,
- require(unify(PrevCalleeCliquePtr, CalleeCliquePtr),
- "process_call_site_dynamics_group: clique mismatch")
- ),
- deep_lookup_csd_own(Deep, CSDPtr, CSDOwn),
- deep_lookup_csd_desc(Deep, CSDPtr, CSDDesc),
- Own1 = add_own_to_own(Own0, CSDOwn),
- Desc1 = add_inherit_to_inherit(Desc0, CSDDesc),
- process_call_site_dynamics_group(CSDPtrs, Deep, CalleePSPtr,
- MaybeCalleeCliquePtr1, MaybeCalleeCliquePtr, Own1, Own, Desc1, Desc).
-
-:- pred accumulate_csd_prof_info(deep::in, proc_static_ptr::in,
- call_site_dynamic_ptr::in,
- own_prof_info::in, own_prof_info::out,
- inherit_prof_info::in, inherit_prof_info::out) is det.
-
-accumulate_csd_prof_info(Deep, CallerPSPtr, CSDPtr, Own0, Own, Desc0, Desc) :-
- deep_lookup_csd_own(Deep, CSDPtr, CSDOwn),
- deep_lookup_csd_desc(Deep, CSDPtr, CSDDesc),
- add_own_to_own(Own0, CSDOwn) = Own,
- add_inherit_to_inherit(Desc0, CSDDesc) = Desc1,
- deep_lookup_csd_comp_table(Deep, CSDPtr, CompTableArray),
- ( map.search(CompTableArray, CallerPSPtr, InnerTotal) ->
- Desc = subtract_inherit_from_inherit(InnerTotal, Desc1)
- ;
- Desc = Desc1
- ).
-
-:- func call_site_dynamic_to_html_with_caller(preferences, deep,
- call_site_display, call_site_dynamic_ptr) = two_id_line.
-
-call_site_dynamic_to_html_with_caller(Pref, Deep, Display, CSDPtr)
- = LineGroup :-
- deep_extract_csdptr_caller(Deep, CSDPtr, CallerPDPtr),
- deep_lookup_clique_index(Deep, CallerPDPtr, CallerClique),
- LineGroup = call_site_dynamic_to_html(Pref, Deep, Display,
- yes(CallerClique), CSDPtr).
-
-:- func call_site_dynamic_to_html(preferences, deep, call_site_display,
- maybe(clique_ptr), call_site_dynamic_ptr) = two_id_line.
-
-call_site_dynamic_to_html(Pref, Deep, CallSiteDisplay, MaybeCallerCliquePtr,
- CSDPtr) = LineGroup :-
- require(valid_call_site_dynamic_ptr(Deep, CSDPtr),
- "call_site_dynamic_to_html: invalid call_site_dynamic_ptr"),
- deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
- CallerPDPtr = CSD ^ csd_caller,
- CalleePDPtr = CSD ^ csd_callee,
- CallSiteOwn = CSD ^ csd_own_prof,
- deep_lookup_csd_desc(Deep, CSDPtr, CallSiteDesc),
- deep_lookup_clique_index(Deep, CalleePDPtr, CalleeCliquePtr),
- call_site_dynamic_context(Deep, CSDPtr, FileName, LineNumber),
- Context = string.format("%s:%d",
- [s(escape_break_html_string(FileName)), i(LineNumber)]),
- HTML = call_to_html(Pref, Deep, CallSiteDisplay, Context,
- CallerPDPtr, CalleePDPtr, MaybeCallerCliquePtr, CalleeCliquePtr),
- ProcName = escape_break_html_string(proc_dynamic_name(Deep, CalleePDPtr)),
- LineGroup = line_group(FileName, LineNumber, ProcName,
- CallSiteOwn, CallSiteDesc, HTML, unit).
-
-%-----------------------------------------------------------------------------%
-
-:- type call_site_display
- ---> call_site_display(
- display_context :: call_site_context,
- display_proc_name :: call_site_proc_name,
- display_url :: url_with_proc_name,
- display_wrap :: wrap_with_url
- ).
-
-:- type call_site_context
- ---> call_context
- ; empty_context.
-
-:- type call_site_proc_name
- ---> caller_proc_name
- ; callee_proc_name.
-
-:- type url_with_proc_name
- ---> caller_clique
- ; callee_clique.
-
-:- type wrap_with_url
- ---> wrap_url_always
- ; wrap_url_if_cross_clique(assume_cross_clique)
- ; wrap_url_never.
-
-:- type assume_cross_clique
- ---> assume_cross_clique
- ; assume_within_clique.
-
-:- func ancestor_display = call_site_display.
-:- func downward_display = call_site_display.
-:- func downward_summary_display = call_site_display.
-
-ancestor_display =
- call_site_display(call_context, caller_proc_name, caller_clique,
- wrap_url_always).
-
-downward_display =
- call_site_display(call_context, callee_proc_name, callee_clique,
- wrap_url_if_cross_clique(assume_within_clique)).
-
-downward_summary_display =
- call_site_display(empty_context, callee_proc_name, callee_clique,
- wrap_url_if_cross_clique(assume_within_clique)).
-
-%-----------------------------------------------------------------------------%
-
-:- func call_to_html(preferences, deep, call_site_display, string,
- proc_dynamic_ptr, proc_dynamic_ptr, maybe(clique_ptr), clique_ptr)
- = string.
-
-call_to_html(Pref, Deep, CallSiteDisplay, CallContext,
- CallerPDPtr, CalleePDPtr,
- MaybeCallerCliquePtr, CalleeCliquePtr) = HTML :-
- (
- MaybeCallerCliquePtr = yes(CallerCliquePtr0),
- CallerCliquePtr = CallerCliquePtr0
- ;
- MaybeCallerCliquePtr = no,
- CallerCliquePtr = dummy_clique_ptr
- ),
- (
- CallSiteDisplay ^ display_context = call_context,
- Context = CallContext
- ;
- CallSiteDisplay ^ display_context = empty_context,
- Context = ""
- ),
- (
- CallSiteDisplay ^ display_proc_name = caller_proc_name,
- ProcName = proc_dynamic_name(Deep, CallerPDPtr)
- ;
- CallSiteDisplay ^ display_proc_name = callee_proc_name,
- ProcName = proc_dynamic_name(Deep, CalleePDPtr)
- ),
- (
- CallSiteDisplay ^ display_url = caller_clique,
- ChosenCliquePtr = CallerCliquePtr
- ;
- CallSiteDisplay ^ display_url = callee_clique,
- ChosenCliquePtr = CalleeCliquePtr
- ),
- WrappedProcName = string.format("<A HREF=""%s"">%s</A>",
- [s(deep_cmd_pref_to_url(Pref, Deep, deep_cmd_clique(ChosenCliquePtr))),
- s(escape_break_html_string(ProcName))]),
- (
- CallSiteDisplay ^ display_wrap = wrap_url_always,
- UsedProcName0 = WrappedProcName
- ;
- CallSiteDisplay ^ display_wrap = wrap_url_if_cross_clique(Assume),
- (
- MaybeCallerCliquePtr = yes(_),
- ( CallerCliquePtr \= CalleeCliquePtr ->
- UsedProcName0 = WrappedProcName
- ;
- UsedProcName0 = escape_break_html_string(ProcName)
- )
- ;
- MaybeCallerCliquePtr = no,
- (
- Assume = assume_cross_clique,
- UsedProcName0 = WrappedProcName
- ;
- Assume = assume_within_clique,
- UsedProcName0 = escape_break_html_string(ProcName)
- )
- )
- ;
- CallSiteDisplay ^ display_wrap = wrap_url_never,
- UsedProcName0 = escape_break_html_string(ProcName)
- ),
- (
- UsedProcName0 = WrappedProcName,
- valid_clique_ptr(Deep, ChosenCliquePtr)
- ->
- UsedProcName = UsedProcName0
- ;
- UsedProcName = escape_break_html_string(ProcName)
- ),
- HTML =
- string.format("<TD CLASS=id>%s</TD>\n", [s(Context)]) ++
- string.format("<TD CLASS=id>%s</TD>\n", [s(UsedProcName)]).
-
-%-----------------------------------------------------------------------------%
-
-:- pred call_site_dynamic_context(deep::in, call_site_dynamic_ptr::in,
- string::out, int::out) is det.
-
-call_site_dynamic_context(Deep, CSDPtr, FileName, LineNumber) :-
- deep_lookup_call_site_static_map(Deep, CSDPtr, CSSPtr),
- deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
- PSPtr = CSS ^ css_container,
- LineNumber = CSS ^ css_line_num,
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- FileName = PS ^ ps_file_name.
-
-%-----------------------------------------------------------------------------%
-
-:- pred proc_callers_to_html(preferences::in, deep::in, proc_static_ptr::in,
- caller_groups::in, int::in,
- maybe_error({id_fields, string, string, string})::out,
- io::di, io::uo) is det.
-
-proc_callers_to_html(Pref, Deep, PSPtr, CallerGroups, BunchNum0, MaybePage,
- !IO) :-
- deep_lookup_proc_callers(Deep, PSPtr, CallerCSDPtrs),
- PrefContour = Pref ^ pref_contour,
- (
- PrefContour = do_not_apply_contour_exclusion,
- CallerCSDPtrPairs = list.map(pair_self, CallerCSDPtrs),
- MaybeErrorMsg = no
- ;
- PrefContour = apply_contour_exclusion,
- MaybeMaybeExcludeFile = Deep ^ exclude_contour_file,
- (
- MaybeMaybeExcludeFile = no,
- % There is no contour exclusion file, so do the same as for
- % do_not_apply_contour_exclusion.
- CallerCSDPtrPairs = list.map(pair_self, CallerCSDPtrs),
- MaybeErrorMsg = no
- ;
- MaybeMaybeExcludeFile = yes(MaybeExcludeFile),
- (
- MaybeExcludeFile = ok(ExcludeSpec),
- CallerCSDPtrPairs = list.map(pair_contour(Deep, ExcludeSpec),
- CallerCSDPtrs),
- MaybeErrorMsg = no
- ;
- MaybeExcludeFile = error(ErrorMsg),
- MaybeErrorMsg = yes(ErrorMsg ++ "\n<br>"),
- CallerCSDPtrPairs = list.map(pair_self, CallerCSDPtrs)
- )
- )
- ),
- ProcName = proc_static_name(Deep, PSPtr),
- CmdSite = deep_cmd_proc_callers(PSPtr, group_by_call_site, 1,
- PrefContour),
- CmdProc = deep_cmd_proc_callers(PSPtr, group_by_proc, 1,
- PrefContour),
- CmdModule = deep_cmd_proc_callers(PSPtr, group_by_module, 1,
- PrefContour),
- CmdClique = deep_cmd_proc_callers(PSPtr, group_by_clique, 1,
- PrefContour),
- LinkSite = "[Group callers by call site]",
- LinkProc = "[Group callers by procedure]",
- LinkModule = "[Group callers by module]",
- LinkClique = "[Group callers by clique]",
- % Don't display more lines than BunchSize, to avoid quadratic behaviour
- % in Netscape.
- BunchSize = 100,
- (
- CallerGroups = group_by_call_site,
- GroupList = group_csds_by_call_site(Deep, CallerCSDPtrPairs),
- Lines = list.map(proc_callers_call_site_to_html(Pref, Deep, PSPtr),
- GroupList),
- SortedLines = sort_line_groups(Pref ^ pref_criteria, Lines),
- IdFields = source_proc,
- Entity = "call site",
- GroupToggles =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdProc)),
- s(LinkProc)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdModule)),
- s(LinkModule)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdClique)),
- s(LinkClique)])
- ;
- CallerGroups = group_by_proc,
- GroupList = group_csds_by_procedure(Deep, CallerCSDPtrPairs),
- Lines = list.map(proc_callers_proc_to_html(Pref, Deep, PSPtr),
- GroupList),
- SortedLines = sort_line_groups(Pref ^ pref_criteria, Lines),
- IdFields = source_proc,
- Entity = "procedure",
- GroupToggles =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdSite)),
- s(LinkSite)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdModule)),
- s(LinkModule)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdClique)),
- s(LinkClique)])
- ;
- CallerGroups = group_by_module,
- GroupList = group_csds_by_module(Deep, CallerCSDPtrPairs),
- RawLines = list.map(proc_callers_module_to_html(Pref, Deep, PSPtr),
- GroupList),
- SortedRawLines = sort_line_groups(Pref ^ pref_criteria, RawLines),
- SortedLines = add_ranks(SortedRawLines),
- IdFields = rank_module,
- Entity = "module",
- GroupToggles =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdSite)),
- s(LinkSite)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdProc)),
- s(LinkProc)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdClique)),
- s(LinkClique)])
- ;
- CallerGroups = group_by_clique,
- GroupList = group_csds_by_clique(Deep, CallerCSDPtrPairs),
- RawLines = list.map(proc_callers_clique_to_html(Pref, Deep, PSPtr),
- GroupList),
- SortedRawLines = sort_line_groups(Pref ^ pref_criteria, RawLines),
- SortedLines = add_ranks(SortedRawLines),
- IdFields = source_proc,
- Entity = "clique",
- GroupToggles =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdSite)),
- s(LinkSite)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdProc)),
- s(LinkProc)]) ++
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, CmdModule)),
- s(LinkModule)])
- ),
- % SortedLines may contain many thousand elements, and Netscape
- % chokes on the output unless we filter them or break them into chunks.
- % This simple limit device is temporary until we decide what filtering
- % and/or chunking mechanism we want to use.
- list.length(SortedLines, NumLines),
- select_line_bunch(NumLines, BunchNum0, BunchNum, BunchSize,
- SortedLines, DisplayedLines),
- Banner = proc_callers_banner(PSPtr, ProcName, Pref, Deep,
- NumLines, BunchSize, BunchNum, Entity),
- DisplayedHTMLs = list.map(
- two_id_line_to_html(Pref, Deep, totals_meaningful),
- DisplayedLines),
- HTML = string.append_list(DisplayedHTMLs),
- ( BunchNum > 1 ->
- FirstCmd = deep_cmd_proc_callers(PSPtr, CallerGroups, 1, PrefContour),
- FirstLink = "First group",
- FirstToggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, FirstCmd)), s(FirstLink)])
- ;
- FirstToggle = ""
- ),
- ( BunchNum > 2 ->
- PrevCmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum - 1,
- PrefContour),
- PrevLink = "Previous group",
- PrevToggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, PrevCmd)), s(PrevLink)])
- ;
- PrevToggle = ""
- ),
- ( NumLines > BunchNum * BunchSize ->
- NextCmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum + 1,
- PrefContour),
- NextLink = "Next group",
- NextToggle =
- string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, NextCmd)), s(NextLink)])
- ;
- NextToggle = ""
- ),
- Toggles = GroupToggles ++ FirstToggle ++ PrevToggle ++ NextToggle,
- (
- MaybeErrorMsg = no,
- MaybePage = ok({IdFields, Banner, HTML, Toggles})
- ;
- MaybeErrorMsg = yes(Msg),
- MaybePage = error(Msg)
- ).
-
-:- pred select_line_bunch(int::in, int::in, int::out, int::in, list(T)::in,
- list(T)::out) is det.
-
-select_line_bunch(NumLines, BunchNum0, BunchNum, BunchSize,
- Lines, DisplayedLines) :-
- ToDelete = (BunchNum0 - 1) * BunchSize,
- (
- list.drop(ToDelete, Lines, RemainingLines0),
- RemainingLines0 = [_ | _]
- ->
- BunchNum = BunchNum0,
- RemainingLines = RemainingLines0,
- RemainingNumLines = NumLines - ToDelete
- ;
- BunchNum = 1,
- RemainingLines = Lines,
- RemainingNumLines = NumLines
- ),
- ( RemainingNumLines > BunchSize ->
- list.take_upto(BunchSize, RemainingLines, DisplayedLines)
- ;
- DisplayedLines = RemainingLines
- ).
-
-:- func proc_callers_banner(proc_static_ptr, string, preferences, deep,
- int, int, int, string) = string.
-
-proc_callers_banner(PSPtr, ProcName, Pref, Deep, NumLines, BunchSize, BunchNum,
- Parent) = HTML :-
- Cmd = deep_cmd_proc(PSPtr),
- WrappedProcName = string.format("<A HREF=""%s"">%s</A>",
- [s(deep_cmd_pref_to_url(Pref, Deep, Cmd)),
- s(escape_break_html_string(ProcName))]),
- ( NumLines = 0 ->
- HTML = string.format("<H3>There are no %ss calling %s</H3>",
- [s(Parent), s(WrappedProcName)])
- ; NumLines = 1 ->
- HTML = string.format("<H3>There is one %s calling %s:</H3>\n",
- [s(Parent), s(WrappedProcName)])
- ; NumLines =< BunchSize ->
- HTML = string.format("<H3>The %d %ss calling %s:</H3>",
- [i(NumLines), s(Parent), s(WrappedProcName)])
- ; BunchNum = 1 ->
- HTML = string.format(
- "<H3>There are %d %ss calling %s, showing first %d:</H3>",
- [i(NumLines), s(Parent), s(WrappedProcName), i(BunchSize)])
- ;
- First = (BunchNum - 1) * BunchSize + 1,
- Last0 = (BunchNum) * BunchSize,
- ( Last0 > NumLines ->
- Last = NumLines
- ;
- Last = Last0
- ),
- HTML = string.format(
- "<H3>There are %d %ss calling %s, showing %d to %d:</H3>",
- [i(NumLines), s(Parent), s(WrappedProcName), i(First), i(Last)])
- ).
-
-:- func proc_callers_call_site_to_html(preferences, deep, proc_static_ptr,
- pair(call_site_static_ptr, list(call_site_dynamic_ptr))) = two_id_line.
-
-proc_callers_call_site_to_html(Pref, Deep, CalleePSPtr, CSSPtr - CSDPtrs)
- = LineGroup :-
- call_site_context(Deep, CSSPtr, FileName, LineNumber),
- deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
- CallerPSPtr = CSS ^ css_container,
- deep_lookup_proc_statics(Deep, CallerPSPtr, CallerPS),
- CallerProcName = CallerPS ^ ps_refined_id,
- compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
- HTML =
- string.format("<TD CLASS=id>%s:%d</TD>\n",
- [s(escape_break_html_string(FileName)), i(LineNumber)]) ++
- string.format("<TD CLASS=id>%s</TD>\n",
- [s(proc_static_to_html_ref(Pref, Deep, CallerPSPtr))]),
- LineGroup = line_group(FileName, LineNumber, CallerProcName,
- Own, Desc, HTML, unit).
-
-:- func proc_callers_proc_to_html(preferences, deep, proc_static_ptr,
- pair(proc_static_ptr, list(call_site_dynamic_ptr))) = two_id_line.
-
-proc_callers_proc_to_html(Pref, Deep, CalleePSPtr, CallerPSPtr - CSDPtrs)
- = LineGroup :-
- proc_static_context(Deep, CallerPSPtr, FileName, LineNumber),
- deep_lookup_proc_statics(Deep, CallerPSPtr, CallerPS),
- CallerProcName = CallerPS ^ ps_refined_id,
- compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
- HTML =
- string.format("<TD CLASS=id>%s:%d</TD>\n",
- [s(escape_break_html_string(FileName)), i(LineNumber)]) ++
- string.format("<TD CLASS=id>%s</TD>\n",
- [s(proc_static_to_html_ref(Pref, Deep, CallerPSPtr))]),
- LineGroup = line_group(FileName, LineNumber, CallerProcName,
- Own, Desc, HTML, unit).
-
-:- func proc_callers_module_to_html(preferences, deep, proc_static_ptr,
- pair(string, list(call_site_dynamic_ptr))) = one_id_line.
-
-proc_callers_module_to_html(Pref, Deep, CalleePSPtr, ModuleName - CSDPtrs)
- = LineGroup :-
- compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
- HTML = string.format("<TD CLASS=id>%s</TD>\n",
- [s(module_name_to_html_ref(Pref, Deep, ModuleName))]),
- % We don't have filename information for modules, and line numbers
- % are not meaningful for modules.
- LineGroup = line_group(ModuleName, 0, ModuleName,
- Own, Desc, HTML, unit).
-
-:- func proc_callers_clique_to_html(preferences, deep, proc_static_ptr,
- pair(clique_ptr, list(call_site_dynamic_ptr))) = one_id_line.
-
-proc_callers_clique_to_html(Pref, Deep, CalleePSPtr, CliquePtr - CSDPtrs)
- = LineGroup :-
- compute_parent_csd_prof_info(Deep, CalleePSPtr, CSDPtrs, Own, Desc),
- deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
- deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
- EntryPDPtr = EntryCSD ^ csd_callee,
- proc_dynamic_context(Deep, EntryPDPtr, FileName, LineNumber),
- ProcName = proc_dynamic_name(Deep, EntryPDPtr),
- HTML = string.format("<TD CLASS=id>%s</TD>\n",
- [s(clique_ptr_to_html_ref(Pref, Deep, ProcName, CliquePtr))]),
- LineGroup = line_group(FileName, LineNumber, ProcName,
- Own, Desc, HTML, unit).
-
-%-----------------------------------------------------------------------------%
-
-:- func proc_summary_to_html(preferences, deep, proc_static_ptr) = string.
-
-proc_summary_to_html(Pref, Deep, PSPtr) = HTML :-
- SumHTML = two_id_line_to_html(Pref, Deep, totals_meaningful,
- lookup_proc_total_to_two_id_line(Pref, Deep, yes, "", PSPtr)),
- deep_lookup_proc_statics(Deep, PSPtr, PS),
- CSSPtrsArray = PS ^ ps_sites,
- array.to_list(CSSPtrsArray, CSSPtrs),
- CallSiteGroups = list.map(call_site_summary_to_html(Pref, Deep), CSSPtrs),
- SortedCallSiteGroups = sort_line_groups(Pref ^ pref_criteria,
- CallSiteGroups),
- BodyHTMLs = list.map(
- two_id_line_group_to_html(Pref, Deep, totals_meaningful),
- SortedCallSiteGroups),
- string.append_list(BodyHTMLs, BodyHTML0),
- (
- SortedCallSiteGroups = [],
- BodyHTML = BodyHTML0
- ;
- SortedCallSiteGroups = [_ | _],
- BodyHTML =
- BodyHTML0 ++
- separator_row(Pref, source_proc, totals_meaningful)
- ),
- HTML =
- SumHTML ++
- separator_row(Pref, source_proc, totals_meaningful) ++
- BodyHTML.
-
-:- func proc_summary_toggles_to_html(preferences, deep, proc_static_ptr)
- = string.
-
-proc_summary_toggles_to_html(Pref, Deep, PSPtr) = HTML :-
- PrefContour = Pref ^ pref_contour,
- Msg1 = "[Parent call sites]",
- Cmd1 = deep_cmd_proc_callers(PSPtr, group_by_call_site, 1, PrefContour),
- Msg2 = "[Parent procedures]",
- Cmd2 = deep_cmd_proc_callers(PSPtr, group_by_proc, 1, PrefContour),
- Msg3 = "[Parent modules]",
- Cmd3 = deep_cmd_proc_callers(PSPtr, group_by_module, 1, PrefContour),
- Msg4 = "[Parent cliques]",
- Cmd4 = deep_cmd_proc_callers(PSPtr, group_by_clique, 1, PrefContour),
- Link1 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, Cmd1)), s(Msg1)]),
- Link2 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, Cmd2)), s(Msg2)]),
- Link3 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, Cmd3)), s(Msg3)]),
- Link4 = string.format("<A CLASS=""button"" HREF=""%s"">%s</A>\n",
- [s(deep_cmd_pref_to_url(Pref, Deep, Cmd4)), s(Msg4)]),
- HTML =
- Link1 ++
- Link2 ++
- Link3 ++
- Link4.
-
-%-----------------------------------------------------------------------------%
-
-:- func wrap_clique_links(clique_ptr, preferences, deep, string,
- order_criteria) = string.
-
-wrap_clique_links(CliquePtr, Pref0, Deep, Str0, Criteria) = Str :-
- Cmd = deep_cmd_clique(CliquePtr),
- Pref = Pref0 ^ pref_criteria := Criteria,
- URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
- Str = string.format("<A HREF=%s>%s</A>",
- [s(URL), s(escape_break_html_string(Str0))]).
-
-:- func wrap_proc_links(proc_static_ptr, preferences, deep, string,
- order_criteria) = string.
-
-wrap_proc_links(PSPtr, Pref0, Deep, Str0, Criteria) = Str :-
- Cmd = deep_cmd_proc(PSPtr),
- Pref = Pref0 ^ pref_criteria := Criteria,
- URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
- Str = string.format("<A HREF=%s>%s</A>",
- [s(URL), s(escape_break_html_string(Str0))]).
-
-:- func wrap_proc_callers_links(proc_static_ptr, caller_groups, int,
- preferences, deep, string, order_criteria) = string.
-
-wrap_proc_callers_links(PSPtr, CallerGroups, BunchNum, Pref0, Deep,
- Str0, Criteria) = Str :-
- PrefContour = Pref0 ^ pref_contour,
- Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, PrefContour),
- Pref = Pref0 ^ pref_criteria := Criteria,
- URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
- Str = string.format("<A HREF=%s>%s</A>",
- [s(URL), s(escape_break_html_string(Str0))]).
-
-:- func wrap_module_links(string, preferences, deep, string,
- order_criteria) = string.
-
-wrap_module_links(ModuleName, Pref0, Deep, Str0, Criteria) = Str :-
- Cmd = deep_cmd_module(ModuleName),
- Pref = Pref0 ^ pref_criteria := Criteria,
- URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
- Str = string.format("<A HREF=%s>%s</A>",
- [s(URL), s(escape_break_html_string(Str0))]).
-
-:- func wrap_modules_links(preferences, deep, string, order_criteria) = string.
-
-wrap_modules_links(Pref0, Deep, Str0, Criteria) = Str :-
- Cmd = deep_cmd_program_modules,
- Pref = Pref0 ^ pref_criteria := Criteria,
- URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
- Str = string.format("<A HREF=%s>%s</A>",
- [s(URL), s(escape_break_html_string(Str0))]).
-
-:- func wrap_top_procs_links(display_limit, preferences, deep, string,
- order_criteria) = string.
-
-wrap_top_procs_links(Limit, Pref, Deep, Str0, Criteria) = Str :-
- (
- Criteria = by_context,
- Str = Str0
- ;
- Criteria = by_name,
- Str = Str0
- ;
- Criteria = by_cost(CostKind, InclDesc, Scope),
- Cmd = deep_cmd_top_procs(Limit, CostKind, InclDesc, Scope),
- URL = deep_cmd_pref_to_url(Pref, Deep, Cmd),
- Str = string.format("<A HREF=%s>%s</A>",
- [s(URL), s(escape_break_html_string(Str0))])
- ).
%-----------------------------------------------------------------------------%
% Display times only if the profile was derived from a run that ran for
cvs diff: Diffing notes
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list