[m-rev.] for post-commit review: use reports for rest of deep profiler commands

Zoltan Somogyi zs at csse.unimelb.edu.au
Thu Sep 25 13:46:37 AEST 2008


Move the remaining deep profiler commands, dump_clique, clique and root,
to the report mechanism.

deep_profiler/report.m:
	Define the representation of the new reports.

	Change some names to be more consistent.

deep_profiler/create_report.m:
	Add code to create the new reports.

deep_profiler/measurement units.m:
	Add a predicate to needed by the root command.

deep_profiler/display_report.m:
	Add code for converting the new reports to displays.

	Factor out some previously duplicated code for describing procedures
	and call sites and for comparing them by name and by context.

	Conform to the changes in display.m.

deep_profiler/display.m:
	Expand the display representation to allow the specification of
	attributed text, with the available attributes being bold, italic
	and underlined. We now use bold in clique reports.

deep_profiler/html_format.m:
	Handle the changes in display.m.

	Generate HTML with more structured line breaks.

deep_profiler/query.m:
	Switch the default handling of the three commands over to the new
	mechanism.

	Remove a long unused function.

deep_profiler/profile.m:
	Parameterize the call_site_and_callee type, to allow report.m
	to associate a procedure description, not a proc_static_ptr,
	with a normal call site.

Zoltan.

cvs diff: Diffing .
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/libatomic_ops-1.2
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/doc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/tests
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing boehm_gc/windows-untested
cvs diff: Diffing boehm_gc/windows-untested/vc60
cvs diff: Diffing boehm_gc/windows-untested/vc70
cvs diff: Diffing boehm_gc/windows-untested/vc71
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing debian/patches
cvs diff: Diffing deep_profiler
Index: deep_profiler/create_report.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/create_report.m,v
retrieving revision 1.10
diff -u -b -r1.10 create_report.m
--- deep_profiler/create_report.m	20 Sep 2008 11:38:04 -0000	1.10
+++ deep_profiler/create_report.m	25 Sep 2008 00:18:02 -0000
@@ -39,6 +39,7 @@
 :- import_module top_procs.
 
 :- import_module array.
+:- import_module assoc_list.
 :- import_module exception.
 :- import_module float.
 :- import_module int.
@@ -78,6 +79,14 @@
             NumCallseqs, NumCSD, NumCSS, NumPD, NumPS, NumCliques),
         Report = report_menu(ok(MenuReport))
     ;
+        Cmd = deep_cmd_root(MaybePercent),
+        create_root_report(Deep, MaybePercent, MaybeCliqueReport),
+        Report = report_clique(MaybeCliqueReport)
+    ;
+        Cmd = deep_cmd_clique(CliquePtr),
+        create_clique_report(Deep, CliquePtr, MaybeCliqueReport),
+        Report = report_clique(MaybeCliqueReport)
+    ;
         Cmd = deep_cmd_program_modules,
         create_program_modules_report(Deep, MaybeProgramModulesReport),
         Report = report_program_modules(MaybeProgramModulesReport)
@@ -130,22 +139,339 @@
             MaybeCallSiteStaticDump),
         Report = report_call_site_dynamic_dump(MaybeCallSiteStaticDump)
     ;
+        Cmd = deep_cmd_dump_clique(CliquePtr),
+        create_clique_dump_report(Deep, CliquePtr, MaybeCliqueDump),
+        Report = report_clique_dump(MaybeCliqueDump)
+    ;
         Cmd = deep_cmd_restart,
         error("create_report/3", "unexpected restart command")
+    ).
+
+%-----------------------------------------------------------------------------%
+%
+% Code to build a clique report for the root clique, or the clique where
+% the action begins.
+%
+
+:- pred create_root_report(deep::in, maybe(int)::in,
+    maybe_error(clique_report)::out) is det.
+
+create_root_report(Deep, MaybePercent, MaybeReport) :-
+    deep_lookup_clique_index(Deep, Deep ^ root, RootCliquePtr),
+    create_clique_report(Deep, RootCliquePtr, MaybeRootCliqueReport),
+    (
+        MaybeRootCliqueReport = error(_),
+        MaybeReport = MaybeRootCliqueReport
+    ;
+        MaybeRootCliqueReport = ok(RootCliqueReport),
+        (
+            MaybePercent = no,
+            MaybeReport = ok(RootCliqueReport)
+        ;
+            MaybePercent = yes(Percent),
+            find_start_of_action(Deep, Percent, RootCliqueReport, Report),
+            MaybeReport = ok(Report)
+        )
+    ).
+
+:- pred find_start_of_action(deep::in, int::in,
+    clique_report::in, clique_report::out) is det.
+
+find_start_of_action(Deep, Percent, CurrentReport, SelectedReport) :-
+    CurrentReport = clique_report(_, _, CliqueProcs),
+    list.foldl(find_start_of_action_clique_proc(Percent), CliqueProcs,
+        [], ActionCliquePtrs),
+    (
+        ActionCliquePtrs = [ActionCliquePtr],
+        create_clique_report(Deep, ActionCliquePtr, MaybeActionCliqueReport),
+        MaybeActionCliqueReport = ok(ActionCliqueReport)
+    ->
+        find_start_of_action(Deep, Percent, ActionCliqueReport, SelectedReport)
+    ;
+        SelectedReport = CurrentReport
+    ).
+
+:- pred find_start_of_action_clique_proc(int::in, clique_proc_report::in,
+    list(clique_ptr)::in, list(clique_ptr)::out) is det.
+
+find_start_of_action_clique_proc(Percent, CliqueProcReport,
+        !ActionCliquePtrs) :-
+    CliqueProcReport = clique_proc_report(_, FirstPDReport, LaterPDReports),
+    find_start_of_action_clique_proc_dynamic(Percent,
+        FirstPDReport, !ActionCliquePtrs),
+    list.foldl(find_start_of_action_clique_proc_dynamic(Percent),
+        LaterPDReports, !ActionCliquePtrs).
+
+:- pred find_start_of_action_clique_proc_dynamic(int::in,
+    clique_proc_dynamic_report::in,
+    list(clique_ptr)::in, list(clique_ptr)::out) is det.
+
+find_start_of_action_clique_proc_dynamic(Percent, CliquePDReport,
+        !ActionCliquePtrs) :-
+    CliquePDReport = clique_proc_dynamic_report(_, CallSites),
+    list.foldl(find_start_of_action_call_site(Percent), CallSites,
+        !ActionCliquePtrs).
+
+:- pred find_start_of_action_call_site(int::in, clique_call_site_report::in,
+    list(clique_ptr)::in, list(clique_ptr)::out) is det.
+
+find_start_of_action_call_site(Percent, CallSiteReport, !ActionCliquePtrs) :-
+    CallSiteReport = clique_call_site_report(_, _, CalleeRowDatas),
+    list.foldl(find_start_of_action_callee(Percent), CalleeRowDatas,
+        !ActionCliquePtrs).
+
+:- pred find_start_of_action_callee(int::in, perf_row_data(clique_desc)::in,
+    list(clique_ptr)::in, list(clique_ptr)::out) is det.
+
+find_start_of_action_callee(Percent, RowData, !ActionCliquePtrs) :-
+    MaybeTotalPerf = RowData ^ perf_row_maybe_total,
+    (
+        MaybeTotalPerf = no,
+        error("find_start_of_action_callee: no total perf")
+    ;
+        MaybeTotalPerf = yes(TotalPerf),
+        CallSeqsPercent = TotalPerf ^ perf_row_callseqs_percent,
+        ( percent_at_or_above_threshold(Percent, CallSeqsPercent) ->
+            CliqueDesc = RowData ^ perf_row_subject,
+            CliquePtr = CliqueDesc ^ cdesc_clique_ptr,
+            !:ActionCliquePtrs = [CliquePtr | !.ActionCliquePtrs]
     ;
-        ( Cmd = deep_cmd_root(_)
-        ; Cmd = deep_cmd_clique(_)
-        ; Cmd = deep_cmd_dump_clique(_)
+            true
+        )
+    ).
+
+%-----------------------------------------------------------------------------%
+%
+% Code to build a clique report.
+%
+
+    % Create a clique report, from the given data with the specified
+    % parameters.
+    %
+:- pred create_clique_report(deep::in, clique_ptr::in,
+    maybe_error(clique_report)::out) is det.
+
+create_clique_report(Deep, CliquePtr, MaybeCliqueReport) :-
+    AncestorRowDatas = find_clique_ancestors(Deep, CliquePtr),
+
+    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),
+        PStoPDsList = EntryGroup ++ RestGroup
+    ;
+        PStoPDsList = PStoPDsList0
         ),
-        error("create_report/3", "Command not supported: " ++ string(Cmd))
+    list.map(create_clique_proc_report(Deep, CliquePtr),
+        PStoPDsList, CliqueProcs),
+
+    CliqueReport = clique_report(CliquePtr, AncestorRowDatas, CliqueProcs),
+    MaybeCliqueReport = ok(CliqueReport).
+
+:- func find_clique_ancestors(deep, clique_ptr) =
+    list(perf_row_data(ancestor_desc)).
+
+find_clique_ancestors(Deep, CliquePtr) = Ancestors :-
+    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 could return the true root node, which is the Mercury runtime
+            % system, but that is of no interest to either users or programs.
+            Ancestors = []
+        ;
+            deep_lookup_clique_index(Deep, EntryPDPtr, EntryCliquePtr),
+            CalleePDPtr = EntryCSD ^ csd_callee,
+            deep_lookup_proc_dynamics(Deep, CalleePDPtr, CalleePD),
+            CalleePSPtr = CalleePD ^ pd_proc_static,
+            CalleeDesc = describe_proc(Deep, CalleePSPtr),
+            deep_lookup_call_site_static_map(Deep, EntryCSDPtr, EntryCSSPtr),
+            EntryCallSiteDesc = describe_call_site(Deep, EntryCSSPtr),
+            AncestorDesc = ancestor_desc(EntryCliquePtr, CliquePtr,
+                CalleeDesc, EntryCallSiteDesc),
+            Own = EntryCSD ^ csd_own_prof,
+            deep_lookup_csd_desc(Deep, EntryCSDPtr, Desc),
+            own_and_inherit_to_perf_row_data(Deep, AncestorDesc, Own, Desc,
+                Parent),
+            MoreAncestors = find_clique_ancestors(Deep, EntryCliquePtr),
+            Ancestors = [Parent | MoreAncestors]
+        )
+    ;
+        Ancestors = []
+    ).
+
+:- 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 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 create_clique_proc_report(deep::in, clique_ptr::in,
+    pair(proc_static_ptr, list(proc_dynamic_ptr))::in,
+    clique_proc_report::out) is det.
+
+create_clique_proc_report(Deep, CliquePtr, PSPtr - PDPtrs, CliqueProcReport) :-
+    (
+        PDPtrs = [],
+        error("create_clique_proc_report", "PDPtrs = []")
+    ;
+        PDPtrs = [FirstPDPtr | LaterPDPtrs],
+        ProcDesc = describe_proc(Deep, PSPtr),
+        create_clique_proc_dynamic_report(Deep, CliquePtr, ProcDesc,
+            FirstPDPtr, FirstPDOwn, FirstPDDesc, FirstPDReport),
+        list.map3(create_clique_proc_dynamic_report(Deep, CliquePtr, ProcDesc),
+            LaterPDPtrs, LaterPDOwns, LaterPDDescs, LaterPDReports),
+        SummaryOwn = sum_own_infos([FirstPDOwn | LaterPDOwns]),
+        SummaryDesc = sum_inherit_infos([FirstPDDesc | LaterPDDescs]),
+        own_and_inherit_to_perf_row_data(Deep, ProcDesc,
+            SummaryOwn, SummaryDesc, ProcSummaryRowData),
+        CliqueProcReport = clique_proc_report(ProcSummaryRowData,
+            FirstPDReport, LaterPDReports)
     ).
 
+:- pred create_clique_proc_dynamic_report(deep::in, clique_ptr::in,
+    proc_desc::in, proc_dynamic_ptr::in,
+    own_prof_info::out, inherit_prof_info::out,
+    clique_proc_dynamic_report::out) is det.
+
+create_clique_proc_dynamic_report(Deep, _CliquePtr, ProcDesc, PDPtr,
+        Own, Desc, CliquePDReport) :-
+    ( valid_proc_dynamic_ptr(Deep, PDPtr) ->
+        deep_lookup_pd_own(Deep, PDPtr, Own),
+        deep_lookup_pd_desc(Deep, PDPtr, Desc),
+        own_and_inherit_to_perf_row_data(Deep, ProcDesc, Own, Desc,
+            PDRowData),
+        deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+        PSPtr = PD ^ pd_proc_static,
+        require(unify(PSPtr, ProcDesc ^ pdesc_ps_ptr),
+            "create_clique_proc_dynamic_report: psptr mismatch"),
+        create_child_call_site_reports(Deep, PDPtr, CliqueCallSiteReports),
+        CliquePDReport = clique_proc_dynamic_report(PDRowData,
+            CliqueCallSiteReports)
+    ;
+        error("invalid proc_dynamic index")
+    ).
+
+:- pred create_child_call_site_reports(deep::in, proc_dynamic_ptr::in,
+    list(clique_call_site_report)::out) is det.
+
+create_child_call_site_reports(Deep, PDPtr, CliqueCallSiteReports) :-
+    deep_lookup_proc_dynamics(Deep, PDPtr, PD),
+    PSPtr = PD ^ pd_proc_static,
+    CSDArray = PD ^ pd_sites,
+    deep_lookup_proc_statics(Deep, PSPtr, PS),
+    CSSArray = PS ^ ps_sites,
+    array.to_list(CSDArray, CSDSlots),
+    array.to_list(CSSArray, CSSSlots),
+    assoc_list.from_corresponding_lists(CSSSlots, CSDSlots, PairedSlots),
+    list.map(create_child_call_site_report(Deep), PairedSlots,
+        CliqueCallSiteReports).
+
+:- pred create_child_call_site_report(deep::in,
+    pair(call_site_static_ptr, call_site_array_slot)::in,
+    clique_call_site_report::out) is det.
+
+create_child_call_site_report(Deep, Pair, CliqueCallSiteReport) :-
+    Pair = CSSPtr - CallSiteArraySlot,
+    deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
+    CallSiteDesc = describe_call_site(Deep, CSSPtr),
+    Kind = CSS ^ css_kind,
+    (
+        Kind = normal_call_and_callee(CalleePSPtr, TypeSubst),
+        KnownCalleeDesc = describe_proc(Deep, CalleePSPtr),
+        ProcDescKind = normal_call_and_callee(KnownCalleeDesc, TypeSubst),
+        (
+            CallSiteArraySlot = slot_normal(CSDPtr)
+        ;
+            CallSiteArraySlot = slot_multi(_, _),
+            error("create_child_call_site_report: normal_call error")
+        ),
+        ( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
+            create_callee_clique_perf_row_data(Deep, CSDPtr,
+                Own, Desc, CalleeCliqueRowData),
+            CalleeCliqueRowDatas = [CalleeCliqueRowData]
+        ;
+            Own = zero_own_prof_info,
+            Desc = zero_inherit_prof_info,
+            CalleeCliqueRowDatas = []
+        )
+    ;
+        (
+            Kind = special_call_and_no_callee,
+            ProcDescKind = special_call_and_no_callee
+        ;
+            Kind = higher_order_call_and_no_callee,
+            ProcDescKind = higher_order_call_and_no_callee
+        ;
+            Kind = method_call_and_no_callee,
+            ProcDescKind = method_call_and_no_callee
+        ;
+            Kind = callback_and_no_callee,
+            ProcDescKind = callback_and_no_callee
+        ),
+        (
+            CallSiteArraySlot = slot_normal(_),
+            error("create_child_call_site_report: non-normal_call error")
+        ;
+            CallSiteArraySlot = slot_multi(_IsZeroed, CSDPtrsArray),
+            array.to_list(CSDPtrsArray, CSDPtrs)
+        ),
+        list.map3(create_callee_clique_perf_row_data(Deep), CSDPtrs,
+            Owns, Descs, CalleeCliqueRowDatas),
+        Own = sum_own_infos(Owns),
+        Desc = sum_inherit_infos(Descs)
+    ),
+    own_and_inherit_to_perf_row_data(Deep, CallSiteDesc, Own, Desc,
+        SummaryRowData),
+    CliqueCallSiteReport = clique_call_site_report(SummaryRowData,
+        ProcDescKind, CalleeCliqueRowDatas).
+
+:- pred create_callee_clique_perf_row_data(deep::in, call_site_dynamic_ptr::in,
+    own_prof_info::out, inherit_prof_info::out,
+    perf_row_data(clique_desc)::out) is det.
+
+create_callee_clique_perf_row_data(Deep, CSDPtr, Own, Desc,
+        CalleeCliqueRowData) :-
+    require(valid_call_site_dynamic_ptr(Deep, CSDPtr),
+        "create_callee_clique_perf_row_data: invalid call_site_dynamic_ptr"),
+    deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
+    CalleePDPtr = CSD ^ csd_callee,
+    Own = CSD ^ csd_own_prof,
+    deep_lookup_csd_desc(Deep, CSDPtr, Desc),
+    deep_lookup_clique_index(Deep, CalleePDPtr, CalleeCliquePtr),
+    CliqueDesc = describe_clique(Deep, CalleeCliquePtr),
+    own_and_inherit_to_perf_row_data(Deep, CliqueDesc, Own, Desc,
+        CalleeCliqueRowData).
+
 %-----------------------------------------------------------------------------%
 %
 % Code to build a program_modules report.
 %
 
-    % Create a modules report, from the given data with the specified
+    % Create a program_modules report, from the given data with the specified
     % parameters.
     %
 :- pred create_program_modules_report(deep::in,
@@ -680,6 +1006,21 @@
         MaybeCallSiteDynamicDumpInfo = error("invalid call_site_dynamic index")
     ).
 
+:- pred create_clique_dump_report(deep::in, clique_ptr::in,
+    maybe_error(clique_dump_info)::out) is det.
+
+create_clique_dump_report(Deep, CliquePtr, MaybeCliqueDumpInfo) :-
+    ( valid_clique_ptr(Deep, CliquePtr) ->
+        CliqueDesc = describe_clique(Deep, CliquePtr),
+        deep_lookup_clique_parents(Deep, CliquePtr, ParentCSDPtr),
+        deep_lookup_clique_members(Deep, CliquePtr, MemberPDPtrs),
+        CliqueDumpInfo = clique_dump_info(CliqueDesc, ParentCSDPtr,
+            MemberPDPtrs),
+        MaybeCliqueDumpInfo = ok(CliqueDumpInfo)
+    ;
+        MaybeCliqueDumpInfo = error("invalid clique_ptr")
+    ).
+
 %-----------------------------------------------------------------------------%
 
     % Lookup the proc_static structure with the given PSI index number
@@ -867,8 +1208,17 @@
 describe_clique(Deep, CliquePtr) = CliqueDesc :-
     ( valid_clique_ptr(Deep, CliquePtr) ->
         deep_lookup_clique_members(Deep, CliquePtr, MemberPDPtrs),
-        ProcDescs = list.map(describe_clique_member(Deep), MemberPDPtrs),
-        CliqueDesc = clique_desc(CliquePtr, ProcDescs)
+        deep_lookup_clique_parents(Deep, CliquePtr, ParentCSDPtr),
+        deep_lookup_call_site_dynamics(Deep, ParentCSDPtr, ParentCSD),
+        EntryPDPtr = ParentCSD ^ csd_callee,
+        ( list.delete_first(MemberPDPtrs, EntryPDPtr, OtherPDPtrs) ->
+            EntryProcDesc = describe_clique_member(Deep, EntryPDPtr),
+            OtherProcDescs =
+                list.map(describe_clique_member(Deep), OtherPDPtrs),
+            CliqueDesc = clique_desc(CliquePtr, EntryProcDesc, OtherProcDescs)
+        ;
+            error("describe_clique", "entry pdptr not a member")
+        )
     ;
         error("describe_clique", "invalid clique_ptr")
     ).
Index: deep_profiler/display.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/display.m,v
retrieving revision 1.9
diff -u -b -r1.9 display.m
--- deep_profiler/display.m	28 Aug 2008 10:26:14 -0000	1.9
+++ deep_profiler/display.m	24 Sep 2008 03:49:36 -0000
@@ -190,8 +190,20 @@
             )
     ;       td_p(percent)
     ;       td_s(string)
+    ;       td_as(attr_string)
     ;       td_t(time).
 
+:- type attr_string
+    --->    attr_str(
+                list(str_attr),
+                string
+            ).
+
+:- type str_attr
+    --->    attr_bold
+    ;       attr_italic
+    ;       attr_underline.
+
 %-----------------------------------------------------------------------------%
 %
 % List specific structures
@@ -217,7 +229,7 @@
                 maybe(preferences),
 
                 % A label for the link.
-                string,
+                attr_string,
 
                 % Class of the link; may control how it is displayed.
                 link_class
Index: deep_profiler/display_report.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/display_report.m,v
retrieving revision 1.12
diff -u -b -r1.12 display_report.m
--- deep_profiler/display_report.m	17 Sep 2008 03:26:29 -0000	1.12
+++ deep_profiler/display_report.m	25 Sep 2008 00:39:45 -0000
@@ -69,6 +69,15 @@
             Display = display(no, [display_heading(Msg)])
         )
     ;
+        Report = report_clique(MaybeCliqueReport),
+        (
+            MaybeCliqueReport = ok(CliqueReport),
+            display_report_clique(Prefs, CliqueReport, Display)
+        ;
+            MaybeCliqueReport = error(Msg),
+            Display = display(no, [display_heading(Msg)])
+        )
+    ;
         Report = report_program_modules(MaybeProgramModulesReport),
         (
             MaybeProgramModulesReport = ok(ProgramModulesReport),
@@ -163,6 +172,15 @@
             MaybeCallSiteDynamicDumpInfo = error(Msg),
             Display = display(no, [display_heading(Msg)])
         )
+    ;
+        Report = report_clique_dump(MaybeCliqueDumpInfo),
+        (
+            MaybeCliqueDumpInfo = ok(CliqueDumpInfo),
+            display_report_clique_dump(Prefs, CliqueDumpInfo, Display)
+        ;
+            MaybeCliqueDumpInfo = error(Msg),
+            Display = display(no, [display_heading(Msg)])
+        )
     ).
 
 %-----------------------------------------------------------------------------%
@@ -287,6 +305,241 @@
 
 %-----------------------------------------------------------------------------%
 %
+% Code to display a clique report.
+%
+
+    % Create a display_report structure for a clique report.
+    %
+:- pred display_report_clique(preferences::in, clique_report::in,
+    display::out) is det.
+
+display_report_clique(Prefs, CliqueReport, Display) :-
+    CliqueReport = clique_report(CliquePtr, InnerToOuterAncestorCallSites0,
+        CliqueProcs0),
+    Cmd = deep_cmd_clique(CliquePtr),
+    CliquePtr = clique_ptr(CliqueNum),
+    Title = string.format("Clique %d:", [i(CliqueNum)]),
+
+    % Build the table of all modules.
+    SortByContextPrefs = Prefs ^ pref_criteria := by_context,
+    SortByNamePrefs = Prefs ^ pref_criteria := by_name,
+    SourceHeaderCell = td_l(deep_link(Cmd, yes(SortByContextPrefs),
+        attr_str([], "Source"), link_class_link)),
+    ProcHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
+        attr_str([], "Procedure"), link_class_link)),
+    SourceHeaderGroup =
+        make_single_table_header_group(SourceHeaderCell,
+            table_column_class_source_context, column_do_not_colour),
+    ProcHeaderGroup =
+        make_single_table_header_group(ProcHeaderCell,
+            table_column_class_proc, column_do_not_colour),
+    MakeHeaderData = override_order_criteria_header_data(Cmd),
+    perf_table_header(total_columns_meaningful, Prefs, MakeHeaderData,
+        PerfHeaderGroups),
+    AllHeaderGroups = [SourceHeaderGroup, ProcHeaderGroup] ++ PerfHeaderGroups,
+    header_groups_to_header(AllHeaderGroups, NumColumns, Header),
+
+    list.length(InnerToOuterAncestorCallSites0, NumAncestors),
+    MaybeAncestorLimit = Prefs ^ pref_anc,
+    (
+        MaybeAncestorLimit = yes(AncestorLimit),
+        NumAncestors > AncestorLimit
+    ->
+        AncestorTitle = string.format("The %d closest ancestor call sites:",
+            [i(AncestorLimit)]),
+        list.take_upto(AncestorLimit,
+            InnerToOuterAncestorCallSites0, InnerToOuterAncestorCallSites)
+    ;
+        AncestorTitle = "Ancestor call sites:",
+        InnerToOuterAncestorCallSites = InnerToOuterAncestorCallSites0
+    ),
+
+    list.reverse(InnerToOuterAncestorCallSites, AncestorCallSites),
+    AncestorDataRows = list.map(clique_ancestor_to_row(Prefs),
+        AncestorCallSites),
+    AncestorSectionHeaderRow = table_section_header(td_s(AncestorTitle)),
+    AncestorRows = [AncestorSectionHeaderRow, table_separator_row] ++
+        AncestorDataRows,
+
+    CliqueProcsHeaderRow =
+        table_section_header(td_s("Procedures of the clique:")),
+
+    sort_clique_procs_by_preferences(Prefs, CliqueProcs0, CliqueProcs),
+    ProcRowLists = list.map(clique_proc_to_table_rows(Prefs, CliquePtr),
+        CliqueProcs),
+    list.condense(ProcRowLists, ProcRows),
+
+    AllRows = AncestorRows ++
+        [table_separator_row, CliqueProcsHeaderRow, table_separator_row] ++
+        ProcRows,
+    Table = table(table_class_box_if_pref, NumColumns, yes(Header), AllRows),
+    DisplayTable = display_table(Table),
+
+    % Build controls at the bottom of the page.
+    AncestorControls = ancestor_controls(Prefs, Cmd),
+    FieldControls = field_controls(Prefs, Cmd),
+    FormatControls = format_controls(Prefs, Cmd),
+    MenuRestartQuitControls = cmds_menu_restart_quit(yes(Prefs)),
+
+    Display = display(yes(Title),
+        [DisplayTable,
+        display_paragraph_break, AncestorControls,
+        display_paragraph_break, FieldControls,
+        display_paragraph_break, FormatControls,
+        display_paragraph_break, MenuRestartQuitControls]).
+
+:- func clique_ancestor_to_row(preferences, perf_row_data(ancestor_desc))
+    = table_row.
+
+clique_ancestor_to_row(Prefs, AncestorRowData) = Row :-
+    AncestorDesc = AncestorRowData ^ perf_row_subject,
+    CallSiteDesc = AncestorDesc ^ ad_call_site_desc,
+    SourceCell = call_site_desc_source_cell(CallSiteDesc),
+    CliqueProcCell = call_site_desc_clique_proc_cell(Prefs, AncestorDesc),
+    Fields = Prefs ^ pref_fields,
+    perf_table_row(total_columns_meaningful, Fields, AncestorRowData,
+        PerfCells),
+    AllCells = [SourceCell, CliqueProcCell] ++ PerfCells,
+    Row = table_row(AllCells).
+
+:- func clique_proc_to_table_rows(preferences, clique_ptr, clique_proc_report)
+    = list(table_row).
+
+clique_proc_to_table_rows(Prefs, CliquePtr, CliqueProcReport) = ProcRows :-
+    CliqueProcReport = clique_proc_report(SummaryRowData,
+        FirstPDReport, LaterPDReports),
+    (
+        LaterPDReports = [],
+        ProcRows = clique_proc_dynamic_to_table_rows(Prefs, CliquePtr,
+            FirstPDReport)
+    ;
+        LaterPDReports = [_ | _],
+        AllPDReports = [FirstPDReport | LaterPDReports],
+        sort_clique_proc_dynamics_by_preferences(Prefs, AllPDReports,
+            SortedAllPDReports),
+        PDProcRowLists =
+            list.map(clique_proc_dynamic_to_table_rows(Prefs, CliquePtr),
+                SortedAllPDReports),
+        % Do we want separators between the rows of different proc dynamics?
+        list.condense(PDProcRowLists, PDProcRows),
+        Fields = Prefs ^ pref_fields,
+        perf_table_row(total_columns_meaningful, Fields, SummaryRowData,
+            SummaryPerfCells),
+        ProcDesc = SummaryRowData ^ perf_row_subject,
+        SourceCell = proc_desc_to_source_cell(ProcDesc),
+        ProcCell = proc_desc_to_prefix_proc_name_cell(Prefs, [attr_bold],
+            ProcDesc, "summary "),
+        SummaryRowCells = [SourceCell, ProcCell] ++ SummaryPerfCells,
+        SummaryRow = table_row(SummaryRowCells),
+        ProcRows = [SummaryRow, table_separator_row] ++ PDProcRows
+    ).
+
+:- func clique_proc_dynamic_to_table_rows(preferences, clique_ptr,
+    clique_proc_dynamic_report) = list(table_row).
+
+clique_proc_dynamic_to_table_rows(Prefs, CliquePtr, CliqueProcDynamicReport)
+        = ProcRows :-
+    CliqueProcDynamicReport = clique_proc_dynamic_report(SummaryRowData,
+        CallSiteReports),
+    ProcDesc = SummaryRowData ^ perf_row_subject,
+    ProcCell = proc_desc_to_proc_name_cell_span(Prefs, [attr_bold],
+        ProcDesc, 2),
+    Fields = Prefs ^ pref_fields,
+    perf_table_row(total_columns_meaningful, Fields, SummaryRowData,
+        SummaryPerfCells),
+    SummaryRowCells = [ProcCell] ++ SummaryPerfCells,
+    SummaryRow = table_row(SummaryRowCells),
+    CallSiteRowLists =
+        list.map(clique_call_site_to_rows(Prefs, CliquePtr), CallSiteReports),
+    list.condense(CallSiteRowLists, CallSiteRows),
+    ProcRows = [SummaryRow, table_separator_row] ++ CallSiteRows.
+
+:- func clique_call_site_to_rows(preferences, clique_ptr,
+    clique_call_site_report) = list(table_row).
+
+clique_call_site_to_rows(Prefs, CliquePtr, CallSiteReport) = Rows :-
+    CallSiteReport = clique_call_site_report(CallSiteRowData, Kind,
+        CalleePerfs),
+    CallSiteDesc = CallSiteRowData ^ perf_row_subject,
+    SourceCell = call_site_desc_source_cell(CallSiteDesc),
+    Fields = Prefs ^ pref_fields,
+    perf_table_row(total_columns_meaningful, Fields, CallSiteRowData,
+        SummaryPerfCells),
+    (
+        Kind = normal_call_and_callee(CalleeProcDesc, _TypeSubst),
+        (
+            CalleePerfs = [],
+            CalleeProcCell = proc_desc_to_prefix_proc_name_cell(Prefs,
+                [], CalleeProcDesc, "no calls made to "),
+            RowCells = [SourceCell, CalleeProcCell] ++ SummaryPerfCells,
+            Row = table_row(RowCells),
+            Rows = [Row]
+        ;
+            CalleePerfs = [CalleePerf],
+            CalleeCliqueDesc = CalleePerf ^ perf_row_subject,
+            CalleeProcCell = clique_desc_to_non_self_link_proc_name_cell(Prefs,
+                CalleeCliqueDesc, CliquePtr),
+            RowCells = [SourceCell, CalleeProcCell] ++ SummaryPerfCells,
+            Row = table_row(RowCells),
+            Rows = [Row]
+        ;
+            CalleePerfs = [_, _ | _],
+            error("clique_call_site_to_rows: more than one callee at normal")
+        )
+    ;
+        (
+            Kind = special_call_and_no_callee,
+            CalleeCellStr0 = "special call"
+        ;
+            Kind = higher_order_call_and_no_callee,
+            CalleeCellStr0 = "higher order call"
+        ;
+            Kind = method_call_and_no_callee,
+            CalleeCellStr0 = "method call"
+        ;
+            Kind = callback_and_no_callee,
+            CalleeCellStr0 = "callback"
+        ),
+        (
+            CalleePerfs = [],
+            CalleeCellStr = CalleeCellStr0 ++ " (no calls made)"
+        ;
+            CalleePerfs = [_ | _],
+            CalleeCellStr = CalleeCellStr0 ++ " (summary)"
+        ),
+        CalleeCell = table_cell(td_s(CalleeCellStr)),
+        SummaryRowCells = [SourceCell, CalleeCell] ++ SummaryPerfCells,
+        SummaryRow = table_row(SummaryRowCells),
+        Summarize = Prefs ^ pref_summarize,
+        (
+            Summarize = summarize,
+            Rows = [SummaryRow]
+        ;
+            Summarize = do_not_summarize,
+            sort_clique_rows_by_preferences(Prefs, CalleePerfs,
+                SortedCalleePerfs),
+            CalleeRows =
+                list.map(clique_call_site_callee_to_row(Prefs, CliquePtr),
+                    SortedCalleePerfs),
+            Rows = [SummaryRow] ++ CalleeRows
+        )
+    ).
+
+:- func clique_call_site_callee_to_row(preferences, clique_ptr,
+    perf_row_data(clique_desc)) = table_row.
+
+clique_call_site_callee_to_row(Prefs, CliquePtr, CalleeRowData) = Row :-
+    CalleeCliqueDesc = CalleeRowData ^ perf_row_subject,
+    CalleeProcCell = clique_desc_to_non_self_link_proc_name_cell(Prefs,
+        CalleeCliqueDesc, CliquePtr),
+    Fields = Prefs ^ pref_fields,
+    perf_table_row(total_columns_meaningful, Fields, CalleeRowData, PerfCells),
+    EmptyCell = table_cell(td_s("")),
+    Cells = [EmptyCell, CalleeProcCell] ++ PerfCells,
+    Row = table_row(Cells).
+
+%-----------------------------------------------------------------------------%
+%
 % Code to display a program_modules report.
 %
 
@@ -315,8 +568,8 @@
 
     % Build the table of all modules.
     SortByNamePrefs = Prefs ^ pref_criteria := by_name,
-    ModuleHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs), "Module",
-        link_class_link)),
+    ModuleHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
+        attr_str([], "Module"), link_class_link)),
     RankHeaderGroup =
         make_single_table_header_group(td_s("Rank"),
             table_column_class_ordinal_rank, column_do_not_colour),
@@ -332,7 +585,7 @@
 
     list.map_foldl(
         maybe_ranked_subject_perf_table_row(Prefs, ranked,
-            total_columns_not_meaningful, module_active_to_cell),
+            total_columns_not_meaningful, module_active_to_module_name_cell),
         ModuleRowDatas, Rows, 1, _),
     Table = table(table_class_box_if_pref, NumColumns, yes(Header), Rows),
     DisplayTable = display_table(Table),
@@ -395,8 +648,8 @@
 
     % Build the table of all modules.
     SortByNamePrefs = Prefs ^ pref_criteria := by_name,
-    ProcHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs), "Procedure",
-        link_class_link)),
+    ProcHeaderCell = td_l(deep_link(Cmd, yes(SortByNamePrefs),
+        attr_str([], "Procedure"), link_class_link)),
     RankHeaderGroup =
         make_single_table_header_group(td_s("Rank"),
             table_column_class_ordinal_rank, column_do_not_colour),
@@ -412,7 +665,7 @@
 
     list.map_foldl(
         maybe_ranked_subject_perf_table_row(Prefs, ranked,
-            total_columns_meaningful, proc_active_to_cell),
+            total_columns_meaningful, proc_active_to_proc_name_cell),
         ProcRowDatas, Rows, 1, _),
     Table = table(table_class_box_if_pref, NumColumns, yes(Header), Rows),
     DisplayTable = display_table(Table),
@@ -459,7 +712,7 @@
         NumColumns, Header),
     list.map_foldl(
         maybe_ranked_subject_perf_table_row(Prefs, ranked,
-            total_columns_meaningful, proc_desc_to_cell),
+            total_columns_meaningful, proc_desc_to_proc_name_cell),
         TopProcs, Rows, 1, _),
     Table = table(table_class_box_if_pref, NumColumns, yes(Header), Rows),
     DisplayTable = display_table(Table),
@@ -594,10 +847,7 @@
         call_site_perf(KindAndCallee, SummaryPerfRowData, SubPerfs0, _),
 
     CallSiteDesc = SummaryPerfRowData ^ perf_row_subject,
-    FileName = CallSiteDesc ^ csdesc_file_name,
-    LineNumber = CallSiteDesc ^ csdesc_line_number,
-    Context = string.format("%s:%d", [s(FileName), i(LineNumber)]),
-    ContextCell = table_cell(td_s(Context)),
+    ContextCell = call_site_desc_source_cell(CallSiteDesc),
 
     (
         KindAndCallee = normal_call_and_info(NormalCalleeId),
@@ -612,7 +862,7 @@
         CalleePSPtr = CalleeDesc ^ pdesc_ps_ptr,
         CallSiteLinkCmd = deep_cmd_proc(CalleePSPtr),
         CallSiteLink = deep_link(CallSiteLinkCmd, yes(Prefs),
-            CallSiteStr, link_class_link),
+            attr_str([], CallSiteStr), link_class_link),
         CallSiteCell = table_cell(td_l(CallSiteLink)),
 
         require(unify(SubPerfs0, []),
@@ -656,18 +906,10 @@
 
 report_proc_call_site_callee(Prefs, RowData) = Row :-
     Fields = Prefs ^ pref_fields,
-
     EmptyCell = table_empty_cell,
-
     ProcDesc = RowData ^ perf_row_subject,
-    ProcDesc = proc_desc(PSPtr, _FileName, _LineNumber, RefinedName),
-    ProcLinkCmd = deep_cmd_proc(PSPtr),
-    ProcLink = deep_link(ProcLinkCmd, yes(Prefs), RefinedName,
-        link_class_link),
-    ProcCell = table_cell(td_l(ProcLink)),
-
+    ProcCell = proc_desc_to_proc_name_cell(Prefs, ProcDesc),
     perf_table_row(total_columns_meaningful, Fields, RowData, PerfCells),
-
     Cells = [EmptyCell, ProcCell] ++ PerfCells,
     Row = table_row(Cells).
 
@@ -892,17 +1134,8 @@
     !:RowNum = !.RowNum + 1,
 
     CallSiteDesc = CallSiteRowData ^ perf_row_subject,
-    PSPtr = CallSiteDesc ^ csdesc_container,
-    FileName = CallSiteDesc ^ csdesc_file_name,
-    LineNumber = CallSiteDesc ^ csdesc_line_number,
-    CallerRefinedName = CallSiteDesc ^ csdesc_caller_refined_name,
-
-    Source = string.format("%s:%d", [s(FileName), i(LineNumber)]),
-    SourceCell = table_cell(td_s(Source)),
-    ProcLinkCmd = deep_cmd_proc(PSPtr),
-    ProcLink = deep_link(ProcLinkCmd, yes(Prefs), CallerRefinedName,
-        link_class_link),
-    ProcCell = table_cell(td_l(ProcLink)),
+    SourceCell = call_site_desc_to_source_cell(CallSiteDesc),
+    ProcCell = call_site_desc_to_caller_proc_name_cell(Prefs, CallSiteDesc),
 
     Fields = Prefs ^ pref_fields,
     perf_table_row(total_columns_meaningful, Fields, CallSiteRowData,
@@ -918,17 +1151,8 @@
     !:RowNum = !.RowNum + 1,
 
     ProcDesc = ProcRowData ^ perf_row_subject,
-    PSPtr = ProcDesc ^ pdesc_ps_ptr,
-    FileName = ProcDesc ^ pdesc_file_name,
-    LineNumber = ProcDesc ^ pdesc_line_number,
-    RefinedName = ProcDesc ^ pdesc_refined_name,
-
-    Source = string.format("%s:%d", [s(FileName), i(LineNumber)]),
-    SourceCell = table_cell(td_s(Source)),
-    ProcLinkCmd = deep_cmd_proc(PSPtr),
-    ProcLink = deep_link(ProcLinkCmd, yes(Prefs), RefinedName,
-        link_class_link),
-    ProcCell = table_cell(td_l(ProcLink)),
+    SourceCell = proc_desc_to_source_cell(ProcDesc),
+    ProcCell = proc_desc_to_proc_name_cell(Prefs, ProcDesc),
 
     Fields = Prefs ^ pref_fields,
     perf_table_row(total_columns_meaningful, Fields, ProcRowData, PerfCells),
@@ -958,17 +1182,17 @@
     !:RowNum = !.RowNum + 1,
 
     CliqueDesc = CliqueRowData ^ perf_row_subject,
-    CliquePtr = CliqueDesc ^ cdesc_clique_ptr,
+    CliqueDesc = clique_desc(CliquePtr, EntryProcDesc, OtherProcDescs),
     CliquePtr = clique_ptr(CliqueNum),
 
     CliqueLinkCmd = deep_cmd_clique(CliquePtr),
     CliqueText = string.format("clique %d", [i(CliqueNum)]),
-    CliqueLink = deep_link(CliqueLinkCmd, yes(Prefs), CliqueText,
+    CliqueLink = deep_link(CliqueLinkCmd, yes(Prefs), attr_str([], CliqueText),
         link_class_link),
     CliqueCell = table_cell(td_l(CliqueLink)),
 
     MembersStrs = list.map(project_proc_desc_refined_name,
-        CliqueDesc ^ cdesc_members),
+        [EntryProcDesc | OtherProcDescs]),
     MembersStr = string.join_list(", ", MembersStrs),
     MembersCell = table_cell(td_s(MembersStr)),
 
@@ -987,7 +1211,7 @@
 make_proc_callers_link(Prefs, Label, PSPtr, CallerGroups, BunchNum,
         ContourExcl) = Item :-
     Cmd = deep_cmd_proc_callers(PSPtr, CallerGroups, BunchNum, ContourExcl),
-    Link = deep_link(Cmd, yes(Prefs), Label, link_class_control),
+    Link = deep_link(Cmd, yes(Prefs), attr_str([], Label), link_class_control),
     Item = display_link(Link).
             
 %-----------------------------------------------------------------------------%
@@ -1082,7 +1306,7 @@
     string.format("Dump of proc_dynamic %d", [i(PDI)], Title),
 
     ProcStaticLink = deep_link(deep_cmd_dump_proc_static(PSPtr), yes(Prefs),
-        string.int_to_string(PSI), link_class_link),
+        attr_str([], string.int_to_string(PSI)), link_class_link),
     MainValues =
         [("Proc static:"            - td_l(ProcStaticLink)),
         ("Raw name:"                - td_s(RawName)),
@@ -1115,7 +1339,8 @@
         CallSite = slot_normal(CSDPtr),
         CSDPtr = call_site_dynamic_ptr(CSDI),
         CSDLink = deep_link(deep_cmd_dump_call_site_dynamic(CSDPtr),
-            yes(Prefs), string.int_to_string(CSDI), link_class_link),
+            yes(Prefs), attr_str([], string.int_to_string(CSDI)),
+            link_class_link),
         CSDCell = table_cell(td_l(CSDLink)),
         FirstRow = table_row([CallSiteNumCell, CSDCell]),
         Rows = [FirstRow]
@@ -1144,7 +1369,7 @@
 dump_psd_call_site_multi_entry(Prefs, CSDPtr, Row) :-
     CSDPtr = call_site_dynamic_ptr(CSDI),
     CSDLink = deep_link(deep_cmd_dump_call_site_dynamic(CSDPtr), yes(Prefs),
-        string.int_to_string(CSDI), link_class_link),
+        attr_str([], string.int_to_string(CSDI)), link_class_link),
     CSDCell = table_cell(td_l(CSDLink)),
     EmptyCell = table_cell(td_s("")),
     Row = table_row([EmptyCell, CSDCell]).
@@ -1163,7 +1388,7 @@
 
     ContainingProcStaticLink = deep_link(
         deep_cmd_dump_proc_static(ContainingPSPtr), yes(Prefs),
-        string.int_to_string(ContainingPSI), link_class_link),
+        attr_str([], string.int_to_string(ContainingPSI)), link_class_link),
 
     (
         CallSiteKind = normal_call_and_callee(CalleePSPtr, TypeSpecDesc),
@@ -1175,8 +1400,8 @@
             CalleeDesc = CalleeDesc0 ++ " typespec " ++ TypeSpecDesc
         ),
         CalleeProcStaticLink = deep_link(
-            deep_cmd_dump_proc_static(CalleePSPtr), yes(Prefs), CalleeDesc,
-            link_class_link),
+            deep_cmd_dump_proc_static(CalleePSPtr), yes(Prefs),
+            attr_str([], CalleeDesc), link_class_link),
         CallSiteKindData = td_l(CalleeProcStaticLink)
     ;
         CallSiteKind = special_call_and_no_callee,
@@ -1208,20 +1433,22 @@
 :- pred display_report_call_site_dynamic_dump(preferences::in,
     call_site_dynamic_dump_info::in, display::out) is det.
 
-display_report_call_site_dynamic_dump(Prefs, CallSiteStaticDumpInfo,
+display_report_call_site_dynamic_dump(Prefs, CallSiteDynamiccDumpInfo,
         Display) :-
-    CallSiteStaticDumpInfo = call_site_dynamic_dump_info(CSDPtr,
+    CallSiteDynamiccDumpInfo = call_site_dynamic_dump_info(CSDPtr,
         CallerPDPtr, CalleePDPtr, RowData),
     CSDPtr = call_site_dynamic_ptr(CSDI),
     string.format("Dump of call_site_dynamic %d", [i(CSDI)], Title),
 
     CallerPDPtr = proc_dynamic_ptr(CallerPDI),
     CallerProcDynamicLink = deep_link(deep_cmd_dump_proc_dynamic(CallerPDPtr),
-        yes(Prefs), string.int_to_string(CallerPDI), link_class_link),
+        yes(Prefs), attr_str([], string.int_to_string(CallerPDI)),
+        link_class_link),
 
     CalleePDPtr = proc_dynamic_ptr(CalleePDI),
     CalleeProcDynamicLink = deep_link(deep_cmd_dump_proc_dynamic(CalleePDPtr),
-        yes(Prefs), string.int_to_string(CalleePDI), link_class_link),
+        yes(Prefs), attr_str([], string.int_to_string(CalleePDI)),
+        link_class_link),
 
     FirstValues =
         [("Caller proc_dynamic:"    - td_l(CallerProcDynamicLink)),
@@ -1234,13 +1461,55 @@
     maybe_ranked_proc_table_header(Prefs, non_ranked, MakeHeaderData,
         NumColumns, Header),
     maybe_ranked_subject_perf_table_row(Prefs, non_ranked,
-        total_columns_meaningful, call_site_desc_to_cell, RowData, PerfRow,
-        1, _),
+        total_columns_meaningful, call_site_desc_to_name_path_slot_cell,
+        RowData, PerfRow, 1, _),
     PerfTable = table(table_class_box, NumColumns, yes(Header), [PerfRow]),
 
     Display = display(yes(Title),
         [display_table(FirstTable), display_table(PerfTable)]).
 
+    % Create a display_report structure for a clique_dump report.
+    %
+:- pred display_report_clique_dump(preferences::in, clique_dump_info::in,
+    display::out) is det.
+
+display_report_clique_dump(Prefs, CliqueDumpInfo, Display) :-
+    CliqueDumpInfo = clique_dump_info(CliqueDesc, EntryCSDPtr, MemberPDPtrs),
+    CliquePtr = CliqueDesc ^ cdesc_clique_ptr,
+    CliquePtr = clique_ptr(CliqueNum),
+    string.format("Dump of clique %d", [i(CliqueNum)], Title),
+
+    EntryCSDPtr = call_site_dynamic_ptr(EntryCSDI),
+    EntryLink = deep_link(deep_cmd_dump_call_site_dynamic(EntryCSDPtr),
+        yes(Prefs), attr_str([], string.int_to_string(EntryCSDI)),
+        link_class_link),
+
+    list.map_foldl(display_report_clique_dump_member(Prefs), MemberPDPtrs,
+        MemberPDLinks, "Member proc_dynamics:", _),
+
+    Values =
+        [("Caller call_site_dynamic:" - td_l(EntryLink))] ++
+        MemberPDLinks,
+
+    Rows = list.map(make_labelled_table_row, Values),
+    Table = table(table_class_do_not_box, 2, no, Rows),
+
+    Display = display(yes(Title), [display_table(Table)]).
+
+:- pred display_report_clique_dump_member(preferences::in,
+    proc_dynamic_ptr::in, pair(string, table_data)::out,
+    string::in, string::out) is det.
+
+display_report_clique_dump_member(Prefs, PDPtr, Pair, !Label) :-
+    PDLabel = !.Label,
+    !:Label = "",
+    PDPtr = proc_dynamic_ptr(PDI),
+    Link = deep_link(deep_cmd_dump_proc_dynamic(PDPtr),
+        yes(Prefs), attr_str([], string.int_to_string(PDI)),
+        link_class_link),
+    PDData = td_l(Link),
+    Pair = PDLabel - PDData.
+
 %-----------------------------------------------------------------------------%
 %
 % Common column header strings.
@@ -1260,10 +1529,12 @@
     ( Criteria = Criteria0 ->
         % Should we display a simple string to indicate that this link
         % leads back to the same page, or would that be confusing?
-        Link = deep_link(Cmd, yes(Prefs), Label, link_class_link),
+        Link = deep_link(Cmd, yes(Prefs), attr_str([], Label),
+            link_class_link),
         TableData = td_l(Link)
     ;
-        Link = deep_link(Cmd, yes(Prefs), Label, link_class_link),
+        Link = deep_link(Cmd, yes(Prefs), attr_str([], Label),
+            link_class_link),
         TableData = td_l(Link)
     ).
 
@@ -1286,10 +1557,12 @@
         ( Cmd = Cmd0 ->
             % Should we display a simple string to indicate that this link
             % leads back to the same page, or would that be confusing?
-            Link = deep_link(Cmd, yes(Prefs0), Label, link_class_link),
+            Link = deep_link(Cmd, yes(Prefs0), attr_str([], Label),
+                link_class_link),
             TableData = td_l(Link)
         ;
-            Link = deep_link(Cmd, yes(Prefs0), Label, link_class_link),
+            Link = deep_link(Cmd, yes(Prefs0), attr_str([], Label),
+                link_class_link),
             TableData = td_l(Link)
         )
     ).
@@ -2082,6 +2355,31 @@
 
 %-----------------------------------------------------------------------------%
 %
+% Some utility procedures.
+%
+
+:- func call_site_desc_source_cell(call_site_desc) = table_cell.
+
+call_site_desc_source_cell(CallSiteDesc) = Cell :-
+    FileName = CallSiteDesc ^ csdesc_file_name,
+    LineNumber = CallSiteDesc ^ csdesc_line_number,
+    Context = string.format("%s:%d", [s(FileName), i(LineNumber)]),
+    Cell = table_cell(td_s(Context)).
+
+:- func call_site_desc_clique_proc_cell(preferences, ancestor_desc)
+    = table_cell.
+
+call_site_desc_clique_proc_cell(Prefs, AncestorDesc) = Cell :-
+    AncestorDesc = ancestor_desc(CallerCliquePtr, _CalleeCliquePtr,
+        _CalleeProcDesc, CallSiteDesc),
+    ContainingProcName = CallSiteDesc ^ csdesc_caller_refined_name,
+    Cmd = deep_cmd_clique(CallerCliquePtr),
+    Link = deep_link(Cmd, yes(Prefs), attr_str([], ContainingProcName),
+        link_class_link),
+    Cell = table_cell(td_l(Link)).
+
+%-----------------------------------------------------------------------------%
+%
 % The basic predicates for creating the controls at the bottoms of pages.
 %
 
@@ -2122,7 +2420,8 @@
         % Item = display_pseudo_link(PseudoLink),
         % Items = [Item]
     ;
-        Link = deep_link(Cmd, yes(Prefs), Label, link_class_control),
+        Link = deep_link(Cmd, yes(Prefs), attr_str([], Label),
+            link_class_control),
         Item = display_link(Link),
         Items = [Item]
     ).
@@ -2164,7 +2463,8 @@
         % Item = display_pseudo_link(PseudoLink),
         % Items = [Item]
     ;
-        Link = deep_link(Cmd, yes(Prefs), Label, link_class_control),
+        Link = deep_link(Cmd, yes(Prefs), attr_str([], Label),
+            link_class_control),
         Item = display_link(Link),
         Items = [Item]
     ).
@@ -2195,7 +2495,8 @@
         % Item = display_pseudo_link(PseudoLink),
         % Items = [Item]
     ;
-        Link = deep_link(Cmd, yes(Prefs), Label, link_class_control),
+        Link = deep_link(Cmd, yes(Prefs), attr_str([], Label),
+            link_class_control),
         Item = display_link(Link),
         Items = [Item]
     ).
@@ -2585,9 +2886,10 @@
 
 proc_reports(Proc, NotCmd) = Reports :-
     Reports0 = [
-        deep_cmd_proc(Proc) - "Procedure",
+        deep_cmd_proc(Proc) -
+            "Procedure",
         deep_cmd_procrep_coverage(Proc) -
-            "Coverage annotated Procedure Representation"
+            "Coverage annotated procedure representation"
         ],
     list.filter((pred((Cmd - _)::in) is semidet :-
             Cmd \= NotCmd
@@ -2664,6 +2966,68 @@
 
 %-----------------------------------------------------------------------------%
 %
+% Control how many ancestors we display.
+%
+
+:- func ancestor_controls(preferences, cmd) = display_item.
+
+ancestor_controls(Prefs, Cmd) = ControlsItem :-
+    MaybeAncestorLimit = Prefs ^ pref_anc,
+    (
+        MaybeAncestorLimit = no,
+        make_prefs_controls_item(Prefs, Cmd, no,
+            ancestor_toggles_no, AncestorControls)
+    ;
+        MaybeAncestorLimit = yes(AncestorLimit),
+        make_prefs_controls_item(Prefs, Cmd, no,
+            ancestor_toggles_yes(AncestorLimit), AncestorControls)
+    ),
+    Controls = [AncestorControls],
+    ControlsItem = display_list(list_class_vertical_no_bullets,
+        yes("Toggle display of ancestors:"), Controls).
+
+:- func ancestor_toggles_no =
+    (assoc_list(string, (pred(preferences, preferences)))::
+    out(list_skel(pair(ground, (pred(in, out) is det))))) is det.
+
+ancestor_toggles_no = [
+    "One ancestor" -
+        set_ancestor_limit(yes(1)),
+    "Two ancestors" -
+        set_ancestor_limit(yes(2)),
+    "Three ancestors" -
+        set_ancestor_limit(yes(3)),
+    "Five ancestors" -
+        set_ancestor_limit(yes(5)),
+    "Ten ancestors" -
+        set_ancestor_limit(yes(10))
+].
+
+:- func ancestor_toggles_yes(int::in) =
+    (assoc_list(string, (pred(preferences, preferences)))::
+    out(list_skel(pair(ground, (pred(in, out) is det))))) is det.
+
+ancestor_toggles_yes(CurrentLimit) = [
+    "Halve ancestors" -
+        set_ancestor_limit(yes(CurrentLimit // 2)),
+    "Remove an ancestor" -
+        set_ancestor_limit(yes(CurrentLimit - 1)),
+    "Add an ancestor" -
+        set_ancestor_limit(yes(CurrentLimit + 1)),
+    "Double ancestors" -
+        set_ancestor_limit(yes(CurrentLimit * 2)),
+    "Unlimited ancestors" -
+        set_ancestor_limit(no)
+].
+
+:- pred set_ancestor_limit(maybe(int)::in,
+    preferences::in, preferences::out) is det.
+
+set_ancestor_limit(MaybeAncestorLimit, !Prefs) :-
+    !Prefs ^ pref_anc := MaybeAncestorLimit.
+
+%-----------------------------------------------------------------------------%
+%
 % Control the set of displayed fields.
 %
 
@@ -2809,12 +3173,12 @@
 :- func cmds_menu_restart_quit(maybe(preferences)) = display_item.
 
 cmds_menu_restart_quit(MaybePrefs) = ControlsItem :-
-    Menu = display_link(deep_link(deep_cmd_menu, MaybePrefs, "Menu",
-        link_class_control)),
-    Restart = display_link(deep_link(deep_cmd_restart, MaybePrefs, "Restart",
-        link_class_control)),
-    Quit = display_link(deep_link(deep_cmd_quit, MaybePrefs, "Quit",
-        link_class_control)),
+    Menu = display_link(deep_link(deep_cmd_menu, MaybePrefs,
+        attr_str([], "Menu"), link_class_control)),
+    Restart = display_link(deep_link(deep_cmd_restart, MaybePrefs,
+        attr_str([], "Restart"), link_class_control)),
+    Quit = display_link(deep_link(deep_cmd_quit, MaybePrefs,
+        attr_str([], "Quit"), link_class_control)),
     List = display_list(list_class_horizontal, no,
         [Menu, Restart, Quit]),
     ControlsItem = display_list(list_class_vertical_no_bullets,
@@ -2822,37 +3186,110 @@
 
 %-----------------------------------------------------------------------------%
 %
-% Convert procedure and call site descriptions into table cells.
+% Convert procedure, call site and clique descriptions into table cells.
 %
 
-:- func module_active_to_cell(preferences, module_active) = table_cell.
+:- func module_active_to_module_name_cell(preferences, module_active) =
+    table_cell.
 
-module_active_to_cell(Prefs, ModuleActive) = table_cell(Data) :-
+module_active_to_module_name_cell(Prefs, ModuleActive) = Cell :-
     ModuleName = ModuleActive ^ ma_module_name,
     Cmd = deep_cmd_module(ModuleName),
-    Data = td_l(deep_link(Cmd, yes(Prefs), ModuleName, link_class_link)).
+    Link = deep_link(Cmd, yes(Prefs), attr_str([], ModuleName),
+        link_class_link),
+    Cell = table_cell(td_l(Link)).
+
+:- func proc_active_to_proc_name_cell(preferences, proc_active) = table_cell.
+
+proc_active_to_proc_name_cell(Prefs, ProcActive) =
+    proc_desc_to_proc_name_cell(Prefs, ProcActive ^ pa_proc_desc).
+
+:- func proc_desc_to_source_cell(proc_desc) = table_cell.
+
+proc_desc_to_source_cell(ProcDesc) = Cell :-
+    FileName = ProcDesc ^ pdesc_file_name,
+    LineNumber = ProcDesc ^ pdesc_line_number,
+    Source = string.format("%s:%d", [s(FileName), i(LineNumber)]),
+    Cell = table_cell(td_s(Source)).
+
+:- func proc_desc_to_proc_name_cell(preferences, proc_desc) = table_cell.
+
+proc_desc_to_proc_name_cell(Prefs, ProcDesc) = Cell :-
+    PSPtr = ProcDesc ^ pdesc_ps_ptr,
+    RefinedName = ProcDesc ^ pdesc_refined_name,
+    Cmd = deep_cmd_proc(PSPtr),
+    Link = deep_link(Cmd, yes(Prefs), attr_str([], RefinedName),
+        link_class_link),
+    Cell = table_cell(td_l(Link)).
 
-:- func proc_active_to_cell(preferences, proc_active) = table_cell.
+:- func proc_desc_to_proc_name_cell_span(preferences, list(str_attr),
+    proc_desc, int) = table_cell.
 
-proc_active_to_cell(Prefs, ProcActive) =
-    proc_desc_to_cell(Prefs, ProcActive ^ pa_proc_desc).
+proc_desc_to_proc_name_cell_span(Prefs, Attrs, ProcDesc, Span) = Cell :-
+    PSPtr = ProcDesc ^ pdesc_ps_ptr,
+    RefinedName = ProcDesc ^ pdesc_refined_name,
+    Cmd = deep_cmd_proc(PSPtr),
+    Link = deep_link(Cmd, yes(Prefs), attr_str(Attrs, RefinedName),
+        link_class_link),
+    Cell = table_multi_cell(td_l(Link), Span).
 
-:- func proc_desc_to_cell(preferences, proc_desc) = table_cell.
+:- func proc_desc_to_prefix_proc_name_cell(preferences, list(str_attr),
+    proc_desc, string) = table_cell.
 
-proc_desc_to_cell(Prefs, ProcDesc) = table_cell(Data) :-
-    ProcDesc = proc_desc(PSPtr, _FileName, _LineNumber, RefinedName),
+proc_desc_to_prefix_proc_name_cell(Prefs, Attrs, ProcDesc, Prefix) = Cell :-
+    PSPtr = ProcDesc ^ pdesc_ps_ptr,
+    RefinedName = ProcDesc ^ pdesc_refined_name,
     Cmd = deep_cmd_proc(PSPtr),
-    Data = td_l(deep_link(Cmd, yes(Prefs), RefinedName, link_class_link)).
+    Link = deep_link(Cmd, yes(Prefs), attr_str(Attrs, Prefix ++ RefinedName),
+        link_class_link),
+    Cell = table_cell(td_l(Link)).
 
-:- func call_site_desc_to_cell(preferences, call_site_desc) = table_cell.
+:- func call_site_desc_to_name_path_slot_cell(preferences, call_site_desc)
+    = table_cell.
 
-call_site_desc_to_cell(Prefs, CallSiteDesc) = table_cell(Data) :-
+call_site_desc_to_name_path_slot_cell(Prefs, CallSiteDesc) = Cell :-
     CallSiteDesc = call_site_desc(CSSPtr, _ContainerPSPtr,
         _FileName, _LineNumber, RefinedName, SlotNumber, GoalPath),
     string.format("%s @ %s #%d", [s(RefinedName), s(GoalPath), i(SlotNumber)],
         Name),
     Cmd = deep_cmd_dump_call_site_static(CSSPtr),
-    Data = td_l(deep_link(Cmd, yes(Prefs), Name, link_class_link)).
+    Link = deep_link(Cmd, yes(Prefs), attr_str([], Name), link_class_link),
+    Cell = table_cell(td_l(Link)).
+
+:- func call_site_desc_to_source_cell(call_site_desc) = table_cell.
+
+call_site_desc_to_source_cell(CallSiteDesc) = Cell :-
+    FileName = CallSiteDesc ^ csdesc_file_name,
+    LineNumber = CallSiteDesc ^ csdesc_line_number,
+    Source = string.format("%s:%d", [s(FileName), i(LineNumber)]),
+    Cell = table_cell(td_s(Source)).
+
+:- func call_site_desc_to_caller_proc_name_cell(preferences,
+    call_site_desc) = table_cell.
+
+call_site_desc_to_caller_proc_name_cell(Prefs, CallSiteDesc) = Cell :-
+    PSPtr = CallSiteDesc ^ csdesc_container,
+    CallerRefinedName = CallSiteDesc ^ csdesc_caller_refined_name,
+    Cmd = deep_cmd_proc(PSPtr),
+    Link = deep_link(Cmd, yes(Prefs), attr_str([], CallerRefinedName),
+        link_class_link),
+    Cell = table_cell(td_l(Link)).
+
+:- func clique_desc_to_non_self_link_proc_name_cell(preferences,
+    clique_desc, clique_ptr) = table_cell.
+
+clique_desc_to_non_self_link_proc_name_cell(Prefs, CliqueDesc, SelfCliquePtr)
+        = Cell :-
+    CliqueDesc = clique_desc(CliquePtr, EntryProcDesc, _OtherProcDescs),
+    EntryProcName = EntryProcDesc ^ pdesc_refined_name,
+    ( CliquePtr = SelfCliquePtr ->
+        Cell = table_cell(td_s(EntryProcName))
+    ;
+        Cmd = deep_cmd_clique(CliquePtr),
+        Link = deep_link(Cmd, yes(Prefs), attr_str([], EntryProcName),
+            link_class_link),
+        Cell = table_cell(td_l(Link))
+    ).
 
 %-----------------------------------------------------------------------------%
 %
@@ -2871,7 +3308,8 @@
 :- pred make_link(pair(cmd, string)::in, display_item::out) is det.
 
 make_link(Cmd - Label, Item) :-
-    Item = display_link(deep_link(Cmd, no, Label, link_class_link)).
+    Item = display_link(deep_link(Cmd, no, attr_str([], Label),
+        link_class_link)).
 
     % Make a control from a command and label and optional preferences
     % structure.
@@ -2880,7 +3318,166 @@
     display_item::out) is det.
 
 make_control(MaybePrefs, Cmd - Label, Item) :-
-    Item = display_link(deep_link(Cmd, MaybePrefs, Label, link_class_control)).
+    Item = display_link(deep_link(Cmd, MaybePrefs, attr_str([], Label),
+        link_class_control)).
+
+%-----------------------------------------------------------------------------%
+%
+% Sort procedures in a clique by the preferred criteria of performance.
+%
+
+:- pred sort_clique_procs_by_preferences(preferences::in,
+    list(clique_proc_report)::in, list(clique_proc_report)::out) is det.
+
+sort_clique_procs_by_preferences(Prefs, !CliqueProcs) :-
+    OrderCriteria = Prefs ^ pref_criteria,
+    (
+        OrderCriteria = by_context,
+        list.sort(compare_clique_procs_by_context, !CliqueProcs)
+    ;
+        OrderCriteria = by_name,
+        list.sort(compare_clique_procs_by_name, !CliqueProcs)
+    ;
+        OrderCriteria = by_cost(CostKind, InclDesc, Scope),
+        list.sort(compare_clique_procs_by_cost(CostKind, InclDesc, Scope),
+            !CliqueProcs),
+        % We want the most expensive procedures to appear first.
+        list.reverse(!CliqueProcs)
+    ).
+
+:- pred compare_clique_procs_by_context(
+    clique_proc_report::in, clique_proc_report::in, comparison_result::out)
+    is det.
+
+compare_clique_procs_by_context(CliqueProcReportA, CliqueProcReportB,
+        Result) :-
+    CliqueProcDescA = CliqueProcReportA ^ cpr_proc_summary ^ perf_row_subject,
+    CliqueProcDescB = CliqueProcReportB ^ cpr_proc_summary ^ perf_row_subject,
+    compare_proc_descs_by_context(CliqueProcDescA, CliqueProcDescB, Result).
+
+:- pred compare_clique_procs_by_name(
+    clique_proc_report::in, clique_proc_report::in, comparison_result::out)
+    is det.
+
+compare_clique_procs_by_name(CliqueProcReportA, CliqueProcReportB, Result) :-
+    CliqueProcDescA = CliqueProcReportA ^ cpr_proc_summary ^ perf_row_subject,
+    CliqueProcDescB = CliqueProcReportB ^ cpr_proc_summary ^ perf_row_subject,
+    compare_proc_descs_by_name(CliqueProcDescA, CliqueProcDescB, Result).
+
+:- pred compare_clique_procs_by_cost(
+    cost_kind::in, include_descendants::in, measurement_scope::in,
+    clique_proc_report::in, clique_proc_report::in, comparison_result::out)
+    is det.
+
+compare_clique_procs_by_cost(CostKind, InclDesc, Scope,
+        CliqueProcReportA, CliqueProcReportB, Result) :-
+    ProcRowDataA = CliqueProcReportA ^ cpr_proc_summary,
+    ProcRowDataB = CliqueProcReportB ^ cpr_proc_summary,
+    compare_perf_row_datas_by_cost(CostKind, InclDesc, Scope,
+        ProcRowDataA, ProcRowDataB, Result).
+
+%-----------------------------------------------------------------------------%
+%
+% Sort proc_dynamics in a clique by the preferred criteria of performance.
+%
+
+:- pred sort_clique_proc_dynamics_by_preferences(preferences::in,
+    list(clique_proc_dynamic_report)::in,
+    list(clique_proc_dynamic_report)::out) is det.
+
+sort_clique_proc_dynamics_by_preferences(Prefs, !CliqueProcDynamics) :-
+    OrderCriteria = Prefs ^ pref_criteria,
+    (
+        ( OrderCriteria = by_context
+        ; OrderCriteria = by_name
+        ),
+        % All the proc_dynamics we want to sort have the same name and context,
+        % so it does not make sense to sort on these criteria. Instead, we sort
+        % on the default performance criteria.
+        CostKind = default_cost_kind,
+        InclDesc = default_incl_desc,
+        Scope = default_scope
+    ;
+        OrderCriteria = by_cost(CostKind, InclDesc, Scope)
+    ),
+    list.sort(compare_clique_proc_dynamics_by_cost(CostKind, InclDesc, Scope),
+        !CliqueProcDynamics),
+    % We want the most expensive procedures to appear first.
+    list.reverse(!CliqueProcDynamics).
+
+:- pred compare_clique_proc_dynamics_by_cost(
+    cost_kind::in, include_descendants::in, measurement_scope::in,
+    clique_proc_dynamic_report::in, clique_proc_dynamic_report::in,
+    comparison_result::out) is det.
+
+compare_clique_proc_dynamics_by_cost(CostKind, InclDesc, Scope,
+        CliqueProcDynamicReportA, CliqueProcDynamicReportB, Result) :-
+    ProcDynamicRowDataA = CliqueProcDynamicReportA ^ cpdr_proc_summary,
+    ProcDynamicRowDataB = CliqueProcDynamicReportB ^ cpdr_proc_summary,
+    compare_perf_row_datas_by_cost(CostKind, InclDesc, Scope,
+        ProcDynamicRowDataA, ProcDynamicRowDataB, Result).
+
+%-----------------------------------------------------------------------------%
+%
+% Sort clique_call_site_reports by the preferred criteria of performance.
+%
+
+:- pred sort_clique_call_site_reports_by_preferences(preferences::in,
+    list(clique_call_site_report)::in, list(clique_call_site_report)::out)
+    is det.
+
+sort_clique_call_site_reports_by_preferences(Prefs, !CallSiteReports) :-
+    OrderCriteria = Prefs ^ pref_criteria,
+    (
+        OrderCriteria = by_context,
+        list.sort(compare_clique_call_site_reports_by_context,
+            !CallSiteReports)
+    ;
+        OrderCriteria = by_name,
+        list.sort(compare_clique_call_site_reports_by_name, !CallSiteReports)
+    ;
+        OrderCriteria = by_cost(CostKind, InclDesc, Scope),
+        list.sort(compare_clique_call_site_reports_by_cost(CostKind,
+            InclDesc, Scope), !CallSiteReports),
+        % We want the most expensive call sites to appear first.
+        list.reverse(!CallSiteReports)
+    ).
+
+:- pred compare_clique_call_site_reports_by_context(
+    clique_call_site_report::in, clique_call_site_report::in,
+    comparison_result::out) is det.
+
+compare_clique_call_site_reports_by_context(CallSiteReportA,
+        CallSiteReportB, Result) :-
+    CallSiteDescA =
+        CallSiteReportA ^ ccsr_call_site_summary ^ perf_row_subject,
+    CallSiteDescB =
+        CallSiteReportB ^ ccsr_call_site_summary ^ perf_row_subject,
+    compare_call_site_descs_by_context(CallSiteDescA, CallSiteDescB, Result).
+
+:- pred compare_clique_call_site_reports_by_name(
+    clique_call_site_report::in, clique_call_site_report::in,
+    comparison_result::out) is det.
+
+compare_clique_call_site_reports_by_name(CallSiteReportA, CallSiteReportB,
+        Result) :-
+    CallSiteDescA =
+        CallSiteReportA ^ ccsr_call_site_summary ^ perf_row_subject,
+    CallSiteDescB =
+        CallSiteReportB ^ ccsr_call_site_summary ^ perf_row_subject,
+    compare_call_site_descs_by_name(CallSiteDescA, CallSiteDescB, Result).
+
+:- pred compare_clique_call_site_reports_by_cost(
+    cost_kind::in, include_descendants::in, measurement_scope::in,
+    clique_call_site_report::in, clique_call_site_report::in,
+    comparison_result::out) is det.
+
+compare_clique_call_site_reports_by_cost(CostKind, InclDesc, Scope,
+        CliqueCallSiteReportA, CliqueCallSiteReportB, Result) :-
+    PerfA = CliqueCallSiteReportA ^ ccsr_call_site_summary,
+    PerfB = CliqueCallSiteReportB ^ ccsr_call_site_summary,
+    compare_perf_row_datas_by_cost(CostKind, InclDesc, Scope, PerfA, PerfB,
+        Result).
 
 %-----------------------------------------------------------------------------%
 %
@@ -2912,20 +3509,7 @@
 compare_call_site_perfs_by_context(CallSitePerfA, CallSitePerfB, Result) :-
     CallSiteDescA = CallSitePerfA ^ csf_summary_perf ^ perf_row_subject,
     CallSiteDescB = CallSitePerfB ^ csf_summary_perf ^ perf_row_subject,
-    FileNameA = CallSiteDescA ^ csdesc_file_name,
-    FileNameB = CallSiteDescB ^ csdesc_file_name,
-    compare(FileNameResult, FileNameA, FileNameB),
-    (
-        ( FileNameResult = (<)
-        ; FileNameResult = (>)
-        ),
-        Result = FileNameResult
-    ;
-        FileNameResult = (=),
-        LineNumberA = CallSiteDescA ^ csdesc_line_number,
-        LineNumberB = CallSiteDescB ^ csdesc_line_number,
-        compare(Result, LineNumberA, LineNumberB)
-    ).
+    compare_call_site_descs_by_context(CallSiteDescA, CallSiteDescB, Result).
 
 :- pred compare_call_site_perfs_by_name(
     call_site_perf::in, call_site_perf::in, comparison_result::out) is det.
@@ -2933,9 +3517,7 @@
 compare_call_site_perfs_by_name(CallSitePerfA, CallSitePerfB, Result) :-
     CallSiteDescA = CallSitePerfA ^ csf_summary_perf ^ perf_row_subject,
     CallSiteDescB = CallSitePerfB ^ csf_summary_perf ^ perf_row_subject,
-    NameA = CallSiteDescA ^ csdesc_caller_refined_name,
-    NameB = CallSiteDescB ^ csdesc_caller_refined_name,
-    compare(Result, NameA, NameB).
+    compare_call_site_descs_by_name(CallSiteDescA, CallSiteDescB, Result).
 
 :- pred compare_call_site_perfs_by_cost(
     cost_kind::in, include_descendants::in, measurement_scope::in,
@@ -2981,20 +3563,7 @@
         CallSiteDescRowDataA, CallSiteDescRowDataB, Result) :-
     CallSiteDescA = CallSiteDescRowDataA ^ perf_row_subject,
     CallSiteDescB = CallSiteDescRowDataB ^ perf_row_subject,
-    FileNameA = CallSiteDescA ^ csdesc_file_name,
-    FileNameB = CallSiteDescB ^ csdesc_file_name,
-    compare(FileNameResult, FileNameA, FileNameB),
-    (
-        ( FileNameResult = (<)
-        ; FileNameResult = (>)
-        ),
-        Result = FileNameResult
-    ;
-        FileNameResult = (=),
-        LineNumberA = CallSiteDescA ^ csdesc_line_number,
-        LineNumberB = CallSiteDescB ^ csdesc_line_number,
-        compare(Result, LineNumberA, LineNumberB)
-    ).
+    compare_call_site_descs_by_context(CallSiteDescA, CallSiteDescB, Result).
 
 :- pred compare_call_site_desc_rows_by_name(
     perf_row_data(call_site_desc)::in, perf_row_data(call_site_desc)::in,
@@ -3004,9 +3573,7 @@
         Result) :-
     CallSiteDescA = CallSiteDescRowDataA ^ perf_row_subject,
     CallSiteDescB = CallSiteDescRowDataB ^ perf_row_subject,
-    NameA = CallSiteDescA ^ csdesc_caller_refined_name,
-    NameB = CallSiteDescB ^ csdesc_caller_refined_name,
-    compare(Result, NameA, NameB).
+    compare_call_site_descs_by_name(CallSiteDescA, CallSiteDescB, Result).
 
 %-----------------------------------------------------------------------------%
 %
@@ -3050,28 +3617,7 @@
 compare_proc_desc_rows_by_name(ProcDescRowDataA, ProcDescRowDataB, Result) :-
     ProcDescA = ProcDescRowDataA ^ perf_row_subject,
     ProcDescB = ProcDescRowDataB ^ perf_row_subject,
-    NameA = ProcDescA ^ pdesc_refined_name,
-    NameB = ProcDescB ^ pdesc_refined_name,
-    compare(Result, NameA, NameB).
-
-:- pred compare_proc_descs_by_context(proc_desc::in, proc_desc::in,
-    comparison_result::out) is det.
-
-compare_proc_descs_by_context(ProcDescA, ProcDescB, Result) :-
-    FileNameA = ProcDescA ^ pdesc_file_name,
-    FileNameB = ProcDescB ^ pdesc_file_name,
-    compare(FileNameResult, FileNameA, FileNameB),
-    (
-        ( FileNameResult = (<)
-        ; FileNameResult = (>)
-        ),
-        Result = FileNameResult
-    ;
-        FileNameResult = (=),
-        LineNumberA = ProcDescA ^ pdesc_line_number,
-        LineNumberB = ProcDescB ^ pdesc_line_number,
-        compare(Result, LineNumberA, LineNumberB)
-    ).
+    compare_proc_descs_by_name(ProcDescA, ProcDescB, Result).
 
 %-----------------------------------------------------------------------------%
 %
@@ -3103,10 +3649,8 @@
     comparison_result::out) is det.
 
 compare_proc_active_rows_by_context(ProcRowDataA, ProcRowDataB, Result) :-
-    ProcActiveA = ProcRowDataA ^ perf_row_subject,
-    ProcActiveB = ProcRowDataB ^ perf_row_subject,
-    ProcDescA = ProcActiveA ^ pa_proc_desc,
-    ProcDescB = ProcActiveB ^ pa_proc_desc,
+    ProcDescA = ProcRowDataA ^ perf_row_subject ^ pa_proc_desc,
+    ProcDescB = ProcRowDataB ^ perf_row_subject ^ pa_proc_desc,
     compare_proc_descs_by_context(ProcDescA, ProcDescB, Result).
 
 :- pred compare_proc_active_rows_by_name(
@@ -3114,11 +3658,9 @@
     comparison_result::out) is det.
 
 compare_proc_active_rows_by_name(ModuleRowDataA, ModuleRowDataB, Result) :-
-    ProcActiveA = ModuleRowDataA ^ perf_row_subject,
-    ProcActiveB = ModuleRowDataB ^ perf_row_subject,
-    ProcNameA = ProcActiveA ^ pa_proc_desc ^ pdesc_refined_name,
-    ProcNameB = ProcActiveB ^ pa_proc_desc ^ pdesc_refined_name,
-    compare(Result, ProcNameA, ProcNameB).
+    ProcDescA = ModuleRowDataA ^ perf_row_subject ^ pa_proc_desc,
+    ProcDescB = ModuleRowDataB ^ perf_row_subject ^ pa_proc_desc,
+    compare_proc_descs_by_name(ProcDescA, ProcDescB, Result).
 
 %-----------------------------------------------------------------------------%
 %
@@ -3242,17 +3784,69 @@
         Result) :-
     CliqueDescA = CliqueRowDataA ^ perf_row_subject,
     CliqueDescB = CliqueRowDataB ^ perf_row_subject,
-    ProcDescsA = CliqueDescA ^ cdesc_members,
-    ProcDescsB = CliqueDescB ^ cdesc_members,
+    EntryProcDescA = CliqueDescA ^ cdesc_entry_member,
+    EntryProcDescB = CliqueDescB ^ cdesc_entry_member,
+    compare_proc_descs_by_context(EntryProcDescA, EntryProcDescB, Result).
+
+%-----------------------------------------------------------------------------%
+%
+% Sort call_site_descs and proc_descs by context and by name.
+%
+
+:- pred compare_call_site_descs_by_context(
+    call_site_desc::in, call_site_desc::in, comparison_result::out) is det.
+
+compare_call_site_descs_by_context(CallSiteDescA, CallSiteDescB, Result) :-
+    FileNameA = CallSiteDescA ^ csdesc_file_name,
+    FileNameB = CallSiteDescB ^ csdesc_file_name,
+    compare(FileNameResult, FileNameA, FileNameB),
     (
-        ProcDescsA = [FirstProcDescA | _],
-        ProcDescsB = [FirstProcDescB | _]
-    ->
-        compare_proc_descs_by_context(FirstProcDescA, FirstProcDescB, Result)
+        ( FileNameResult = (<)
+        ; FileNameResult = (>)
+        ),
+        Result = FileNameResult
+    ;
+        FileNameResult = (=),
+        LineNumberA = CallSiteDescA ^ csdesc_line_number,
+        LineNumberB = CallSiteDescB ^ csdesc_line_number,
+        compare(Result, LineNumberA, LineNumberB)
+    ).
+
+:- pred compare_proc_descs_by_context(proc_desc::in, proc_desc::in,
+    comparison_result::out) is det.
+
+compare_proc_descs_by_context(ProcDescA, ProcDescB, Result) :-
+    FileNameA = ProcDescA ^ pdesc_file_name,
+    FileNameB = ProcDescB ^ pdesc_file_name,
+    compare(FileNameResult, FileNameA, FileNameB),
+    (
+        ( FileNameResult = (<)
+        ; FileNameResult = (>)
+        ),
+        Result = FileNameResult
     ;
-        error("compare_clique_rows_by_first_proc_name: missing first proc")
+        FileNameResult = (=),
+        LineNumberA = ProcDescA ^ pdesc_line_number,
+        LineNumberB = ProcDescB ^ pdesc_line_number,
+        compare(Result, LineNumberA, LineNumberB)
     ).
 
+:- pred compare_call_site_descs_by_name(call_site_desc::in, call_site_desc::in,
+    comparison_result::out) is det.
+
+compare_call_site_descs_by_name(CallSiteDescA, CallSiteDescB, Result) :-
+    NameA = CallSiteDescA ^ csdesc_caller_refined_name,
+    NameB = CallSiteDescB ^ csdesc_caller_refined_name,
+    compare(Result, NameA, NameB).
+
+:- pred compare_proc_descs_by_name(proc_desc::in, proc_desc::in,
+    comparison_result::out) is det.
+
+compare_proc_descs_by_name(ProcDescA, ProcDescB, Result) :-
+    NameA = ProcDescA ^ pdesc_refined_name,
+    NameB = ProcDescB ^ pdesc_refined_name,
+    compare(Result, NameA, NameB).
+
 %-----------------------------------------------------------------------------%
 %
 % Sort perf_row_datas by a criterion of performance.
Index: deep_profiler/html_format.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/html_format.m,v
retrieving revision 1.31
diff -u -b -r1.31 html_format.m
--- deep_profiler/html_format.m	28 Aug 2008 10:26:14 -0000	1.31
+++ deep_profiler/html_format.m	24 Sep 2008 08:29:47 -0000
@@ -160,12 +160,14 @@
     % escapes.
     %
 :- func escape_html_string(string) = string.
+:- func escape_html_attr_string(attr_string) = string.
 
     % Like escape_html_string, but additionally inserts zero-width space
     % characters to suggest where long strings can be broken over multiple
     % lines.
     %
 :- func escape_break_html_string(string) = string.
+:- func escape_break_html_attr_string(attr_string) = string.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -386,7 +388,7 @@
         map_join_html(table_header_group_to_html_row_1(FormatInfo, THNumRows),
             !StyleControlMap, THCells, InnerHeaderRowOneHTML),
         HeaderRowOneHTML =
-            wrap_tags("<tr>", "</tr>\n", InnerHeaderRowOneHTML),
+            wrap_tags("<tr>\n", "</tr>\n", InnerHeaderRowOneHTML),
         (
             THNumRows = one_header_row,
             HeaderRowTwoHTML = empty_html
@@ -395,12 +397,12 @@
             map_join_html(table_header_group_to_html_row_2(FormatInfo),
                 !StyleControlMap, THCells, InnerHeaderRowTwoHTML),
             HeaderRowTwoHTML =
-                wrap_tags("<tr>", "</tr>\n", InnerHeaderRowTwoHTML)
+                wrap_tags("<tr>\n", "</tr>\n", InnerHeaderRowTwoHTML)
         ),
         InnerHeaderRowThree =
             string.format("<td colspan=\"%d\"/>", [i(NumColumns)]),
         HeaderRowThreeHTML =
-            wrap_tags("<tr>", "</tr>\n",  str_to_html(InnerHeaderRowThree)),
+            wrap_tags("<tr>", "</tr>",  str_to_html(InnerHeaderRowThree)),
         HeaderHTML = HeaderRowOneHTML ++ HeaderRowTwoHTML ++ HeaderRowThreeHTML
     ;
         MaybeHeader = no,
@@ -413,7 +415,10 @@
         !StyleControlMap, BodyRows, BodyRowsHTML),
 
     % Construct the table.
-    HTML = wrap_tags(TableStartTag, TableEndTag, HeaderHTML ++ BodyRowsHTML).
+    WrappedHeaderHTML = wrap_tags("<thead>\n", "</thead>\n", HeaderHTML),
+    WrappedBodyHTML = wrap_tags("<tbody>\n", "</tbody>\n", BodyRowsHTML),
+    HTML = wrap_tags(TableStartTag, TableEndTag,
+        WrappedHeaderHTML ++ WrappedBodyHTML).
 
 %-----------------------------------------------------------------------------%
 
@@ -593,7 +598,7 @@
         TableRow = table_row(Cells),
         map_join_html_count(table_cell_to_html(FormatInfo, MaybeColClassMap),
             !StyleControlMap, 0, Cells, InnerHTML),
-        HTML = wrap_tags("<tr>", "</tr>\n", InnerHTML)
+        HTML = wrap_tags("<tr>\n", "</tr>\n", InnerHTML)
     ).
 
 %-----------------------------------------------------------------------------%
@@ -663,6 +668,8 @@
     str_to_html(format_percent(Percent)).
 table_data_to_html(_, td_s(String)) =
     str_to_html(escape_break_html_string(String)).
+table_data_to_html(_, td_as(AttrString)) =
+    str_to_html(escape_break_html_attr_string(AttrString)).
 table_data_to_html(_, td_t(Time)) =
     str_to_html(format_time(Time)).
 
@@ -855,7 +862,7 @@
         FormatString = "<a class=\"link\" href=\"%s\">%s</a>"
     ),
     string.format(FormatString,
-        [s(URL), s(escape_break_html_string(Label))], HTMLStr),
+        [s(URL), s(escape_break_html_attr_string(Label))], HTMLStr),
     HTML = str_to_html(HTMLStr).
 
     % Transform a pseudo link into HTML.
@@ -3121,9 +3128,32 @@
 escape_html_string(String) =
     replace_special_chars(special_html_char, String).
 
+escape_html_attr_string(attr_str(Attrs, String)) =
+    handle_html_attrs(Attrs, replace_special_chars(special_html_char, String)).
+
 escape_break_html_string(String) =
     replace_special_chars(special_html_char_or_break, String).
 
+escape_break_html_attr_string(attr_str(Attrs, String)) =
+    handle_html_attrs(Attrs,
+        replace_special_chars(special_html_char_or_break, String)).
+
+:- func handle_html_attrs(list(str_attr), string) = string.
+
+handle_html_attrs([], Str) = Str.
+handle_html_attrs([Attr | Attrs], InsideStr) = Str :-
+    InnerStr = handle_html_attrs(Attrs, InsideStr),
+    (
+        Attr = attr_bold,
+        Str = "<b>" ++ InnerStr ++ "</b>"
+    ;
+        Attr = attr_italic,
+        Str = "<i>" ++ InnerStr ++ "</i>"
+    ;
+        Attr = attr_underline,
+        Str = "<u>" ++ InnerStr ++ "</u>"
+    ).
+
 :- func replace_special_chars(pred(char, string)::in(pred(in, out) is semidet),
     string::in) = (string::out) is det.
 
Index: deep_profiler/measurement_units.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/measurement_units.m,v
retrieving revision 1.3
diff -u -b -r1.3 measurement_units.m
--- deep_profiler/measurement_units.m	18 Aug 2008 02:14:51 -0000	1.3
+++ deep_profiler/measurement_units.m	24 Sep 2008 15:36:52 -0000
@@ -77,6 +77,8 @@
     %
 :- func format_percent(percent) = string.
 
+:- pred percent_at_or_above_threshold(int::in, percent::in) is semidet.
+
 %-----------------------------------------------------------------------------%
 %
 % Time
@@ -187,6 +189,9 @@
 format_percent(percent_float(P)) = String :-
     string.format("%.2f", [f(P * 100.0)], String).
 
+percent_at_or_above_threshold(Threshold, percent_float(P)) :-
+    (P * float(100)) >= float(Threshold).
+
 %-----------------------------------------------------------------------------%
 %
 % Time.
Index: deep_profiler/profile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/profile.m,v
retrieving revision 1.22
diff -u -b -r1.22 profile.m
--- deep_profiler/profile.m	25 Aug 2008 07:19:39 -0000	1.22
+++ deep_profiler/profile.m	24 Sep 2008 04:31:36 -0000
@@ -220,9 +220,12 @@
     ;       callback.
 
 :- type call_site_kind_and_callee
+    == call_site_kind_and_callee(proc_static_ptr).
+
+:- type call_site_kind_and_callee(T)
     --->    normal_call_and_callee(
                 % The identity of the callee.
-                proc_static_ptr,
+                T,
 
                 % A description of the type substitution, if any and if known.
                 string
Index: deep_profiler/query.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/query.m,v
retrieving revision 1.28
diff -u -b -r1.28 query.m
--- deep_profiler/query.m	28 Aug 2008 10:26:14 -0000	1.28
+++ deep_profiler/query.m	25 Sep 2008 00:16:18 -0000
@@ -402,6 +402,8 @@
         ; Cmd = deep_cmd_restart
         ; Cmd = deep_cmd_timeout(_)
         ; Cmd = deep_cmd_menu
+        ; Cmd = deep_cmd_root(_)
+        ; Cmd = deep_cmd_clique(_)
         ; Cmd = deep_cmd_program_modules
         ; Cmd = deep_cmd_module(_)
         ; Cmd = deep_cmd_top_procs(_, _, _, _)
@@ -411,6 +413,7 @@
         ; Cmd = deep_cmd_dump_proc_dynamic(_)
         ; Cmd = deep_cmd_dump_call_site_static(_)
         ; Cmd = deep_cmd_dump_call_site_dynamic(_)
+        ; Cmd = deep_cmd_dump_clique(_)
         ),
         (
             FileExists = yes,
@@ -420,12 +423,6 @@
             new_exec(Cmd, Prefs, Deep, MaybeProgRep, HTMLStr, !IO)
         )
     ;
-        ( Cmd = deep_cmd_root(_)
-        ; Cmd = deep_cmd_clique(_)
-        ; Cmd = deep_cmd_dump_clique(_)
-        ),
-        old_exec(Cmd, Prefs, Deep, HTMLStr, !IO)
-    ;
         Cmd = deep_cmd_procrep_coverage(_),
         new_exec(Cmd, Prefs, Deep, MaybeProgRep, HTMLStr, !IO)
     ).
@@ -1725,7 +1722,6 @@
     ;       assume_within_clique.
 
 :- func ancestor_display = call_site_display.
-:- func upward_display = call_site_display.
 :- func downward_display = call_site_display.
 :- func downward_summary_display = call_site_display.
 
@@ -1733,10 +1729,6 @@
     call_site_display(call_context, caller_proc_name, caller_clique,
         wrap_url_always).
 
-upward_display =
-    call_site_display(call_context, caller_proc_name, callee_clique,
-        wrap_url_always).
-
 downward_display =
     call_site_display(call_context, callee_proc_name, callee_clique,
         wrap_url_if_cross_clique(assume_within_clique)).
Index: deep_profiler/report.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/report.m,v
retrieving revision 1.9
diff -u -b -r1.9 report.m
--- deep_profiler/report.m	17 Sep 2008 03:26:29 -0000	1.9
+++ deep_profiler/report.m	25 Sep 2008 00:16:36 -0000
@@ -38,6 +38,7 @@
 :- type deep_report
     --->    report_message(message_report)
     ;       report_menu(maybe_error(menu_report))
+    ;       report_clique(maybe_error(clique_report))
     ;       report_program_modules(maybe_error(program_modules_report))
     ;       report_module(maybe_error(module_report))
     ;       report_top_procs(maybe_error(top_procs_report))
@@ -49,7 +50,8 @@
     ;       report_call_site_static_dump(
                 maybe_error(call_site_static_dump_info))
     ;       report_call_site_dynamic_dump(
-                maybe_error(call_site_dynamic_dump_info)).
+                maybe_error(call_site_dynamic_dump_info))
+    ;       report_clique_dump(maybe_error(clique_dump_info)).
 
 :- type message_report
     --->    message_report(
@@ -78,6 +80,60 @@
                 menu_num_clique             :: int
             ).
 
+:- type clique_report
+    --->    clique_report(
+                % The clique the report is for.
+                cr_clique_ptr               :: clique_ptr,
+
+                % The ancestor call sites of the clique,
+                % - from the innermost ancestor call site (in the parent)
+                % - to the outermost ancestor call site (in main/2).
+                cr_ancestor_call_sites      :: list(
+                                                perf_row_data(ancestor_desc)),
+
+                % Reports for every procedure in the clique.
+                cr_clique_procs             :: list(clique_proc_report)
+            ).
+
+:- type clique_proc_report
+    --->    clique_proc_report(
+                % Summary information for the cost of this procedure in this
+                % clique.
+                cpr_proc_summary            :: perf_row_data(proc_desc),
+
+                cpr_first_proc_dynamic      :: clique_proc_dynamic_report,
+                cpr_other_proc_dynamics     :: list(clique_proc_dynamic_report)
+            ).
+
+:- type clique_proc_dynamic_report
+    --->    clique_proc_dynamic_report(
+                % Summary information for the cost of this proc _dynamic
+                % in this clique.
+                cpdr_proc_summary            :: perf_row_data(proc_desc),
+
+                % Information about the costs of the call sites in this
+                % procedure in this clique.
+                cpdr_call_sites              :: list(clique_call_site_report)
+            ).
+
+:- type clique_call_site_report
+    --->    clique_call_site_report(
+                % The id of the call site, and the summary performance for
+                % that call site.
+                ccsr_call_site_summary      :: perf_row_data(call_site_desc),
+
+                ccsr_kind_and_callee        :: call_site_kind_and_callee(
+                                                proc_desc),
+
+                % All the callees and their associated performance information.
+                % If ccsr_kind_and_callee indicates a normal call, the list
+                % will have either zero entries (no calls through this site)
+                % or one entry (some calls through this site). If this is
+                % some other kind of call site, the list may have any number
+                % of entries.
+                ccsr_callee_perfs           :: list(perf_row_data(clique_desc))
+            ).
+
 :- type program_modules_report
     --->    program_modules_report(
                 % Summary information about all the modules of the program.
@@ -238,6 +294,20 @@
                 csddi_own_perf              :: perf_row_data(call_site_desc)
             ).
 
+:- type clique_dump_info
+    --->    clique_dump_info(
+                cdi_clique_desc             :: clique_desc,
+                cdi_caller_csd_ptr          :: call_site_dynamic_ptr,
+                cdi_member_pdptrs           :: list(proc_dynamic_ptr)
+            ).
+
+    % This type represents information about the performance of the subject.
+    % It is intended to be displayed on a browser page or used by a tool as is.
+    % It is NOT intended to be subject to further processing, such as adding
+    % two perf_row_datas together. Any such arithmetic is much better done
+    % on the data structures from which perf_row_datas are derived
+    % (own_prof_info and inherit_prof_info in the measurements module).
+    %
 :- type perf_row_data(T)
     --->    perf_row_data(
                 % The item represented by this data row.
@@ -261,7 +331,7 @@
                 % represent clock ticks, whereas for time, we use more
                 % user-friendly units. When the total time for the program
                 % is close to zero, i.e. the number of ticks or quanta is zero
-                % for the whole programs, then the percentage may be zero
+                % for the whole program, then the percentage may be zero
                 % for everyhing (it used to be a NaN for 0/0, but we now
                 % check explicitly for division by zero).
                 perf_row_ticks             :: int,
@@ -348,12 +418,27 @@
                 csdesc_goal_path            :: string
             ).
 
+:- type ancestor_desc
+    --->    ancestor_desc(
+                % The caller and callee cliques.
+                ad_caller_clique_ptr        :: clique_ptr,
+                ad_callee_clique_ptr        :: clique_ptr,
+
+                % The callee procedure.
+                ad_callee_pdesc             :: proc_desc,
+
+                % The description of the call site. This includes a description
+                % of the caller procedure.
+                ad_call_site_desc           :: call_site_desc
+            ).
+
     % The description of a clique in a report structure.
     %
 :- type clique_desc
     --->    clique_desc(
                 cdesc_clique_ptr            :: clique_ptr,
-                cdesc_members               :: list(proc_desc)
+                cdesc_entry_member          :: proc_desc,
+                cdesc_other_members         :: list(proc_desc)
             ).
 
 %-----------------------------------------------------------------------------%
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/base64
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/fixed
cvs diff: Diffing extras/gator
cvs diff: Diffing extras/gator/generations
cvs diff: Diffing extras/gator/generations/1
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_allegro
cvs diff: Diffing extras/graphics/mercury_allegro/examples
cvs diff: Diffing extras/graphics/mercury_allegro/samples
cvs diff: Diffing extras/graphics/mercury_allegro/samples/demo
cvs diff: Diffing extras/graphics/mercury_allegro/samples/mandel
cvs diff: Diffing extras/graphics/mercury_allegro/samples/pendulum2
cvs diff: Diffing extras/graphics/mercury_allegro/samples/speed
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/log4m
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/mopenssl
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/net
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/posix/samples
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/solver_types
cvs diff: Diffing extras/solver_types/library
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/windows_installer_generator
cvs diff: Diffing extras/windows_installer_generator/sample
cvs diff: Diffing extras/windows_installer_generator/sample/images
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
cvs diff: Diffing mdbcomp
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/standalone_c
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/solver_types
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
cvs diff: Diffing ssdb
cvs diff: Diffing tests
cvs diff: Diffing tests/analysis
cvs diff: Diffing tests/analysis/ctgc
cvs diff: Diffing tests/analysis/excp
cvs diff: Diffing tests/analysis/ext
cvs diff: Diffing tests/analysis/sharing
cvs diff: Diffing tests/analysis/table
cvs diff: Diffing tests/analysis/trail
cvs diff: Diffing tests/analysis/unused_args
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/par_conj
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/trailing
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
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