[m-rev.] deep profiler server enhancements

Zoltan Somogyi zs at cs.mu.OZ.AU
Mon Jun 4 20:04:03 AEST 2001


These have built up in the queue while the original code was supposed to be
reviewed. Since the code in the deep_profiler directory had only a superficial
review, unless Tom has an objection, I will commit this tomorrow evening or
on wednesday. It has been tested, and Tom agrees on the parts I have discussed
with him.

Zoltan.

deep_profiler/read_profile.m:
	Delete the ptr_info structure; it is not needed anymore.

deep_profiler/read_profile.m:
deep_profiler/io_combinator.m:
	Separate out the I/O combinator part of read_profile.m into a new file.

deep_profiler/startup.m:
deep_profiler/canonical.m:
	Separate out the part of startup.m that attempts to canonicalize call
	graphs, and add code for merging call graphs from separate profiling
	runs. This code is not yet complete.

deep_profiler/startup.m:
deep_profiler/callgraph.m:
	Separate out the part of startup.m that generates the call graph
	(whose cliques we compute), for use by the new file canonical.m,
	and clean it up.

deep_profiler/array_util.m:
	Make the names of the predicates more expressive.

	Add a new utility predicate.

deep_profiler/interface.m:
deep_profiler/server.m:
	Make the number of ancestor call sites displayed configurable.

deep_profiler/measurements.m:
	Use a more compact representation for profiling information. This
	change reduced the resident set size of the server in one case from
	130 Mb to 110 Mb.

deep_profiler/profile.m:
	Remove the redirection field, since that info is now stored in
	separate, temporary arrays by canonical.m.

	Clarify the documentation of the fields giving the sizes of arrays.

deep_profiler/server.m:
	Output more structured HTML.

	Make the format for times prettier.

deep_profiler/notes/deep_profilint.html:
	Document the new modules.

cvs diff: Diffing .
Index: array_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/array_util.m,v
retrieving revision 1.1
diff -u -b -r1.1 array_util.m
--- array_util.m	2001/05/31 05:59:57	1.1
+++ array_util.m	2001/06/01 11:31:11
@@ -14,36 +14,53 @@
 
 :- import_module array, list.
 
+	% Perform a mode cast on the given array, making the compiler believe
+	% that the ground array is unique. Should be used only if the only use
+	% of the old value is as input to the upcoming destructive operation
+	% that needs the array to be unique. Otherwise, calling this function
+	% is dangerous.
 :- func u(T) = T.
 :- mode (u(in) = array_uo) is det.
 
-:- pred array_foldl(pred(int, T, U, U), array(T), U, U).
-:- mode array_foldl(pred(in, in, di, uo) is det, in, di, uo) is det.
-:- mode array_foldl(pred(in, in, array_di, array_uo) is det, in,
+	% Performs a foldl on all the elements of the given array,
+	% starting at index 1.
+:- pred array_foldl_from_1(pred(int, T, U, U), array(T), U, U).
+:- mode array_foldl_from_1(pred(in, in, di, uo) is det, in, di, uo) is det.
+:- mode array_foldl_from_1(pred(in, in, array_di, array_uo) is det, in,
 	array_di, array_uo) is det.
-:- mode array_foldl(pred(in, in, in, out) is det, in, in, out) is det.
+:- mode array_foldl_from_1(pred(in, in, in, out) is det, in, in, out) is det.
 
-:- pred array_foldl0(pred(int, T, U, U), array(T), U, U).
-:- mode array_foldl0(pred(in, in, di, uo) is det, in, di, uo) is det.
-:- mode array_foldl0(pred(in, in, array_di, array_uo) is det, in,
+	% Performs a foldl on all the elements of the given array,
+	% starting at index 0.
+:- pred array_foldl_from_0(pred(int, T, U, U), array(T), U, U).
+:- mode array_foldl_from_0(pred(in, in, di, uo) is det, in, di, uo) is det.
+:- mode array_foldl_from_0(pred(in, in, array_di, array_uo) is det, in,
 	array_di, array_uo) is det.
-:- mode array_foldl0(pred(in, in, in, out) is det, in, in, out) is det.
+:- mode array_foldl_from_0(pred(in, in, in, out) is det, in, in, out) is det.
 
+	% Performs a foldl on all the elements of the given array
+	% between the two index values given by the first two arguments,
+	% both inclusive.
 :- pred array_foldl(int, int, pred(int, T, U, U), array(T), U, U).
 :- mode array_foldl(in, in, pred(in, in, di, uo) is det, in, di, uo) is det.
 :- mode array_foldl(in, in, pred(in, in, array_di, array_uo) is det, in,
 	array_di, array_uo) is det.
 :- mode array_foldl(in, in, pred(in, in, in, out) is det, in, in, out) is det.
 
-:- pred array_foldl2(pred(int, T, U, U, V, V), array(T), U, U, V, V).
-:- mode array_foldl2(pred(in, in, di, uo, di, uo) is det, in, di, uo, di, uo)
-	is det.
-:- mode array_foldl2(pred(in, in, array_di, array_uo, array_di, array_uo)
-	is det, in, array_di, array_uo, array_di, array_uo)
-	is det.
-:- mode array_foldl2(pred(in, in, in, out, di, uo) is det, in, in, out, di, uo)
-	is det.
-
+	% Performs a foldl2 on all the elements of the given array,
+	% starting at index 1.
+:- pred array_foldl2_from_1(pred(int, T, U, U, V, V), array(T), U, U, V, V).
+:- mode array_foldl2_from_1(pred(in, in, di, uo, di, uo) is det,
+	in, di, uo, di, uo) is det.
+:- mode array_foldl2_from_1(pred(in, in, array_di, array_uo,
+	array_di, array_uo) is det,
+	in, array_di, array_uo, array_di, array_uo) is det.
+:- mode array_foldl2_from_1(pred(in, in, in, out, di, uo) is det,
+	in, in, out, di, uo) is det.
+
+	% Performs a foldl2 on all the elements of the given array
+	% between the two index values given by the first two arguments,
+	% both inclusive.
 :- pred array_foldl2(int, int, pred(int, T, U, U, V, V), array(T), U, U, V, V).
 :- mode array_foldl2(in, in, pred(in, in, di, uo, di, uo) is det, in,
 	di, uo, di, uo) is det.
@@ -53,16 +70,30 @@
 :- mode array_foldl2(in, in, pred(in, in, in, out, di, uo) is det, in,
 	in, out, di, uo) is det.
 
+	% Performs the same computation as list__foldl; the only difference
+	% is that the accumulator is an array and has an array mode.
 :- pred array_list_foldl(pred(T, array(U), array(U)), list(T),
 	array(U), array(U)).
 :- mode array_list_foldl(pred(in, array_di, array_uo) is det, in,
 	array_di, array_uo) is det.
 
+	% Performs the same computation as list__foldl2; the only difference
+	% is that the accumulators are arrays and have array modes.
 :- pred array_list_foldl2(pred(T, array(U), array(U), array(V), array(V)),
 	list(T), array(U), array(U), array(V), array(V)).
 :- mode array_list_foldl2(pred(in, array_di, array_uo, array_di, array_uo)
 	is det, in, array_di, array_uo, array_di, array_uo) is det.
 
+	% Performs a map on all the elements of the given array,
+	% starting at index 0.
+:- pred array_map_from_0(pred(T, T), array(T), array(T)).
+:- mode array_map_from_0(pred(in, out) is det, array_di, array_uo) is det.
+
+	% Performs a map on all the elements of the given array,
+	% starting at index 1.
+:- pred array_map_from_1(pred(T, T), array(T), array(T)).
+:- mode array_map_from_1(pred(in, out) is det, array_di, array_uo) is det.
+
 %-----------------------------------------------------------------------------%
 
 :- implementation.
@@ -74,11 +105,11 @@
 	"B = A;"
 ).
 
-array_foldl(P, A, U0, U) :-
+array_foldl_from_1(P, A, U0, U) :-
 	array__max(A, Max),
 	array_foldl(1, Max, P, A, U0, U).
 
-array_foldl0(P, A, U0, U) :-
+array_foldl_from_0(P, A, U0, U) :-
 	array__max(A, Max),
 	array_foldl(0, Max, P, A, U0, U).
 
@@ -91,7 +122,7 @@
 		U = U0
 	).
 
-array_foldl2(P, A, U0, U, V0, V) :-
+array_foldl2_from_1(P, A, U0, U, V0, V) :-
 	array__max(A, Max),
 	array_foldl2(1, Max, P, A, U0, U, V0, V).
 
@@ -114,3 +145,24 @@
 array_list_foldl2(P, [X | Xs], AccU0, AccU, AccV0, AccV) :-
 	call(P, X, AccU0, AccU1, AccV0, AccV1),
 	array_list_foldl2(P, Xs, AccU1, AccU, AccV1, AccV).
+
+array_map_from_0(P, U0, U) :-
+	array__max(U0, Max),
+	array_map(0, Max, P, U0, U).
+
+array_map_from_1(P, U0, U) :-
+	array__max(U0, Max),
+	array_map(1, Max, P, U0, U).
+
+:- pred array_map(int, int, pred(T, T), array(T), array(T)).
+:- mode array_map(in, in, pred(in, out) is det, array_di, array_uo) is det.
+
+array_map(N, Size, Closure, Array0, Array) :-
+	( N >= Size ->
+		Array = Array0
+	;
+		array__lookup(Array0, N, OldElem),
+		Closure(OldElem, NewElem),
+		array__set(Array0, N, NewElem, Array1),
+		array_map(N + 1, Size, Closure, Array1, Array)
+	).
Index: canonical.m
===================================================================
RCS file: canonical.m
diff -N canonical.m
--- /dev/null	Fri Dec  1 02:25:58 2000
+++ canonical.m	Mon Jun  4 19:42:03 2001
@@ -0,0 +1,980 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2001 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% Authors: conway, zs.
+%
+% This module contains code for recursively merging sets of ProcDynamic and
+% CallSiteDynamic nodes.
+
+:- module merge.
+
+:- interface.
+
+:- import_module profile.
+
+:- pred canonicalize_cliques(initial_deep::in, initial_deep::out) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module measurements, callgraph, array_util.
+:- import_module unsafe, io.
+:- import_module std_util, bool, int, array, list, map, set, require.
+
+:- type merge_info
+	--->	merge_info(
+			merge_clique_members :: array(list(proc_dynamic_ptr)),
+			merge_clique_index   :: array(clique_ptr)
+		).
+
+:- type redirect
+	--->	redirect(
+			csd_redirect	:: array(call_site_dynamic_ptr),
+						% index: call_site_dynamic_ptr
+			pd_redirect	:: array(proc_dynamic_ptr)
+						% index: proc_dynamic_ptr
+		).
+
+canonicalize_cliques(InitDeep0, InitDeep) :-
+	MaxCSDs = array__max(InitDeep0 ^ init_call_site_dynamics),
+	MaxPDs = array__max(InitDeep0 ^ init_proc_dynamics),
+	NumCSDs = MaxCSDs + 1,
+	NumPDs = MaxPDs + 1,
+
+	find_cliques(InitDeep0, CliqueList),
+	make_clique_indexes(NumPDs, CliqueList, Cliques, CliqueIndex),
+	MergeInfo = merge_info(Cliques, CliqueIndex),
+
+	CSDRedirect0 = array__init(NumCSDs, call_site_dynamic_ptr(0)),
+	PDRedirect0 = array__init(NumPDs, proc_dynamic_ptr(0)),
+	Redirect0 = redirect(CSDRedirect0, PDRedirect0),
+	merge_cliques(CliqueList, MergeInfo, InitDeep0, Redirect0,
+		InitDeep1, Redirect1),
+	compact_dynamics(InitDeep1, Redirect1, NumCSDs, NumPDs, InitDeep).
+
+:- pred merge_cliques(list(list(proc_dynamic_ptr))::in,
+	merge_info::in, initial_deep::in, redirect::in,
+	initial_deep::out, redirect::out) is det.
+
+merge_cliques([], _, InitDeep, Redirect, InitDeep, Redirect).
+merge_cliques([Clique | Cliques], MergeInfo, InitDeep0, Redirect0,
+		InitDeep, Redirect) :-
+	merge_clique(Clique, MergeInfo, InitDeep0, Redirect0,
+		InitDeep1, Redirect1),
+	merge_cliques(Cliques, MergeInfo, InitDeep1, Redirect1,
+		InitDeep, Redirect).
+
+:- pred merge_clique(list(proc_dynamic_ptr)::in,
+	merge_info::in, initial_deep::in, redirect::in,
+	initial_deep::out, redirect::out) is det.
+
+merge_clique(CliquePDs, MergeInfo, InitDeep0, Redirect0, InitDeep, Redirect) :-
+	% find set of proc_statics in the CliquePDs
+	% for all (first order) calls in CliquePDs, if call is to a procedure
+	%	that CliquePDs contains a call to, add its PD to the set
+
+	map__init(ProcMap0),
+	set__list_to_set(CliquePDs, Clique),
+	list__foldl(cluster_pds_by_ps(InitDeep0), CliquePDs,
+		ProcMap0, ProcMap),
+	map__values(ProcMap, PDsList),
+	list__filter(two_or_more, PDsList, ToMergePDsList),
+	list__foldl2(merge_proc_dynamics(MergeInfo, Clique),
+		ToMergePDsList, InitDeep0, InitDeep, Redirect0, Redirect).
+
+:- pred merge_proc_dynamics(merge_info::in, set(proc_dynamic_ptr)::in,
+	list(proc_dynamic_ptr)::in, proc_dynamic_ptr::out,
+	initial_deep::in, initial_deep::out, redirect::in, redirect::out)
+	is det.
+
+merge_proc_dynamics(MergeInfo, Clique, CandidatePDPtrs, ChosenPDPtr,
+		InitDeep0, InitDeep, Redirect0, Redirect) :-
+	ProcDynamics0 = InitDeep0 ^ init_proc_dynamics,
+	list__filter(valid_proc_dynamic_ptr_raw(ProcDynamics0),
+		CandidatePDPtrs, ValidPDPtrs),
+	( ValidPDPtrs = [PrimePDPtr | RestPDPtrs] ->
+		record_pd_redirect(RestPDPtrs, PrimePDPtr,
+			Redirect0, Redirect1),
+		lookup_proc_dynamics(ProcDynamics0, PrimePDPtr, PrimePD0),
+		list__map(lookup_proc_dynamics(ProcDynamics0),
+			RestPDPtrs, RestPDs),
+		list__map(extract_pd_sites, RestPDs, RestSites),
+		PrimeSites0 = PrimePD0 ^ pd_sites,
+		array__max(PrimeSites0, MaxSiteNum),
+		merge_proc_dynamic_slots(MergeInfo, MaxSiteNum, Clique,
+			PrimePDPtr, u(PrimeSites0), RestSites, PrimeSites,
+			InitDeep0, InitDeep1, Redirect1, Redirect),
+		PrimePD = PrimePD0 ^ pd_sites := PrimeSites,
+		ProcDynamics1 = InitDeep1 ^ init_proc_dynamics,
+		update_proc_dynamics(u(ProcDynamics1), PrimePDPtr, PrimePD,
+			ProcDynamics),
+		InitDeep = InitDeep1 ^ init_proc_dynamics := ProcDynamics,
+		ChosenPDPtr = PrimePDPtr
+	;
+		% This can happen when merging the callees of CSDs
+		% representing special calls.
+		ChosenPDPtr = proc_dynamic_ptr(0),
+		InitDeep = InitDeep0,
+		Redirect = Redirect0
+	).
+
+:- pred merge_proc_dynamic_slots(merge_info::in, int::in,
+	set(proc_dynamic_ptr)::in, proc_dynamic_ptr::in,
+	array(call_site_array_slot)::array_di,
+	list(array(call_site_array_slot))::in,
+	array(call_site_array_slot)::array_uo,
+	initial_deep::in, initial_deep::out, redirect::in, redirect::out)
+	is det.
+
+merge_proc_dynamic_slots(MergeInfo, SlotNum, Clique, PrimePDPtr,
+		PrimeSiteArray0, RestSiteArrays, PrimeSiteArray,
+		InitDeep0, InitDeep, Redirect0, Redirect) :-
+	( SlotNum >= 0 ->
+		array__lookup(PrimeSiteArray0, SlotNum, PrimeSite0),
+		(
+			PrimeSite0 = normal(PrimeCSDPtr0),
+			merge_proc_dynamic_normal_slot(MergeInfo, SlotNum,
+				Clique, PrimePDPtr, PrimeCSDPtr0,
+				RestSiteArrays, PrimeCSDPtr,
+				InitDeep0, InitDeep1, Redirect0, Redirect1),
+			array__set(PrimeSiteArray0, SlotNum,
+				normal(PrimeCSDPtr), PrimeSiteArray1)
+		;
+			PrimeSite0 = multi(PrimeCSDPtrArray0),
+			array__to_list(PrimeCSDPtrArray0, PrimeCSDPtrList0),
+			merge_proc_dynamic_multi_slot(MergeInfo, SlotNum,
+				Clique, PrimePDPtr, PrimeCSDPtrList0,
+				RestSiteArrays, PrimeCSDPtrList,
+				InitDeep0, InitDeep1, Redirect0, Redirect1),
+			PrimeCSDPtrArray = array(PrimeCSDPtrList),
+			array__set(PrimeSiteArray0, SlotNum,
+				multi(PrimeCSDPtrArray), PrimeSiteArray1)
+		),
+		merge_proc_dynamic_slots(MergeInfo, SlotNum - 1, Clique,
+			PrimePDPtr, PrimeSiteArray1, RestSiteArrays,
+			PrimeSiteArray, InitDeep1, InitDeep,
+			Redirect1, Redirect)
+	;
+		PrimeSiteArray = PrimeSiteArray0,
+		InitDeep = InitDeep0,
+		Redirect = Redirect0
+	).
+
+:- pred merge_proc_dynamic_normal_slot(merge_info::in, int::in,
+	set(proc_dynamic_ptr)::in, proc_dynamic_ptr::in,
+	call_site_dynamic_ptr::in, list(array(call_site_array_slot))::in,
+	call_site_dynamic_ptr::out, initial_deep::in, initial_deep::out,
+	redirect::in, redirect::out) is det.
+
+merge_proc_dynamic_normal_slot(MergeInfo, SlotNum, Clique,
+		PrimePDPtr, PrimeCSDPtr0, RestSiteArrays, PrimeCSDPtr,
+		InitDeep0, InitDeep, Redirect0, Redirect) :-
+	lookup_normal_sites(RestSiteArrays, SlotNum, RestCSDPtrs),
+	merge_call_site_dynamics(MergeInfo, Clique, PrimePDPtr,
+		[PrimeCSDPtr0 | RestCSDPtrs], PrimeCSDPtr,
+		InitDeep0, InitDeep, Redirect0, Redirect).
+
+:- pred accumulate_csd_owns(call_site_dynamic::in,
+	own_prof_info::in, own_prof_info::out) is det.
+
+accumulate_csd_owns(CSD, Own0, Own) :-
+	Own = add_own_to_own(Own0, CSD ^ csd_own_prof).
+
+:- pred callee_in_clique(initial_deep::in, set(proc_dynamic_ptr)::in,
+	call_site_dynamic_ptr::in) is semidet.
+
+callee_in_clique(InitDeep, Clique, CSDPtr) :-
+	lookup_call_site_dynamics(InitDeep ^ init_call_site_dynamics,
+		CSDPtr, CSD),
+	CalleePDPtr = CSD ^ csd_callee,
+	set__member(CalleePDPtr, Clique).
+
+:- pred merge_proc_dynamic_multi_slot(merge_info::in, int::in,
+	set(proc_dynamic_ptr)::in, proc_dynamic_ptr::in,
+	list(call_site_dynamic_ptr)::in, list(array(call_site_array_slot))::in,
+	list(call_site_dynamic_ptr)::out, initial_deep::in, initial_deep::out,
+	redirect::in, redirect::out) is det.
+
+merge_proc_dynamic_multi_slot(MergeInfo, SlotNum, Clique,
+		ParentPDPtr, PrimeCSDPtrs0, RestSiteArrays, PrimeCSDPtrs,
+		InitDeep0, InitDeep, Redirect0, Redirect) :-
+	lookup_multi_sites(RestSiteArrays, SlotNum, RestCSDPtrLists),
+	list__condense([PrimeCSDPtrs0 | RestCSDPtrLists], AllCSDPtrs),
+	map__init(ProcMap0),
+	list__foldl(cluster_csds_by_ps(InitDeep0), AllCSDPtrs,
+		ProcMap0, ProcMap),
+	map__values(ProcMap, CSDPtrsClusters),
+	list__foldl3(merge_multi_slot_cluster(MergeInfo, ParentPDPtr, Clique),
+		CSDPtrsClusters, [], PrimeCSDPtrs, InitDeep0, InitDeep,
+		Redirect0, Redirect).
+
+:- pred merge_multi_slot_cluster(merge_info::in, proc_dynamic_ptr::in,
+	set(proc_dynamic_ptr)::in, list(call_site_dynamic_ptr)::in,
+	list(call_site_dynamic_ptr)::in, list(call_site_dynamic_ptr)::out,
+	initial_deep::in, initial_deep::out, redirect::in, redirect::out)
+	is det.
+
+merge_multi_slot_cluster(MergeInfo, ParentPDPtr, Clique, ClusterCSDPtrs,
+		PrimeCSDPtrs0, PrimeCSDPtrs, InitDeep0, InitDeep,
+		Redirect0, Redirect) :-
+	merge_call_site_dynamics(MergeInfo, Clique,
+		ParentPDPtr, ClusterCSDPtrs, PrimeCSDPtr,
+		InitDeep0, InitDeep, Redirect0, Redirect),
+	PrimeCSDPtrs = [PrimeCSDPtr | PrimeCSDPtrs0].
+
+:- pred merge_call_site_dynamics(merge_info::in, set(proc_dynamic_ptr)::in,
+	proc_dynamic_ptr::in, list(call_site_dynamic_ptr)::in,
+	call_site_dynamic_ptr::out, initial_deep::in, initial_deep::out,
+	redirect::in, redirect::out) is det.
+
+merge_call_site_dynamics(MergeInfo, Clique, ParentPDPtr, CandidateCSDPtrs,
+		ChosenCSDPtr, InitDeep0, InitDeep, Redirect0, Redirect) :-
+	CallSiteDynamics0 = InitDeep0 ^ init_call_site_dynamics,
+	list__filter(valid_call_site_dynamic_ptr_raw(CallSiteDynamics0),
+		CandidateCSDPtrs, ValidCSDPtrs),
+	(
+		ValidCSDPtrs = [],
+			% This signifies that there is no call here.
+		ChosenCSDPtr = call_site_dynamic_ptr(0),
+		InitDeep = InitDeep0,
+		Redirect = Redirect0
+	;
+		ValidCSDPtrs = [FirstCSDPtr | LaterCSDPtrs],
+		lookup_call_site_dynamics(CallSiteDynamics0, FirstCSDPtr,
+			FirstCSD0),
+		FirstCSD = FirstCSD0 ^ csd_caller := ParentPDPtr,
+		update_call_site_dynamics(u(CallSiteDynamics0), FirstCSDPtr,
+			FirstCSD, CallSiteDynamics),
+		InitDeep1 = InitDeep0 ^ init_call_site_dynamics
+			:= CallSiteDynamics,
+		(
+			LaterCSDPtrs = [],
+			InitDeep = InitDeep1,
+			Redirect = Redirect0
+		;
+			LaterCSDPtrs = [_ | _],
+			merge_call_site_dynamics_2(MergeInfo, Clique,
+				FirstCSDPtr, LaterCSDPtrs, InitDeep1, InitDeep,
+				Redirect0, Redirect)
+		),
+		ChosenCSDPtr = FirstCSDPtr
+	).
+
+:- pred merge_call_site_dynamics_2(merge_info::in, set(proc_dynamic_ptr)::in,
+	call_site_dynamic_ptr::in, list(call_site_dynamic_ptr)::in,
+	initial_deep::in, initial_deep::out, redirect::in, redirect::out)
+	is det.
+
+merge_call_site_dynamics_2(MergeInfo, Clique, PrimeCSDPtr, RestCSDPtrs,
+		InitDeep0, InitDeep, Redirect0, Redirect) :-
+	% We must check whether PrimeCSDPtr and RestCSDPtrs are in Clique
+	% *before* we update the proc_dynamics array in InitDeep0, which is
+	% destructive updated to create InitDeep1.
+	list__filter(callee_in_clique(InitDeep0, Clique), RestCSDPtrs,
+		InClique, NotInClique),
+	% XXX design error: should take union of cliques
+	% i.e. if call is within clique in *any* caller, it should be within
+	% clique in the final configuration
+	( callee_in_clique(InitDeep0, Clique, PrimeCSDPtr) ->
+		require(unify(NotInClique, []),
+			"merge_proc_dynamic_normal_slot: prime in clique, others not in clique"),
+		MergeChildren = no
+	;
+		require(unify(InClique, []),
+			"merge_proc_dynamic_normal_slot: prime not in clique, others in clique"),
+		MergeChildren = yes
+	),
+	record_csd_redirect(RestCSDPtrs, PrimeCSDPtr, Redirect0, Redirect1),
+	CallSiteDynamics0 = InitDeep0 ^ init_call_site_dynamics,
+	lookup_call_site_dynamics(CallSiteDynamics0, PrimeCSDPtr, PrimeCSD0),
+	list__map(lookup_call_site_dynamics(CallSiteDynamics0),
+		RestCSDPtrs, RestCSDs),
+	PrimeOwn0 = PrimeCSD0 ^ csd_own_prof,
+	list__foldl(accumulate_csd_owns, RestCSDs, PrimeOwn0, PrimeOwn1),
+	PrimeCSD1 = PrimeCSD0 ^ csd_own_prof := PrimeOwn1,
+	update_call_site_dynamics(u(CallSiteDynamics0), PrimeCSDPtr, PrimeCSD1,
+		CallSiteDynamics1),
+	InitDeep1 = InitDeep0 ^ init_call_site_dynamics := CallSiteDynamics1,
+	(
+		MergeChildren = no,
+		InitDeep = InitDeep1,
+		Redirect = Redirect1
+	;
+		MergeChildren = yes,
+		merge_call_site_dynamics_descendants(MergeInfo,
+			PrimeCSDPtr, RestCSDPtrs, ChosenPDPtr,
+			InitDeep1, InitDeep2, Redirect1, Redirect),
+		% We must ensure that PrimeCSDPtr ^ csd_callee
+		% is updated to reflect the chosen merged ProcDynamic.
+		CallSiteDynamics2 = InitDeep2 ^ init_call_site_dynamics,
+		lookup_call_site_dynamics(CallSiteDynamics2, PrimeCSDPtr,
+			PrimeCSD2),
+		PrimeCSD = PrimeCSD2 ^ csd_callee := ChosenPDPtr,
+		update_call_site_dynamics(u(CallSiteDynamics2),
+			PrimeCSDPtr, PrimeCSD, CallSiteDynamics),
+		InitDeep = InitDeep2 ^ init_call_site_dynamics
+			:= CallSiteDynamics
+	).
+
+:- pred merge_call_site_dynamics_descendants(merge_info::in,
+	call_site_dynamic_ptr::in, list(call_site_dynamic_ptr)::in,
+	proc_dynamic_ptr::out, initial_deep::in, initial_deep::out,
+	redirect::in, redirect::out) is det.
+
+merge_call_site_dynamics_descendants(MergeInfo, PrimeCSDPtr, RestCSDPtrs,
+		ChosenPDPtr, InitDeep0, InitDeep, Redirect0, Redirect) :-
+	CallSiteDynamics = InitDeep0 ^ init_call_site_dynamics,
+	lookup_call_site_dynamics(CallSiteDynamics, PrimeCSDPtr, PrimeCSD),
+	extract_csd_callee(PrimeCSD, PrimeCSDCallee),
+	list__map(lookup_call_site_dynamics(CallSiteDynamics), 
+		RestCSDPtrs, RestCSDs),
+	list__map(extract_csd_callee, RestCSDs, RestCSDCallees),
+	PDPtrs = [PrimeCSDCallee | RestCSDCallees],
+	list__foldl(union_cliques(MergeInfo), PDPtrs, set__init, CliqueUnion),
+	merge_proc_dynamics(MergeInfo, CliqueUnion, PDPtrs, ChosenPDPtr,
+		InitDeep0, InitDeep, Redirect0, Redirect).
+
+:- pred union_cliques(merge_info::in, proc_dynamic_ptr::in,
+	set(proc_dynamic_ptr)::in, set(proc_dynamic_ptr)::out) is det.
+
+union_cliques(MergeInfo, PDPtr, CliqueUnion0, CliqueUnion) :-
+	( PDPtr = proc_dynamic_ptr(0) ->
+		% This can happen with calls to the unify/compare preds
+		% of builtin types.
+		CliqueUnion = CliqueUnion0
+	;
+		lookup_clique_index(MergeInfo ^ merge_clique_index, PDPtr,
+			CliquePtr),
+		lookup_clique_members(MergeInfo ^ merge_clique_members,
+			CliquePtr, Members),
+		set__insert_list(CliqueUnion0, Members, CliqueUnion)
+	).
+
+:- pred lookup_normal_sites(list(array(call_site_array_slot))::in, int::in,
+	list(call_site_dynamic_ptr)::out) is det.
+
+lookup_normal_sites([], _, []).
+lookup_normal_sites([RestArray | RestArrays], SlotNum, [CSDPtr | CSDPtrs]) :-
+	array__lookup(RestArray, SlotNum, Slot),
+	(
+		Slot = normal(CSDPtr)
+	;
+		Slot = multi(_),
+		error("lookup_normal_sites: found multi")
+	),
+	lookup_normal_sites(RestArrays, SlotNum, CSDPtrs).
+
+:- pred lookup_multi_sites(list(array(call_site_array_slot))::in, int::in,
+	list(list(call_site_dynamic_ptr))::out) is det.
+
+lookup_multi_sites([], _, []).
+lookup_multi_sites([RestArray | RestArrays], SlotNum, [CSDList | CSDLists]) :-
+	array__lookup(RestArray, SlotNum, Slot),
+	(
+		Slot = normal(_),
+		error("lookup_multi_sites: found normal")
+	;
+		Slot = multi(CSDArray),
+		array__to_list(CSDArray, CSDList)
+	),
+	lookup_multi_sites(RestArrays, SlotNum, CSDLists).
+
+:- pragma promise_pure(record_pd_redirect/4).
+:- pred record_pd_redirect(list(proc_dynamic_ptr)::in, proc_dynamic_ptr::in,
+	redirect::in, redirect::out) is det.
+
+record_pd_redirect(RestPDPtrs, PrimePDPtr, Redirect0, Redirect) :-
+	impure unsafe_perform_io(io__write_string("pd redirect: ")),
+	impure unsafe_perform_io(io__print(RestPDPtrs)),
+	impure unsafe_perform_io(io__write_string(" -> ")),
+	impure unsafe_perform_io(io__print(PrimePDPtr)),
+	impure unsafe_perform_io(io__nl),
+	lookup_pd_redirect(Redirect0 ^ pd_redirect, PrimePDPtr, OldRedirect),
+	( OldRedirect = proc_dynamic_ptr(0) ->
+		record_pd_redirect_2(RestPDPtrs, PrimePDPtr,
+			Redirect0, Redirect)
+	;
+		error("record_pd_redirect: prime is redirected")
+	).
+
+:- pred record_pd_redirect_2(list(proc_dynamic_ptr)::in, proc_dynamic_ptr::in,
+	redirect::in, redirect::out) is det.
+
+record_pd_redirect_2([], _, Redirect, Redirect).
+record_pd_redirect_2([RestPDPtr | RestPDPtrs], PrimePDPtr,
+		Redirect0, Redirect) :-
+	ProcRedirect0 = Redirect0 ^ pd_redirect,
+	lookup_pd_redirect(ProcRedirect0, RestPDPtr, OldRedirect),
+	( OldRedirect = proc_dynamic_ptr(0) ->
+		set_pd_redirect(u(ProcRedirect0), RestPDPtr, PrimePDPtr,
+			ProcRedirect)
+	;
+		error("record_pd_redirect_2: already redirected")
+	),
+	Redirect1 = Redirect0 ^ pd_redirect := ProcRedirect,
+	record_pd_redirect_2(RestPDPtrs, PrimePDPtr, Redirect1, Redirect).
+
+:- pragma promise_pure(record_csd_redirect/4).
+:- pred record_csd_redirect(list(call_site_dynamic_ptr)::in,
+	call_site_dynamic_ptr::in, redirect::in, redirect::out) is det.
+
+record_csd_redirect(RestCSDPtrs, PrimeCSDPtr, Redirect0, Redirect) :-
+	impure unsafe_perform_io(io__write_string("csd redirect: ")),
+	impure unsafe_perform_io(io__print(RestCSDPtrs)),
+	impure unsafe_perform_io(io__write_string(" -> ")),
+	impure unsafe_perform_io(io__print(PrimeCSDPtr)),
+	impure unsafe_perform_io(io__nl),
+	lookup_csd_redirect(Redirect0 ^ csd_redirect, PrimeCSDPtr, OldRedirect),
+	( OldRedirect = call_site_dynamic_ptr(0) ->
+		record_csd_redirect_2(RestCSDPtrs, PrimeCSDPtr,
+			Redirect0, Redirect)
+	;
+		error("record_pd_redirect: prime is redirected")
+	).
+
+:- pred record_csd_redirect_2(list(call_site_dynamic_ptr)::in,
+	call_site_dynamic_ptr::in, redirect::in, redirect::out) is det.
+
+record_csd_redirect_2([], _, Redirect, Redirect).
+record_csd_redirect_2([RestCSDPtr | RestCSDPtrs], PrimeCSDPtr,
+		Redirect0, Redirect) :-
+	CallSiteRedirect0 = Redirect0 ^ csd_redirect,
+	lookup_csd_redirect(CallSiteRedirect0, RestCSDPtr, OldRedirect),
+	( OldRedirect = call_site_dynamic_ptr(0) ->
+		set_csd_redirect(u(CallSiteRedirect0), RestCSDPtr, PrimeCSDPtr,
+			CallSiteRedirect)
+	;
+		error("record_csd_redirect_2: already redirected")
+	),
+	Redirect1 = Redirect0 ^ csd_redirect := CallSiteRedirect,
+	record_csd_redirect_2(RestCSDPtrs, PrimeCSDPtr, Redirect1, Redirect).
+
+:- pred extract_pd_sites(proc_dynamic::in, array(call_site_array_slot)::out)
+	is det.
+
+extract_pd_sites(PD, PD ^ pd_sites).
+
+:- pred extract_csd_callee(call_site_dynamic::in, proc_dynamic_ptr::out)
+	is det.
+
+extract_csd_callee(CSD, CSD ^ csd_callee).
+
+:- pred two_or_more(list(proc_dynamic_ptr)::in) is semidet.
+
+two_or_more([_, _ | _]).
+
+:- pred cluster_pds_by_ps(initial_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.
+
+cluster_pds_by_ps(InitDeep, PDPtr, ProcMap0, ProcMap) :-
+	ProcDynamics = InitDeep ^ init_proc_dynamics,
+	( valid_proc_dynamic_ptr_raw(ProcDynamics, PDPtr) ->
+		lookup_proc_dynamics(ProcDynamics, PDPtr, PD),
+		PSPtr = PD ^ pd_proc_static,
+		( map__search(ProcMap0, PSPtr, PDPtrs0) ->
+			map__det_update(ProcMap0, PSPtr, [PDPtr | PDPtrs0],
+				ProcMap)
+		;
+			map__det_insert(ProcMap0, PSPtr, [PDPtr], ProcMap)
+		)
+	;
+		ProcMap = ProcMap0
+	).
+
+:- pred cluster_csds_by_ps(initial_deep::in, call_site_dynamic_ptr::in,
+	map(proc_static_ptr, list(call_site_dynamic_ptr))::in,
+	map(proc_static_ptr, list(call_site_dynamic_ptr))::out) is det.
+
+cluster_csds_by_ps(InitDeep, CSDPtr, ProcMap0, ProcMap) :-
+	CallSiteDynamics = InitDeep ^ init_call_site_dynamics,
+	( valid_call_site_dynamic_ptr_raw(CallSiteDynamics, CSDPtr) ->
+		lookup_call_site_dynamics(CallSiteDynamics, CSDPtr, CSD),
+		PDPtr = CSD ^ csd_callee,
+		ProcDynamics = InitDeep ^ init_proc_dynamics,
+		( valid_proc_dynamic_ptr_raw(ProcDynamics, PDPtr) ->
+			lookup_proc_dynamics(ProcDynamics, PDPtr, PD),
+			PSPtr = PD ^ pd_proc_static
+		;
+			PSPtr = proc_static_ptr(0)
+		),
+		( map__search(ProcMap0, PSPtr, CSDPtrs0) ->
+			map__det_update(ProcMap0, PSPtr, [CSDPtr | CSDPtrs0],
+				ProcMap)
+		;
+			map__det_insert(ProcMap0, PSPtr, [CSDPtr], ProcMap)
+		)
+	;
+		ProcMap = ProcMap0
+	).
+
+:- pred lookup_pd_redirect(array(proc_dynamic_ptr)::in,
+	proc_dynamic_ptr::in, proc_dynamic_ptr::out) is det.
+
+lookup_pd_redirect(ProcRedirect0, PDPtr, OldRedirect) :-
+	PDPtr = proc_dynamic_ptr(PDI),
+	array__lookup(ProcRedirect0, PDI, OldRedirect).
+
+:- pred set_pd_redirect(array(proc_dynamic_ptr)::array_di,
+	proc_dynamic_ptr::in, proc_dynamic_ptr::in,
+	array(proc_dynamic_ptr)::array_uo) is det.
+
+set_pd_redirect(ProcRedirect0, PDPtr, NewRedirect, ProcRedirect) :-
+	PDPtr = proc_dynamic_ptr(PDI),
+	array__set(ProcRedirect0, PDI, NewRedirect, ProcRedirect).
+
+:- pred lookup_csd_redirect(array(call_site_dynamic_ptr)::in,
+	call_site_dynamic_ptr::in, call_site_dynamic_ptr::out) is det.
+
+lookup_csd_redirect(CallSiteRedirect0, CSDPtr, OldRedirect) :-
+	CSDPtr = call_site_dynamic_ptr(CSDI),
+	array__lookup(CallSiteRedirect0, CSDI, OldRedirect).
+
+:- pred set_csd_redirect(array(call_site_dynamic_ptr)::array_di,
+	call_site_dynamic_ptr::in, call_site_dynamic_ptr::in,
+	array(call_site_dynamic_ptr)::array_uo) is det.
+
+set_csd_redirect(CallSiteRedirect0, CSDPtr, NewRedirect, CallSiteRedirect) :-
+	CSDPtr = call_site_dynamic_ptr(CSDI),
+	array__set(CallSiteRedirect0, CSDI, NewRedirect, CallSiteRedirect).
+
+%-----------------------------------------------------------------------------%
+
+:- pred deref_call_site_dynamic(redirect::in, call_site_dynamic_ptr::in,
+	call_site_dynamic_ptr::out) is det.
+
+deref_call_site_dynamic(Redirect, CSDPtr0, CSDPtr) :-
+	lookup_csd_redirect(Redirect ^ csd_redirect, CSDPtr0, RedirectCSDPtr),
+	RedirectCSDPtr = call_site_dynamic_ptr(RedirectCSDI),
+	( RedirectCSDI > 0 ->
+		deref_call_site_dynamic(Redirect, RedirectCSDPtr, CSDPtr)
+	;
+		CSDPtr = CSDPtr0
+	).
+
+:- pred deref_proc_dynamic(redirect::in, proc_dynamic_ptr::in,
+	proc_dynamic_ptr::out) is det.
+
+deref_proc_dynamic(Redirect, PDPtr0, PDPtr) :-
+	lookup_pd_redirect(Redirect ^ pd_redirect, PDPtr0, RedirectPDPtr),
+	RedirectPDPtr = proc_dynamic_ptr(RedirectPDI),
+	( RedirectPDI > 0 ->
+		deref_proc_dynamic(Redirect, RedirectPDPtr, PDPtr)
+	;
+		PDPtr = PDPtr0
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred compact_dynamics(initial_deep::in, redirect::in, int::in, int::in,
+	initial_deep::out) is det.
+
+compact_dynamics(InitDeep0, Redirect0, MaxCSD0, MaxPD0, InitDeep) :-
+	Redirect0 = redirect(CSDredirect0, PDredirect0),
+	InitDeep0 = initial_deep(Stats, Root0, CSDs0, PDs0, CSSs, PSs),
+	compact_csd_redirect(1, 1, MaxCSD0, NumCSD,
+		u(CSDredirect0), CSDredirect),
+	compact_pd_redirect(1, 1, MaxPD0, NumPD,
+		u(PDredirect0), PDredirect),
+	Redirect = redirect(CSDredirect, PDredirect),
+	array_map_from_1(subst_in_call_site_dynamic(Redirect),
+		u(CSDs0), CSDs1),
+	array_map_from_1(subst_in_proc_dynamic(Redirect),
+		u(PDs0), PDs1),
+	array__shrink(CSDs1, NumCSD, CSDs),
+	array__shrink(PDs1, NumPD, PDs),
+	lookup_pd_redirect(PDredirect, Root0, Root),
+	InitDeep = initial_deep(Stats, Root, CSDs, PDs, CSSs, PSs).
+
+:- pred compact_csd_redirect(int::in, int::in, int::in, int::out,
+	array(call_site_dynamic_ptr)::array_di,
+	array(call_site_dynamic_ptr)::array_uo) is det.
+
+compact_csd_redirect(CurOld, CurNew, MaxOld, NumNew,
+		CSDredirect0, CSDredirect) :-
+	( CurOld > MaxOld ->
+		NumNew = CurNew,
+		CSDredirect = CSDredirect0
+	;
+		array__lookup(CSDredirect0, CurOld, Redirect0),
+		( Redirect0 = call_site_dynamic_ptr(0) ->
+			array__set(CSDredirect0, CurOld,
+				call_site_dynamic_ptr(CurNew), CSDredirect1),
+			compact_csd_redirect(CurOld + 1, CurNew + 1,
+				MaxOld, NumNew, CSDredirect1, CSDredirect)
+		;
+			% Since this CSD is being redirected, its slot is
+			% available for another (non-redirected) CSD.
+			compact_csd_redirect(CurOld + 1, CurNew,
+				MaxOld, NumNew, CSDredirect0, CSDredirect)
+		)
+	).
+
+:- pred compact_pd_redirect(int::in, int::in, int::in, int::out,
+	array(proc_dynamic_ptr)::array_di,
+	array(proc_dynamic_ptr)::array_uo) is det.
+
+compact_pd_redirect(CurOld, CurNew, MaxOld, NumNew,
+		PDredirect0, PDredirect) :-
+	( CurOld > MaxOld ->
+		NumNew = CurNew,
+		PDredirect = PDredirect0
+	;
+		array__lookup(PDredirect0, CurOld, Redirect0),
+		( Redirect0 = proc_dynamic_ptr(0) ->
+			array__set(PDredirect0, CurOld,
+				proc_dynamic_ptr(CurNew), PDredirect1),
+			compact_pd_redirect(CurOld + 1, CurNew + 1,
+				MaxOld, NumNew, PDredirect1, PDredirect)
+		;
+			% Since this PD is being redirected, its slot is
+			% available for another (non-redirected) PD.
+			compact_pd_redirect(CurOld + 1, CurNew,
+				MaxOld, NumNew, PDredirect0, PDredirect)
+		)
+	).
+
+:- pred subst_in_call_site_dynamic(redirect::in, call_site_dynamic::in,
+	call_site_dynamic::out) is det.
+
+subst_in_call_site_dynamic(Redirect, CSD0, CSD) :-
+	CSD0 = call_site_dynamic(Caller0, Callee0, Own),
+	lookup_pd_redirect(Redirect ^ pd_redirect, Caller0, Caller),
+	lookup_pd_redirect(Redirect ^ pd_redirect, Callee0, Callee),
+	CSD = call_site_dynamic(Caller, Callee, Own).
+
+:- pred subst_in_proc_dynamic(redirect::in, proc_dynamic::in,
+	proc_dynamic::out) is det.
+
+subst_in_proc_dynamic(Redirect, PD0, PD) :-
+	PD0 = proc_dynamic(PDPtr, Slots0),
+	array__map(subst_in_slot(Redirect), u(Slots0), Slots),
+	PD = proc_dynamic(PDPtr, Slots).
+
+:- pred subst_in_slot(redirect::in, call_site_array_slot::in,
+	call_site_array_slot::out) is det.
+
+subst_in_slot(Redirect, normal(CSDPtr0), normal(CSDPtr)) :-
+	lookup_csd_redirect(Redirect ^ csd_redirect, CSDPtr0, CSDPtr).
+subst_in_slot(Redirect, multi(CSDPtrs0), multi(CSDPtrs)) :-
+	array__map(lookup_csd_redirect(Redirect ^ csd_redirect),
+		u(CSDPtrs0), CSDPtrs).
+
+%-----------------------------------------------------------------------------%
+
+:- pred merge_profiles(list(initial_deep)::in, maybe_error(initial_deep)::out)
+	is det.
+
+merge_profiles(InitDeeps, MaybeMergedInitDeep) :-
+	( InitDeeps = [FirstInitDeep | LaterInitDeeps] ->
+		( all_compatible(FirstInitDeep, LaterInitDeeps) ->
+			do_merge_profiles(FirstInitDeep, LaterInitDeeps,
+				MergedInitDeep),
+			MaybeMergedInitDeep = ok(MergedInitDeep)
+		;
+			MaybeMergedInitDeep =
+				error("profiles are not from the same executable")
+		)
+	;
+		MaybeMergedInitDeep =
+			error("merge_profiles: empty list of profiles")
+	).
+
+:- pred all_compatible(initial_deep::in, list(initial_deep)::in) is semidet.
+
+all_compatible(BaseInitDeep, OtherInitDeeps) :-
+	extract_max_css(BaseInitDeep, BaseMaxCSS),
+	extract_max_ps(BaseInitDeep, BaseMaxPS),
+	extract_ticks_per_sec(BaseInitDeep, BaseTicksPerSec),
+	list__map(extract_max_css, OtherInitDeeps, OtherMaxCSSs),
+	list__map(extract_max_ps, OtherInitDeeps, OtherMaxPSs),
+	list__map(extract_ticks_per_sec, OtherInitDeeps, OtherTicksPerSec),
+	all_true(unify(BaseMaxCSS), OtherMaxCSSs),
+	all_true(unify(BaseMaxPS), OtherMaxPSs),
+	all_true(unify(BaseTicksPerSec), OtherTicksPerSec),
+	extract_init_call_site_statics(BaseInitDeep, BaseCallSiteStatics),
+	extract_init_proc_statics(BaseInitDeep, BaseProcStatics),
+	list__map(extract_init_call_site_statics, OtherInitDeeps,
+		OtherCallSiteStatics),
+	list__map(extract_init_proc_statics, OtherInitDeeps,
+		OtherProcStatics),
+	array_match_elements(1, BaseMaxCSS, BaseCallSiteStatics,
+		OtherCallSiteStatics),
+	array_match_elements(1, BaseMaxPS, BaseProcStatics,
+		OtherProcStatics).
+
+:- pred do_merge_profiles(initial_deep::in, list(initial_deep)::in,
+	initial_deep::out) is det.
+
+do_merge_profiles(BaseInitDeep, OtherInitDeeps, MergedInitDeep) :-
+	extract_max_csd(BaseInitDeep, BaseMaxCSD),
+	extract_max_pd(BaseInitDeep, BaseMaxPD),
+	list__map(extract_max_csd, OtherInitDeeps, OtherMaxCSDs),
+	list__map(extract_max_pd, OtherInitDeeps, OtherMaxPDs),
+	list__foldl(int_add, OtherMaxCSDs, BaseMaxCSD, ConcatMaxCSD),
+	list__foldl(int_add, OtherMaxPDs, BaseMaxPD, ConcatMaxPD),
+	extract_init_call_site_dynamics(BaseInitDeep, BaseCallSiteDynamics),
+	extract_init_proc_dynamics(BaseInitDeep, BaseProcDynamics),
+	array__lookup(BaseCallSiteDynamics, 0, DummyCSD),
+	array__lookup(BaseProcDynamics, 0, DummyPD),
+	array__init(ConcatMaxCSD + 1, DummyCSD, ConcatCallSiteDynamics0),
+	array__init(ConcatMaxPD + 1, DummyPD, ConcatProcDynamics0),
+	AllInitDeeps = [BaseInitDeep | OtherInitDeeps],
+	concatenate_profiles(AllInitDeeps, 0, 0,
+		ConcatCallSiteDynamics0, ConcatCallSiteDynamics,
+		ConcatProcDynamics0, ConcatProcDynamics),
+
+	extract_max_css(BaseInitDeep, BaseMaxCSS),
+	extract_max_ps(BaseInitDeep, BaseMaxPS),
+	extract_ticks_per_sec(BaseInitDeep, BaseTicksPerSec),
+	list__map(extract_instrument_quanta, AllInitDeeps, InstrumentQuantas),
+	list__map(extract_user_quanta, AllInitDeeps, UserQuantas),
+	list__foldl(int_add, InstrumentQuantas, 0, InstrumentQuanta),
+	list__foldl(int_add, UserQuantas, 0, UserQuanta),
+	ConcatProfileStats = profile_stats(
+		ConcatMaxCSD, BaseMaxCSS, ConcatMaxPD, BaseMaxPS,
+		BaseTicksPerSec, InstrumentQuanta, UserQuanta),
+	% The root part is a temporary lie.
+	MergedInitDeep = initial_deep(ConcatProfileStats,
+		BaseInitDeep ^ init_root,
+		ConcatCallSiteDynamics,
+		ConcatProcDynamics,
+		BaseInitDeep ^ init_call_site_statics,
+		BaseInitDeep ^ init_proc_statics).
+	% list__map(extract_init_root, AllInitDeeps, Roots),
+	% merge clique of roots, replacing root with chosen pd
+
+:- pred concatenate_profiles(list(initial_deep)::in, int::in, int::in,
+	call_site_dynamics::array_di, call_site_dynamics::array_uo,
+	proc_dynamics::array_di, proc_dynamics::array_uo) is det.
+
+concatenate_profiles([], _PrevMaxCSD, _PrevMaxPD,
+		ConcatCallSiteDynamics, ConcatCallSiteDynamics,
+		ConcatProcDynamics, ConcatProcDynamics).
+concatenate_profiles([InitDeep | InitDeeps], PrevMaxCSD, PrevMaxPD,
+		ConcatCallSiteDynamics0, ConcatCallSiteDynamics,
+		ConcatProcDynamics0, ConcatProcDynamics) :-
+	concatenate_profile(InitDeep,
+		PrevMaxCSD, PrevMaxPD, NextMaxCSD, NextMaxPD,
+		ConcatCallSiteDynamics0, ConcatCallSiteDynamics,
+		ConcatProcDynamics0, ConcatProcDynamics),
+	concatenate_profiles(InitDeeps, NextMaxCSD, NextMaxPD,
+		ConcatCallSiteDynamics0, ConcatCallSiteDynamics,
+		ConcatProcDynamics0, ConcatProcDynamics).
+
+:- pred concatenate_profile(initial_deep::in,
+	int::in, int::in, int::out, int::out,
+	call_site_dynamics::array_di, call_site_dynamics::array_uo,
+	proc_dynamics::array_di, proc_dynamics::array_uo) is det.
+
+concatenate_profile(InitDeep, PrevMaxCSD, PrevMaxPD, NextMaxCSD, NextMaxPD,
+		ConcatCallSiteDynamics0, ConcatCallSiteDynamics,
+		ConcatProcDynamics0, ConcatProcDynamics) :-
+	extract_max_csd(InitDeep, MaxCSD),
+	extract_max_pd(InitDeep, MaxPD),
+	NextMaxCSD = PrevMaxCSD + MaxCSD,
+	NextMaxPD = PrevMaxPD + MaxPD,
+	concatenate_profile_csds(1, MaxCSD, PrevMaxCSD, PrevMaxPD,
+		InitDeep ^ init_call_site_dynamics,
+		ConcatCallSiteDynamics0, ConcatCallSiteDynamics),
+	concatenate_profile_pds(1, MaxPD, PrevMaxCSD, PrevMaxPD,
+		InitDeep ^ init_proc_dynamics,
+		ConcatProcDynamics0, ConcatProcDynamics).
+
+:- pred concatenate_profile_csds(int::in, int::in, int::in, int::in,
+	call_site_dynamics::in,
+	call_site_dynamics::array_di, call_site_dynamics::array_uo) is det.
+
+concatenate_profile_csds(Cur, Max, PrevMaxCSD, PrevMaxPD, CallSiteDynamics,
+		ConcatCallSiteDynamics0, ConcatCallSiteDynamics) :-
+	( Cur =< Max ->
+		array__lookup(CallSiteDynamics, Cur, CSD0),
+		CSD0 = call_site_dynamic(CallerPDPtr0, CalleePDPtr0, Own),
+		concat_proc_dynamic_ptr(PrevMaxPD, CallerPDPtr0, CallerPDPtr),
+		concat_proc_dynamic_ptr(PrevMaxPD, CalleePDPtr0, CalleePDPtr),
+		CSD = call_site_dynamic(CallerPDPtr, CalleePDPtr, Own),
+		array__set(ConcatCallSiteDynamics0, PrevMaxCSD + Cur, CSD,
+			ConcatCallSiteDynamics1),
+		concatenate_profile_csds(Cur + 1, Max, PrevMaxCSD, PrevMaxPD,
+			CallSiteDynamics,
+			ConcatCallSiteDynamics1, ConcatCallSiteDynamics)
+	;
+		ConcatCallSiteDynamics = ConcatCallSiteDynamics0
+	).
+
+:- pred concatenate_profile_pds(int::in, int::in, int::in, int::in,
+	proc_dynamics::in,
+	proc_dynamics::array_di, proc_dynamics::array_uo) is det.
+
+concatenate_profile_pds(Cur, Max, PrevMaxCSD, PrevMaxPD, ProcDynamics,
+		ConcatProcDynamics0, ConcatProcDynamics) :-
+	( Cur =< Max ->
+		array__lookup(ProcDynamics, Cur, PD0),
+		PD0 = proc_dynamic(PSPtr, Sites0),
+		array__max(Sites0, MaxSite),
+		concatenate_profile_slots(0, MaxSite, PrevMaxCSD, PrevMaxPD,
+			u(Sites0), Sites),
+		PD = proc_dynamic(PSPtr, Sites),
+		array__set(ConcatProcDynamics0, PrevMaxPD + Cur, PD,
+			ConcatProcDynamics1),
+		concatenate_profile_pds(Cur + 1, Max, PrevMaxCSD, PrevMaxPD,
+			ProcDynamics,
+			ConcatProcDynamics1, ConcatProcDynamics)
+	;
+		ConcatProcDynamics = ConcatProcDynamics0
+	).
+
+:- pred concatenate_profile_slots(int::in, int::in, int::in, int::in,
+	array(call_site_array_slot)::array_di,
+	array(call_site_array_slot)::array_uo) is det.
+
+concatenate_profile_slots(Cur, Max, PrevMaxCSD, PrevMaxPD, Sites0, Sites) :-
+	( Cur =< Max ->
+		array__lookup(Sites0, Cur, Slot0),
+		(
+			Slot0 = normal(CSDPtr0),
+			concat_call_site_dynamic_ptr(PrevMaxCSD,
+				CSDPtr0, CSDPtr),
+			Slot = normal(CSDPtr)
+		;
+			Slot0 = multi(CSDPtrs0),
+			array_map_from_0(
+				concat_call_site_dynamic_ptr(PrevMaxCSD),
+				CSDPtrs0, CSDPtrs),
+			Slot = multi(CSDPtrs)
+		),
+		array__set(Sites0, Cur, Slot, Sites1),
+		concatenate_profile_slots(Cur + 1, Max, PrevMaxCSD, PrevMaxPD,
+			Sites1, Sites)
+	;
+		Sites = Sites0
+	).
+
+:- pred concat_call_site_dynamic_ptr(int::in, call_site_dynamic_ptr::in,
+	call_site_dynamic_ptr::out) is det.
+
+concat_call_site_dynamic_ptr(PrevMaxCSD, CSDPtr0, CSDPtr) :-
+	CSDPtr0 = call_site_dynamic_ptr(CSDI0),
+	( CSDI0 = 0 ->
+		CSDPtr = CSDPtr0
+	;
+		CSDPtr = call_site_dynamic_ptr(CSDI0 + PrevMaxCSD)
+	).
+
+:- pred concat_proc_dynamic_ptr(int::in, proc_dynamic_ptr::in,
+	proc_dynamic_ptr::out) is det.
+
+concat_proc_dynamic_ptr(PrevMaxPD, PDPtr0, PDPtr) :-
+	PDPtr0 = proc_dynamic_ptr(PDI0),
+	( PDI0 = 0 ->
+		PDPtr = PDPtr0
+	;
+		PDPtr = proc_dynamic_ptr(PDI0 + PrevMaxPD)
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred extract_ticks_per_sec(initial_deep::in, int::out) is det.
+
+extract_ticks_per_sec(InitDeep,
+	InitDeep ^ init_profile_stats ^ ticks_per_sec).
+
+:- pred extract_instrument_quanta(initial_deep::in, int::out) is det.
+
+extract_instrument_quanta(InitDeep,
+	InitDeep ^ init_profile_stats ^ instrument_quanta).
+
+:- pred extract_user_quanta(initial_deep::in, int::out) is det.
+
+extract_user_quanta(InitDeep,
+	InitDeep ^ init_profile_stats ^ user_quanta).
+
+:- pred extract_max_css(initial_deep::in, int::out) is det.
+
+extract_max_css(InitDeep, MaxCSS) :-
+	array__max(InitDeep ^ init_call_site_statics, MaxCSS).
+
+:- pred extract_max_ps(initial_deep::in, int::out) is det.
+
+extract_max_ps(InitDeep, MaxPS) :-
+	array__max(InitDeep ^ init_proc_statics, MaxPS).
+
+:- pred extract_max_csd(initial_deep::in, int::out) is det.
+
+extract_max_csd(InitDeep, MaxCSD) :-
+	array__max(InitDeep ^ init_call_site_dynamics, MaxCSD).
+
+:- pred extract_max_pd(initial_deep::in, int::out) is det.
+
+extract_max_pd(InitDeep, MaxPD) :-
+	array__max(InitDeep ^ init_proc_dynamics, MaxPD).
+
+:- pred extract_init_call_site_dynamics(initial_deep::in,
+	call_site_dynamics::out) is det.
+
+extract_init_call_site_dynamics(InitDeep, InitDeep ^ init_call_site_dynamics).
+
+:- pred extract_init_call_site_statics(initial_deep::in,
+	call_site_statics::out) is det.
+
+extract_init_call_site_statics(InitDeep, InitDeep ^ init_call_site_statics).
+
+:- pred extract_init_proc_dynamics(initial_deep::in,
+	proc_dynamics::out) is det.
+
+extract_init_proc_dynamics(InitDeep, InitDeep ^ init_proc_dynamics).
+
+:- pred extract_init_proc_statics(initial_deep::in,
+	proc_statics::out) is det.
+
+extract_init_proc_statics(InitDeep, InitDeep ^ init_proc_statics).
+
+:- pred extract_init_root(initial_deep::in,
+	proc_dynamic_ptr::out) is det.
+
+extract_init_root(InitDeep, InitDeep ^ init_root).
+
+	% list__all_true(P, L) succeeds iff P is true for all elements of the
+	% list L.
+:- pred all_true(pred(X), list(X)).
+:- mode all_true(pred(in) is semidet, in) is semidet.
+
+all_true(_, []).
+all_true(P, [H | T]) :-
+	call(P, H),
+	all_true(P, T).
+
+	% array_match_elements(Min, Max, BaseArray, OtherArrays):
+	% Succeeds iff all the elements of all the OtherArrays are equal to the
+	% corresponding element of BaseArray.
+:- pred array_match_elements(int::in, int::in, array(T)::in,
+	list(array(T))::in) is semidet.
+
+array_match_elements(N, Max, BaseArray, OtherArrays) :-
+	( N =< Max ->
+		array__lookup(BaseArray, N, BaseElement),
+		match_element(BaseElement, N, OtherArrays),
+		array_match_elements(N + 1, Max, BaseArray, OtherArrays)
+	;
+		true
+	).
+
+	% match_element(TestElement, Index, Arrays):
+	% Succeeds iff the elements of all the Arrays at index Index
+	% are equal to TestElement.
+:- pred match_element(T::in, int::in, list(array(T))::in) is semidet.
+
+match_element(_, _, []).
+match_element(TestElement, Index, [Array | Arrays]) :-
+	array__lookup(Array, Index, Element),
+	Element = TestElement,
+	match_element(Element, Index, Arrays).
+
+:- pred int_add(int::in, int::in, int::out) is det.
+
+int_add(A, B, C) :-
+	C = A + B.
Index: cliques.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/cliques.m,v
retrieving revision 1.1
diff -u -b -r1.1 cliques.m
--- cliques.m	2001/05/31 05:59:57	1.1
+++ cliques.m	2001/06/01 11:31:11
@@ -18,17 +18,18 @@
 
 :- import_module list, set.
 
-% Create a graph with no edges.
+	% Create a graph with no edges.
 :- pred init(graph::out) is det.
 
-% Add an arc from one node to another.
+	% Add an arc from one node to another.
 :- pred add_arc(graph::in, int::in, int::in, graph::out) is det.
 
-% Perform a topological sort on the graph. Each set of integers in the
-% resulting list gives the ids of the nodes in a clique. The list contains
-% the cliques in bottom-up order: if there is an arc from node A to node B
-% and the two nodes are not in the same clique, then the clique containing
-% node A will be before the clique containing node B.
+	% Perform a topological sort on the graph. Each set of integers in the
+	% resulting list gives the ids of the nodes in a clique. The list
+	% contains the cliques in top-down order: if there is an arc from
+	% node A to node B and the two nodes are not in the same clique,
+	% then the clique containing node A will be before the clique
+	% containing node B.
 :- pred topological_sort(graph::in, list(set(int))::out) is det.
 
 :- implementation.
@@ -36,8 +37,8 @@
 :- import_module array_util, dense_bitset.
 :- import_module array, int.
 
-:- type graph	--->
-		graph(
+:- type graph
+	--->	graph(
 			int,
 			array(set(int))
 		).
Index: deep_cliques.m
===================================================================
RCS file: deep_cliques.m
diff -N deep_cliques.m
cvs diff: deep_cliques.m: No such file or directory
Index: interface.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/interface.m,v
retrieving revision 1.1
diff -u -b -r1.1 interface.m
--- interface.m	2001/05/31 05:59:57	1.1
+++ interface.m	2001/06/02 10:11:37
@@ -21,7 +21,7 @@
 	;	timeout(int)
 	;	menu
 	;	root(fields)
-	;	clique(int, fields)
+	;	clique(int, fields, maybe(int))
 	;	proc(int, fields)
 	;	top_procs(sort_measurement, include_descendants,
 			display_limit, fields)
@@ -60,6 +60,8 @@
 					% w: memory words
 					% The characters must be sorted.
 
+:- func default_ancestor_limit = maybe(int).
+
 :- func default_fields = string.
 :- func all_fields = string.
 
@@ -81,8 +83,9 @@
 :- import_module util.
 :- import_module char, string, list, set, require.
 
-default_fields = "pqw".
+default_ancestor_limit = yes(5).
 
+default_fields = "pqw".
 all_fields = "apqtw".
 
 to_server_pipe_name(DataFileName) =
@@ -154,8 +157,16 @@
 		Cmd = root(Fields),
 		Query = format("root+%s", [s(Fields)])
 	;
-		Cmd = clique(CliqueNum, Fields),
-		Query = format("clique+%s+%d", [s(Fields), i(CliqueNum)])
+		Cmd = clique(CliqueNum, Fields, MaybeAncestorLimit),
+		(
+			MaybeAncestorLimit = yes(AncestorLimit),
+			Query = format("clique+%s+%d+%d",
+				[s(Fields), i(CliqueNum), i(AncestorLimit)])
+		;
+			MaybeAncestorLimit = no,
+			Query = format("clique+%s+%d+no",
+				[s(Fields), i(CliqueNum)])
+		)
 	;
 		Cmd = proc(ProcNum, Fields),
 		Query = format("proc+%s+%d", [s(Fields), i(ProcNum)])
@@ -199,16 +210,30 @@
 	split(QueryString, ('+'), Pieces),
 	(
 		(
-			Pieces = ["clique", NStr],
+			Pieces = ["clique", NStr, AncestorLimitStr],
 			string__to_int(NStr, N),
+			( string__to_int(AncestorLimitStr, AncestorLimit) ->
+				MaybeAncestorLimit = yes(AncestorLimit)
+			; AncestorLimitStr = "no" ->
+				MaybeAncestorLimit = no
+			;
+				fail
+			),
 			Fields = default_fields
 		;
-			Pieces = ["clique", Fields, NStr],
+			Pieces = ["clique", Fields, NStr, AncestorLimitStr],
 			string__to_int(NStr, N),
+			( string__to_int(AncestorLimitStr, AncestorLimit) ->
+				MaybeAncestorLimit = yes(AncestorLimit)
+			; AncestorLimitStr = "no" ->
+				MaybeAncestorLimit = no
+			;
+				fail
+			),
 			validate_fields(Fields)
 		)
 	->
-		MaybeCmd = yes(clique(N, Fields))
+		MaybeCmd = yes(clique(N, Fields, MaybeAncestorLimit))
 	;
 		(
 			Pieces = ["proc", NStr],
Index: io_combinator.m
===================================================================
RCS file: io_combinator.m
diff -N io_combinator.m
--- /dev/null	Fri Dec  1 02:25:58 2000
+++ io_combinator.m	Fri Jun  1 21:38:15 2001
@@ -0,0 +1,1636 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 1993-2001 The University of Melbourne.
+% This file may only be copied under the terms of the GNU Library General
+% Public License - see the file COPYING.LIB in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: io.m.
+% Authors: conway, zs.
+% Stability: low
+%
+% This file implements I/O "combinators".
+%
+% Each of these predicates takes as its inputs N I/O actions, and a predicate
+% that combines the results of these actions into a single result.
+%
+% The io_combinator__sequence_N forms combine actions that return io__result(T)
+% and return io__result(T) themselves. They return ok if all the actions
+% succeeded. They return error if an action resulted in an error after the
+% previous ones succeeded, and they return eof if one of the actions found eof
+% after the previous ones succeeded. In either case, the inputs of those
+% earlier successful actions have already been consumed, but their results
+% are not returned.
+%
+% The io_combinator__res_sequence_N forms are similar, except they combine
+% actions that return io__res(T) and return io__res(T) themselves. This means
+% that neither the individual actions nor the combinators can ever return a
+% separate eof indication. These forms are for use in situations in which
+% an action finding eof is an error.
+%
+% The io_combinator__maybe_error_sequence_N forms are identical to the
+% io_combinator__res_sequence_N forms, except they return strings, not
+% io__errors, when they find an error.
+%
+%-----------------------------------------------------------------------------%
+
+:- module io_combinator.
+:- interface.
+:- import_module io, std_util.
+
+%-----------------------------------------------------------------------------%
+
+:- pred io_combinator__sequence_2(
+    pred(io__result(T1), io__state, io__state),
+    pred(io__result(T2), io__state, io__state),
+    pred(T1, T2, io__result(T)),
+    io__result(T), io__state, io__state).
+:- mode io_combinator__sequence_2(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__sequence_3(
+    pred(io__result(T1), io__state, io__state),
+    pred(io__result(T2), io__state, io__state),
+    pred(io__result(T3), io__state, io__state),
+    pred(T1, T2, T3, io__result(T)),
+    io__result(T), io__state, io__state).
+:- mode io_combinator__sequence_3(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__sequence_4(
+    pred(io__result(T1), io__state, io__state),
+    pred(io__result(T2), io__state, io__state),
+    pred(io__result(T3), io__state, io__state),
+    pred(io__result(T4), io__state, io__state),
+    pred(T1, T2, T3, T4, io__result(T)),
+    io__result(T), io__state, io__state).
+:- mode io_combinator__sequence_4(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__sequence_5(
+    pred(io__result(T1), io__state, io__state),
+    pred(io__result(T2), io__state, io__state),
+    pred(io__result(T3), io__state, io__state),
+    pred(io__result(T4), io__state, io__state),
+    pred(io__result(T5), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, io__result(T)),
+    io__result(T), io__state, io__state).
+:- mode io_combinator__sequence_5(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__sequence_6(
+    pred(io__result(T1), io__state, io__state),
+    pred(io__result(T2), io__state, io__state),
+    pred(io__result(T3), io__state, io__state),
+    pred(io__result(T4), io__state, io__state),
+    pred(io__result(T5), io__state, io__state),
+    pred(io__result(T6), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, io__result(T)),
+    io__result(T), io__state, io__state).
+:- mode io_combinator__sequence_6(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__sequence_7(
+    pred(io__result(T1), io__state, io__state),
+    pred(io__result(T2), io__state, io__state),
+    pred(io__result(T3), io__state, io__state),
+    pred(io__result(T4), io__state, io__state),
+    pred(io__result(T5), io__state, io__state),
+    pred(io__result(T6), io__state, io__state),
+    pred(io__result(T7), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, io__result(T)),
+    io__result(T), io__state, io__state).
+:- mode io_combinator__sequence_7(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__sequence_8(
+    pred(io__result(T1), io__state, io__state),
+    pred(io__result(T2), io__state, io__state),
+    pred(io__result(T3), io__state, io__state),
+    pred(io__result(T4), io__state, io__state),
+    pred(io__result(T5), io__state, io__state),
+    pred(io__result(T6), io__state, io__state),
+    pred(io__result(T7), io__state, io__state),
+    pred(io__result(T8), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, T8, io__result(T)),
+    io__result(T), io__state, io__state).
+:- mode io_combinator__sequence_8(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__sequence_9(
+    pred(io__result(T1), io__state, io__state),
+    pred(io__result(T2), io__state, io__state),
+    pred(io__result(T3), io__state, io__state),
+    pred(io__result(T4), io__state, io__state),
+    pred(io__result(T5), io__state, io__state),
+    pred(io__result(T6), io__state, io__state),
+    pred(io__result(T7), io__state, io__state),
+    pred(io__result(T8), io__state, io__state),
+    pred(io__result(T9), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, T8, T9, io__result(T)),
+    io__result(T), io__state, io__state).
+:- mode io_combinator__sequence_9(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- pred io_combinator__res_sequence_2(
+    pred(io__res(T1), io__state, io__state),
+    pred(io__res(T2), io__state, io__state),
+    pred(T1, T2, io__res(T)),
+    io__res(T), io__state, io__state).
+:- mode io_combinator__res_sequence_2(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__res_sequence_3(
+    pred(io__res(T1), io__state, io__state),
+    pred(io__res(T2), io__state, io__state),
+    pred(io__res(T3), io__state, io__state),
+    pred(T1, T2, T3, io__res(T)),
+    io__res(T), io__state, io__state).
+:- mode io_combinator__res_sequence_3(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__res_sequence_4(
+    pred(io__res(T1), io__state, io__state),
+    pred(io__res(T2), io__state, io__state),
+    pred(io__res(T3), io__state, io__state),
+    pred(io__res(T4), io__state, io__state),
+    pred(T1, T2, T3, T4, io__res(T)),
+    io__res(T), io__state, io__state).
+:- mode io_combinator__res_sequence_4(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__res_sequence_5(
+    pred(io__res(T1), io__state, io__state),
+    pred(io__res(T2), io__state, io__state),
+    pred(io__res(T3), io__state, io__state),
+    pred(io__res(T4), io__state, io__state),
+    pred(io__res(T5), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, io__res(T)),
+    io__res(T), io__state, io__state).
+:- mode io_combinator__res_sequence_5(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__res_sequence_6(
+    pred(io__res(T1), io__state, io__state),
+    pred(io__res(T2), io__state, io__state),
+    pred(io__res(T3), io__state, io__state),
+    pred(io__res(T4), io__state, io__state),
+    pred(io__res(T5), io__state, io__state),
+    pred(io__res(T6), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, io__res(T)),
+    io__res(T), io__state, io__state).
+:- mode io_combinator__res_sequence_6(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__res_sequence_7(
+    pred(io__res(T1), io__state, io__state),
+    pred(io__res(T2), io__state, io__state),
+    pred(io__res(T3), io__state, io__state),
+    pred(io__res(T4), io__state, io__state),
+    pred(io__res(T5), io__state, io__state),
+    pred(io__res(T6), io__state, io__state),
+    pred(io__res(T7), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, io__res(T)),
+    io__res(T), io__state, io__state).
+:- mode io_combinator__res_sequence_7(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__res_sequence_8(
+    pred(io__res(T1), io__state, io__state),
+    pred(io__res(T2), io__state, io__state),
+    pred(io__res(T3), io__state, io__state),
+    pred(io__res(T4), io__state, io__state),
+    pred(io__res(T5), io__state, io__state),
+    pred(io__res(T6), io__state, io__state),
+    pred(io__res(T7), io__state, io__state),
+    pred(io__res(T8), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, T8, io__res(T)),
+    io__res(T), io__state, io__state).
+:- mode io_combinator__res_sequence_8(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__res_sequence_9(
+    pred(io__res(T1), io__state, io__state),
+    pred(io__res(T2), io__state, io__state),
+    pred(io__res(T3), io__state, io__state),
+    pred(io__res(T4), io__state, io__state),
+    pred(io__res(T5), io__state, io__state),
+    pred(io__res(T6), io__state, io__state),
+    pred(io__res(T7), io__state, io__state),
+    pred(io__res(T8), io__state, io__state),
+    pred(io__res(T9), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, T8, T9, io__res(T)),
+    io__res(T), io__state, io__state).
+:- mode io_combinator__res_sequence_9(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- pred io_combinator__maybe_error_sequence_2(
+    pred(maybe_error(T1), io__state, io__state),
+    pred(maybe_error(T2), io__state, io__state),
+    pred(T1, T2, maybe_error(T)),
+    maybe_error(T), io__state, io__state).
+:- mode io_combinator__maybe_error_sequence_2(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__maybe_error_sequence_3(
+    pred(maybe_error(T1), io__state, io__state),
+    pred(maybe_error(T2), io__state, io__state),
+    pred(maybe_error(T3), io__state, io__state),
+    pred(T1, T2, T3, maybe_error(T)),
+    maybe_error(T), io__state, io__state).
+:- mode io_combinator__maybe_error_sequence_3(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__maybe_error_sequence_4(
+    pred(maybe_error(T1), io__state, io__state),
+    pred(maybe_error(T2), io__state, io__state),
+    pred(maybe_error(T3), io__state, io__state),
+    pred(maybe_error(T4), io__state, io__state),
+    pred(T1, T2, T3, T4, maybe_error(T)),
+    maybe_error(T), io__state, io__state).
+:- mode io_combinator__maybe_error_sequence_4(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__maybe_error_sequence_5(
+    pred(maybe_error(T1), io__state, io__state),
+    pred(maybe_error(T2), io__state, io__state),
+    pred(maybe_error(T3), io__state, io__state),
+    pred(maybe_error(T4), io__state, io__state),
+    pred(maybe_error(T5), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, maybe_error(T)),
+    maybe_error(T), io__state, io__state).
+:- mode io_combinator__maybe_error_sequence_5(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__maybe_error_sequence_6(
+    pred(maybe_error(T1), io__state, io__state),
+    pred(maybe_error(T2), io__state, io__state),
+    pred(maybe_error(T3), io__state, io__state),
+    pred(maybe_error(T4), io__state, io__state),
+    pred(maybe_error(T5), io__state, io__state),
+    pred(maybe_error(T6), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, maybe_error(T)),
+    maybe_error(T), io__state, io__state).
+:- mode io_combinator__maybe_error_sequence_6(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__maybe_error_sequence_7(
+    pred(maybe_error(T1), io__state, io__state),
+    pred(maybe_error(T2), io__state, io__state),
+    pred(maybe_error(T3), io__state, io__state),
+    pred(maybe_error(T4), io__state, io__state),
+    pred(maybe_error(T5), io__state, io__state),
+    pred(maybe_error(T6), io__state, io__state),
+    pred(maybe_error(T7), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, maybe_error(T)),
+    maybe_error(T), io__state, io__state).
+:- mode io_combinator__maybe_error_sequence_7(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__maybe_error_sequence_8(
+    pred(maybe_error(T1), io__state, io__state),
+    pred(maybe_error(T2), io__state, io__state),
+    pred(maybe_error(T3), io__state, io__state),
+    pred(maybe_error(T4), io__state, io__state),
+    pred(maybe_error(T5), io__state, io__state),
+    pred(maybe_error(T6), io__state, io__state),
+    pred(maybe_error(T7), io__state, io__state),
+    pred(maybe_error(T8), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, T8, maybe_error(T)),
+    maybe_error(T), io__state, io__state).
+:- mode io_combinator__maybe_error_sequence_8(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+:- pred io_combinator__maybe_error_sequence_9(
+    pred(maybe_error(T1), io__state, io__state),
+    pred(maybe_error(T2), io__state, io__state),
+    pred(maybe_error(T3), io__state, io__state),
+    pred(maybe_error(T4), io__state, io__state),
+    pred(maybe_error(T5), io__state, io__state),
+    pred(maybe_error(T6), io__state, io__state),
+    pred(maybe_error(T7), io__state, io__state),
+    pred(maybe_error(T8), io__state, io__state),
+    pred(maybe_error(T9), io__state, io__state),
+    pred(T1, T2, T3, T4, T5, T6, T7, T8, T9, maybe_error(T)),
+    maybe_error(T), io__state, io__state).
+:- mode io_combinator__maybe_error_sequence_9(
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(out, di, uo) is det,
+    pred(in, in, in, in, in, in, in, in, in, out) is det,
+    out, di, uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+io_combinator__sequence_2(P1, P2, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            { call(Combine, T1, T2, Res) }
+        ;
+            { Res2 = eof },
+            { Res = eof }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = eof },
+        { Res = eof }
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__sequence_3(P1, P2, P3, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                { call(Combine, T1, T2, T3, Res) }
+            ;
+                { Res3 = eof },
+                { Res = eof }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = eof },
+            { Res = eof }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = eof },
+        { Res = eof }
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__sequence_4(P1, P2, P3, P4, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    { call(Combine, T1, T2, T3, T4, Res) }
+                ;
+                    { Res4 = eof },
+                    { Res = eof }
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = eof },
+                { Res = eof }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = eof },
+            { Res = eof }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = eof },
+        { Res = eof }
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__sequence_5(P1, P2, P3, P4, P5, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        { call(Combine, T1, T2, T3, T4,
+                            T5, Res) }
+                    ;
+                        { Res5 = eof },
+                        { Res = eof }
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = eof },
+                    { Res = eof }
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = eof },
+                { Res = eof }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = eof },
+            { Res = eof }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = eof },
+        { Res = eof }
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__sequence_6(P1, P2, P3, P4, P5, P6, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            { call(Combine, T1, T2,
+                                T3, T4, T5,
+                                T6, Res) }
+                        ;
+                            { Res6 = eof },
+                            { Res = eof }
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = eof },
+                        { Res = eof }
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = eof },
+                    { Res = eof }
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = eof },
+                { Res = eof }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = eof },
+            { Res = eof }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = eof },
+        { Res = eof }
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__sequence_7(P1, P2, P3, P4, P5, P6, P7, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                { call(Combine, T1, T2, T3, T4, T5, T6, T7,
+                                    Res) }
+                            ;
+                                { Res7 = eof },
+                                { Res = eof }
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = eof },
+                            { Res = eof }
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = eof },
+                        { Res = eof }
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = eof },
+                    { Res = eof }
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = eof },
+                { Res = eof }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = eof },
+            { Res = eof }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = eof },
+        { Res = eof }
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__sequence_8(P1, P2, P3, P4, P5, P6, P7, P8, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                call(P8, Res8),
+                                (
+                                    { Res8 = ok(T8) },
+                                    { call(Combine, T1, T2, T3, T4, T5, T6,
+                                        T7, T8, Res) }
+                                ;
+                                    { Res8 = eof },
+                                    { Res = eof }
+                                ;
+                                    { Res8 = error(Err) },
+                                    { Res = error(Err) }
+                                )
+                            ;
+                                { Res7 = eof },
+                                { Res = eof }
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = eof },
+                            { Res = eof }
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = eof },
+                        { Res = eof }
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = eof },
+                    { Res = eof }
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = eof },
+                { Res = eof }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = eof },
+            { Res = eof }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = eof },
+        { Res = eof }
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__sequence_9(P1, P2, P3, P4, P5, P6, P7, P8, P9, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                call(P8, Res8),
+                                (
+                                    { Res8 = ok(T8) },
+                                    call(P9, Res9),
+                                    (
+                                        { Res9 = ok(T9) },
+                                        { call(Combine, T1, T2, T3, T4, T5,
+                                            T6, T7, T8, T9, Res) }
+                                    ;
+                                        { Res9 = eof },
+                                        { Res = eof }
+                                    ;
+                                        { Res9 = error(Err) },
+                                        { Res = error(Err) }
+                                    )
+                                ;
+                                    { Res8 = eof },
+                                    { Res = eof }
+                                ;
+                                    { Res8 = error(Err) },
+                                    { Res = error(Err) }
+                                )
+                            ;
+                                { Res7 = eof },
+                                { Res = eof }
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = eof },
+                            { Res = eof }
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = eof },
+                        { Res = eof }
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = eof },
+                    { Res = eof }
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = eof },
+                { Res = eof }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = eof },
+            { Res = eof }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = eof },
+        { Res = eof }
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+%-----------------------------------------------------------------------------%
+
+io_combinator__res_sequence_2(P1, P2, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            { call(Combine, T1, T2, Res) }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__res_sequence_3(P1, P2, P3, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                { call(Combine, T1, T2, T3, Res) }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__res_sequence_4(P1, P2, P3, P4, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    { call(Combine, T1, T2, T3, T4, Res) }
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__res_sequence_5(P1, P2, P3, P4, P5, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        { call(Combine, T1, T2, T3, T4,
+                            T5, Res) }
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__res_sequence_6(P1, P2, P3, P4, P5, P6, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            { call(Combine, T1, T2,
+                                T3, T4, T5,
+                                T6, Res) }
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__res_sequence_7(P1, P2, P3, P4, P5, P6, P7, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                { call(Combine, T1, T2, T3, T4, T5, T6, T7,
+                                    Res) }
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__res_sequence_8(P1, P2, P3, P4, P5, P6, P7, P8, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                call(P8, Res8),
+                                (
+                                    { Res8 = ok(T8) },
+                                    { call(Combine, T1, T2, T3, T4, T5, T6,
+                                        T7, T8, Res) }
+                                ;
+                                    { Res8 = error(Err) },
+                                    { Res = error(Err) }
+                                )
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__res_sequence_9(P1, P2, P3, P4, P5, P6, P7, P8, P9,
+        Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                call(P8, Res8),
+                                (
+                                    { Res8 = ok(T8) },
+                                    call(P9, Res9),
+                                    (
+                                        { Res9 = ok(T9) },
+                                        { call(Combine, T1, T2, T3, T4, T5,
+                                            T6, T7, T8, T9, Res) }
+                                    ;
+                                        { Res9 = error(Err) },
+                                        { Res = error(Err) }
+                                    )
+                                ;
+                                    { Res8 = error(Err) },
+                                    { Res = error(Err) }
+                                )
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+%-----------------------------------------------------------------------------%
+
+io_combinator__maybe_error_sequence_2(P1, P2, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            { call(Combine, T1, T2, Res) }
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__maybe_error_sequence_3(P1, P2, P3, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                { call(Combine, T1, T2, T3, Res) }
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__maybe_error_sequence_4(P1, P2, P3, P4, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    { call(Combine, T1, T2, T3, T4, Res) }
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__maybe_error_sequence_5(P1, P2, P3, P4, P5, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        { call(Combine, T1, T2, T3, T4,
+                            T5, Res) }
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__maybe_error_sequence_6(P1, P2, P3, P4, P5, P6, Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            { call(Combine, T1, T2,
+                                T3, T4, T5,
+                                T6, Res) }
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__maybe_error_sequence_7(P1, P2, P3, P4, P5, P6, P7,
+        Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                { call(Combine, T1, T2, T3, T4, T5, T6, T7,
+                                    Res) }
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__maybe_error_sequence_8(P1, P2, P3, P4, P5, P6, P7, P8,
+        Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                call(P8, Res8),
+                                (
+                                    { Res8 = ok(T8) },
+                                    { call(Combine, T1, T2, T3, T4, T5, T6,
+                                        T7, T8, Res) }
+                                ;
+                                    { Res8 = error(Err) },
+                                    { Res = error(Err) }
+                                )
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+io_combinator__maybe_error_sequence_9(P1, P2, P3, P4, P5, P6, P7, P8, P9,
+        Combine, Res) -->
+    call(P1, Res1),
+    (
+        { Res1 = ok(T1) },
+        call(P2, Res2),
+        (
+            { Res2 = ok(T2) },
+            call(P3, Res3),
+            (
+                { Res3 = ok(T3) },
+                call(P4, Res4),
+                (
+                    { Res4 = ok(T4) },
+                    call(P5, Res5),
+                    (
+                        { Res5 = ok(T5) },
+                        call(P6, Res6),
+                        (
+                            { Res6 = ok(T6) },
+                            call(P7, Res7),
+                            (
+                                { Res7 = ok(T7) },
+                                call(P8, Res8),
+                                (
+                                    { Res8 = ok(T8) },
+                                    call(P9, Res9),
+                                    (
+                                        { Res9 = ok(T9) },
+                                        { call(Combine, T1, T2, T3, T4, T5,
+                                            T6, T7, T8, T9, Res) }
+                                    ;
+                                        { Res9 = error(Err) },
+                                        { Res = error(Err) }
+                                    )
+                                ;
+                                    { Res8 = error(Err) },
+                                    { Res = error(Err) }
+                                )
+                            ;
+                                { Res7 = error(Err) },
+                                { Res = error(Err) }
+                            )
+                        ;
+                            { Res6 = error(Err) },
+                            { Res = error(Err) }
+                        )
+                    ;
+                        { Res5 = error(Err) },
+                        { Res = error(Err) }
+                    )
+                ;
+                    { Res4 = error(Err) },
+                    { Res = error(Err) }
+                )
+            ;
+                { Res3 = error(Err) },
+                { Res = error(Err) }
+            )
+        ;
+            { Res2 = error(Err) },
+            { Res = error(Err) }
+        )
+    ;
+        { Res1 = error(Err) },
+        { Res = error(Err) }
+    ).
+
+%-----------------------------------------------------------------------------%
Index: measurements.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/measurements.m,v
retrieving revision 1.1
diff -u -b -r1.1 measurements.m
--- measurements.m	2001/05/31 05:59:58	1.1
+++ measurements.m	2001/06/01 17:27:01
@@ -23,13 +23,13 @@
 :- func fails(own_prof_info) = int.
 :- func redos(own_prof_info) = int.
 :- func quanta(own_prof_info) = int.
-:- func mallocs(own_prof_info) = int.
+:- func allocs(own_prof_info) = int.
 :- func words(own_prof_info) = int.
 
 :- func zero_own_prof_info = own_prof_info.
 
 :- func inherit_quanta(inherit_prof_info) = int.
-:- func inherit_mallocs(inherit_prof_info) = int.
+:- func inherit_allocs(inherit_prof_info) = int.
 :- func inherit_words(inherit_prof_info) = int.
 
 :- func zero_inherit_prof_info = inherit_prof_info.
@@ -46,7 +46,7 @@
 :- func sum_own_infos(list(own_prof_info)) = own_prof_info.
 :- func sum_inherit_infos(list(inherit_prof_info)) = inherit_prof_info.
 
-:- func compress_profile(int, int, int, int, int, int, int) = own_prof_info.
+:- func compress_profile(int, int, int, int, int, int) = own_prof_info.
 :- func compress_profile(own_prof_info) = own_prof_info.
 
 :- func own_to_string(own_prof_info) = string.
@@ -59,95 +59,109 @@
 :- import_module string.
 
 :- type own_prof_info
-	--->	all(int, int, int, int, int, int, int)
-					% calls, exits, fails, redos, quanta,
-					% memory_mallocs, memory_words
-	;	det(int, int, int, int)	% calls, quanta, mallocs, words;
-					% implicit exits == calls,
+	--->	all(int, int, int, int, int, int)
+			% exits, fails, redos, quanta, allocs, words
+			% implicit calls = exits + fails - redos
+	;	det(int, int, int, int)
+			% exits, quanta, allocs, words;
 					% implicit fails == redos == 0
-	;	zdet(int, int, int).	% calls, mallocs, words;
-					% implicit exits == calls,
+			% implicit calls == exits
+	;	fast_det(int, int, int)
+			% exits, allocs, words;
 					% implicit fails == redos == 0
+			% implicit calls == exits
 					% implicit quanta == 0
+	;	fast_nomem_semi(int, int).
+			% exits, fails
+			% implicit redos == 0
+			% implicit calls == exits + fails
+			% implicit quanta == 0
+			% implicit allocs == words == 0
 
 :- type inherit_prof_info
 	--->	inherit_prof_info(
 			int, 		% quanta
-			int, 		% memory_mallocs
-			int 		% memory_words
+			int, 		% allocs
+			int 		% words
 		).
 
-calls(zdet(Calls, _, _)) = Calls.
-exits(zdet(Calls, _, _)) = Calls.
-fails(zdet(_, _, _)) = 0.
-redos(zdet(_, _, _)) = 0.
-quanta(zdet(_, _, _)) = 0.
-mallocs(zdet(_, Mallocs, _)) = Mallocs.
-words(zdet(_, _, Words)) = Words.
+calls(fast_nomem_semi(Exits, Fails)) = Exits + Fails.
+exits(fast_nomem_semi(Exits, _)) = Exits.
+fails(fast_nomem_semi(_, Fails)) = Fails.
+redos(fast_nomem_semi(_, _)) = 0.
+quanta(fast_nomem_semi(_, _)) = 0.
+allocs(fast_nomem_semi(_, _)) = 0.
+words(fast_nomem_semi(_, _)) = 0.
+
+calls(fast_det(Exits, _, _)) = Exits.
+exits(fast_det(Exits, _, _)) = Exits.
+fails(fast_det(_, _, _)) = 0.
+redos(fast_det(_, _, _)) = 0.
+quanta(fast_det(_, _, _)) = 0.
+allocs(fast_det(_, Allocs, _)) = Allocs.
+words(fast_det(_, _, Words)) = Words.
 
-calls(det(Calls, _, _, _)) = Calls.
-exits(det(Calls, _, _, _)) = Calls.
+calls(det(Exits, _, _, _)) = Exits.
+exits(det(Exits, _, _, _)) = Exits.
 fails(det(_, _, _, _)) = 0.
 redos(det(_, _, _, _)) = 0.
 quanta(det(_, Quanta, _, _)) = Quanta.
-mallocs(det(_, _, Mallocs, _)) = Mallocs.
+allocs(det(_, _, Allocs, _)) = Allocs.
 words(det(_, _, _, Words)) = Words.
 
-calls(all(Calls, _, _, _, _, _, _)) = Calls.
-exits(all(_, Exits, _, _, _, _, _)) = Exits.
-fails(all(_, _, Fails, _, _, _, _)) = Fails.
-redos(all(_, _, _, Redos, _, _, _)) = Redos.
-quanta(all(_, _, _, _, Quanta, _, _)) = Quanta.
-mallocs(all(_, _, _, _, _, Mallocs, _)) = Mallocs.
-words(all(_, _, _, _, _, _, Words)) = Words.
+calls(all(Exits, Fails, Redos, _, _, _)) = Exits + Fails - Redos.
+exits(all(Exits, _, _, _, _, _)) = Exits.
+fails(all(_, Fails, _, _, _, _)) = Fails.
+redos(all(_, _, Redos, _, _, _)) = Redos.
+quanta(all(_, _, _, Quanta, _, _)) = Quanta.
+allocs(all(_, _, _, _, Allocs, _)) = Allocs.
+words(all(_, _, _, _, _, Words)) = Words.
 
-zero_own_prof_info = zdet(0, 0, 0).
+zero_own_prof_info = fast_nomem_semi(0, 0).
 
 inherit_quanta(inherit_prof_info(Quanta, _, _)) = Quanta.
-inherit_mallocs(inherit_prof_info(_, Mallocs, _)) = Mallocs.
+inherit_allocs(inherit_prof_info(_, Allocs, _)) = Allocs.
 inherit_words(inherit_prof_info(_, _, Words)) = Words.
 
 zero_inherit_prof_info = inherit_prof_info(0, 0, 0).
 
 add_inherit_to_inherit(PI1, PI2) = SumPI :-
 	Quanta = inherit_quanta(PI1) + inherit_quanta(PI2),
-	Mallocs = inherit_mallocs(PI1) + inherit_mallocs(PI2),
+	Allocs = inherit_allocs(PI1) + inherit_allocs(PI2),
 	Words = inherit_words(PI1) + inherit_words(PI2),
-	SumPI = inherit_prof_info(Quanta, Mallocs, Words).
+	SumPI = inherit_prof_info(Quanta, Allocs, Words).
 
 add_own_to_inherit(PI1, PI2) = SumPI :-
 	Quanta = quanta(PI1) + inherit_quanta(PI2),
-	Mallocs = mallocs(PI1) + inherit_mallocs(PI2),
+	Allocs = allocs(PI1) + inherit_allocs(PI2),
 	Words = words(PI1) + inherit_words(PI2),
-	SumPI = inherit_prof_info(Quanta, Mallocs, Words).
+	SumPI = inherit_prof_info(Quanta, Allocs, Words).
 
 subtract_own_from_inherit(PI1, PI2) = SumPI :-
 	Quanta = inherit_quanta(PI2) - quanta(PI1),
-	Mallocs = inherit_mallocs(PI2) - mallocs(PI1),
+	Allocs = inherit_allocs(PI2) - allocs(PI1),
 	Words = inherit_words(PI2) - words(PI1),
-	SumPI = inherit_prof_info(Quanta, Mallocs, Words).
+	SumPI = inherit_prof_info(Quanta, Allocs, Words).
 
 add_inherit_to_own(PI1, PI2) = SumPI :-
-	Calls = calls(PI2),
 	Exits = exits(PI2),
 	Fails = fails(PI2),
 	Redos = redos(PI2),
 	Quanta = inherit_quanta(PI1) + quanta(PI2),
-	Mallocs = inherit_mallocs(PI1) + mallocs(PI2),
+	Allocs = inherit_allocs(PI1) + allocs(PI2),
 	Words = inherit_words(PI1) + words(PI2),
-	SumPI = compress_profile(Calls, Exits, Fails, Redos,
-		Quanta, Mallocs, Words).
+	SumPI = compress_profile(Exits, Fails, Redos,
+		Quanta, Allocs, Words).
 
 add_own_to_own(PI1, PI2) = SumPI :-
-	Calls = calls(PI1) + calls(PI2),
 	Exits = exits(PI1) + exits(PI2),
 	Fails = fails(PI1) + fails(PI2),
 	Redos = redos(PI1) + redos(PI2),
 	Quanta = quanta(PI1) + quanta(PI2),
-	Mallocs = mallocs(PI1) + mallocs(PI2),
+	Allocs = allocs(PI1) + allocs(PI2),
 	Words = words(PI1) + words(PI2),
-	SumPI = compress_profile(Calls, Exits, Fails, Redos,
-		Quanta, Mallocs, Words).
+	SumPI = compress_profile(Exits, Fails, Redos,
+		Quanta, Allocs, Words).
 
 sum_own_infos(Owns) =
 	list__foldl(add_own_to_own, Owns, zero_own_prof_info).
@@ -155,60 +169,74 @@
 sum_inherit_infos(Inherits) =
 	list__foldl(add_inherit_to_inherit, Inherits, zero_inherit_prof_info).
 
-compress_profile(Calls, Exits, Fails, Redos, Quanta, Mallocs, Words) = PI :-
+compress_profile(Exits, Fails, Redos, Quanta, Allocs, Words) = PI :-
 	(
-		Calls = Exits,
+		Redos = 0,
+		Quanta = 0,
+		Allocs = 0,
+		Words = 0
+	->
+		PI = fast_nomem_semi(Exits, Fails)
+	;
 		Fails = 0,
 		Redos = 0
-	->
-		(
-			Quanta = 0
 		->
-			PI = zdet(Calls, Mallocs, Words)
+		( Quanta = 0 ->
+			PI = fast_det(Exits, Allocs, Words)
 		;
-			PI = det(Calls, Quanta, Mallocs, Words)
+			PI = det(Exits, Quanta, Allocs, Words)
 		)
 	;
-		PI = all(Calls, Exits, Fails, Redos, Quanta, Mallocs, Words)
+		PI = all(Exits, Fails, Redos, Quanta, Allocs, Words)
 	).
 
 compress_profile(PI0) = PI :-
 	(
-		PI0 = all(Calls, Exits, Fails, Redos, Quanta, Mallocs, Words),
+		PI0 = all(Exits, Fails, Redos, Quanta, Allocs, Words),
 		(
-			Calls = Exits,
+			Redos = 0,
+			Quanta = 0,
+			Allocs = 0,
+			Words = 0
+		->
+			PI = fast_nomem_semi(Exits, Fails)
+		;
 			Fails = 0,
 			Redos = 0
 		->
-			(
-				Quanta = 0
-			->
-				PI = zdet(Calls, Mallocs, Words)
+			( Quanta = 0 ->
+				PI = fast_det(Exits, Allocs, Words)
 			;
-				PI = det(Calls, Quanta, Mallocs, Words)
+				PI = det(Exits, Quanta, Allocs, Words)
 			)
 		;
 			PI = PI0
 		)
 	;
-		PI0 = det(Calls, Quanta, Mallocs, Words),
-		(
-			Quanta = 0
-		->
-			PI = zdet(Calls, Mallocs, Words)
+		PI0 = det(Exits, Quanta, Allocs, Words),
+		( Allocs = 0, Words = 0 ->
+			PI = fast_nomem_semi(Exits, 0)
+		; Quanta = 0 ->
+			PI = fast_det(Exits, Allocs, Words)
+		;
+			PI = PI0
+		)
+	;
+		PI0 = fast_det(Exits, Allocs, Words),
+		( Allocs = 0, Words = 0 ->
+			PI = fast_nomem_semi(Exits, 0)
 		;
 			PI = PI0
 		)
 	;
-		PI0 = zdet(_, _, _),
+		PI0 = fast_nomem_semi(_, _),
 		PI = PI0
 	).
 
 %-----------------------------------------------------------------------------%
 
-own_to_string(all(Calls, Exits, Fails, Redos, Quanta, Allocs, Words)) =
+own_to_string(all(Exits, Fails, Redos, Quanta, Allocs, Words)) =
 	"all(" ++
-	string__int_to_string(Calls) ++ ", " ++
 	string__int_to_string(Exits) ++ ", " ++
 	string__int_to_string(Fails) ++ ", " ++
 	string__int_to_string(Redos) ++ ", " ++
@@ -216,16 +244,21 @@
 	string__int_to_string(Allocs) ++ ", " ++
 	string__int_to_string(Words) ++
 	")".
-own_to_string(det(Calls, Quanta, Allocs, Words)) =
+own_to_string(det(Exits, Quanta, Allocs, Words)) =
 	"det(" ++
-	string__int_to_string(Calls) ++ ", " ++
+	string__int_to_string(Exits) ++ ", " ++
 	string__int_to_string(Quanta) ++ ", " ++
 	string__int_to_string(Allocs) ++ ", " ++
 	string__int_to_string(Words) ++
 	")".
-own_to_string(zdet(Calls, Allocs, Words)) =
-	"det(" ++
-	string__int_to_string(Calls) ++ ", " ++
+own_to_string(fast_det(Exits, Allocs, Words)) =
+	"fast_det(" ++
+	string__int_to_string(Exits) ++ ", " ++
 	string__int_to_string(Allocs) ++ ", " ++
 	string__int_to_string(Words) ++
+	")".
+own_to_string(fast_nomem_semi(Exits, Fails)) =
+	"fast_det(" ++
+	string__int_to_string(Exits) ++ ", " ++
+	string__int_to_string(Fails) ++
 	")".
Index: profile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/profile.m,v
retrieving revision 1.1
diff -u -b -r1.1 profile.m
--- profile.m	2001/05/31 05:59:58	1.1
+++ profile.m	2001/06/01 11:38:41
@@ -7,7 +7,7 @@
 % Authors: conway, zs.
 %
 % This file defines the main data structures of the Mercury deep profiler,
-% and predicates for accessing it. The main concern of the access predicates
+% and predicates for accessing them. The main concern of the access predicates
 % is ensuring the safety of array accesses.
 %
 % For historical reasons, all the top-level arrays (i.e. those directly
@@ -25,13 +25,13 @@
 
 :- type profile_stats --->
 	profile_stats(
+		max_csd			:: int,
+		max_css			:: int,
+		max_pd			:: int,
+		max_ps			:: int,
+		ticks_per_sec		:: int,
 		instrument_quanta	:: int,
-		user_quanta		:: int,
-		num_csds		:: int,
-		num_pds			:: int,
-		num_csss		:: int,
-		num_pss			:: int,
-		ticks_per_sec		:: int
+		user_quanta		:: int
 	).
 
 :- type initial_deep --->
@@ -112,8 +112,7 @@
 :- type proc_dynamic
 	--->	proc_dynamic(
 			pd_proc_static	:: proc_static_ptr,
-			pd_sites	:: array(call_site_array_slot),
-			pd_redirect	:: maybe(proc_dynamic_ptr)
+			pd_sites	:: array(call_site_array_slot)
 		).
 
 :- type proc_static
@@ -129,8 +128,7 @@
 	--->	call_site_dynamic(
 			csd_caller	:: proc_dynamic_ptr,
 			csd_callee	:: proc_dynamic_ptr,
-			csd_own_prof	:: own_prof_info,
-			csd_redirect	:: maybe(call_site_dynamic_ptr)
+			csd_own_prof	:: own_prof_info
 		).
 
 :- type call_site_static
Index: read_profile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/read_profile.m,v
retrieving revision 1.1
diff -u -b -r1.1 read_profile.m
--- read_profile.m	2001/05/31 05:59:58	1.1
+++ read_profile.m	2001/06/01 17:26:24
@@ -21,24 +21,13 @@
 :- implementation.
 
 :- import_module measurements, array_util.
-:- import_module array, char, string, int, float, std_util, list, require.
+:- import_module array, char, string, int, float, list, require.
+:- import_module io_combinator.
 
-:- type deep_result(T)
-	--->	ok(T)
-	;	error(string).
-
-:- type deep_result2(T1, T2)
+:- type maybe_error2(T1, T2)
 	--->	ok2(T1, T2)
 	;	error2(string).
 
-:- type ptr_info --->
-		ptr_info(
-			ps	:: int,
-			css	:: int,
-			pd	:: int,
-			csd	:: int
-		).
-
 :- type ptr_kind
 	--->	ps
 	;	pd
@@ -52,7 +41,7 @@
 		read_id_string(Res1),
 		(
 			{ Res1 = ok(_) },
-			read_sequence7(
+			io_combinator__maybe_error_sequence_7(
 				read_fixed_size_int,
 				read_fixed_size_int,
 				read_fixed_size_int,
@@ -60,14 +49,13 @@
 				read_num,
 				read_num,
 				read_num,
-				(pred(NumCSDs::in, NumCSSs::in,
-						NumPDs::in, NumPSs::in,
+				(pred(MaxCSD::in, MaxCSS::in,
+						MaxPD::in, MaxPS::in,
 						TicksPerSec::in,
 						InstrumentQuanta::in,
 						UserQuanta::in,
 						ResInitDeep::out) is det :-
-					init_deep(NumCSDs, NumCSSs,
-						NumPDs, NumPSs,
+					init_deep(MaxCSD, MaxCSS, MaxPD, MaxPS,
 						TicksPerSec,
 						InstrumentQuanta, UserQuanta,
 						InitDeep0),
@@ -76,10 +64,8 @@
 				Res2),
 			(
 				{ Res2 = ok(InitDeep) },
-				{ PtrInfo0 = ptr_info(0, 0, 0, 0) },
-				read_nodes(InitDeep, PtrInfo0, Res3),
-				io__seen_binary,
-				{ resize_arrays(Res3, Res) }
+				read_nodes(InitDeep, Res),
+				io__seen_binary
 			;
 				{ Res2 = error(Err) },
 				{ Res = error(Err) }
@@ -94,7 +80,7 @@
 		{ Res = error(Msg) }
 	).
 
-:- pred read_id_string(deep_result(string)::out,
+:- pred read_id_string(maybe_error(string)::out,
 	io__state::di, io__state::uo) is det.
 
 read_id_string(Res) -->
@@ -117,131 +103,119 @@
 
 :- pred init_deep(int::in, int::in, int::in, int::in, int::in, int::in,
 	int::in, initial_deep::out) is det.
+
+init_deep(MaxCSD, MaxCSS, MaxPD, MaxPS, TicksPerSec,
+		InstrumentQuanta, UserQuanta, InitDeep) :-
+	InitStats = profile_stats(MaxCSD, MaxCSS, MaxPD, MaxPS,
+		TicksPerSec, InstrumentQuanta, UserQuanta),
 
-init_deep(NumCSDs, NumCSSs, NumPDs, NumPSs, InstrumentQuanta, UserQuanta,
-		TicksPerSec, InitDeep) :-
-	InitStats = profile_stats(
-		InstrumentQuanta,
-		UserQuanta,
-		-1, -1, -1, -1,
-		TicksPerSec),
 	InitDeep = initial_deep(
 		InitStats,
 		proc_dynamic_ptr(-1),
-		array__init(NumCSDs + 1,
+		array__init(MaxCSD + 1,
 			call_site_dynamic(
 				proc_dynamic_ptr(-1),
 				proc_dynamic_ptr(-1),
-				zero_own_prof_info,
-				no
+				zero_own_prof_info
 			)),
-		array__init(NumPDs + 1,
-			proc_dynamic(proc_static_ptr(-1), array([]), no)),
-		array__init(NumCSSs + 1,
+		array__init(MaxPD + 1,
+			proc_dynamic(proc_static_ptr(-1), array([]))),
+		array__init(MaxCSS + 1,
 			call_site_static(
 				proc_static_ptr(-1), -1,
 				normal_call(proc_static_ptr(-1), ""), -1, ""
 			)),
-		array__init(NumPSs + 1,
+		array__init(MaxPS + 1,
 			proc_static(dummy_proc_id, "", "", "", array([])))
 	).
 
-:- pred read_nodes(initial_deep::in, ptr_info::in,
-	deep_result2(initial_deep, ptr_info)::out,
+:- pred read_nodes(initial_deep::in, maybe_error(initial_deep)::out,
 	io__state::di, io__state::uo) is det.
 
-read_nodes(InitDeep0, PtrInfo0, Res) -->
+read_nodes(InitDeep0, Res) -->
 	read_byte(Res0),
 	(
 		{ Res0 = ok(Byte) },
-		( { Byte = token_call_site_static } ->
-			read_call_site_static(Res1),
+		( { Byte = token_call_site_dynamic } ->
+			read_call_site_dynamic(Res1),
 			(
-				{ Res1 = ok2(CallSiteStatic, CSSI) },
+				{ Res1 = ok2(CallSiteDynamic, CSDI) },
 				{ deep_insert(
-					InitDeep0 ^ init_call_site_statics,
-					CSSI, CallSiteStatic, CSSs) },
+					InitDeep0 ^ init_call_site_dynamics,
+					CSDI, CallSiteDynamic, CSDs) },
 				{ InitDeep1 = InitDeep0
-					^ init_call_site_statics := CSSs },
-				{ PtrInfo1 = PtrInfo0 ^ css
-					:= max(PtrInfo0 ^ css, CSSI) },
-				read_nodes(InitDeep1, PtrInfo1, Res)
+					^ init_call_site_dynamics := CSDs },
+				read_nodes(InitDeep1, Res)
 			;
 				{ Res1 = error2(Err) },
-				{ Res = error2(Err) }
+				{ Res = error(Err) }
 			)
-		; { Byte = token_proc_static } ->
-			read_proc_static(Res1),
+		; { Byte = token_proc_dynamic } ->
+			read_proc_dynamic(Res1),
 			(
-				{ Res1 = ok2(ProcStatic, PSI) },
+				{ Res1 = ok2(ProcDynamic, PDI) },
 				{ deep_insert(
-					InitDeep0 ^ init_proc_statics,
-					PSI, ProcStatic, PSs) },
+					InitDeep0 ^ init_proc_dynamics,
+					PDI, ProcDynamic, PDs) },
 				{ InitDeep1 = InitDeep0
-					^ init_proc_statics := PSs },
-				{ PtrInfo1 = PtrInfo0 ^ ps
-					:= max(PtrInfo0 ^ ps, PSI) },
-				read_nodes(InitDeep1, PtrInfo1, Res)
+					^ init_proc_dynamics := PDs },
+				read_nodes(InitDeep1, Res)
 			;
 				{ Res1 = error2(Err) },
-				{ Res = error2(Err) }
+				{ Res = error(Err) }
 			)
-		; { Byte = token_call_site_dynamic } ->
-			read_call_site_dynamic(Res1),
+		; { Byte = token_call_site_static } ->
+			read_call_site_static(Res1),
 			(
-				{ Res1 = ok2(CallSiteDynamic, CSDI) },
+				{ Res1 = ok2(CallSiteStatic, CSSI) },
 				{ deep_insert(
-					InitDeep0 ^ init_call_site_dynamics,
-					CSDI, CallSiteDynamic, CSDs) },
+					InitDeep0 ^ init_call_site_statics,
+					CSSI, CallSiteStatic, CSSs) },
 				{ InitDeep1 = InitDeep0
-					^ init_call_site_dynamics := CSDs },
-				{ PtrInfo1 = PtrInfo0 ^ csd
-					:= max(PtrInfo0 ^ csd, CSDI) },
-				read_nodes(InitDeep1, PtrInfo1, Res)
+					^ init_call_site_statics := CSSs },
+				read_nodes(InitDeep1, Res)
 			;
 				{ Res1 = error2(Err) },
-				{ Res = error2(Err) }
+				{ Res = error(Err) }
 			)
-		; { Byte = token_proc_dynamic } ->
-			read_proc_dynamic(Res1),
+		; { Byte = token_proc_static } ->
+			read_proc_static(Res1),
 			(
-				{ Res1 = ok2(ProcDynamic, PDI) },
+				{ Res1 = ok2(ProcStatic, PSI) },
 				{ deep_insert(
-					InitDeep0 ^ init_proc_dynamics,
-					PDI, ProcDynamic, PDs) },
+					InitDeep0 ^ init_proc_statics,
+					PSI, ProcStatic, PSs) },
 				{ InitDeep1 = InitDeep0
-					^ init_proc_dynamics := PDs },
-				{ PtrInfo1 = PtrInfo0 ^ pd
-					:= max(PtrInfo0 ^ pd, PDI) },
-				read_nodes(InitDeep1, PtrInfo1, Res)
+					^ init_proc_statics := PSs },
+				read_nodes(InitDeep1, Res)
 			;
 				{ Res1 = error2(Err) },
-				{ Res = error2(Err) }
+				{ Res = error(Err) }
 			)
 		; { Byte = token_root } ->
 			read_root(Res1),
 			(
 				{ Res1 = ok(PDPtr) },
 				{ InitDeep1 = InitDeep0 ^ init_root := PDPtr },
-				read_nodes(InitDeep1, PtrInfo0, Res)
+				read_nodes(InitDeep1, Res)
 			;
 				{ Res1 = error(Err) },
-				{ Res = error2(Err) }
+				{ Res = error(Err) }
 			)
 		;
 			{ format("unexpected token %d", [i(Byte)], Msg) },
-			{ Res = error2(Msg) }
+			{ Res = error(Msg) }
 		)
 	;
 		{ Res0 = eof },
-		{ Res = ok2(InitDeep0, PtrInfo0) }
+		{ Res = ok(InitDeep0) }
 	;
 		{ Res0 = error(Err) },
 		{ io__error_message(Err, Msg) },
-		{ Res = error2(Msg) }
+		{ Res = error(Msg) }
 	).
 
-:- pred read_root(deep_result(proc_dynamic_ptr)::out,
+:- pred read_root(maybe_error(proc_dynamic_ptr)::out,
 	io__state::di, io__state::uo) is det.
 
 read_root(Res) -->
@@ -256,12 +230,12 @@
 		{ Res = error(Err) }
 	).
 
-:- pred read_call_site_static(deep_result2(call_site_static, int)::out,
+:- pred read_call_site_static(maybe_error2(call_site_static, int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_call_site_static(Res) -->
 	% format("reading call_site_static.\n", []),
-	read_sequence4(
+	io_combinator__maybe_error_sequence_4(
 		read_ptr(css),
 		read_call_site_kind_and_callee,
 		read_num,
@@ -284,12 +258,12 @@
 	).
 
 
-:- pred read_proc_static(deep_result2(proc_static, int)::out,
+:- pred read_proc_static(maybe_error2(proc_static, int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_proc_static(Res) -->
 	% format("reading proc_static.\n", []),
-	read_sequence4(
+	io_combinator__maybe_error_sequence_4(
 		read_ptr(ps),
 		read_proc_id,
 		read_string,
@@ -321,7 +295,7 @@
 		{ Res = error2(Err) }
 	).
 
-:- pred read_proc_id(deep_result(proc_id)::out,
+:- pred read_proc_id(maybe_error(proc_id)::out,
 	io__state::di, io__state::uo) is det.
 
 read_proc_id(Res) -->
@@ -344,11 +318,11 @@
 		{ Res = error(Err) }
 	).
 
-:- pred read_proc_id_compiler_generated(deep_result(proc_id)::out,
+:- pred read_proc_id_compiler_generated(maybe_error(proc_id)::out,
 	io__state::di, io__state::uo) is det.
 
 read_proc_id_compiler_generated(Res) -->
-	read_sequence6(
+	io_combinator__maybe_error_sequence_6(
 		read_string,
 		read_string,
 		read_string,
@@ -363,11 +337,11 @@
 		),
 		Res).
 
-:- pred read_proc_id_user_defined(pred_or_func::in, deep_result(proc_id)::out,
+:- pred read_proc_id_user_defined(pred_or_func::in, maybe_error(proc_id)::out,
 	io__state::di, io__state::uo) is det.
 
 read_proc_id_user_defined(PredOrFunc, Res) -->
-	read_sequence5(
+	io_combinator__maybe_error_sequence_5(
 		read_string,
 		read_string,
 		read_string,
@@ -525,12 +499,12 @@
 		fail
 	).
 
-:- pred read_proc_dynamic(deep_result2(proc_dynamic, int)::out,
+:- pred read_proc_dynamic(maybe_error2(proc_dynamic, int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_proc_dynamic(Res) -->
 	% format("reading proc_dynamic.\n", []),
-	read_sequence3(
+	io_combinator__maybe_error_sequence_3(
 		read_ptr(pd),
 		read_ptr(ps),
 		read_num,
@@ -544,7 +518,7 @@
 		(
 			{ Res2 = ok(Refs) },
 			{ PSPtr = proc_static_ptr(PSI) },
-			{ ProcDynamic = proc_dynamic(PSPtr, array(Refs), no) },
+			{ ProcDynamic = proc_dynamic(PSPtr, array(Refs)) },
 			{ Res = ok2(ProcDynamic, PDI) }
 		;
 			{ Res2 = error(Err) },
@@ -555,7 +529,7 @@
 		{ Res = error2(Err) }
 	).
 
-:- pred read_call_site_dynamic(deep_result2(call_site_dynamic, int)::out,
+:- pred read_call_site_dynamic(maybe_error2(call_site_dynamic, int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_call_site_dynamic(Res) -->
@@ -572,7 +546,7 @@
 				{ PDPtr = proc_dynamic_ptr(PDI) },
 				{ DummyPDPtr = proc_dynamic_ptr(-1) },
 				{ CallSiteDynamic = call_site_dynamic(
-					DummyPDPtr, PDPtr, Profile, no) },
+					DummyPDPtr, PDPtr, Profile) },
 				{ Res = ok2(CallSiteDynamic, CSDI) }
 			;
 				{ Res3 = error(Err) },
@@ -587,7 +561,7 @@
 		{ Res = error2(Err) }
 	).
 
-:- pred read_profile(deep_result(own_prof_info)::out,
+:- pred read_profile(maybe_error(own_prof_info)::out,
 	io__state::di, io__state::uo) is det.
 
 read_profile(Res) -->
@@ -651,8 +625,7 @@
 			{ Res = error(Error) }
 		;
 			{ MaybeError7 = no },
-			{ Calls = Exits + Fails - Redos },
-			{ Res = ok(compress_profile(Calls, Exits, Fails, Redos, 
+			{ Res = ok(compress_profile(Exits, Fails, Redos, 
 				Quanta, Mallocs, Words)) }
 		)
 	;
@@ -675,7 +648,7 @@
 		{ MaybeError = yes(Error) }
 	).
 
-:- pred read_call_site_ref(deep_result(call_site_array_slot)::out,
+:- pred read_call_site_ref(maybe_error(call_site_array_slot)::out,
 	io__state::di, io__state::uo) is det.
 
 read_call_site_ref(Res) -->
@@ -711,7 +684,7 @@
 		{ Res = error(Err) }
 	).
 
-:- pred read_call_site_kind(deep_result(call_site_kind)::out,
+:- pred read_call_site_kind(maybe_error(call_site_kind)::out,
 	io__state::di, io__state::uo) is det.
 
 read_call_site_kind(Res) -->
@@ -742,7 +715,7 @@
 	).
 
 :- pred read_call_site_kind_and_callee(
-	deep_result(call_site_kind_and_callee)::out,
+	maybe_error(call_site_kind_and_callee)::out,
 	io__state::di, io__state::uo) is det.
 
 read_call_site_kind_and_callee(Res) -->
@@ -791,8 +764,8 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred read_n_things(int, pred(deep_result(T), io__state, io__state),
-		deep_result(list(T)), io__state, io__state).
+:- pred read_n_things(int, pred(maybe_error(T), io__state, io__state),
+	maybe_error(list(T)), io__state, io__state).
 :- mode read_n_things(in, pred(out, di, uo) is det, out, di, uo) is det.
 
 read_n_things(N, ThingReader, Res) -->
@@ -806,8 +779,8 @@
 		{ Res = error(Err) }
 	).
 
-:- pred read_n_things(int, pred(deep_result(T), io__state, io__state),
-		list(T), deep_result(list(T)), io__state, io__state).
+:- pred read_n_things(int, pred(maybe_error(T), io__state, io__state),
+	list(T), maybe_error(list(T)), io__state, io__state).
 :- mode read_n_things(in, pred(out, di, uo) is det, in, out, di, uo) is det.
 
 read_n_things(N, ThingReader, Things0, Res) -->
@@ -824,15 +797,15 @@
 		)
 	).
 
-:- pred read_things(pred(deep_result(T), io__state, io__state),
-		deep_result(list(T)), io__state, io__state).
+:- pred read_things(pred(maybe_error(T), io__state, io__state),
+	maybe_error(list(T)), io__state, io__state).
 :- mode read_things(pred(out, di, uo) is det, out, di, uo) is det.
 
 read_things(ThingReader, Res) -->
 	read_things(ThingReader, [], Res).
 
-:- pred read_things(pred(deep_result(T), io__state, io__state),
-		list(T), deep_result(list(T)), io__state, io__state).
+:- pred read_things(pred(maybe_error(T), io__state, io__state),
+	list(T), maybe_error(list(T)), io__state, io__state).
 :- mode read_things(pred(out, di, uo) is det, in, out, di, uo) is det.
 
 read_things(ThingReader, Things0, Res) -->
@@ -858,317 +831,8 @@
 	).
 
 %-----------------------------------------------------------------------------%
-
-:- pred read_sequence2(
-	pred(deep_result(T1), io__state, io__state),
-	pred(deep_result(T2), io__state, io__state),
-	pred(T1, T2, deep_result(T3)),
-	deep_result(T3), io__state, io__state).
-:- mode read_sequence2(
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(in, in, out) is det,
-	out, di, uo) is det.
-
-read_sequence2(P1, P2, Combine, Res) -->
-	call(P1, Res1),
-	(
-		{ Res1 = ok(T1) },
-		call(P2, Res2),
-		(
-			{ Res2 = ok(T2) },
-			{ call(Combine, T1, T2, Res) }
-		;
-			{ Res2 = error(Err) },
-			{ Res = error(Err) }
-		)
-	;
-		{ Res1 = error(Err) },
-		{ Res = error(Err) }
-	).
-
-:- pred read_sequence3(
-	pred(deep_result(T1), io__state, io__state),
-	pred(deep_result(T2), io__state, io__state),
-	pred(deep_result(T3), io__state, io__state),
-	pred(T1, T2, T3, deep_result(T4)),
-	deep_result(T4), io__state, io__state).
-:- mode read_sequence3(
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(in, in, in, out) is det,
-	out, di, uo) is det.
-
-read_sequence3(P1, P2, P3, Combine, Res) -->
-	call(P1, Res1),
-	(
-		{ Res1 = ok(T1) },
-		call(P2, Res2),
-		(
-			{ Res2 = ok(T2) },
-			call(P3, Res3),
-			(
-				{ Res3 = ok(T3) },
-				{ call(Combine, T1, T2, T3, Res) }
-			;
-				{ Res3 = error(Err) },
-				{ Res = error(Err) }
-			)
-		;
-			{ Res2 = error(Err) },
-			{ Res = error(Err) }
-		)
-	;
-		{ Res1 = error(Err) },
-		{ Res = error(Err) }
-	).
 
-:- pred read_sequence4(
-	pred(deep_result(T1), io__state, io__state),
-	pred(deep_result(T2), io__state, io__state),
-	pred(deep_result(T3), io__state, io__state),
-	pred(deep_result(T4), io__state, io__state),
-	pred(T1, T2, T3, T4, deep_result(T5)),
-	deep_result(T5), io__state, io__state).
-:- mode read_sequence4(
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(in, in, in, in, out) is det,
-	out, di, uo) is det.
-
-read_sequence4(P1, P2, P3, P4, Combine, Res) -->
-	call(P1, Res1),
-	(
-		{ Res1 = ok(T1) },
-		call(P2, Res2),
-		(
-			{ Res2 = ok(T2) },
-			call(P3, Res3),
-			(
-				{ Res3 = ok(T3) },
-				call(P4, Res4),
-				(
-					{ Res4 = ok(T4) },
-					{ call(Combine, T1, T2, T3, T4, Res) }
-				;
-					{ Res4 = error(Err) },
-					{ Res = error(Err) }
-				)
-			;
-				{ Res3 = error(Err) },
-				{ Res = error(Err) }
-			)
-		;
-			{ Res2 = error(Err) },
-			{ Res = error(Err) }
-		)
-	;
-		{ Res1 = error(Err) },
-		{ Res = error(Err) }
-	).
-
-:- pred read_sequence5(
-	pred(deep_result(T1), io__state, io__state),
-	pred(deep_result(T2), io__state, io__state),
-	pred(deep_result(T3), io__state, io__state),
-	pred(deep_result(T4), io__state, io__state),
-	pred(deep_result(T5), io__state, io__state),
-	pred(T1, T2, T3, T4, T5, deep_result(T6)),
-	deep_result(T6), io__state, io__state).
-:- mode read_sequence5(
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(in, in, in, in, in, out) is det,
-	out, di, uo) is det.
-
-read_sequence5(P1, P2, P3, P4, P5, Combine, Res) -->
-	call(P1, Res1),
-	(
-		{ Res1 = ok(T1) },
-		call(P2, Res2),
-		(
-			{ Res2 = ok(T2) },
-			call(P3, Res3),
-			(
-				{ Res3 = ok(T3) },
-				call(P4, Res4),
-				(
-					{ Res4 = ok(T4) },
-					call(P5, Res5),
-					(
-						{ Res5 = ok(T5) },
-						{ call(Combine, T1, T2, T3, T4,
-							T5, Res) }
-					;
-						{ Res5 = error(Err) },
-						{ Res = error(Err) }
-					)
-				;
-					{ Res4 = error(Err) },
-					{ Res = error(Err) }
-				)
-			;
-				{ Res3 = error(Err) },
-				{ Res = error(Err) }
-			)
-		;
-			{ Res2 = error(Err) },
-			{ Res = error(Err) }
-		)
-	;
-		{ Res1 = error(Err) },
-		{ Res = error(Err) }
-	).
-
-:- pred read_sequence6(
-	pred(deep_result(T1), io__state, io__state),
-	pred(deep_result(T2), io__state, io__state),
-	pred(deep_result(T3), io__state, io__state),
-	pred(deep_result(T4), io__state, io__state),
-	pred(deep_result(T5), io__state, io__state),
-	pred(deep_result(T6), io__state, io__state),
-	pred(T1, T2, T3, T4, T5, T6, deep_result(T7)),
-	deep_result(T7), io__state, io__state).
-:- mode read_sequence6(
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(in, in, in, in, in, in, out) is det,
-	out, di, uo) is det.
-
-read_sequence6(P1, P2, P3, P4, P5, P6, Combine, Res) -->
-	call(P1, Res1),
-	(
-		{ Res1 = ok(T1) },
-		call(P2, Res2),
-		(
-			{ Res2 = ok(T2) },
-			call(P3, Res3),
-			(
-				{ Res3 = ok(T3) },
-				call(P4, Res4),
-				(
-					{ Res4 = ok(T4) },
-					call(P5, Res5),
-					(
-						{ Res5 = ok(T5) },
-						call(P6, Res6),
-						(
-							{ Res6 = ok(T6) },
-							{ call(Combine, T1, T2,
-								T3, T4, T5,
-								T6, Res) }
-						;
-							{ Res6 = error(Err) },
-							{ Res = error(Err) }
-						)
-					;
-						{ Res5 = error(Err) },
-						{ Res = error(Err) }
-					)
-				;
-					{ Res4 = error(Err) },
-					{ Res = error(Err) }
-				)
-			;
-				{ Res3 = error(Err) },
-				{ Res = error(Err) }
-			)
-		;
-			{ Res2 = error(Err) },
-			{ Res = error(Err) }
-		)
-	;
-		{ Res1 = error(Err) },
-		{ Res = error(Err) }
-	).
-
-:- pred read_sequence7(
-	pred(deep_result(T1), io__state, io__state),
-	pred(deep_result(T2), io__state, io__state),
-	pred(deep_result(T3), io__state, io__state),
-	pred(deep_result(T4), io__state, io__state),
-	pred(deep_result(T5), io__state, io__state),
-	pred(deep_result(T6), io__state, io__state),
-	pred(deep_result(T7), io__state, io__state),
-	pred(T1, T2, T3, T4, T5, T6, T7, deep_result(T8)),
-	deep_result(T8), io__state, io__state).
-:- mode read_sequence7(
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(out, di, uo) is det,
-	pred(in, in, in, in, in, in, in, out) is det,
-	out, di, uo) is det.
-
-read_sequence7(P1, P2, P3, P4, P5, P6, P7, Combine, Res) -->
-	call(P1, Res1),
-	(
-	    { Res1 = ok(T1) },
-	    call(P2, Res2),
-	    (
-	        { Res2 = ok(T2) },
-	        call(P3, Res3),
-	        (
-	            { Res3 = ok(T3) },
-	            call(P4, Res4),
-	            (
-	                { Res4 = ok(T4) },
-	                call(P5, Res5),
-	                (
-	                    { Res5 = ok(T5) },
-	                    call(P6, Res6),
-	                    (
-	                        { Res6 = ok(T6) },
-	                        call(P7, Res7),
-	                        (
-	                            { Res7 = ok(T7) },
-	                            { call(Combine, T1, T2, T3, T4, T5, T6, T7,
-	                                Res) }
-	                        ;
-	                            { Res7 = error(Err) },
-	                            { Res = error(Err) }
-	                        )
-	                    ;
-	                        { Res6 = error(Err) },
-	                        { Res = error(Err) }
-	                    )
-	                ;
-	                    { Res5 = error(Err) },
-	                    { Res = error(Err) }
-	                )
-	            ;
-	                { Res4 = error(Err) },
-	                { Res = error(Err) }
-	            )
-	        ;
-	            { Res3 = error(Err) },
-	            { Res = error(Err) }
-	        )
-	    ;
-	        { Res2 = error(Err) },
-	        { Res = error(Err) }
-	    )
-	;
-	    { Res1 = error(Err) },
-	    { Res = error(Err) }
-	).
-
-%-----------------------------------------------------------------------------%
-
-:- pred read_string(deep_result(string)::out,
+:- pred read_string(maybe_error(string)::out,
 	io__state::di, io__state::uo) is det.
 
 read_string(Res) -->
@@ -1185,7 +849,7 @@
 		{ Res = error(Err) }
 	).
 
-:- pred read_n_byte_string(int::in, deep_result(string)::out,
+:- pred read_n_byte_string(int::in, maybe_error(string)::out,
 	io__state::di, io__state::uo) is det.
 
 read_n_byte_string(Length, Res) -->
@@ -1210,7 +874,7 @@
 	% io__write(Res),
 	% io__write_string("\n")
 
-:- pred read_ptr(ptr_kind::in, deep_result(int)::out,
+:- pred read_ptr(ptr_kind::in, maybe_error(int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_ptr(_Kind, Res) -->
@@ -1219,7 +883,7 @@
 	% io__write(Res),
 	% io__write_string("\n").
 
-:- pred read_num(deep_result(int)::out, io__state::di, io__state::uo) is det.
+:- pred read_num(maybe_error(int)::out, io__state::di, io__state::uo) is det.
 
 read_num(Res) -->
 	read_num1(0, Res).
@@ -1227,7 +891,7 @@
 	% io__write(Res),
 	% io__write_string("\n").
 
-:- pred read_num1(int::in, deep_result(int)::out,
+:- pred read_num1(int::in, maybe_error(int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_num1(Num0, Res) -->
@@ -1256,13 +920,13 @@
 
 fixed_size_int_bytes = 4.
 
-:- pred read_fixed_size_int(deep_result(int)::out,
+:- pred read_fixed_size_int(maybe_error(int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_fixed_size_int(Res) -->
 	read_fixed_size_int1(fixed_size_int_bytes, 0, 0, Res).
 
-:- pred read_fixed_size_int1(int::in, int::in, int::in, deep_result(int)::out,
+:- pred read_fixed_size_int1(int::in, int::in, int::in, maybe_error(int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_fixed_size_int1(BytesLeft, Num0, ShiftBy, Res) -->
@@ -1281,7 +945,7 @@
 		)
 	).
 
-:- pred read_n_bytes(int::in, deep_result(list(int))::out,
+:- pred read_n_bytes(int::in, maybe_error(list(int))::out,
 	io__state::di, io__state::uo) is det.
 
 read_n_bytes(N, Res) -->
@@ -1295,7 +959,7 @@
 		{ Res = error(Err) }
 	).
 
-:- pred read_n_bytes(int::in, list(int)::in, deep_result(list(int))::out,
+:- pred read_n_bytes(int::in, list(int)::in, maybe_error(list(int))::out,
 	io__state::di, io__state::uo) is det.
 
 read_n_bytes(N, Bytes0, Res) -->
@@ -1312,7 +976,7 @@
 		)
 	).
 
-:- pred read_deep_byte(deep_result(int)::out,
+:- pred read_deep_byte(maybe_error(int)::out,
 	io__state::di, io__state::uo) is det.
 
 read_deep_byte(Res) -->
@@ -1419,41 +1083,3 @@
 
 %------------------------------------------------------------------------------%
 %------------------------------------------------------------------------------%
-
-:- pred resize_arrays(deep_result2(initial_deep, ptr_info)::in,
-	maybe_error(initial_deep)::out) is det.
-
-resize_arrays(error2(Err), error(Err)).
-resize_arrays(ok2(InitDeep0, PI), ok(InitDeep)) :-
-	PI ^ csd = CSDMax,
-	CSDs0 = InitDeep0 ^ init_call_site_dynamics,
-	array__lookup(CSDs0, 0, CSDx),
-	array__resize(u(CSDs0), CSDMax + 1, CSDx, CSDs),
-	InitDeep1 = InitDeep0 ^ init_call_site_dynamics := CSDs,
-
-	PI ^ pd = PDMax,
-	PDs0 = InitDeep1 ^ init_proc_dynamics,
-	array__lookup(PDs0, 0, PDx),
-	array__resize(u(PDs0), PDMax + 1, PDx, PDs),
-	InitDeep2 = InitDeep1 ^ init_proc_dynamics := PDs,
-
-	PI ^ css = CSSMax,
-	CSSs0 = InitDeep2 ^ init_call_site_statics,
-	array__lookup(CSSs0, 0, CSSx),
-	array__resize(u(CSSs0), CSSMax + 1, CSSx, CSSs),
-	InitDeep3 = InitDeep2 ^ init_call_site_statics := CSSs,
-
-	PI ^ ps = PSMax,
-	PSs0 = InitDeep3 ^ init_proc_statics,
-	array__lookup(PSs0, 0, PSx),
-	array__resize(u(PSs0), PSMax + 1, PSx, PSs),
-	InitDeep4 = InitDeep3 ^ init_proc_statics := PSs,
-
-	ProfileStats0 = InitDeep4 ^ init_profile_stats,
-	ProfileStats0 = profile_stats(InstrumentQuanta, UserQuanta,
-		_, _, _, _, TicksPerSec),
-	ProfileStats = profile_stats(InstrumentQuanta, UserQuanta,
-		CSDMax, PDMax, CSSMax, PSMax, TicksPerSec),
-	InitDeep = InitDeep4 ^ init_profile_stats := ProfileStats.
-
-%-----------------------------------------------------------------------------%
Index: server.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/server.m,v
retrieving revision 1.1
diff -u -b -r1.1 server.m
--- server.m	2001/05/31 05:59:58	1.1
+++ server.m	2001/06/04 09:54:43
@@ -52,7 +52,8 @@
 
 test_cliques(Cur, Max, DirName, Deep, Fields) -->
 	( { Cur =< Max } ->
-		{ try_exec(clique(Cur, Fields), Deep, HTML) },
+		{ try_exec(clique(Cur, Fields, default_ancestor_limit),
+			Deep, HTML) },
 		write_html(DirName, "clique", Cur, HTML),
 		test_cliques(Cur + 1, Max, DirName, Deep, Fields)
 	;
@@ -176,7 +177,7 @@
 			{ ReadRes = error(Msg, Line) },
 			(
 				{ Debug = yes },
-				format(StdErr,
+				io__format(StdErr,
 					"error reading input line %d: %s\n",
 					[i(Line), s(Msg)])
 			;
@@ -189,7 +190,7 @@
 			{ try_exec(Cmd, Deep, HTML) },
 			(
 				{ Debug = yes },
-				format(StdErr, "query %d output:\n%s\n",
+				io__format(StdErr, "query %d output:\n%s\n",
 					[i(QueryNum), s(HTML)])
 			;
 				{ Debug = no }
@@ -237,7 +238,8 @@
 			Msg = "unknown exception"
 		),
 		HTML =
-			format("<H1>AN EXCEPTION HAS OCCURRED: %s.</H1>\n",
+			string__format(
+				"<H1>AN EXCEPTION HAS OCCURRED: %s.</H1>\n",
 				[s(Msg)])
 	).
 
@@ -246,12 +248,14 @@
 exec(Cmd, Deep, HTML) :-
 	Cmd = quit,
 	HTML =
-		format("<H1>Shutting down deep profile server for %s.</H1>\n",
+		string__format(
+			"<H1>Shutting down deep profile server for %s.</H1>\n",
 			[s(Deep ^ data_file_name)]).
 
 exec(Cmd, _Deep, HTML) :-
 	Cmd = timeout(TimeOut),
-	HTML = format("<H1>Timeout set to %d minutes</H1>\n", [i(TimeOut)]).
+	HTML = string__format("<H1>Timeout set to %d minutes</H1>\n",
+		[i(TimeOut)]).
 
 exec(Cmd, Deep, HTML) :-
 	Cmd = menu,
@@ -308,16 +312,17 @@
 	Cmd = root(Fields),
 	deep_lookup_clique_index(Deep, Deep ^ root, RootCliquePtr),
 	RootCliquePtr = clique_ptr(RootCliqueNum),
-	exec(clique(RootCliqueNum, Fields), Deep, HTML).
+	exec(clique(RootCliqueNum, Fields, default_ancestor_limit),
+		Deep, HTML).
 
 exec(Cmd, Deep, HTML) :-
-	Cmd = clique(CliqueNum, Fields),
+	Cmd = clique(CliqueNum, Fields, MaybeAncestorLimit),
 	( valid_clique_ptr(Deep, clique_ptr(CliqueNum)) ->
 		HTML =
 			banner ++
-			"<TABLE>\n" ++
+			"<TABLE border=1 rules=cols frame=void>\n" ++
 			fields_header(Fields) ++
-			clique_to_html(Deep, Fields,
+			clique_to_html(Deep, Fields, MaybeAncestorLimit,
 				clique_ptr(CliqueNum)) ++
 			"</TABLE>\n" ++
 			footer(Cmd, Deep)
@@ -398,7 +403,7 @@
 		PSPtr = proc_static_ptr(PSI),
 		HTML =
 			"<HTML>\n" ++
-			format("proc_static %d, ", [i(PSI)]) ++
+			string__format("proc_static %d, ", [i(PSI)]) ++
 			array_slots_to_html(PD ^ pd_sites) ++
 			"</HTML>\n"
 	;
@@ -456,7 +461,7 @@
 	( valid_clique_ptr(Deep, CliquePtr) ->
 		deep_lookup_clique_parents(Deep, CliquePtr, Parent),
 		Parent = call_site_dynamic_ptr(ParentPDI),
-		ParentStr = format("%d ->", [i(ParentPDI)]),
+		ParentStr = string__format("%d ->", [i(ParentPDI)]),
 		deep_lookup_clique_members(Deep, CliquePtr, Members),
 		HTML =
 			"<HTML>\n" ++
@@ -474,28 +479,28 @@
 	Cmd = num_proc_dynamics,
 	HTML =
 		"<HTML>\n" ++
-		string__int_to_string(Deep ^ profile_stats ^ num_pds) ++
+		string__int_to_string(Deep ^ profile_stats ^ max_pd) ++
 		"</HTML>\n".
 
 exec(Cmd, Deep, HTML) :-
 	Cmd = num_call_site_dynamics,
 	HTML =
 		"<HTML>\n" ++
-		string__int_to_string(Deep ^ profile_stats ^ num_csds) ++
+		string__int_to_string(Deep ^ profile_stats ^ max_csd) ++
 		"</HTML>\n".
 
 exec(Cmd, Deep, HTML) :-
 	Cmd = num_proc_statics,
 	HTML =
 		"<HTML>\n" ++
-		string__int_to_string(Deep ^ profile_stats ^ num_pss) ++
+		string__int_to_string(Deep ^ profile_stats ^ max_ps) ++
 		"</HTML>\n".
 
 exec(Cmd, Deep, HTML) :-
 	Cmd = num_call_site_statics,
 	HTML =
 		"<HTML>\n" ++
-		string__int_to_string(Deep ^ profile_stats ^ num_csss) ++
+		string__int_to_string(Deep ^ profile_stats ^ max_css) ++
 		"</HTML>\n".
 
 %-----------------------------------------------------------------------------%
@@ -521,7 +526,8 @@
 	array__to_list(CSDPtrArray, CSDPtrs),
 	list__foldl(append_csdi_to_string, CSDPtrs, "", CSDI_HTML),
 	list__length(CSDPtrs, CSDPtrCount),
-	HTML = format("multi(%d): [", [i(CSDPtrCount)]) ++ CSDI_HTML ++ "]".
+	HTML = string__format("multi(%d): [", [i(CSDPtrCount)])
+		++ CSDI_HTML ++ "]".
 
 :- pred append_csdi_to_string(call_site_dynamic_ptr::in,
 	string::in, string::out) is det.
@@ -549,37 +555,57 @@
 
 present_stats(Deep) = HTML :-
 	Stats = Deep ^ profile_stats,
+	lookup_ticks_per_sec(Stats, TicksPerSec, Assumed),
+	(
+		Assumed = yes,
+		AssumedStr = " (assumed)"
+	;
+		Assumed = no,
+		AssumedStr = ""
+	),
 	HTML =
 		"<TABLE>\n" ++
+		"<TR><TD ALIGN=left>Quanta per second:</TD>\n" ++
+		string__format("<TD ALIGN=right>%d%s</TD></TR>\n",
+			[i(TicksPerSec), s(AssumedStr)]) ++
 		"<TR><TD ALIGN=left>Quanta in user code:</TD>\n" ++
-		format("<TD ALIGN=right>%d</TD></TR>\n",
+		string__format("<TD ALIGN=right>%d</TD></TR>\n",
 			[i(Stats ^ user_quanta)]) ++
 		"<TR><TD ALIGN=left>Quanta in instrumentation:</TD>\n" ++
-		format("<TD ALIGN=right>%d</TD></TR>\n",
+		string__format("<TD ALIGN=right>%d</TD></TR>\n",
 			[i(Stats ^ instrument_quanta)]) ++
 		"<TR><TD ALIGN=left>CallSiteDynamic structures:</TD>\n" ++
-		format("<TD ALIGN=right>%d</TD></TR>\n",
-			[i(Stats ^ num_csds)]) ++
+		string__format("<TD ALIGN=right>%d</TD></TR>\n",
+			[i(Stats ^ max_csd)]) ++
 		"<TR><TD ALIGN=left>ProcDynamic structures:</TD>\n" ++
-		format("<TD ALIGN=right>%d</TD></TR>\n",
-			[i(Stats ^ num_pds)]) ++
+		string__format("<TD ALIGN=right>%d</TD></TR>\n",
+			[i(Stats ^ max_pd)]) ++
 		"<TR><TD ALIGN=left>CallSiteStatic structures:</TD>\n" ++
-		format("<TD ALIGN=right>%d</TD></TR>\n",
-			[i(Stats ^ num_csss)]) ++
+		string__format("<TD ALIGN=right>%d</TD></TR>\n",
+			[i(Stats ^ max_css)]) ++
 		"<TR><TD ALIGN=left>ProcStatic structures:</TD>\n" ++
-		format("<TD ALIGN=right>%d</TD></TR>\n",
-			[i(Stats ^ num_pss)]) ++
+		string__format("<TD ALIGN=right>%d</TD></TR>\n",
+			[i(Stats ^ max_ps)]) ++
 		"<TR><TD ALIGN=left>Cliques:</TD>\n" ++
-		format("<TD ALIGN=right>%d</TD></TR>\n",
+		string__format("<TD ALIGN=right>%d</TD></TR>\n",
 			[i(array__max(Deep ^ clique_members))]) ++
 		"</TABLE>\n".
 
 %-----------------------------------------------------------------------------%
 
-:- func clique_to_html(deep, fields, clique_ptr) = string.
+:- func clique_to_html(deep, fields, maybe(int), clique_ptr) = string.
 
-clique_to_html(Deep, Fields, CliquePtr) = HTML :-
-	Ancestors = clique_ancestors_to_html(Deep, Fields, CliquePtr),
+clique_to_html(Deep, Fields, MaybeAncestorLimit, CliquePtr) = HTML :-
+	(
+		MaybeAncestorLimit = yes(AncestorLimit),
+		RespectLimit = yes
+	;
+		MaybeAncestorLimit = no,
+		AncestorLimit = 0, % the value doesn't matter
+		RespectLimit = no
+	),
+	Ancestors = clique_ancestors_to_html(Deep, Fields, MaybeAncestorLimit,
+		AncestorLimit, RespectLimit, CliquePtr),
 	deep_lookup_clique_members(Deep, CliquePtr, PDPtrs),
 	list__foldl(group_proc_dynamics_by_proc_static(Deep), PDPtrs,
 		map__init, PStoPDsMap),
@@ -596,8 +622,8 @@
 		PStoPDsList = PStoPDsList0
 	),
 
-	PDsStrs = list__map(procs_in_clique_to_html(Deep, Fields, CliquePtr),
-		PStoPDsList),
+	PDsStrs = list__map(procs_in_clique_to_html(Deep, Fields,
+		MaybeAncestorLimit, CliquePtr), PStoPDsList),
 	string__append_list(PDsStrs, ProcGroups),
 	HTML =
 		Ancestors ++
@@ -611,23 +637,29 @@
 proc_group_contains(EntryPDPtr, _ - PDPtrs) :-
 	list__member(EntryPDPtr, PDPtrs).
 
-:- func clique_ancestors_to_html(deep, fields, clique_ptr) = string.
+:- func clique_ancestors_to_html(deep, fields, maybe(int), int, bool,
+	clique_ptr) = string.
 
-clique_ancestors_to_html(Deep, Fields, CliquePtr) = HTML :-
+clique_ancestors_to_html(Deep, Fields, OrigMaybeAncestorLimit,
+		AncestorLimit, RespectLimit, CliquePtr) = HTML :-
 	deep_lookup_clique_index(Deep, Deep ^ root, RootCliquePtr),
 	( CliquePtr = RootCliquePtr ->
 		HTML = ""
+	; RespectLimit = yes, AncestorLimit =< 0 ->
+		HTML = "<TR><TD>..."
 	;
 		deep_lookup_clique_parents(Deep, CliquePtr, EntryCSDPtr),
 		ThisHTML = call_site_dynamic_to_html(Deep, Fields,
-			call_site_line_number, no, EntryCSDPtr),
+			OrigMaybeAncestorLimit, call_site_line_number,
+			no, EntryCSDPtr),
 		deep_lookup_call_site_dynamics(Deep, EntryCSDPtr, EntryCSD),
 		EntryPDPtr = EntryCSD ^ csd_caller,
 		require(valid_proc_dynamic_ptr(Deep, EntryPDPtr),
 			"clique_ancestors_to_html: invalid proc_dynamic"),
 		deep_lookup_clique_index(Deep, EntryPDPtr, EntryCliquePtr),
 		AncestorHTML = clique_ancestors_to_html(Deep, Fields,
-			EntryCliquePtr),
+			OrigMaybeAncestorLimit,
+			AncestorLimit - 1, RespectLimit, EntryCliquePtr),
 		HTML =
 			AncestorHTML ++
 			ThisHTML
@@ -649,14 +681,16 @@
 		map__det_insert(PStoPDsMap0, PSPtr, [PDPtr], PStoPDsMap)
 	).
 
-:- func procs_in_clique_to_html(deep, fields, clique_ptr,
+:- func procs_in_clique_to_html(deep, fields, maybe(int), clique_ptr,
 	pair(proc_static_ptr, list(proc_dynamic_ptr))) = string.
 
-procs_in_clique_to_html(Deep, Fields, CliquePtr, PSPtr - PDPtrs) = HTML :-
+procs_in_clique_to_html(Deep, Fields, OrigMaybeAncestorLimit, CliquePtr,
+		PSPtr - PDPtrs) = HTML :-
 	( PDPtrs = [] ->
 		HTML = ""
 	; PDPtrs = [PDPtr] ->
-		HTML = proc_in_clique_to_html(Deep, Fields, CliquePtr, PDPtr)
+		HTML = proc_in_clique_to_html(Deep, Fields,
+			OrigMaybeAncestorLimit, CliquePtr, PDPtr)
 	;
 		Separator = separator_row(Fields),
 		list__map(deep_lookup_pd_own(Deep), PDPtrs, ProcOwns),
@@ -666,7 +700,7 @@
 		ProcTotal = proc_total_in_clique(Deep, Fields,
 			PSPtr, no, ProcOwn, ProcDesc),
 		ComponentHTMLs = list__map(proc_in_clique_to_html(Deep, Fields,
-			CliquePtr), PDPtrs),
+			OrigMaybeAncestorLimit, CliquePtr), PDPtrs),
 		string__append_list(ComponentHTMLs, ComponentHTML),
 		HTML =
 			Separator ++
@@ -675,10 +709,11 @@
 			ComponentHTML
 	).
 
-:- func proc_in_clique_to_html(deep, fields, clique_ptr, proc_dynamic_ptr)
-	= string.
+:- func proc_in_clique_to_html(deep, fields, maybe(int), clique_ptr,
+	proc_dynamic_ptr) = string.
 
-proc_in_clique_to_html(Deep, Fields, CliquePtr, PDPtr) = HTML :-
+proc_in_clique_to_html(Deep, Fields, OrigMaybeAncestorLimit, CliquePtr, PDPtr)
+		= HTML :-
 	( valid_proc_dynamic_ptr(Deep, PDPtr) ->
 		InitialSeparator = separator_row(Fields),
 		deep_lookup_pd_own(Deep, PDPtr, ProcOwn),
@@ -689,7 +724,8 @@
 			PSPtr, yes, ProcOwn, ProcDesc),
 		child_call_sites(Deep ^ proc_dynamics, Deep ^ proc_statics,
 			PDPtr, GroupPairs),
-		list__foldl(call_site_group_to_html(Deep, Fields, CliquePtr),
+		list__foldl(call_site_group_to_html(Deep, Fields,
+			OrigMaybeAncestorLimit, CliquePtr),
 			GroupPairs, map__init, GroupMap),
 		map__to_assoc_list(GroupMap, GroupPairLists),
 		assoc_list__values(GroupPairLists, GroupLists),
@@ -736,18 +772,18 @@
 	),
 	HTML = 
 		"<TR>\n" ++
-		format("<TD COLSPAN=2><B>%s%s</B></TD>\n",
+		string__format("<TD COLSPAN=2><B>%s%s</B></TD>\n",
 			[s(OnlyStr), s(ProcName)]) ++
 		own_and_desc_to_html(Own, Desc, Deep, Fields) ++
 		"</TR>\n".
 
-:- pred call_site_group_to_html(deep::in, fields::in,
+:- pred call_site_group_to_html(deep::in, fields::in, maybe(int)::in,
 	clique_ptr::in, pair(call_site_static_ptr, call_site_array_slot)::in,
 	map(pair(string, int), list(string))::in,
 	map(pair(string, int), list(string))::out) is det.
 
-call_site_group_to_html(Deep, Fields, ThisCliquePtr, Pair,
-		GroupMap0, GroupMap) :-
+call_site_group_to_html(Deep, Fields, OrigMaybeAncestorLimit, ThisCliquePtr,
+		Pair, GroupMap0, GroupMap) :-
 	Pair = CSSPtr - CallSiteArray,
 	deep_lookup_call_site_statics(Deep, CSSPtr, CSS),
 	CSS = call_site_static(PSPtr, _SlotNum, Kind, LineNumber, _GoalPath),
@@ -760,7 +796,8 @@
 			error("call_site_group_to_html: normal_call error")
 		),
 		HTML = maybe_call_site_dynamic_to_html(Deep, Fields,
-			call_site_line_number, ThisCliquePtr, CSDPtr)
+			OrigMaybeAncestorLimit, call_site_line_number,
+			ThisCliquePtr, CSDPtr)
 	;
 		( CallSiteArray = multi(CSDPtrs0) ->
 			array__to_list(CSDPtrs0, CSDPtrs)
@@ -769,8 +806,8 @@
 		),
 		Tuple0 = { "", zero_own_prof_info, zero_inherit_prof_info },
 		Tuple = list__foldl(call_site_array_to_html(Deep, Fields,
-			no_call_site_line_number, ThisCliquePtr),
-			CSDPtrs, Tuple0),
+			OrigMaybeAncestorLimit, no_call_site_line_number,
+			ThisCliquePtr), CSDPtrs, Tuple0),
 		Tuple = { GroupHTML, SumOwn, SumDesc },
 		CallSiteName0 = call_site_kind_and_callee_to_html(Kind),
 		( GroupHTML = "" ->
@@ -780,9 +817,9 @@
 		),
 		HTML =
 			"<TR>\n" ++
-			format("<TD>%s:%d</TD>\n",
+			string__format("<TD>%s:%d</TD>\n",
 				[s(FileName), i(LineNumber)]) ++
-			format("<TD>%s</TD>\n", [s(CallSiteName)]) ++
+			string__format("<TD>%s</TD>\n", [s(CallSiteName)]) ++
 			own_and_desc_to_html(SumOwn, SumDesc, Deep, Fields) ++
 			"</TR>\n" ++
 			GroupHTML
@@ -794,17 +831,19 @@
 		map__det_insert(GroupMap0, Key, [HTML], GroupMap)
 	).
 
-:- func call_site_array_to_html(deep, fields, call_site_line_number,
-	clique_ptr, call_site_dynamic_ptr,
+:- func call_site_array_to_html(deep, fields, maybe(int),
+	call_site_line_number, clique_ptr, call_site_dynamic_ptr,
 	{string, own_prof_info, inherit_prof_info}) =
 	{string, own_prof_info, inherit_prof_info}.
 
-call_site_array_to_html(Deep, Fields, PrintCallSiteLineNmber,
-		ThisCliquePtr, CSDPtr, Tuple0) = Tuple :-
+call_site_array_to_html(Deep, Fields, OrigMaybeAncestorLimit,
+		PrintCallSiteLineNmber, ThisCliquePtr, CSDPtr, Tuple0)
+		= Tuple :-
 	( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
 		Tuple0 = { HTML0, Own0, Desc0 },
 		HTML1 = call_site_dynamic_to_html(Deep, Fields,
-			PrintCallSiteLineNmber, yes(ThisCliquePtr), CSDPtr),
+			OrigMaybeAncestorLimit, PrintCallSiteLineNmber,
+			yes(ThisCliquePtr), CSDPtr),
 		string__append(HTML0, HTML1, HTML),
 		deep_lookup_csd_own(Deep, CSDPtr, CallSiteOwn),
 		deep_lookup_csd_desc(Deep, CSDPtr, CallSiteDesc),
@@ -848,12 +887,13 @@
 	process_call_site_dynamics_group(CSDPtrs, Deep, CalleePSPtr,
 		MaybeToCliquePtr1, MaybeToCliquePtr, Own1, Own, Desc1, Desc).
 
-:- func call_site_dynamics_to_html(deep, fields, maybe(pair(string, int)),
-	clique_ptr, clique_ptr, proc_static_ptr,
+:- func call_site_dynamics_to_html(deep, fields, maybe(int),
+	maybe(pair(string, int)), clique_ptr, clique_ptr, proc_static_ptr,
 	own_prof_info, inherit_prof_info) = string.
 
-call_site_dynamics_to_html(Deep, Fields, MaybeFileNameLineNumber,
-		ThisCliquePtr, ToCliquePtr, PSPtr, Own, Desc) = HTML :-
+call_site_dynamics_to_html(Deep, Fields, OrigMaybeAncestorLimit,
+		MaybeFileNameLineNumber, ThisCliquePtr, ToCliquePtr,
+		PSPtr, Own, Desc) = HTML :-
 	deep_lookup_proc_statics(Deep, PSPtr, PS),
 	CalleeName = PS ^ ps_refined_id,
 	( ThisCliquePtr = ToCliquePtr ->
@@ -862,14 +902,14 @@
 	;
 		ToCliquePtr = clique_ptr(ToCliqueNum),
 		ToCliqueURL = deep_cmd_to_url(Deep,
-			clique(ToCliqueNum, Fields)),
+			clique(ToCliqueNum, Fields, OrigMaybeAncestorLimit)),
 		ProcName =
-			format("<A HREF=""%s"">%s</A>\n",
+			string__format("<A HREF=""%s"">%s</A>\n",
 				[s(ToCliqueURL), s(CalleeName)])
 	),
 	( MaybeFileNameLineNumber = yes(FileName - LineNumber) ->
 		SourceField =
-			format("<TD>%s:%d</TD>\n",
+			string__format("<TD>%s:%d</TD>\n",
 				[s(FileName), i(LineNumber)])
 	;
 		SourceField = "<TD> </TD>\n"
@@ -877,27 +917,29 @@
 	HTML =
 		"<TR>\n" ++
 		SourceField ++
-		format("<TD>%s</TD>\n", [s(ProcName)]) ++
+		string__format("<TD>%s</TD>\n", [s(ProcName)]) ++
 		own_and_desc_to_html(Own, Desc, Deep, Fields) ++
 		"</TR>\n".
 
-:- func maybe_call_site_dynamic_to_html(deep, fields, call_site_line_number,
-	clique_ptr, call_site_dynamic_ptr) = string.
+:- func maybe_call_site_dynamic_to_html(deep, fields, maybe(int),
+	call_site_line_number, clique_ptr, call_site_dynamic_ptr) = string.
 
-maybe_call_site_dynamic_to_html(Deep, Fields, PrintCallSiteLineNmber,
-		ThisCliquePtr, CSDPtr) = HTML :-
+maybe_call_site_dynamic_to_html(Deep, Fields, OrigMaybeAncestorLimit,
+		PrintCallSiteLineNmber, ThisCliquePtr, CSDPtr) = HTML :-
 	( valid_call_site_dynamic_ptr(Deep, CSDPtr) ->
 		HTML = call_site_dynamic_to_html(Deep, Fields,
-			PrintCallSiteLineNmber, yes(ThisCliquePtr), CSDPtr)
+			OrigMaybeAncestorLimit, PrintCallSiteLineNmber,
+			yes(ThisCliquePtr), CSDPtr)
 	;
 		HTML = ""
 	).
 
-:- func call_site_dynamic_to_html(deep, fields, call_site_line_number,
-	maybe(clique_ptr), call_site_dynamic_ptr) = string.
+:- func call_site_dynamic_to_html(deep, fields, maybe(int),
+	call_site_line_number, maybe(clique_ptr), call_site_dynamic_ptr)
+	= string.
 
-call_site_dynamic_to_html(Deep, Fields, PrintCallSiteLineNmber,
-		MaybeThisCliquePtr, CSDPtr) = HTML :-
+call_site_dynamic_to_html(Deep, Fields, OrigMaybeAncestorLimit,
+		PrintCallSiteLineNmber, MaybeThisCliquePtr, CSDPtr) = HTML :-
 	require(valid_call_site_dynamic_ptr(Deep, CSDPtr),
 		"call_site_dynamic_to_html: invalid call_site_dynamic_ptr"),
 	deep_lookup_call_site_dynamics(Deep, CSDPtr, CSD),
@@ -916,9 +958,10 @@
 		;
 			ToCliquePtr = clique_ptr(ToCliqueNum),
 			ToCliqueURL = deep_cmd_to_url(Deep,
-				clique(ToCliqueNum, Fields)),
+				clique(ToCliqueNum, Fields,
+					OrigMaybeAncestorLimit)),
 			ProcName =
-				format("<A HREF=""%s"">%s</A>\n",
+				string__format("<A HREF=""%s"">%s</A>\n",
 					[s(ToCliqueURL), s(CalleeName)])
 		)
 	;
@@ -930,7 +973,7 @@
 		CSS = call_site_static(PSPtr, _, _, LineNumber, _),
 		deep_lookup_proc_statics(Deep, PSPtr, PS),
 		SourceField =
-			format("<TD>%s:%d</TD>\n",
+			string__format("<TD>%s:%d</TD>\n",
 				[s(PS ^ ps_filename), i(LineNumber)])
 	;
 		SourceField = "<TD> </TD>\n"
@@ -938,7 +981,7 @@
 	HTML =
 		"<TR>\n" ++
 		SourceField ++
-		format("<TD>%s</TD>\n", [s(ProcName)]) ++
+		string__format("<TD>%s</TD>\n", [s(ProcName)]) ++
 		own_and_desc_to_html(CallSiteOwn, CallSiteDesc,
 			Deep, Fields) ++
 		"</TR>\n".
@@ -966,7 +1009,7 @@
 	deep_lookup_ps_desc(Deep, PSPtr, Desc),
 	HTML =
 		"<TR>\n" ++
-		format("<TD COLSPAN=2>%s</TD>\n",
+		string__format("<TD COLSPAN=2>%s</TD>\n",
 			[s(proc_static_to_html_ref(Deep, Fields,
 				proc_static_ptr(PSI)))]) ++
 		own_and_desc_to_html(Own, Desc, Deep, Fields) ++
@@ -997,7 +1040,7 @@
 			error("normal call site calls more than one procedure")
 		),
 		MainLineRest =
-			format("<TD>%s</TD>\n",
+			string__format("<TD>%s</TD>\n",
 				[s(CalleePS ^ ps_refined_id)]) ++
 			own_and_desc_to_html(Own, Desc, Deep, Fields),
 		AdditionalLines = ""
@@ -1010,7 +1053,7 @@
 			CallSiteName = CallSiteName0
 		),
 		MainLineRest =
-			format("<TD>%s</TD>\n",
+			string__format("<TD>%s</TD>\n",
 				[s(CallSiteName)]) ++
 			own_and_desc_to_html(Own, Desc, Deep, Fields),
 		CallSiteCallLines = list__map(
@@ -1020,7 +1063,8 @@
 	),
 	HTML =
 		"<TR>\n" ++
-		format("<TD>%s:%d</TD>\n", [s(FileName), i(LineNumber)]) ++
+		string__format("<TD>%s:%d</TD>\n",
+			[s(FileName), i(LineNumber)]) ++
 		MainLineRest ++
 		"</TR>\n" ++
 		AdditionalLines.
@@ -1041,7 +1085,7 @@
 		zero_own_prof_info, Own, zero_inherit_prof_info, Desc),
 	HTML =
 		"<TR>\n" ++
-		format("<TD></TD><TD>%s</TD>\n",
+		string__format("<TD></TD><TD>%s</TD>\n",
 			[s(proc_static_to_html_ref(Deep, Fields, PSPtr))]) ++
 		own_and_desc_to_html(Own, Desc, Deep, Fields) ++
 		"</TR>\n".
@@ -1084,7 +1128,7 @@
 		deep_lookup_proc_statics(Deep, PSPtr, PS),
 		PSPtr = proc_static_ptr(PSI),
 		PSURL = deep_cmd_to_url(Deep, proc(PSI, Fields)),
-		HTML = format("<A HREF=""%s"">%s</A>\n",
+		HTML = string__format("<A HREF=""%s"">%s</A>\n",
 				[s(PSURL), s(PS ^ ps_refined_id)])
 	;
 		HTML =
@@ -1093,33 +1137,51 @@
 
 %-----------------------------------------------------------------------------%
 
+	% The number of ticks per sec to assume if the profiling data file
+	% does not record the actual tick rate.
+:- func default_ticks_per_sec = int.
+
+default_ticks_per_sec = 100.
+
+:- pred lookup_ticks_per_sec(profile_stats::in, int::out, bool::out) is det.
+
+lookup_ticks_per_sec(Stats, TicksPerSec, Assumed) :-
+	TicksPerSec0 = Stats ^ ticks_per_sec,
+	( TicksPerSec0 = 0 ->
+		TicksPerSec = default_ticks_per_sec,
+		Assumed = yes
+	;
+		TicksPerSec = TicksPerSec0,
+		Assumed = no
+	).
+
 :- func quantum_time(deep, int) = string.
 
 quantum_time(Deep, Quanta) = TimeStr :-
-	% Time is in units of milliseconds.
-	TicksPerSec = Deep ^ profile_stats ^ ticks_per_sec,
-	Time = float(Quanta) * 1000.0 / float(TicksPerSec),
-	format("%5.2f", [f(Time)], Str0),
+	lookup_ticks_per_sec(Deep ^ profile_stats, TicksPerSec, _Assumed),
+	% We display Time as seconds, with two digits after the decimal point.
+	% This is the most we can do, given clock granularity.
+	Time = 100.0 * float(Quanta) / float(TicksPerSec),
+	string__format("%d", [i(floor_to_int(Time))], Str0),
 	string__to_char_list(Str0, Chars0),
 	reverse(Chars0, RevChars0),
 	string__from_char_list(reverse(
-		milliseconds_to_seconds(RevChars0)), TimeStr).
+		centiseconds_to_seconds(RevChars0)), TimeStr).
 
 :- func commas(int) = string.
 
 commas(Num) = Str :-
-	format("%d", [i(Num)], Str0),
+	string__format("%d", [i(Num)], Str0),
 	string__to_char_list(Str0, Chars0),
 	reverse(Chars0, RevChars0),
 	string__from_char_list(reverse(add_commas(RevChars0)), Str).
 
-:- func milliseconds_to_seconds(list(char)) = list(char).
+:- func centiseconds_to_seconds(list(char)) = list(char).
 
-milliseconds_to_seconds([]) = ['0', '0', '.', '0'].
-milliseconds_to_seconds([_C]) = ['0', '0', '.', '0'].
-milliseconds_to_seconds([_C, D]) = [D, '0', '.', '0'].
-milliseconds_to_seconds([_C, D, E]) = [D, E, '.', '0'].
-milliseconds_to_seconds([_C, D, E, F | R]) = [D, E, '.' | add_commas([F | R])].
+centiseconds_to_seconds([]) = ['0', '0', '.', '0'].
+centiseconds_to_seconds([D]) = [D, '0', '.', '0'].
+centiseconds_to_seconds([D, E]) = [D, E, '.', '0'].
+centiseconds_to_seconds([D, E, F | R]) = [D, E, '.' | add_commas([F | R])].
 
 :- func add_commas(list(char)) = list(char).
 
@@ -1294,8 +1356,8 @@
 	PSOwn = Deep ^ ps_own,
 	array__lookup(PSOwn, PSI1, Own1),
 	array__lookup(PSOwn, PSI2, Own2),
-	OwnAllocs1 = mallocs(Own1),
-	OwnAllocs2 = mallocs(Own2),
+	OwnAllocs1 = allocs(Own1),
+	OwnAllocs2 = allocs(Own2),
 	compare(Result, OwnAllocs1, OwnAllocs2).
 
 :- pred compare_ps_allocs_both(deep::in, int::in, int::in,
@@ -1308,10 +1370,10 @@
 	array__lookup(PSOwn, PSI2, Own2),
 	array__lookup(PSDesc, PSI1, Desc1),
 	array__lookup(PSDesc, PSI2, Desc2),
-	OwnAllocs1 = mallocs(Own1),
-	OwnAllocs2 = mallocs(Own2),
-	DescAllocs1 = inherit_mallocs(Desc1),
-	DescAllocs2 = inherit_mallocs(Desc2),
+	OwnAllocs1 = allocs(Own1),
+	OwnAllocs2 = allocs(Own2),
+	DescAllocs1 = inherit_allocs(Desc1),
+	DescAllocs2 = inherit_allocs(Desc2),
 	TotalAllocs1 = OwnAllocs1 + DescAllocs1,
 	TotalAllocs2 = OwnAllocs2 + DescAllocs2,
 	compare(Result, TotalAllocs1, TotalAllocs2).
@@ -1382,9 +1444,9 @@
 	array__lookup(PSOwn, PSI, Own),
 	RootOwn = root_own_info(Deep),
 	RootDesc = root_desc_info(Deep),
-	OwnAllocs = mallocs(Own),
-	RootOwnAllocs = mallocs(RootOwn),
-	RootDescAllocs = inherit_mallocs(RootDesc),
+	OwnAllocs = allocs(Own),
+	RootOwnAllocs = allocs(RootOwn),
+	RootDescAllocs = inherit_allocs(RootDesc),
 	RootTotalAllocs = RootOwnAllocs + RootDescAllocs,
 	100.0 * float(OwnAllocs) > Threshold * float(RootTotalAllocs).
 
@@ -1397,10 +1459,10 @@
 	array__lookup(PSDesc, PSI, Desc),
 	RootOwn = root_own_info(Deep),
 	RootDesc = root_desc_info(Deep),
-	OwnAllocs = mallocs(Own),
-	RootOwnAllocs = mallocs(RootOwn),
-	DescAllocs = inherit_mallocs(Desc),
-	RootDescAllocs = inherit_mallocs(RootDesc),
+	OwnAllocs = allocs(Own),
+	RootOwnAllocs = allocs(RootOwn),
+	DescAllocs = inherit_allocs(Desc),
+	RootDescAllocs = inherit_allocs(RootDesc),
 	TotalAllocs = OwnAllocs + DescAllocs,
 	RootTotalAllocs = RootOwnAllocs + RootDescAllocs,
 	100.0 * float(TotalAllocs) > Threshold * float(RootTotalAllocs).
@@ -1440,8 +1502,13 @@
 :- func banner = string.
 
 banner =
+	"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01//EN""\n" ++
+	"""http://www.w3.org/TR/html4/strict.dtd"">\n" ++
 	"<HTML>\n" ++
-	"<TITLE>The University of Melbourne Mercury Deep Profiler.</TITLE>\n".
+	"<HEAD>\n" ++
+	"<TITLE>Page created by the Mercury Deep Profiler.</TITLE>\n" ++
+	"</HEAD>\n" ++
+	"<BODY>\n".
 
 :- func footer(cmd, deep) = string.
 
@@ -1449,42 +1516,123 @@
 	% Link back to root,
 	% Search, etc, etc.
 	HTML =
-		footer_field_select(Cmd, Deep) ++
+		footer_cmd_toggles(Cmd, Deep) ++
 		"<p>\n" ++
-		format("<A HREF=""%s"">Menu</A>\n",
+		string__format("<A HREF=""%s"">Menu</A>\n",
 			[s(deep_cmd_to_url(Deep, menu))]) ++
-		format("<A HREF=""%s"">Quit</A>\n",
+		string__format("<A HREF=""%s"">Quit</A>\n",
 			[s(deep_cmd_to_url(Deep, quit))]) ++
+		"</BODY>\n" ++
 		"</HTML>\n".
 
-:- func footer_field_select(cmd, deep) = string.
+:- func footer_cmd_toggles(cmd, deep) = string.
 
-footer_field_select(quit, _) = "".
-footer_field_select(timeout(_), _) = "".
-footer_field_select(menu, _) = "".
-footer_field_select(root(Fields), Deep) =
+footer_cmd_toggles(quit, _) = "".
+footer_cmd_toggles(timeout(_), _) = "".
+footer_cmd_toggles(menu, _) = "".
+footer_cmd_toggles(root(Fields), Deep) =
 	footer_field_toggle(Deep, Fields,
 		func(ArgFields) = root(ArgFields) :- true).
-footer_field_select(clique(CI, Fields), Deep) =
+footer_cmd_toggles(clique(CI, Fields, MaybeAncestorLimit), Deep) =
 	footer_field_toggle(Deep, Fields,
-		func(ArgFields) = clique(CI, ArgFields) :- true).
-footer_field_select(proc(PSI, Fields), Deep) =
+		func(ArgFields) = clique(CI, ArgFields, MaybeAncestorLimit)
+			:- true) ++
+	"<p>\n" ++
+	footer_ancestor_toggle(Deep, MaybeAncestorLimit,
+		func(ArgMaybeAncestorLimit) =
+			clique(CI, Fields, ArgMaybeAncestorLimit) :- true).
+footer_cmd_toggles(proc(PSI, Fields), Deep) =
 	footer_field_toggle(Deep, Fields,
 		func(ArgFields) = proc(PSI, ArgFields) :- true).
-footer_field_select(top_procs(Sort, InclDesc, Limit, Fields), Deep) =
+footer_cmd_toggles(top_procs(Sort, InclDesc, Limit, Fields), Deep) =
 	footer_field_toggle(Deep, Fields,
 		func(ArgFields) = top_procs(Sort, InclDesc, Limit, ArgFields)
 			:- true).
-footer_field_select(proc_static(_), _) = "".
-footer_field_select(proc_dynamic(_), _) = "".
-footer_field_select(call_site_static(_), _) = "".
-footer_field_select(call_site_dynamic(_), _) = "".
-footer_field_select(raw_clique(_), _) = "".
-footer_field_select(num_proc_statics, _) = "".
-footer_field_select(num_call_site_statics, _) = "".
-footer_field_select(num_proc_dynamics, _) = "".
-footer_field_select(num_call_site_dynamics, _) = "".
+footer_cmd_toggles(proc_static(_), _) = "".
+footer_cmd_toggles(proc_dynamic(_), _) = "".
+footer_cmd_toggles(call_site_static(_), _) = "".
+footer_cmd_toggles(call_site_dynamic(_), _) = "".
+footer_cmd_toggles(raw_clique(_), _) = "".
+footer_cmd_toggles(num_proc_statics, _) = "".
+footer_cmd_toggles(num_call_site_statics, _) = "".
+footer_cmd_toggles(num_proc_dynamics, _) = "".
+footer_cmd_toggles(num_call_site_dynamics, _) = "".
+
+:- func footer_ancestor_toggle(deep, maybe(int), func(maybe(int)) = cmd)
+	= string.
 
+footer_ancestor_toggle(Deep, MaybeAncestorLimit, MakeCmd) = HTML :-
+	(
+		MaybeAncestorLimit = no,
+		Display1 = yes,
+		Display2 = yes,
+		Msg1 = "One ancestor",
+		MaybeAncestorLimit1 = yes(1),
+		Msg2 = "Two ancestors",
+		MaybeAncestorLimit2 = yes(2),
+		Msg3 = "Three ancestors",
+		MaybeAncestorLimit3 = yes(3),
+		Msg4 = "Five ancestors",
+		MaybeAncestorLimit4 = yes(5),
+		Msg5 = "Ten ancestors",
+		MaybeAncestorLimit5 = yes(10)
+	;
+		MaybeAncestorLimit = yes(OldAncestorLimit),
+		( OldAncestorLimit > 2 ->
+			Display1 = yes
+		;
+			Display1 = no
+		),
+		( OldAncestorLimit > 1 ->
+			Display2 = yes
+		;
+			Display2 = no
+		),
+		Msg1 = "Halve ancestors",
+		MaybeAncestorLimit1 = yes(OldAncestorLimit // 2),
+		Msg2 = "Remove an ancestor",
+		MaybeAncestorLimit2 = yes(OldAncestorLimit - 1),
+		Msg3 = "Add an ancestor",
+		MaybeAncestorLimit3 = yes(OldAncestorLimit + 1),
+		Msg4 = "Double ancestors",
+		MaybeAncestorLimit4 = yes(OldAncestorLimit * 2),
+		Msg5 = "Unlimited ancestors",
+		MaybeAncestorLimit5 = no
+	),
+	Cmd1 = MakeCmd(MaybeAncestorLimit1),
+	Cmd2 = MakeCmd(MaybeAncestorLimit2),
+	Cmd3 = MakeCmd(MaybeAncestorLimit3),
+	Cmd4 = MakeCmd(MaybeAncestorLimit4),
+	Cmd5 = MakeCmd(MaybeAncestorLimit5),
+	Toggle1 = string__format("<A HREF=""%s"">%s</A>\n",
+			[s(deep_cmd_to_url(Deep, Cmd1)), s(Msg1)]),
+	Toggle2 = string__format("<A HREF=""%s"">%s</A>\n",
+			[s(deep_cmd_to_url(Deep, Cmd2)), s(Msg2)]),
+	Toggle3 = string__format("<A HREF=""%s"">%s</A>\n",
+			[s(deep_cmd_to_url(Deep, Cmd3)), s(Msg3)]),
+	Toggle4 = string__format("<A HREF=""%s"">%s</A>\n",
+			[s(deep_cmd_to_url(Deep, Cmd4)), s(Msg4)]),
+	Toggle5 = string__format("<A HREF=""%s"">%s</A>\n",
+			[s(deep_cmd_to_url(Deep, Cmd5)), s(Msg5)]),
+	(
+		Display1 = yes,
+		MaybeToggle1 = Toggle1
+	;
+		Display1 = no,
+		MaybeToggle1 = ""
+	),
+	(
+		Display2 = yes,
+		MaybeToggle2 = Toggle2
+	;
+		Display2 = no,
+		MaybeToggle2 = ""
+	),
+	HTML =
+		"<p>\n" ++
+		"Toggle ancestors: " ++
+		MaybeToggle1 ++ MaybeToggle2 ++ Toggle3 ++ Toggle4 ++ Toggle5.
+
 :- func footer_field_toggle(deep, string, func(string) = cmd) = string.
 
 footer_field_toggle(Deep, Fields, MakeCmd) = HTML :-
@@ -1532,15 +1680,15 @@
 	HTML =
 		"<p>\n" ++
 		"Toggle fields: " ++
-		format("<A HREF=""%s"">%s</A>\n",
+		string__format("<A HREF=""%s"">%s</A>\n",
 			[s(deep_cmd_to_url(Deep, CmdPort)), s(PortMsg)]) ++
-		format("<A HREF=""%s"">%s</A>\n",
+		string__format("<A HREF=""%s"">%s</A>\n",
 			[s(deep_cmd_to_url(Deep, CmdQuanta)), s(QuantaMsg)]) ++
-		format("<A HREF=""%s"">%s</A>\n",
+		string__format("<A HREF=""%s"">%s</A>\n",
 			[s(deep_cmd_to_url(Deep, CmdTimes)), s(TimesMsg)]) ++
-		format("<A HREF=""%s"">%s</A>\n",
+		string__format("<A HREF=""%s"">%s</A>\n",
 			[s(deep_cmd_to_url(Deep, CmdAllocs)), s(AllocsMsg)]) ++
-		format("<A HREF=""%s"">%s</A>\n",
+		string__format("<A HREF=""%s"">%s</A>\n",
 			[s(deep_cmd_to_url(Deep, CmdWords)), s(WordsMsg)]).
 
 :- func menu_text = string.
@@ -1551,7 +1699,7 @@
 :- func menu_item(deep, cmd, string) = string.
 
 menu_item(Deep, Cmd, Text) = 
-	format("<A HREF=""%s"">%s</A>\n",
+	string__format("<A HREF=""%s"">%s</A>\n",
 		[s(deep_cmd_to_url(Deep, Cmd)), s(Text)]).
 
 %-----------------------------------------------------------------------------%
@@ -1577,65 +1725,122 @@
 
 :- func fields_header(fields) = string.
 
-fields_header(Fields) =
-	"<TR>\n" ++
-	"<TD>Source</TD>\n" ++
-	"<TD>Procedure</TD>\n" ++
+fields_header(Fields) = HTML :-
+	Groups0 = "<COLGROUP>\n" ++
+		"<COL ALIGN=LEFT>\n" ++
+		"<COL ALIGN=LEFT>\n",
+	FirstRow0 = "<TR>\n" ++
+		"<TH ALIGN=LEFT ROWSPAN=2>Source\n" ++
+		"<TH ALIGN=LEFT ROWSPAN=2>Procedure\n",
+	SecondRow0 = "<TR>\n",
 	( show_port_counts(Fields) ->
-		"<TD ALIGN=RIGHT>Calls</TD>\n" ++
-		"<TD ALIGN=RIGHT>Exits</TD>\n" ++
-		"<TD ALIGN=RIGHT>Fails</TD>\n" ++
-		"<TD ALIGN=RIGHT>Redos</TD>\n"
-	;
-		""
-	) ++
-	( show_quanta(Fields) ->
-		"<TD ALIGN=RIGHT>Self quanta</TD>\n"
-	;
-		""
-	) ++
-	( show_times(Fields) ->
-		"<TD ALIGN=RIGHT>Self time</TD>\n"
-	;
-		""
-	) ++
-	( (show_quanta(Fields) ; show_times(Fields)) ->
-		"<TD ALIGN=RIGHT>% of root</TD>\n"
-	;
-		""
-	) ++
-	( show_quanta(Fields) ->
-		"<TD ALIGN=RIGHT>Total quanta</TD>\n"
-	;
-		""
-	) ++
-	( show_times(Fields) ->
-		"<TD ALIGN=RIGHT>Total time</TD>\n"
-	;
-		""
-	) ++
-	( (show_quanta(Fields) ; show_times(Fields)) ->
-		"<TD ALIGN=RIGHT>% of root</TD>\n"
-	;
-		""
-	) ++
+		Groups1 = Groups0 ++
+			"<COLGROUP>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n",
+		FirstRow1 = FirstRow0 ++
+			"<TH COLSPAN=4>Port counts\n",
+		SecondRow1 = SecondRow0 ++
+			"<TH ALIGN=RIGHT>Calls\n" ++
+			"<TH ALIGN=RIGHT>Exits\n" ++
+			"<TH ALIGN=RIGHT>Fails\n" ++
+			"<TH ALIGN=RIGHT>Redos\n"
+	;
+		Groups1 = Groups0,
+		FirstRow1 = FirstRow0,
+		SecondRow1 = SecondRow0
+	),
+	( show_quanta(Fields), show_times(Fields) ->
+		Groups2 = Groups1 ++
+			"<COLGROUP>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n",
+		FirstRow2 = FirstRow1 ++
+			"<TH COLSPAN=6>Clock ticks and times\n",
+		SecondRow2 = SecondRow1 ++
+			"<TH ALIGN=RIGHT ROWSPAN=2>Self\n" ++
+			"<TH ALIGN=RIGHT>%\n" ++
+			"<TH ALIGN=RIGHT ROWSPAN=2>Total\n" ++
+			"<TH ALIGN=RIGHT>%\n"
+	; show_quanta(Fields) ->
+		Groups2 = Groups1 ++
+			"<COLGROUP>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n",
+		FirstRow2 = FirstRow1 ++
+			"<TH COLSPAN=4>Clock ticks\n",
+		SecondRow2 = SecondRow1 ++
+			"<TH ALIGN=RIGHT>Self\n" ++
+			"<TH ALIGN=RIGHT>%\n" ++
+			"<TH ALIGN=RIGHT>Total\n" ++
+			"<TH ALIGN=RIGHT>%\n"
+	; show_times(Fields) ->
+		Groups2 = Groups1 ++
+			"<COLGROUP>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n",
+		FirstRow2 = FirstRow1 ++
+			"<TH COLSPAN=4>Time\n",
+		SecondRow2 = SecondRow1 ++
+			"<TH ALIGN=RIGHT>Self\n" ++
+			"<TH ALIGN=RIGHT>%\n" ++
+			"<TH ALIGN=RIGHT>Total\n" ++
+			"<TH ALIGN=RIGHT>%\n"
+	;
+		Groups2 = Groups1,
+		FirstRow2 = FirstRow1,
+		SecondRow2 = SecondRow1
+	),
 	( show_allocs(Fields) ->
-		"<TD ALIGN=RIGHT>Self allocs</TD>\n" ++
-		"<TD ALIGN=RIGHT>% of root</TD>\n" ++
-		"<TD ALIGN=RIGHT>Total allocs</TD>\n" ++
-		"<TD ALIGN=RIGHT>% of root</TD>\n"
-	;
-		""
-	) ++
+		Groups3 = Groups2 ++
+			"<COLGROUP>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n",
+		FirstRow3 = FirstRow2 ++
+			"<TH COLSPAN=4>Memory allocations\n",
+		SecondRow3 = SecondRow2 ++
+			"<TH ALIGN=RIGHT>Self\n" ++
+			"<TH ALIGN=RIGHT>%\n" ++
+			"<TH ALIGN=RIGHT>Total\n" ++
+			"<TH ALIGN=RIGHT>%\n"
+	;
+		Groups3 = Groups2,
+		FirstRow3 = FirstRow2,
+		SecondRow3 = SecondRow2
+	),
 	( show_words(Fields) ->
-		"<TD ALIGN=RIGHT>Self words</TD>\n" ++
-		"<TD ALIGN=RIGHT>% of root</TD>\n" ++
-		"<TD ALIGN=RIGHT>Total words</TD>\n" ++
-		"<TD ALIGN=RIGHT>% of root</TD>\n"
-	;
-		""
-	) ++
-	"</TR>\n".
+		Groups4 = Groups3 ++
+			"<COLGROUP>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n" ++
+			"<COL ALIGN=RIGHT>\n",
+		FirstRow4 = FirstRow3 ++
+			"<TH COLSPAN=4>Memory words\n",
+		SecondRow4 = SecondRow3 ++
+			"<TH ALIGN=RIGHT>Self\n" ++
+			"<TH ALIGN=RIGHT>%\n" ++
+			"<TH ALIGN=RIGHT>Total\n" ++
+			"<TH ALIGN=RIGHT>%\n"
+	;
+		Groups4 = Groups3,
+		FirstRow4 = FirstRow3,
+		SecondRow4 = SecondRow3
+	),
+	HTML = Groups4 ++ "<THEAD>\n" ++
+		FirstRow4 ++ SecondRow4 ++ "<TBODY>\n".
 
 :- func separator_row(fields) = string.
 
@@ -1692,9 +1897,9 @@
 	OwnQuantaProp = percentage(OwnQuanta, RootQuanta),
 	TotalQuantaProp = percentage(TotalQuanta, RootQuanta),
 
-	OwnAllocs = mallocs(Own),
-	TotalAllocs = inherit_mallocs(OwnPlusDesc),
-	RootAllocs = inherit_mallocs(Root),
+	OwnAllocs = allocs(Own),
+	TotalAllocs = inherit_allocs(OwnPlusDesc),
+	RootAllocs = inherit_allocs(Root),
 	OwnAllocProp = percentage(OwnAllocs, RootAllocs),
 	TotalAllocProp = percentage(TotalAllocs, RootAllocs),
 
@@ -1706,73 +1911,73 @@
 
 	HTML =
 		( show_port_counts(Fields) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(Calls))]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(Exits))]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(Fails))]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(Redos))])
 		;
 			""
 		) ++
 		( show_quanta(Fields) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(OwnQuanta))])
 		;
 			""
 		) ++
 		( show_times(Fields) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(quantum_time(Deep, OwnQuanta))])
 		;
 			""
 		) ++
 		( (show_quanta(Fields) ; show_times(Fields)) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(OwnQuantaProp)])
 		;
 			""
 		) ++
 		( show_quanta(Fields) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(TotalQuanta))])
 		;
 			""
 		) ++
 		( show_times(Fields) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(quantum_time(Deep, TotalQuanta))])
 		;
 			""
 		) ++
 		( (show_quanta(Fields) ; show_times(Fields)) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(TotalQuantaProp)])
 		;
 			""
 		) ++
 		( show_allocs(Fields) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(OwnAllocs))]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(OwnAllocProp)]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(TotalAllocs))]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(TotalAllocProp)])
 		;
 			""
 		) ++
 		( show_words(Fields) ->
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(OwnWords))]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(OwnWordProp)]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(commas(TotalWords))]) ++
-			format("<TD ALIGN=RIGHT>%s</TD>\n",
+			string__format("<TD ALIGN=RIGHT>%s</TD>\n",
 				[s(TotalWordProp)])
 		;
 			""
@@ -1785,7 +1990,7 @@
 		PercentageStr = "N/A"
 	;
 		Percentage = 100.0 * float(Fraction) / float(Whole),
-		PercentageStr = string__format("%4.2f", [f(Percentage)])
+		PercentageStr = string__format("%5.2f", [f(Percentage)])
 	).
 
 :- func deep_cmd_to_url(deep, cmd) = string.
Index: startup.m
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/startup.m,v
retrieving revision 1.1
diff -u -b -r1.1 startup.m
--- startup.m	2001/05/31 05:59:59	1.1
+++ startup.m	2001/06/04 09:42:06
@@ -26,8 +26,9 @@
 :- implementation.
 
 :- import_module unsafe.
-:- import_module profile, read_profile, cliques, measurements, array_util.
-:- import_module std_util, int, array, assoc_list, set, map, require.
+:- import_module profile, read_profile, callgraph.
+:- import_module measurements, array_util.
+:- import_module std_util, int, string, array, assoc_list, set, map, require.
 
 read_and_startup(Machine, DataFileNames, CanonicalClique, Res) -->
 	(
@@ -43,9 +44,9 @@
 		io__write_string(StdErr, "  Done.\n"),
 		io__report_stats,
 		(
-			{ Res0 = ok(InitialDeep) },
+			{ Res0 = ok(InitDeep) },
 			startup(Machine, DataFileName, CanonicalClique,
-				InitialDeep, Deep),
+				InitDeep, Deep),
 			{ Res = ok(Deep) }
 		;
 			{ Res0 = error(Error) },
@@ -59,78 +60,67 @@
 :- pred startup(string::in, string::in, bool::in, initial_deep::in, deep::out,
 	io__state::di, io__state::uo) is det.
 
-startup(Machine, DataFileName, CanonicalClique, InitialDeep0, Deep) -->
+startup(Machine, DataFileName, _CanonicalClique, InitDeep0, Deep) -->
 	stderr_stream(StdErr),
 
-	{ InitialDeep0 = initial_deep(InitStats, Root,
+	{ InitDeep0 = initial_deep(InitStats, Root,
 		CallSiteDynamics0, ProcDynamics,
 		CallSiteStatics0, ProcStatics) },
 
-	format(StdErr,
+	io__format(StdErr,
 		"  Mapping static call sites to containing procedures...\n",
 		[]),
-	{ array_foldl(record_css_containers, ProcStatics,
+	{ array_foldl_from_1(record_css_containers, ProcStatics,
 		u(CallSiteStatics0), CallSiteStatics) },
-	format(StdErr, "  Done.\n", []),
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats,
 
-	format(StdErr,
+	io__format(StdErr,
 		"  Mapping dynamic call sites to containing procedures...\n",
 		[]),
-	{ array_foldl(record_csd_containers, ProcDynamics,
+	{ array_foldl_from_1(record_csd_containers, ProcDynamics,
 		u(CallSiteDynamics0), CallSiteDynamics) },
-	format(StdErr, "  Done.\n", []),
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats,
 
-	{ InitialDeep1 = initial_deep(InitStats, Root,
+	{ InitDeep1 = initial_deep(InitStats, Root,
 		CallSiteDynamics, ProcDynamics,
 		CallSiteStatics, ProcStatics) },
 
-	find_cliques(InitialDeep1, CliqueList0),
-	(
-		{ CanonicalClique = no },
-		{ InitialDeep = InitialDeep1 },
-		{ CliqueList = CliqueList0 }
-	;
-		{ CanonicalClique = yes },
-		format(StdErr, "  Canonicalizing cliques...\n", []),
-		{ merge_cliques(CliqueList0, InitialDeep1, InitialDeep) },
-		io__report_stats,
-
-		find_cliques(InitialDeep, CliqueList)
-	),
-
-	format(StdErr, "  Constructing clique indexes...\n", []),
-	flush_output(StdErr),
+	{ InitDeep = InitDeep1 },
+%	(
+%		{ CanonicalClique = no },
+%		{ InitDeep = InitDeep1 }
+%	;
+%		{ CanonicalClique = yes },
+%		io__format(StdErr, "  Canonicalizing cliques...\n", []),
+%		{ canonicalize_cliques(InitDeep1, InitDeep) },
+%		io__format(StdErr, "  Done.\n", []),
+%		io__report_stats
+%	),
 
-	{ Cliques = array(CliqueList) },
-
-	{ array__max(ProcDynamics, PDMax) },
+	{ array__max(InitDeep ^ init_proc_dynamics, PDMax) },
 	{ NPDs = PDMax + 1 },
-	{ array__max(CallSiteDynamics, CSDMax) },
+	{ array__max(InitDeep ^ init_call_site_dynamics, CSDMax) },
 	{ NCSDs = CSDMax + 1 },
-	{ array__max(ProcStatics, PSMax) },
+	{ array__max(InitDeep ^ init_proc_statics, PSMax) },
 	{ NPSs = PSMax + 1 },
-	{ array__max(CallSiteStatics, CSSMax) },
+	{ array__max(InitDeep ^ init_call_site_statics, CSSMax) },
 	{ NCSSs = CSSMax + 1 },
 
-	{ array__init(NPDs, clique_ptr(-1), CliqueIndex0) },
+	io__format(StdErr, "  Finding cliques...\n", []),
+	flush_output(StdErr),
+	{ find_cliques(InitDeep, CliqueList) },
+	io__format(StdErr, "  Done.\n", []),
+	io__report_stats,
 
-		% For each clique, add entries in an array
-		% that maps from each clique member (ProcDynamic)
-		% back to the clique to which it belongs.
-	{ array_foldl((pred(CliqueN::in, CliqueMembers::in,
-				I0::array_di, I::array_uo) is det :-
-		array_list_foldl((pred(X::in, I1::array_di, I2::array_uo)
-				is det :-
-			X = proc_dynamic_ptr(Y),
-			array__set(I1, Y, clique_ptr(CliqueN), I2)
-		), CliqueMembers, I0, I)
-	), Cliques, CliqueIndex0, CliqueIndex) },
-	format(StdErr, "  Done.\n", []),
+	io__format(StdErr, "  Constructing clique indexes...\n", []),
+	flush_output(StdErr),
+	{ make_clique_indexes(NPDs, CliqueList, Cliques, CliqueIndex) },
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats,
 
-	format(StdErr, "  Constructing clique parent map...\n", []),
+	io__format(StdErr, "  Constructing clique parent map...\n", []),
 
 		% For each CallSiteDynamic pointer, if it points to
 		% a ProcDynamic which is in a different clique to
@@ -143,40 +133,40 @@
 	{ NCliques = CliqueMax + 1 },
 	{ array__init(NCliques, call_site_dynamic_ptr(-1), CliqueParents0) },
 	{ array__init(NCSDs, no, CliqueMaybeChildren0) },
-	{ array_foldl2(construct_clique_parents(InitialDeep, CliqueIndex),
+	{ array_foldl2_from_1(construct_clique_parents(InitDeep, CliqueIndex),
 		CliqueIndex,
 		CliqueParents0, CliqueParents,
 		CliqueMaybeChildren0, CliqueMaybeChildren) },
 
-	format(StdErr, "  Done.\n", []),
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats,
 
-	format(StdErr, "  Finding procedure callers...\n", []),
+	io__format(StdErr, "  Finding procedure callers...\n", []),
 	{ array__init(NPSs, [], ProcCallers0) },
-	{ array_foldl(construct_proc_callers(InitialDeep), CallSiteDynamics,
-		ProcCallers0, ProcCallers) },
-	format(StdErr, "  Done.\n", []),
+	{ array_foldl_from_1(construct_proc_callers(InitDeep),
+		CallSiteDynamics, ProcCallers0, ProcCallers) },
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats,
 
-	format(StdErr, "  Constructing call site static map...\n", []),
+	io__format(StdErr, "  Constructing call site static map...\n", []),
 	{ array__init(NCSDs, call_site_static_ptr(-1), CallSiteStaticMap0) },
-	{ array_foldl(construct_call_site_caller(InitialDeep), ProcDynamics,
-		CallSiteStaticMap0, CallSiteStaticMap) },
-	format(StdErr, "  Done.\n", []),
+	{ array_foldl_from_1(construct_call_site_caller(InitDeep),
+		ProcDynamics, CallSiteStaticMap0, CallSiteStaticMap) },
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats,
 
-	format(StdErr, "  Finding call site calls...\n", []),
+	io__format(StdErr, "  Finding call site calls...\n", []),
 	{ array__init(NCSSs, map__init, CallSiteCalls0) },
-	{ array_foldl(construct_call_site_calls(InitialDeep), ProcDynamics,
-		CallSiteCalls0, CallSiteCalls) },
-	format(StdErr, "  Done.\n", []),
+	{ array_foldl_from_1(construct_call_site_calls(InitDeep),
+		ProcDynamics, CallSiteCalls0, CallSiteCalls) },
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats,
 
-	format(StdErr, "  Propagating time up call graph...\n", []),
+	io__format(StdErr, "  Propagating time up call graph...\n", []),
 
 	{ array__init(NCSDs, zero_inherit_prof_info, CSDDesc0) },
 	{ array__init(NPDs, zero_own_prof_info, PDOwn0) },
-	{ array_foldl(sum_call_sites_in_proc_dynamic,
+	{ array_foldl_from_1(sum_call_sites_in_proc_dynamic,
 		CallSiteDynamics, PDOwn0, PDOwn) },
 	{ array__init(NPDs, zero_inherit_prof_info, PDDesc0) },
 	{ array__init(NPSs, zero_own_prof_info, PSOwn0) },
@@ -191,94 +181,23 @@
 		PDOwn, PDDesc0, CSDDesc0,
 		PSOwn0, PSDesc0, CSSOwn0, CSSDesc0) },
 
-	{ array_foldl(propagate_to_clique, Cliques, Deep0, Deep1) },
-	format(StdErr, "  Done.\n", []),
+	{ array_foldl_from_1(propagate_to_clique, Cliques, Deep0, Deep1) },
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats,
 
-	format(StdErr, "  Summarizing information...\n", []),
+	io__format(StdErr, "  Summarizing information...\n", []),
 	{ summarize_proc_dynamics(Deep1, Deep2) },
 	{ summarize_call_site_dynamics(Deep2, Deep) },
-	format(StdErr, "  Done.\n", []),
+	io__format(StdErr, "  Done.\n", []),
 	io__report_stats.
-
-:- pred find_cliques(initial_deep::in, list(list(proc_dynamic_ptr))::out,
-	io__state::di, io__state::uo) is det.
 
-find_cliques(InitialDeep, CliqueList) -->
-	stderr_stream(StdErr),
-	format(StdErr, "  Constructing graph...\n", []),
-	make_graph(InitialDeep, Graph),
-	format(StdErr, "  Done.\n", []),
-	io__report_stats,
-
-	format(StdErr, "  Constructing cliques...\n", []),
-	{ topological_sort(Graph, CliqueList0) },
+:- pred count_quanta(int::in, call_site_dynamic::in, int::in, int::out) is det.
 
-		% Turn each of the sets into a list.
-		% (We use foldl here because the list may be very
-		% long and map runs out of stack space, and we
-		% want the final list in reverse order anyway.)
-	{ list__foldl((pred(Set::in, L0::in, L::out) is det :-
-		set__to_sorted_list(Set, List0),
-		map((pred(PDI::in, PDPtr::out) is det :-
-			PDPtr = proc_dynamic_ptr(PDI)
-		), List0, List),
-		L = [List | L0]
-	), CliqueList0, [], CliqueList) },
-		% It's actually more convenient to have the list in
-		% reverse order so that foldl works from the bottom
-		% of the tsort to the top, so that we can use it to
-		% do the propagation simply.
-	format(StdErr, "  Done.\n", []),
-	io__report_stats.
+count_quanta(_N, CSD, Quanta0, Quanta) :-
+	Quanta = Quanta0 + quanta(CSD ^ csd_own_prof).
 
 %-----------------------------------------------------------------------------%
 
-:- pred make_graph(initial_deep::in, graph::out,
-	io__state::di, io__state::uo) is det.
-
-make_graph(InitialDeep, Graph) -->
-	{ init(Graph0) },
-	array_foldl2((pred(PDI::in, PD::in, G1::in, G2::out, di, uo) is det -->
-		{ From = PDI },
-		{ CallSiteRefArray = PD ^ pd_sites },
-	        { array__to_list(CallSiteRefArray, CallSiteRefList) },
-	        list__foldl2((pred(CSR::in, G5::in, G6::out, di, uo) is det -->
-		    (
-			{ CSR = normal(call_site_dynamic_ptr(CSDI)) },
-			( { CSDI > 0 } ->
-				{ array__lookup(
-					InitialDeep ^ init_call_site_dynamics,
-					CSDI, CSD) },
-				{ CPDPtr = CSD ^ csd_callee },
-				{ CPDPtr = proc_dynamic_ptr(To) },
-				{ add_arc(G5, From, To, G6) }
-			;
-				{ G6 = G5 }
-			)
-		    ;
-			{ CSR = multi(CallSiteArray) },
-			{ array__to_list(CallSiteArray, CallSites) },
-			list__foldl2((pred(CSDPtr1::in, G7::in, G8::out,
-					di, uo) is det -->
-			    { CSDPtr1 = call_site_dynamic_ptr(CSDI) },
-			    ( { CSDI > 0 } ->
-			    	{ array__lookup(
-					InitialDeep ^ init_call_site_dynamics,
-					CSDI, CSD) },
-				{ CPDPtr = CSD ^ csd_callee },
-			    	{ CPDPtr = proc_dynamic_ptr(To) },
-			    	{ add_arc(G7, From, To, G8) }
-			    ;
-			    	{ G8 = G7 }
-			    )
-			), CallSites, G5, G6)
-		    )
-	        ), CallSiteRefList, G1, G2)
-	), InitialDeep ^ init_proc_dynamics, Graph0, Graph).
-
-%-----------------------------------------------------------------------------%
-
 :- pred record_css_containers(int::in, proc_static::in,
 	array(call_site_static)::array_di,
 	array(call_site_static)::array_uo) is det.
@@ -338,11 +257,10 @@
 record_csd_containers_2(PDPtr, [CSDPtr | CSDPtrs],
 		CallSiteDynamics0, CallSiteDynamics) :-
 	lookup_call_site_dynamics(CallSiteDynamics0, CSDPtr, CSD0),
-	CSD0 = call_site_dynamic(CallerPDPtr0, CalleePDPtr, Own,
-		MaybeRedirect),
+	CSD0 = call_site_dynamic(CallerPDPtr0, CalleePDPtr, Own),
 	require(unify(CallerPDPtr0, proc_dynamic_ptr(-1)),
 		"record_csd_containers_2: real proc_dynamic_ptr"),
-	CSD = call_site_dynamic(PDPtr, CalleePDPtr, Own, MaybeRedirect),
+	CSD = call_site_dynamic(PDPtr, CalleePDPtr, Own),
 	update_call_site_dynamics(CallSiteDynamics0, CSDPtr, CSD,
 		CallSiteDynamics1),
 	record_csd_containers_2(PDPtr, CSDPtrs,
@@ -357,14 +275,14 @@
 	array(maybe(clique_ptr))::array_di,
 	array(maybe(clique_ptr))::array_uo) is det.
 
-construct_clique_parents(InitialDeep, CliqueIndex, PDI, CliquePtr,
+construct_clique_parents(InitDeep, CliqueIndex, PDI, CliquePtr,
 		CliqueParents0, CliqueParents,
 		CliqueMaybeChildren0, CliqueMaybeChildren) :-
 	( PDI > 0 ->
-		flat_call_sites(InitialDeep ^ init_proc_dynamics,
+		flat_call_sites(InitDeep ^ init_proc_dynamics,
 			proc_dynamic_ptr(PDI), CSDPtrs),
 		array_list_foldl2(
-			construct_clique_parents_2(InitialDeep,
+			construct_clique_parents_2(InitDeep,
 				CliqueIndex, CliquePtr),
 			CSDPtrs, CliqueParents0, CliqueParents,
 			CliqueMaybeChildren0, CliqueMaybeChildren)
@@ -379,13 +297,12 @@
 	array(maybe(clique_ptr))::array_di,
 	array(maybe(clique_ptr))::array_uo) is det.
 
-construct_clique_parents_2(InitialDeep, CliqueIndex, ParentCliquePtr, CSDPtr,
+construct_clique_parents_2(InitDeep, CliqueIndex, ParentCliquePtr, CSDPtr,
 		CliqueParents0, CliqueParents,
 		CliqueMaybeChildren0, CliqueMaybeChildren) :-
 	CSDPtr = call_site_dynamic_ptr(CSDI),
 	( CSDI > 0 ->
-		array__lookup(InitialDeep ^ init_call_site_dynamics, CSDI,
-			CSD),
+		array__lookup(InitDeep ^ init_call_site_dynamics, CSDI, CSD),
 		ChildPDPtr = CSD ^ csd_callee,
 		ChildPDPtr = proc_dynamic_ptr(ChildPDI),
 		( ChildPDI > 0 ->
@@ -454,11 +371,11 @@
 	array(list(call_site_dynamic_ptr))::array_di,
 	array(list(call_site_dynamic_ptr))::array_uo) is det.
 
-construct_proc_callers(InitialDeep, CSDI, CSD, ProcCallers0, ProcCallers) :-
+construct_proc_callers(InitDeep, CSDI, CSD, ProcCallers0, ProcCallers) :-
 	PDPtr = CSD ^ csd_callee,
 	PDPtr = proc_dynamic_ptr(PDI),
-	( PDI > 0, array__in_bounds(InitialDeep ^ init_proc_dynamics, PDI) ->
-		array__lookup(InitialDeep ^ init_proc_dynamics, PDI, PD),
+	( PDI > 0, array__in_bounds(InitDeep ^ init_proc_dynamics, PDI) ->
+		array__lookup(InitDeep ^ init_proc_dynamics, PDI, PD),
 		PSPtr = PD ^ pd_proc_static,
 		PSPtr = proc_static_ptr(PSI),
 		array__lookup(ProcCallers0, PSI, Callers0),
@@ -472,16 +389,16 @@
 	array(call_site_static_ptr)::array_di,
 	array(call_site_static_ptr)::array_uo) is det.
 
-construct_call_site_caller(InitialDeep, _PDI, PD,
+construct_call_site_caller(InitDeep, _PDI, PD,
 		CallSiteStaticMap0, CallSiteStaticMap) :-
 	PSPtr = PD ^ pd_proc_static,
 	CSDArraySlots = PD ^ pd_sites,
 	PSPtr = proc_static_ptr(PSI),
-	array__lookup(InitialDeep ^ init_proc_statics, PSI, PS),
+	array__lookup(InitDeep ^ init_proc_statics, PSI, PS),
 	PS = proc_static(_, _, _, _, CSSPtrs),
 	array__max(CSDArraySlots, MaxCS),
 	construct_call_site_caller_2(MaxCS,
-		InitialDeep ^ init_call_site_dynamics, CSSPtrs, CSDArraySlots,
+		InitDeep ^ init_call_site_dynamics, CSSPtrs, CSDArraySlots,
 		CallSiteStaticMap0, CallSiteStaticMap).
 
 :- pred construct_call_site_caller_2(int::in, call_site_dynamics::in,
@@ -502,7 +419,7 @@
 
 		;
 			CSDArraySlot = multi(CSDPtrs),
-			array_foldl0(
+			array_foldl_from_0(
 				construct_call_site_caller_3(Deep, CSSPtr),
 				CSDPtrs,
 				CallSiteStaticMap0, CallSiteStaticMap1)
@@ -532,16 +449,15 @@
 	array(map(proc_static_ptr, list(call_site_dynamic_ptr)))::array_uo)
 	is det.
 
-construct_call_site_calls(InitialDeep, _PDI, PD,
-		CallSiteCalls0, CallSiteCalls) :-
+construct_call_site_calls(InitDeep, _PDI, PD, CallSiteCalls0, CallSiteCalls) :-
 	PSPtr = PD ^ pd_proc_static,
 	CSDArraySlots = PD ^ pd_sites,
 	array__max(CSDArraySlots, MaxCS),
 	PSPtr = proc_static_ptr(PSI),
-	array__lookup(InitialDeep ^ init_proc_statics, PSI, PS),
+	array__lookup(InitDeep ^ init_proc_statics, PSI, PS),
 	CSSPtrs = PS ^ ps_sites,
-	CallSiteDynamics = InitialDeep ^ init_call_site_dynamics,
-	ProcDynamics = InitialDeep ^ init_proc_dynamics,
+	CallSiteDynamics = InitDeep ^ init_call_site_dynamics,
+	ProcDynamics = InitDeep ^ init_proc_dynamics,
 	construct_call_site_calls_2(CallSiteDynamics, ProcDynamics, MaxCS,
 		CSSPtrs, CSDArraySlots, CallSiteCalls0, CallSiteCalls).
 
@@ -564,7 +480,7 @@
 				CSDPtr, CallSiteCalls0, CallSiteCalls1)
 		;
 			CSDArraySlot = multi(CSDPtrs),
-			array_foldl0(
+			array_foldl_from_0(
 				construct_call_site_calls_3(CallSiteDynamics,
 					ProcDynamics, CSSPtr),
 				CSDPtrs, CallSiteCalls0, CallSiteCalls1)
@@ -626,7 +542,8 @@
 summarize_proc_dynamics(Deep0, Deep) :-
 	PSOwn0 = Deep0 ^ ps_own,
 	PSDesc0 = Deep0 ^ ps_desc,
-	array_foldl2(summarize_proc_dynamic(Deep0 ^ pd_own, Deep0 ^ pd_desc),
+	array_foldl2_from_1(
+		summarize_proc_dynamic(Deep0 ^ pd_own, Deep0 ^ pd_desc),
 		Deep0 ^ proc_dynamics,
 		copy(PSOwn0), PSOwn, copy(PSDesc0), PSDesc),
 	Deep = ((Deep0
@@ -663,7 +580,8 @@
 summarize_call_site_dynamics(Deep0, Deep) :-
 	CSSOwn0 = Deep0 ^ css_own,
 	CSSDesc0 = Deep0 ^ css_desc,
-	array_foldl2(summarize_call_site_dynamic(Deep0 ^ call_site_static_map,
+	array_foldl2_from_1(
+		summarize_call_site_dynamic(Deep0 ^ call_site_static_map,
 		Deep0 ^ csd_desc),
 		Deep0 ^ call_site_dynamics,
 		copy(CSSOwn0), CSSOwn, copy(CSSDesc0), CSSDesc),
@@ -777,373 +695,3 @@
 	).
 
 %-----------------------------------------------------------------------------%
-
-:- pred merge_cliques(list(list(proc_dynamic_ptr))::in,
-	initial_deep::in, initial_deep::out) is det.
-
-merge_cliques([], InitDeep, InitDeep).
-merge_cliques([Clique | Cliques], InitDeep0, InitDeep) :-
-	merge_clique(Clique, InitDeep0, InitDeep1),
-	merge_cliques(Cliques, InitDeep1, InitDeep).
-
-:- pred merge_clique(list(proc_dynamic_ptr)::in,
-	initial_deep::in, initial_deep::out) is det.
-
-merge_clique(CliquePDs, InitDeep0, InitDeep) :-
-	map__init(ProcMap0),
-	set__list_to_set(CliquePDs, Clique),
-	list__foldl(cluster_pds_by_ps(InitDeep0), CliquePDs,
-		ProcMap0, ProcMap),
-	map__values(ProcMap, PDsList),
-	list__filter(two_or_more, PDsList, ToMergePDsList),
-	list__foldl(merge_proc_dynamics(Clique), ToMergePDsList,
-		InitDeep0, InitDeep).
-
-:- pred merge_proc_dynamics(set(proc_dynamic_ptr)::in,
-	list(proc_dynamic_ptr)::in,
-	initial_deep::in, initial_deep::out) is det.
-
-merge_proc_dynamics(Clique, CandidatePDPtrs, InitDeep0, InitDeep) :-
-	ProcDynamics0 = InitDeep0 ^ init_proc_dynamics,
-	list__filter(valid_proc_dynamic_ptr_raw(ProcDynamics0),
-		CandidatePDPtrs, ValidPDPtrs),
-	( ValidPDPtrs = [PrimePDPtr | RestPDPtrs] ->
-		record_pd_redirect(RestPDPtrs, PrimePDPtr,
-			InitDeep0, InitDeep1),
-		ProcDynamics1 = InitDeep1 ^ init_proc_dynamics,
-		lookup_proc_dynamics(ProcDynamics1, PrimePDPtr, PrimePD0),
-		list__map(lookup_proc_dynamics(ProcDynamics1),
-			RestPDPtrs, RestPDs),
-		list__map(extract_pd_sites, RestPDs, RestSites),
-		require(unify(PrimePD0 ^ pd_redirect, no),
-			"merge_proc_dynamics: pd already redirected"),
-		PrimeSites0 = PrimePD0 ^ pd_sites,
-		array__max(PrimeSites0, MaxSiteNum),
-		merge_proc_dynamic_slots(MaxSiteNum, Clique, PrimePDPtr,
-			u(PrimeSites0), RestSites, PrimeSites,
-			InitDeep1, InitDeep2),
-		PrimePD = PrimePD0 ^ pd_sites := PrimeSites,
-		ProcDynamics2 = InitDeep2 ^ init_proc_dynamics,
-		update_proc_dynamics(u(ProcDynamics2), PrimePDPtr, PrimePD,
-			ProcDynamics),
-		InitDeep = InitDeep2 ^ init_proc_dynamics := ProcDynamics
-	;
-		% This can happen when merging the callees of CSDs
-		% representing special calls.
-		InitDeep = InitDeep0
-	).
-
-:- pred merge_proc_dynamic_slots(int::in, set(proc_dynamic_ptr)::in,
-	proc_dynamic_ptr::in, array(call_site_array_slot)::array_di,
-	list(array(call_site_array_slot))::in,
-	array(call_site_array_slot)::array_uo,
-	initial_deep::in, initial_deep::out) is det.
-
-merge_proc_dynamic_slots(SlotNum, Clique, PrimePDPtr, PrimeSiteArray0,
-		RestSiteArrays, PrimeSiteArray, InitDeep0, InitDeep) :-
-	( SlotNum >= 0 ->
-		array__lookup(PrimeSiteArray0, SlotNum, PrimeSite0),
-		(
-			PrimeSite0 = normal(PrimeCSDPtr0),
-			merge_proc_dynamic_normal_slot(SlotNum, Clique,
-				PrimePDPtr, PrimeCSDPtr0, RestSiteArrays,
-				PrimeCSDPtr, InitDeep0, InitDeep1),
-			array__set(PrimeSiteArray0, SlotNum,
-				normal(PrimeCSDPtr), PrimeSiteArray1)
-		;
-			PrimeSite0 = multi(PrimeCSDPtrArray0),
-			array__to_list(PrimeCSDPtrArray0, PrimeCSDPtrList0),
-			merge_proc_dynamic_multi_slot(SlotNum, Clique,
-				PrimePDPtr, PrimeCSDPtrList0, RestSiteArrays,
-				PrimeCSDPtrList, InitDeep0, InitDeep1),
-			PrimeCSDPtrArray = array(PrimeCSDPtrList),
-			array__set(PrimeSiteArray0, SlotNum,
-				multi(PrimeCSDPtrArray), PrimeSiteArray1)
-		),
-		merge_proc_dynamic_slots(SlotNum - 1, Clique, PrimePDPtr,
-			PrimeSiteArray1, RestSiteArrays, PrimeSiteArray,
-			InitDeep1, InitDeep)
-	;
-		PrimeSiteArray = PrimeSiteArray0,
-		InitDeep = InitDeep0
-	).
-
-:- pred merge_proc_dynamic_normal_slot(int::in, set(proc_dynamic_ptr)::in,
-	proc_dynamic_ptr::in, call_site_dynamic_ptr::in,
-	list(array(call_site_array_slot))::in, call_site_dynamic_ptr::out,
-	initial_deep::in, initial_deep::out) is det.
-
-merge_proc_dynamic_normal_slot(SlotNum, Clique, PrimePDPtr, PrimeCSDPtr0,
-		RestSiteArrays, PrimeCSDPtr, InitDeep0, InitDeep) :-
-	lookup_normal_sites(RestSiteArrays, SlotNum, RestCSDPtrs),
-	merge_call_site_dynamics(Clique, PrimePDPtr,
-		[PrimeCSDPtr0 | RestCSDPtrs], PrimeCSDPtr,
-		InitDeep0, InitDeep).
-
-:- pred accumulate_csd_owns(call_site_dynamic::in,
-	own_prof_info::in, own_prof_info::out) is det.
-
-accumulate_csd_owns(CSD, Own0, Own) :-
-	Own = add_own_to_own(Own0, CSD ^ csd_own_prof).
-
-:- pred callee_in_clique(initial_deep::in, set(proc_dynamic_ptr)::in,
-	call_site_dynamic_ptr::in) is semidet.
-
-callee_in_clique(InitDeep, Clique, CSDPtr) :-
-	lookup_call_site_dynamics(InitDeep ^ init_call_site_dynamics,
-		CSDPtr, CSD),
-	CalleePDPtr = CSD ^ csd_callee,
-	set__member(CalleePDPtr, Clique).
-
-:- pred merge_proc_dynamic_multi_slot(int::in, set(proc_dynamic_ptr)::in,
-	proc_dynamic_ptr::in, list(call_site_dynamic_ptr)::in,
-	list(array(call_site_array_slot))::in,
-	list(call_site_dynamic_ptr)::out, initial_deep::in, initial_deep::out)
-	is det.
-
-merge_proc_dynamic_multi_slot(SlotNum, Clique, ParentPDPtr, PrimeCSDPtrs0,
-		RestSiteArrays, PrimeCSDPtrs, InitDeep0, InitDeep) :-
-	lookup_multi_sites(RestSiteArrays, SlotNum, RestCSDPtrLists),
-	list__condense([PrimeCSDPtrs0 | RestCSDPtrLists], AllCSDPtrs),
-	map__init(ProcMap0),
-	list__foldl(cluster_csds_by_ps(InitDeep0), AllCSDPtrs,
-		ProcMap0, ProcMap),
-	map__values(ProcMap, CSDPtrsClusters),
-	list__foldl2(merge_multi_slot_cluster(ParentPDPtr, Clique),
-		CSDPtrsClusters, [], PrimeCSDPtrs, InitDeep0, InitDeep).
-
-:- pred merge_multi_slot_cluster(proc_dynamic_ptr::in,
-	set(proc_dynamic_ptr)::in, list(call_site_dynamic_ptr)::in,
-	list(call_site_dynamic_ptr)::in, list(call_site_dynamic_ptr)::out,
-	initial_deep::in, initial_deep::out) is det.
-
-merge_multi_slot_cluster(ParentPDPtr, Clique, ClusterCSDPtrs,
-		PrimeCSDPtrs0, PrimeCSDPtrs, InitDeep0, InitDeep) :-
-	merge_call_site_dynamics(Clique, ParentPDPtr, ClusterCSDPtrs,
-		PrimeCSDPtr, InitDeep0, InitDeep),
-	PrimeCSDPtrs = [PrimeCSDPtr | PrimeCSDPtrs0].
-
-:- pred merge_call_site_dynamics(set(proc_dynamic_ptr)::in,
-	proc_dynamic_ptr::in, list(call_site_dynamic_ptr)::in,
-	call_site_dynamic_ptr::out,
-	initial_deep::in, initial_deep::out) is det.
-
-merge_call_site_dynamics(Clique, ParentPDPtr, CandidateCSDPtrs,
-		FirstCSDPtr, InitDeep0, InitDeep) :-
-	CallSiteDynamics0 = InitDeep0 ^ init_call_site_dynamics,
-	list__filter(valid_call_site_dynamic_ptr_raw(CallSiteDynamics0),
-		CandidateCSDPtrs, ValidCSDPtrs),
-	(
-		ValidCSDPtrs = [],
-			% This signifies that there is no call here.
-		FirstCSDPtr = call_site_dynamic_ptr(0),
-		InitDeep = InitDeep0
-	;
-		ValidCSDPtrs = [FirstCSDPtr | LaterCSDPtrs],
-		lookup_call_site_dynamics(CallSiteDynamics0, FirstCSDPtr,
-			FirstCSD0),
-		FirstCSD = FirstCSD0 ^ csd_caller := ParentPDPtr,
-		update_call_site_dynamics(u(CallSiteDynamics0), FirstCSDPtr,
-			FirstCSD, CallSiteDynamics),
-		InitDeep1 = InitDeep0 ^ init_call_site_dynamics
-			:= CallSiteDynamics,
-		(
-			LaterCSDPtrs = [],
-			InitDeep = InitDeep1
-		;
-			LaterCSDPtrs = [_ | _],
-			merge_call_site_dynamics_2(Clique,
-				FirstCSDPtr, LaterCSDPtrs, InitDeep1, InitDeep)
-		)
-	).
-
-:- pred merge_call_site_dynamics_2(set(proc_dynamic_ptr)::in,
-	call_site_dynamic_ptr::in, list(call_site_dynamic_ptr)::in,
-	initial_deep::in, initial_deep::out) is det.
-
-merge_call_site_dynamics_2(Clique, PrimeCSDPtr, RestCSDPtrs,
-		InitDeep0, InitDeep) :-
-	record_csd_redirect(RestCSDPtrs, PrimeCSDPtr, InitDeep0, InitDeep1),
-	CallSiteDynamics1 = InitDeep1 ^ init_call_site_dynamics,
-	lookup_call_site_dynamics(CallSiteDynamics1, PrimeCSDPtr, PrimeCSD1),
-	list__map(lookup_call_site_dynamics(CallSiteDynamics1),
-		RestCSDPtrs, RestCSDs),
-	PrimeOwn1 = PrimeCSD1 ^ csd_own_prof,
-	list__foldl(accumulate_csd_owns, RestCSDs, PrimeOwn1, PrimeOwn2),
-	PrimeCSD2 = PrimeCSD1 ^ csd_own_prof := PrimeOwn2,
-	update_call_site_dynamics(u(CallSiteDynamics1), PrimeCSDPtr, PrimeCSD2,
-		CallSiteDynamics2),
-	InitDeep2 = InitDeep1 ^ init_call_site_dynamics := CallSiteDynamics2,
-	list__filter(callee_in_clique(InitDeep2, Clique), RestCSDPtrs,
-		InClique, NotInClique),
-	( callee_in_clique(InitDeep2, Clique, PrimeCSDPtr) ->
-		require(unify(NotInClique, []),
-			"merge_proc_dynamic_normal_slot: prime in clique, others not in clique"),
-		InitDeep = InitDeep2
-	;
-		require(unify(InClique, []),
-			"merge_proc_dynamic_normal_slot: prime not in clique, others in clique"),
-		merge_call_site_dynamics_descendants(PrimeCSDPtr, RestCSDPtrs,
-			InitDeep2, InitDeep)
-		% XXX must ensure that PrimeCSDPtr ^ csd_callee is the chosen 
-		% ProcDynamic
-	).
-
-:- pred merge_call_site_dynamics_descendants(call_site_dynamic_ptr::in,
-	list(call_site_dynamic_ptr)::in, initial_deep::in, initial_deep::out)
-	is det.
-
-merge_call_site_dynamics_descendants(PrimeCSDPtr, RestCSDPtrs,
-		InitDeep0, InitDeep) :-
-	CallSiteDynamics = InitDeep0 ^ init_call_site_dynamics,
-	lookup_call_site_dynamics(CallSiteDynamics, PrimeCSDPtr, PrimeCSD),
-	extract_csd_callee(PrimeCSD, PrimeCSDCallee),
-	list__map(lookup_call_site_dynamics(CallSiteDynamics), 
-		RestCSDPtrs, RestCSDs),
-	list__map(extract_csd_callee, RestCSDs, RestCSDCallees),
-	merge_proc_dynamics(set__init, [PrimeCSDCallee | RestCSDCallees],
-		InitDeep0, InitDeep).
-
-:- pred lookup_normal_sites(list(array(call_site_array_slot))::in, int::in,
-	list(call_site_dynamic_ptr)::out) is det.
-
-lookup_normal_sites([], _, []).
-lookup_normal_sites([RestArray | RestArrays], SlotNum, [CSDPtr | CSDPtrs]) :-
-	array__lookup(RestArray, SlotNum, Slot),
-	(
-		Slot = normal(CSDPtr)
-	;
-		Slot = multi(_),
-		error("lookup_normal_sites: found multi")
-	),
-	lookup_normal_sites(RestArrays, SlotNum, CSDPtrs).
-
-:- pred lookup_multi_sites(list(array(call_site_array_slot))::in, int::in,
-	list(list(call_site_dynamic_ptr))::out) is det.
-
-lookup_multi_sites([], _, []).
-lookup_multi_sites([RestArray | RestArrays], SlotNum, [CSDList | CSDLists]) :-
-	array__lookup(RestArray, SlotNum, Slot),
-	(
-		Slot = normal(_),
-		error("lookup_multi_sites: found normal")
-	;
-		Slot = multi(CSDArray),
-		array__to_list(CSDArray, CSDList)
-	),
-	lookup_multi_sites(RestArrays, SlotNum, CSDLists).
-
-:- pragma promise_pure(record_pd_redirect/4).
-:- pred record_pd_redirect(list(proc_dynamic_ptr)::in, proc_dynamic_ptr::in,
-	initial_deep::in, initial_deep::out) is det.
-
-record_pd_redirect(RestPDPtrs, PrimePDPtr, InitDeep0, InitDeep) :-
-	impure unsafe_perform_io(io__write_string("pd redirect: ")),
-	impure unsafe_perform_io(io__print(RestPDPtrs)),
-	impure unsafe_perform_io(io__write_string(" -> ")),
-	impure unsafe_perform_io(io__print(PrimePDPtr)),
-	impure unsafe_perform_io(io__nl),
-	record_pd_redirect_2(RestPDPtrs, PrimePDPtr, InitDeep0, InitDeep).
-
-:- pred record_pd_redirect_2(list(proc_dynamic_ptr)::in, proc_dynamic_ptr::in,
-	initial_deep::in, initial_deep::out) is det.
-
-record_pd_redirect_2([], _, InitDeep, InitDeep).
-record_pd_redirect_2([RestPDPtr | RestPDPtrs], PrimePDPtr,
-		InitDeep0, InitDeep) :-
-	ProcDynamics0 = InitDeep0 ^ init_proc_dynamics,
-	lookup_proc_dynamics(ProcDynamics0, RestPDPtr, RestPD0),
-	require(unify(RestPD0 ^ pd_redirect, no),
-		"record_pd_redirect: already redirected"),
-	RestPD = RestPD0 ^ pd_redirect := yes(PrimePDPtr),
-	update_proc_dynamics(u(ProcDynamics0), RestPDPtr, RestPD,
-		ProcDynamics),
-	InitDeep1 = InitDeep0 ^ init_proc_dynamics := ProcDynamics,
-	record_pd_redirect_2(RestPDPtrs, PrimePDPtr, InitDeep1, InitDeep).
-
-:- pragma promise_pure(record_csd_redirect/4).
-:- pred record_csd_redirect(list(call_site_dynamic_ptr)::in,
-	call_site_dynamic_ptr::in, initial_deep::in, initial_deep::out) is det.
-
-record_csd_redirect(RestCSDPtrs, PrimeCSDPtr, InitDeep0, InitDeep) :-
-	impure unsafe_perform_io(io__write_string("csd redirect: ")),
-	impure unsafe_perform_io(io__print(RestCSDPtrs)),
-	impure unsafe_perform_io(io__write_string(" -> ")),
-	impure unsafe_perform_io(io__print(PrimeCSDPtr)),
-	impure unsafe_perform_io(io__nl),
-	record_csd_redirect_2(RestCSDPtrs, PrimeCSDPtr, InitDeep0, InitDeep).
-
-:- pred record_csd_redirect_2(list(call_site_dynamic_ptr)::in,
-	call_site_dynamic_ptr::in, initial_deep::in, initial_deep::out) is det.
-
-record_csd_redirect_2([], _, InitDeep, InitDeep).
-record_csd_redirect_2([RestCSDPtr | RestCSDPtrs], PrimeCSDPtr,
-		InitDeep0, InitDeep) :-
-	CallSiteDynamics0 = InitDeep0 ^ init_call_site_dynamics,
-	lookup_call_site_dynamics(CallSiteDynamics0, RestCSDPtr, RestCSD0),
-	require(unify(RestCSD0 ^ csd_redirect, no),
-		"record_csd_redirect: already redirected"),
-	RestCSD = RestCSD0 ^ csd_redirect := yes(PrimeCSDPtr),
-	update_call_site_dynamics(u(CallSiteDynamics0), RestCSDPtr, RestCSD,
-		CallSiteDynamics),
-	InitDeep1 = InitDeep0 ^ init_call_site_dynamics := CallSiteDynamics,
-	record_csd_redirect_2(RestCSDPtrs, PrimeCSDPtr, InitDeep1, InitDeep).
-
-:- pred extract_pd_sites(proc_dynamic::in, array(call_site_array_slot)::out)
-	is det.
-
-extract_pd_sites(PD, PD ^ pd_sites).
-
-:- pred extract_csd_callee(call_site_dynamic::in, proc_dynamic_ptr::out)
-	is det.
-
-extract_csd_callee(CSD, CSD ^ csd_callee).
-
-:- pred two_or_more(list(proc_dynamic_ptr)::in) is semidet.
-
-two_or_more([_, _ | _]).
-
-:- pred cluster_pds_by_ps(initial_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.
-
-cluster_pds_by_ps(InitDeep, PDPtr, ProcMap0, ProcMap) :-
-	ProcDynamics = InitDeep ^ init_proc_dynamics,
-	( valid_proc_dynamic_ptr_raw(ProcDynamics, PDPtr) ->
-		lookup_proc_dynamics(ProcDynamics, PDPtr, PD),
-		PSPtr = PD ^ pd_proc_static,
-		( map__search(ProcMap0, PSPtr, PDPtrs0) ->
-			map__det_update(ProcMap0, PSPtr, [PDPtr | PDPtrs0],
-				ProcMap)
-		;
-			map__det_insert(ProcMap0, PSPtr, [PDPtr], ProcMap)
-		)
-	;
-		ProcMap = ProcMap0
-	).
-
-:- pred cluster_csds_by_ps(initial_deep::in, call_site_dynamic_ptr::in,
-	map(proc_static_ptr, list(call_site_dynamic_ptr))::in,
-	map(proc_static_ptr, list(call_site_dynamic_ptr))::out) is det.
-
-cluster_csds_by_ps(InitDeep, CSDPtr, ProcMap0, ProcMap) :-
-	CallSiteDynamics = InitDeep ^ init_call_site_dynamics,
-	( valid_call_site_dynamic_ptr_raw(CallSiteDynamics, CSDPtr) ->
-		lookup_call_site_dynamics(CallSiteDynamics, CSDPtr, CSD),
-		PDPtr = CSD ^ csd_callee,
-		ProcDynamics = InitDeep ^ init_proc_dynamics,
-		( valid_proc_dynamic_ptr_raw(ProcDynamics, PDPtr) ->
-			lookup_proc_dynamics(ProcDynamics, PDPtr, PD),
-			PSPtr = PD ^ pd_proc_static
-		;
-			PSPtr = proc_static_ptr(0)
-		),
-		( map__search(ProcMap0, PSPtr, CSDPtrs0) ->
-			map__det_update(ProcMap0, PSPtr, [CSDPtr | CSDPtrs0],
-				ProcMap)
-		;
-			map__det_insert(ProcMap0, PSPtr, [CSDPtr], ProcMap)
-		)
-	;
-		ProcMap = ProcMap0
-	).
cvs diff: Diffing notes
Index: notes/deep_profiling.html
===================================================================
RCS file: /home/mercury1/repository/mercury/deep_profiler/notes/deep_profiling.html,v
retrieving revision 1.1
diff -u -b -r1.1 deep_profiling.html
--- notes/deep_profiling.html	2001/05/31 06:00:00	1.1
+++ notes/deep_profiling.html	2001/06/04 09:45:22
@@ -293,6 +293,17 @@
 <dt> array_util.m
 <dd>
 This module contains utility predicates for handling arrays.
+<dt> callgraph.m
+<dd>
+This module constructs an explicit representation of the call graph,
+so we can find its cliques.
+<dt> canonical.m
+<dd>
+This module has code to canonicalize call graphs
+(i.e. ensure that no clique contains
+more than one ProcDynamic from a given procedure).
+It also has code that uses canonicalization to merge two call graphs.
+This module is not complete yet.
 <dt> cliques.m
 <dd>
 This module allows you build a description of a directed graph (represented
@@ -313,6 +324,9 @@
 This module defines the type of the commands
 that mdprof_cgi passes to mdprof_server,
 as well as utility predicates for manipulating commands and responses.
+<dt> io_combinator.m
+<dd>
+This module a set of I/O combinators for use by read_profile.m.
 <dt> mdprof_cgi.m
 <dd>
 This file contains the program that is executed by the web server
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list