for review: memory profiling [2/2]

Fergus Henderson fjh at cs.mu.oz.au
Sun Nov 30 01:54:05 AEDT 1997


[continued from part 1]

Index: profiler/mercury_profile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/profiler/mercury_profile.m,v
retrieving revision 1.19
diff -u -u -r1.19 mercury_profile.m
--- mercury_profile.m	1997/07/28 14:57:46	1.19
+++ mercury_profile.m	1997/11/24 20:17:52
@@ -45,7 +45,8 @@
 
 main -->
 	io__command_line_arguments(Args0),
-	{ OptionOps = option_ops(short_option, long_option, option_defaults) },
+	{ OptionOps = option_ops(short_option, long_option, option_defaults,
+				special_handler) },
 	{ getopt__process_options(OptionOps, Args0, Args, Result0) },
 	postprocess_options(Result0, Args, Result),
 	main_2(Result, Args).
Index: profiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/profiler/options.m,v
retrieving revision 1.12
diff -u -u -r1.12 options.m
--- options.m	1997/07/27 15:07:48	1.12
+++ options.m	1997/11/25 18:07:03
@@ -23,6 +23,10 @@
 	% Profiler options
 		;	dynamic_cg
 		;	call_graph
+		;	profile
+		;	profile_time
+		;	profile_memory_words
+		;	profile_memory_cells
 		;	countfile
 		;	pairfile
 		;	declfile
@@ -36,6 +40,8 @@
 :- pred long_option(string::in, option::out) is semidet.
 :- pred option_defaults(option::out, option_data::out) is nondet.
 :- pred option_default(option::out, option_data::out) is multidet.
+:- pred special_handler(option::in, special_data::in,
+       option_table::in, maybe_option_table(option)::out) is semidet.
 
 :- pred options_help(io__state::di, io__state::uo) is det.
 
@@ -48,7 +54,7 @@
 %-----------------------------------------------------------------------------%
 
 :- implementation.
-:- import_module std_util.
+:- import_module std_util, map.
 
 option_defaults(Option, Default) :-
 	semidet_succeed,
@@ -59,12 +65,16 @@
 option_default(very_verbose,	bool(no)).
 
 	% General profiler options
-option_default(dynamic_cg,	bool(no)).
-option_default(call_graph,	bool(no)).
-option_default(countfile,	string("Prof.Counts")).
-option_default(pairfile,	string("Prof.CallPair")).
-option_default(declfile,	string("Prof.Decl")).
-option_default(libraryfile,	string("")).
+option_default(dynamic_cg,		bool(no)).
+option_default(call_graph,		bool(no)).
+option_default(profile,			string_special).
+option_default(profile_time,		special).
+option_default(profile_memory_words,	special).
+option_default(profile_memory_cells,	special).
+option_default(countfile,		string("Prof.Counts")).
+option_default(pairfile,		string("Prof.CallPair")).
+option_default(declfile,		string("Prof.Decl")).
+option_default(libraryfile,		string("")).
 
 	% Miscellaneous Options
 option_default(help,		bool(no)).
@@ -77,7 +87,11 @@
 short_option('D',			declfile).
 short_option('h', 			help).
 short_option('L', 			libraryfile).
+short_option('m', 			profile_memory_words).
+short_option('M', 			profile_memory_cells).
+short_option('p',			profile).
 short_option('P',			pairfile).
+short_option('t', 			profile_time).
 short_option('v', 			verbose).
 short_option('V', 			very_verbose).
 
@@ -87,10 +101,40 @@
 long_option("declaration-file",		declfile).
 long_option("help",			help).
 long_option("library-callgraph",	help).
+long_option("profile",			profile).
+long_option("profile-memory-words",	profile_memory_words).
+long_option("profile-memory-cells",	profile_memory_cells).
+long_option("profile-time",		profile_time).
 long_option("use-dynamic",		dynamic_cg).
 long_option("verbose",			verbose).
 long_option("very-verbose",		very_verbose).
 
+special_handler(profile, string(WhatToProfile), OptionTable0, Result)
+		:-
+	( valid_profile_option(WhatToProfile, CountFile) ->
+		map__set(OptionTable0, countfile, string(CountFile),
+			OptionTable),
+		Result = ok(OptionTable)
+	;
+		Result = error("Invalid argument to `--profile' or `-p' option")
+	).
+special_handler(profile_memory_words, _, OptionTable0, ok(OptionTable)) :-
+	map__set(OptionTable0, countfile, string("Prof.MemoryWords"),
+		OptionTable).
+special_handler(profile_memory_cells, _, OptionTable0, ok(OptionTable)) :-
+	map__set(OptionTable0, countfile, string("Prof.MemoryCells"),
+		OptionTable).
+special_handler(profile_time, _, OptionTable0, ok(OptionTable)) :-
+	map__set(OptionTable0, countfile, string("Prof.Counts"),
+		OptionTable).
+
+:- pred valid_profile_option(string::in, string::out) is semidet.
+valid_profile_option("memory-words", "Prof.MemoryWords").
+valid_profile_option("memory-cells", "Prof.MemoryCells").
+valid_profile_option("time", "Prof.Counts").
+	
+% :- pred special_handler(option::in, special_data::in,
+%       option_table::in, maybe_option_table::out) is semidet.
 
 options_help -->
 	io__write_string("\t-h, --help\n"),
@@ -101,8 +145,20 @@
 	io__write_string("\t\tInclude the call graph profile.\n"),
 	io__write_string("\t-d, --use-dynamic\n"),
 	io__write_string("\t\tBuild the call graph dynamically.\n"),
+	io__write_string("\t-p, --profile {time, memory-words, memory-cells}\n"),
+	io__write_string("\t\tSelect what to profile: time, amount of memory allocated, or\n"),
+	io__write_string("\t\tnumber of memory allocations (regardless of size).\n"),
+	io__write_string("\t-m\n"),
+	io__write_string("\t\tSame as `--profile memory-words'\n"),
+	io__write_string("\t-M\n"),
+	io__write_string("\t\tSame as `--profile memory-cells'.\n"),
+	io__write_string("\t-t\n"),
+	io__write_string("\t\tSame as `--profile time'.\n"),
+
+	io__write_string("\nFilename Options:\n"),
 	io__write_string("\t-C <file>, --count-file <file>\n"),
-	io__write_string("\t\tName of the count file. Usually `Prof.Counts'.\n"),
+	io__write_string("\t\tName of the count file. Usually `Prof.Counts',\n"),
+	io__write_string("\t\t`Prof.MemoryWords', or `Prof.MemoryCells'.\n"),
 	io__write_string("\t-D <file>, --declaration-file <file>\n"),
 	io__write_string("\t\tName of the declaration file. Usually `Prof.Decl'.\n"),
 	io__write_string("\t-P <file>, --call-pair-file <file>\n"),
Index: profiler/output.m
===================================================================
RCS file: /home/mercury1/repository/mercury/profiler/output.m,v
retrieving revision 1.16
diff -u -u -r1.16 output.m
--- output.m	1997/11/17 12:58:24	1.16
+++ output.m	1997/11/29 09:23:33
@@ -35,6 +35,11 @@
 :- import_module globals, options, generate_output.
 
 output__main(Output, IndexMap) -->
+	globals__io_get_globals(Globals),
+	{ globals__get_what_to_profile(Globals, WhatToProfile) },
+	{ what_to_profile(WhatToProfileString, WhatToProfile) },
+	io__format("*** profiling %s ***\n\n", [s(WhatToProfileString)]),
+
 	{ Output = output(InfoMap, CallList, FlatList) },
 	globals__io_lookup_bool_option(call_graph, CallGraphOpt),
 	(
@@ -45,87 +50,126 @@
 	;
 		{ true }
 	),
+
 	output__flat_headers,
 	output__flat_profile(FlatList, 0.0, InfoMap, IndexMap),
+
 	output_alphabet_headers,
 	output_alphabet_listing(IndexMap).
 
+:- type header_category
+	--->	time_headers
+	;	memory_words_headers
+	;	memory_cells_headers.
+
+:- pred classify_profile(what_to_profile::in, header_category::out) is det.
+classify_profile(user_time, time_headers).
+classify_profile(user_plus_system_time, time_headers).
+classify_profile(real_time, time_headers).
+classify_profile(memory_words, memory_words_headers).
+classify_profile(memory_cells, memory_cells_headers).
+
+:- pred units(header_category::in, string::out, string::out, string::out, string::out,
+		string::out, string::out, string::out, string::out) is det.
+units(time_headers,	"time", "time", "running time",
+			"seconds", "seconds", "milliseconds", "ms/call", "spent executing").
+units(memory_words_headers,
+			"mem", "memory", "allocated memory",
+			"k-words", "kilowords", "words", "wds/call", "allocated by").
+units(memory_cells_headers,
+			"cells", "allocations", "number of memory allocations",
+			"k-cells", "kilocells", "cells", "cls/call", "occurring in").
 
 :- pred output__call_graph_headers(io__state, io__state).
 :- mode output__call_graph_headers(di, uo) is det.
 
 output__call_graph_headers -->
+	globals__io_get_globals(Globals),
+	{ globals__get_what_to_profile(Globals, WhatToProfile) },
+	{ classify_profile(WhatToProfile, Category) },
+	{ units(Category, ShortWhat, What, LongWhat,
+			_ShortUnits, Units, _MilliUnits, _MilliUnitsPerCall, SpentIn) },
+
 	io__write_string("call graph profile:\n"),
-	io__write_string("\tSorted on the %time field.\n\n"),
+	io__format("\tSorted on the %%%s field.\n\n", [s(ShortWhat)]),
 
-	io__write_string("\tpredicate entries:\n\n"),
+	io__write_string("\tprocedure entries:\n\n"),
 
-	io__write_string("index\tthe index number of the predicate in the call graph\n"),
-	io__write_string("\tlisting.\n\n"),
+	io__write_string("index\t\tthe index number of the procedure in the call graph\n"),
+	io__write_string("\t\tlisting.\n\n"),
 
-	io__write_string("%time\tthe percentage of the total running time of\n"),
-	io__write_string("\tthe program spent in this predicate and its\n"),
-	io__write_string("\tdescendents.\n\n"),
+	io__format("%%%s\t\tthe percentage of the total %s of\n",
+		[s(ShortWhat), s(LongWhat)]),
+	io__format("\t\tthe program %s this procedure and its\n",
+		[s(SpentIn)]),
+	io__write_string("\t\tdescendents.\n\n"),
 
-	io__write_string("self\tthe number of seconds spent actually executing\n"),
-	io__write_string("\tthe predicate's own code.\n\n"),
+	io__format("self\t\tthe number of %s actually %s\n",
+		[s(Units), s(SpentIn)]),
+	io__write_string("\t\tthe procedure's own code.\n\n"),
 
-	io__write_string("descendents\n"),
-	io__write_string("\tthe number of seconds spent executing the\n"),
-	io__write_string("\tdescendents of the current predicate.\n\n"),
+	io__format("descendents\tthe number of %s %s the\n",
+		[s(Units), s(SpentIn)]),
+	io__write_string("\t\tdescendents of the current procedure.\n\n"),
 
-	io__write_string("called\tthe number of times the current predicate is\n"),
-	io__write_string("\tcalled (not counting self recursive calls).\n\n"),
+	io__write_string("called\t\tthe number of times the current procedure is\n"),
+	io__write_string("\t\tcalled (not counting self recursive calls).\n\n"),
 
-	io__write_string("self\tthe number of self recursive calls.\n\n"), 
+	io__write_string("self\t\tthe number of self recursive calls.\n\n"), 
 
-	io__write_string("name\tthe name of the current predicate.\n\n"),
+	io__write_string("name\t\tthe name of the current procedure.\n\n"),
 
-	io__write_string("index\ta index number to locate the function easily.\n\n\n\n"),
+	io__write_string("index\t\tan index number to locate the function easily.\n\n\n\n"),
 
 	io__write_string("\tparent listings:\n\n"),
 
-	io__write_string("self*\tthe number of seconds of the current predicates self\n"),
-	io__write_string("\ttime due to calls from this parent.\n\n"),
+	io__format("self*\t\tthe number of %s of the current procedure's self\n",
+		[s(Units)]),
+	io__format("\t\t%s due to calls from this parent.\n\n",
+		[s(What)]),
 
-	io__write_string("descendents*\n"),
-	io__write_string("\tthe number of seconds of the current predicate's descendent\n"),
-	io__write_string("\ttime which is due to calls from this parent.\n\n"),
+	io__format("descendents*\tthe number of %s of the current procedure's descendent\n",
+		[s(Units)]),
+	io__format("\t\t%s which is due to calls from this parent.\n\n",
+		[s(What)]),
 
-	io__write_string("called*\tthe number of times the current predicate is called\n"),
-	io__write_string("\tby this parent.\n\n"),
+	io__write_string("called*\t\tthe number of times the current procedure is called\n"),
+	io__write_string("\t\tby this parent.\n\n"),
 
-	io__write_string("total\tthe number of times this predicate is called by its parents.\n\n"),
+	io__write_string("total\t\tthe number of times this procedure is called by its parents.\n\n"),
 
-	io__write_string("parents\tthe name of this parent.\n\n"),
+	io__write_string("parents\t\tthe name of this parent.\n\n"),
 
-	io__write_string("index\tthe index number of the parent predicate\n\n\n\n"),
+	io__write_string("index\t\tthe index number of the parent procedure\n\n\n\n"),
 
 
 
 	io__write_string("children listings:\n\n"),
 
-	io__write_string("self*\tthe number of seconds of this child's self time which is due\n"),
-	io__write_string("\tto being called by the current predicate.\n\n"),
-
-	io__write_string("descendent*\n"),
-	io__write_string("\tthe number of seconds of this child's desdendent time which is due\n"),
-	io__write_string("\tto the current predicate.\n\n"),
+	io__format("self*\t\tthe number of %s of this child's self %s which is\n",
+		[s(Units), s(What)]),
+	io__write_string("\t\tdue to being called by the current procedure.\n\n"),
+
+	io__format("descendent*\tthe number of %s of this child's descendent %s which\n",
+		[s(Units), s(What)]),
+	io__write_string("\t\tis due to the current procedure.\n\n"),
 
-	io__write_string("called*\tthe number of times this child is called by the current\n"),
-	io__write_string("\tpredicate.\n\n"),
+	io__write_string("called*\t\tthe number of times this child is called by the current\n"),
+	io__write_string("\t\tprocedure.\n\n"),
 
-	io__write_string("total*\tthe number of times this child is called by all predicates.\n\n"),
+	io__write_string("total*\t\tthe number of times this child is called by all procedures.\n\n"),
 
 	io__write_string("children\tthe name of this child.\n\n"),
 
-	io__write_string("index\tthe index number of the child.\n\n"),
+	io__write_string("index\t\tthe index number of the child.\n\n\n\n"),
 
 
 
 	io__write_string("                                  called/total"),
 	io__write_string("       parents\n"),
-	io__write_string("index  %time    self descendents  called+self"),
+	{ string__append("%", ShortWhat, PercentShortWhat) },
+	io__format("index %6s    self descendents  called+self",
+		[s(PercentShortWhat)]),
 	io__write_string("    name           index\n"),
 	io__write_string("                                  called/total"),
 	io__write_string("       children\n\n").
@@ -196,7 +240,7 @@
 	),
 
 
-	% Output the info about the current predicate.
+	% Output the info about the current procedure.
 	io__write_string(InitMiddleStr),
 	(
 		{ SelfCalls = 0 }
@@ -225,7 +269,7 @@
 	
 
 % output_formatted_cycle_parent_list
-%	outputs the parents of a predicate that are in the same cycle.
+%	outputs the parents of a procedure that are in the same cycle.
 %
 :- pred output_formatted_cycle_parent_list(list(parent), map(string, int),
                                                         io__state, io__state).
@@ -247,7 +291,7 @@
 	
 
 % output_formatted_parent_list:
-%	Outputs the parent list of the current predicate 
+%	Outputs the parent list of the current procedure 
 
 :- pred output_formatted_parent_list(list(parent), map(string, int), int, 
 							io__state, io__state).
@@ -269,7 +313,7 @@
 	
 
 % output_formatted_cycle_child_list
-%	outputs the childs of a predicate that are in the same cycle.
+%	outputs the childs of a procedure that are in the same cycle.
 %
 :- pred output_formatted_cycle_child_list(list(child), map(string, int),
                                                         io__state, io__state).
@@ -291,7 +335,7 @@
 	
 
 % output_formatted_child_list:
-%	outputs the child list of the current predicate.
+%	outputs the child list of the current procedure.
 %
 :- pred output_formatted_child_list(list(child), map(string, int),
 							io__state, io__state).
@@ -315,31 +359,53 @@
 :- mode output__flat_headers(di, uo) is det.
 
 output__flat_headers -->
-	io__write_string("\nflat profile:\n\n"),
+	globals__io_get_globals(Globals),
+	{ globals__get_what_to_profile(Globals, WhatToProfile) },
+	{ classify_profile(WhatToProfile, Category) },
+	{ units(Category, ShortWhat, _What, LongWhat,
+			ShortUnits, Units, MilliUnits, MilliUnitsPerCall, SpentIn) },
 
-	io__write_string(" %\tthe percentage of total running time of the program\n"),
-	io__write_string("time\tused by this function.\n\n"),
-
-	io__write_string(" cum\tthe total time of the current predicate and the ones\n"),
-	io__write_string("time\tlisted above it.\n\n"),
-
-	io__write_string(" self\tthe number of seconds accounted for by this predicate alone.\n"),
-	io__write_string("seconds\tThe listing is sorted on this row.\n\n"),
-
-	io__write_string("calls\tthe number of times this predicate was called.\n\n"),
-
-	io__write_string(" self\tthe average number of milliseconds spent in\n"),
-	io__write_string("ms/call\tthis predicate per call.\n\n"),
+	io__write_string("\nflat profile:\n\n"),
 
-	io__write_string(" total\tthe average number of milliseconds spent in this predicate and its\n"),
-	io__write_string("ms/call\tdescendents per call.\n\n"),
+	io__format("%%\t\tthe percentage of total %s of the program\n",
+		[s(LongWhat)]),
+	io__format("%s\t\tused by this procedure.\n\n",
+		[s(ShortWhat)]),
+
+	io__format(
+		"cumulative\tthe total number of %s for the current procedure and\n",
+		[s(Units)]),
+	io__format("%s\t\tthe ones listed above it.\n\n",
+		[s(ShortUnits)]),
+
+	io__format(
+	    "self\t\tthe number of %s accounted for by this procedure alone.\n",
+		[s(Units)]),
+	io__format("%s\t\tThe listing is sorted on this row.\n\n",
+		[s(ShortUnits)]),
+
+	io__write_string(
+		"calls\t\tthe number of times this procedure was called.\n\n"),
+
+	io__format("self\t\tthe average number of %s %s\n",
+		[s(MilliUnits), s(SpentIn)]),
+	io__format("%s  \tthis procedure per call.\n\n",
+		[s(MilliUnitsPerCall)]),
+
+	io__format(
+	   "total\tthe average number of %s %s this procedure and its\n",
+		[s(MilliUnits), s(SpentIn)]),
+	io__format("%s  \tdescendents per call.\n\n",
+		[s(MilliUnitsPerCall)]),
 
-	io__write_string("name\tthe name of the predicate followed by its index number.\n\n"),
+	io__write_string(
+	  "name\t\tthe name of the procedure followed by its index number.\n\n"),
 
 	io__write_string("   %  cumulative    self              self"),
 	io__write_string("    total\n"),
-	io__write_string(" time   seconds   seconds    calls  ms/call"),
-	io__write_string("  ms/call name\n").
+	io__format(" %4s    %7s  %7s    calls %8s %8s name\n",
+		[s(ShortWhat), s(ShortUnits), s(ShortUnits),
+		 s(MilliUnitsPerCall), s(MilliUnitsPerCall)]).
 
 
 :- pred output__flat_profile(list(string), float, map(string, output_prof),
Index: profiler/process_file.m
===================================================================
RCS file: /home/mercury1/repository/mercury/profiler/process_file.m,v
retrieving revision 1.16
diff -u -u -r1.16 process_file.m
--- process_file.m	1997/11/17 12:58:25	1.16
+++ process_file.m	1997/11/25 19:06:31
@@ -58,7 +58,7 @@
         maybe_write_string(VVerbose, "\t% Processing "),
 	maybe_write_string(VVerbose, CountFile),
 	maybe_write_string(VVerbose, "..."),
-        process_addr(ProfNodeMap0, ProfNodeMap1, Hertz, ClockTicks,
+        process_addr(ProfNodeMap0, ProfNodeMap1, WhatToProfile, Scale, Units,
 		TotalCounts),
         maybe_write_string(VVerbose, " done.\n"),
 
@@ -70,8 +70,11 @@
         maybe_write_string(VVerbose, " done.\n"),
 
 	{ map__init(CycleMap) },
-        { prof_set_entire(Hertz, ClockTicks, TotalCounts, AddrDeclMap, 
+        { prof_set_entire(Scale, Units, TotalCounts, AddrDeclMap, 
 						ProfNodeMap, CycleMap, Prof) },
+	globals__io_get_globals(Globals0),
+	{ globals__set_what_to_profile(Globals0, WhatToProfile, Globals) },
+	globals__io_set_globals(Globals),
 	
 	(
 		{ Dynamic = no }
@@ -165,17 +168,19 @@
 % 	Reads in the Prof.Counts file and stores all the counts in the 
 % 	prof_node structure.  Also sums the total counts at the same time.
 %
-:- pred process_addr(prof_node_map, prof_node_map, int, int, int,
-							io__state, io__state).
-:- mode process_addr(in, out, out, out, out, di, uo) is det.
+:- pred process_addr(prof_node_map, prof_node_map,
+		what_to_profile, float, string, int, io__state, io__state).
+:- mode process_addr(in, out, out, out, out, out, di, uo) is det.
 
-process_addr(ProfNodeMap0, ProfNodeMap, Hertz, ClockTicks, TotalCounts) -->
+process_addr(ProfNodeMap0, ProfNodeMap, WhatToProfile, Scale, Units,
+		TotalCounts) -->
 	globals__io_lookup_string_option(countfile, CountFile),
 	io__see(CountFile, Result),
 	(
 		{ Result = ok },
-		read_int(Hertz),
-		read_int(ClockTicks),
+		read_what_to_profile(WhatToProfile),
+		read_float(Scale),
+		read_string(Units),
 		process_addr_2(0, ProfNodeMap0, TotalCounts, ProfNodeMap),
 		io__seen
 	;
@@ -186,15 +191,16 @@
 		io__write_string("': "),
 		io__write_string(ErrorMsg),
 		io__write_string("\n"),
-		io__write_string("The generated profile will not include "),
-		io__write_string("timing information.\n\n"),
+		io__write_string("The generated profile will only include "),
+		io__write_string("call counts.\n\n"),
 		{ TotalCounts = 0 },
 		{ ProfNodeMap = ProfNodeMap0 },
-		% We can use any arbitrary values for Hertz and ClockTicks;
-		% the values here won't be used, since all the times will be
-		% zero.
-		{ Hertz = 1 },
-		{ ClockTicks = 1 }
+		% We can use any arbitrary values for WhatToProfile and Scale;
+		% the values specified here won't be used,
+		% since all the times will be zero.
+		{ WhatToProfile = user_plus_system_time },
+		{ Scale = 1.0 },
+		{ Units = "" }
 	).
 
 :- pred process_addr_2(int, prof_node_map, int, prof_node_map, 
Index: profiler/prof_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/profiler/prof_info.m,v
retrieving revision 1.10
diff -u -u -r1.10 prof_info.m
--- prof_info.m	1997/07/27 15:07:52	1.10
+++ prof_info.m	1997/11/25 19:00:59
@@ -75,7 +75,8 @@
 
 	% *** Access prof predicates *** %
 
-:- pred prof_get_entire(prof, int,int,int, addrdecl, prof_node_map, cycle_map).
+:- pred prof_get_entire(prof,
+			float, string, int, addrdecl, prof_node_map, cycle_map).
 :- mode prof_get_entire(in, out, out, out, out, out, out) is det.
 
 :- pred prof_get_addrdeclmap(prof, addrdecl).
@@ -87,7 +88,8 @@
 
 	% *** Update prof predicates *** %
 
-:- pred prof_set_entire(int,int,int, addrdecl, prof_node_map, cycle_map, prof).
+:- pred prof_set_entire(float, string, int, addrdecl, prof_node_map, cycle_map,
+			prof).
 :- mode prof_set_entire(in, in, in, in, in, in, out) is det.
 
 :- pred prof_set_profnodemap(prof_node_map, prof, prof).
@@ -197,9 +199,10 @@
 
 :- type prof --->
 		prof(
-			int,			% Hertz of the system clock
-			int,			% No. of clock ticks between 
-						% each prof signal.
+			float,			% Scaling factor
+			string,			% Units
+						% (Each profiling count is
+						% equivalent to Scale Units)
 			int,			% Total counts of the profile
 						% run
 			addrdecl,		% Map between label name and
Index: profiler/read.m
===================================================================
RCS file: /home/mercury1/repository/mercury/profiler/read.m,v
retrieving revision 1.7
diff -u -u -r1.7 read.m
--- read.m	1997/07/27 15:07:54	1.7
+++ read.m	1997/11/25 19:10:28
@@ -19,6 +19,7 @@
 :- interface.
 
 :- import_module int, io.
+:- import_module globals.
 
 :- pred maybe_read_label_addr(maybe(int), io__state, io__state).
 :- mode	maybe_read_label_addr(out, di, uo) is det.
@@ -32,9 +33,18 @@
 :- pred read_label_name(string, io__state, io__state).
 :- mode	read_label_name(out, di, uo) is det.
 
+:- pred read_string(string, io__state, io__state).
+:- mode read_string(out, di, uo) is det.
+
 :- pred read_int(int, io__state, io__state).
 :- mode read_int(out, di, uo) is det.
 
+:- pred read_float(float, io__state, io__state).
+:- mode read_float(out, di, uo) is det.
+
+:- pred read_what_to_profile(what_to_profile, io__state, io__state).
+:- mode read_what_to_profile(out, di, uo) is det.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -153,28 +163,61 @@
 
 %-----------------------------------------------------------------------------%
 
-read_int(Count) -->
+read_string(String) -->
 	io__read_word(WordResult),
 	(
 		{ WordResult = ok(CharList) },
-		{ string__from_char_list(CharList, CountStr) },
-		(
-			{ string__to_int(CountStr, Count0) }
-		->
-			{ Count = Count0 }
-		;
-			io__write_string("\nInteger = "),
-			io__write_string(CountStr),
-			{ error("\nread_int: Not an integer\n") }
-		)
+		{ string__from_char_list(CharList, String) }
 	;
 		{ WordResult = eof },
-		{ error("read_int: EOF reached") }
+		{ error("read_string: EOF reached") }
 	;
 		{ WordResult = error(Error) },
 		{ io__error_message(Error, ErrorStr) },
-		{ string__append("read_int: ", ErrorStr, Str) },
+		{ string__append("read_string: ", ErrorStr, Str) },
 		{ error(Str) }
+	).
+
+%-----------------------------------------------------------------------------%
+
+read_int(Int) -->
+	read_string(IntStr),
+	(
+		{ string__to_int(IntStr, Int0) }
+	->
+		{ Int = Int0 }
+	;
+		io__write_string("\nInteger = "),
+		io__write_string(IntStr),
+		{ error("\nread_int: Not an integer\n") }
+	).
+
+%-----------------------------------------------------------------------------%
+
+read_float(Float) -->
+	read_string(FloatStr),
+	(
+		{ string__to_float(FloatStr, Float0) }
+	->
+		{ Float = Float0 }
+	;
+		io__write_string("\nFloat = "),
+		io__write_string(FloatStr),
+		{ error("\nread_float: Not an float\n") }
+	).
+
+%-----------------------------------------------------------------------------%
+
+read_what_to_profile(WhatToProfile) -->
+	read_string(Str),
+	(
+		{ what_to_profile(Str, WhatToProfile0) }
+	->
+		{ WhatToProfile = WhatToProfile0 }
+	;
+		io__write_string("\nWhatToProfile = "),
+		io__write_string(Str),
+		{ error("\nread_what_to_profile: invalid input\n") }
 	).
 
 %-----------------------------------------------------------------------------%
cvs diff: Diffing runtime
Index: runtime/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/Mmakefile,v
retrieving revision 1.19
diff -u -u -r1.19 Mmakefile
--- Mmakefile	1997/11/21 12:21:48	1.19
+++ Mmakefile	1997/11/24 19:18:39
@@ -23,14 +23,6 @@
 
 #		  keep this list in alphabetical order, please
 HDRS		=	\
-		  	mercury_engine.h	\
-			mercury_getopt.h	\
-			mercury_goto.h		\
-			mercury_heap.h		\
-			mercury_imp.h		\
-			mercury_init.h		\
-			mercury_label.h		\
-			mercury_memory.h	\
 			mercury_accurate_gc.h	\
 			mercury_calls.h		\
 			mercury_conf.h		\
@@ -39,11 +31,16 @@
 			mercury_deep_copy.h	\
 			mercury_dummy.h		\
 			mercury_dlist.h		\
+		  	mercury_engine.h	\
 			mercury_float.h		\
-			mercury_string.h	\
-			mercury_trace.h		\
-			mercury_trail.h		\
-			mercury_types.h		\
+			mercury_getopt.h	\
+			mercury_goto.h		\
+			mercury_heap.h		\
+			mercury_heap_profile.h	\
+			mercury_imp.h		\
+			mercury_init.h		\
+			mercury_label.h		\
+			mercury_memory.h	\
 			mercury_misc.h		\
 			mercury_overflow.h	\
 			mercury_prof.h		\
@@ -53,9 +50,13 @@
 			mercury_spinlock.h	\
 			mercury_std.h		\
 			mercury_stacks.h	\
+			mercury_string.h	\
 			mercury_table.h		\
 			mercury_tags.h		\
 			mercury_timing.h	\
+			mercury_trace.h		\
+			mercury_trail.h		\
+			mercury_types.h		\
 			mercury_type_info.h	\
 			mercury_wrapper.h	\
 			$(LIBMER_DLL_H)
@@ -74,19 +75,15 @@
 			machdeps/rs6000_regs.h
 
 
-# XXX .mod support is being removed. This will soon disappear.
-MODS		= 
-MOD_CS		= 
-MOD_OS		= $(MOD_CS:.c=.o)
-
 #		  keep this list in alphabetical order, please
-ORIG_CS		= 	mercury_context.c	\
+CFILES		= 	mercury_context.c	\
 			mercury_deep_copy.c	\
 			mercury_dlist.c		\
 			mercury_dummy.c		\
 			mercury_engine.c	\
 			mercury_float.c		\
 			mercury_grade.c		\
+			mercury_heap_profile.c	\
 			mercury_ho_call.c	\
 			mercury_label.c		\
 			mercury_memory.c	\
@@ -102,10 +99,8 @@
 			mercury_type_info.c	\
 			mercury_wrapper.c
 
-ORIG_OS		= $(ORIG_CS:.c=.o)
-ORIG_OS		= $(ORIG_CS:.c=.o)
-OBJS		= $(MOD_OS) $(ORIG_OS)
-PIC_OBJS	= $(OBJS:.o=.$(EXT_FOR_PIC_OBJECTS))
+OBJS		= $(CFILES:.c=.o)
+PIC_OBJS	= $(CFILES:.c=.$(EXT_FOR_PIC_OBJECTS))
 
 LDFLAGS		= -L$(BOEHM_GC_DIR)
 LDLIBS		= \
@@ -151,8 +146,8 @@
 		$(LDFLAGS) $(LDLIBS)					\
 		$(SHARED_LIBS)
 
-runtime.init: $(ORIG_CS)
-	cat `vpath_find $(ORIG_CS)` | grep '^INIT ' > runtime.init
+runtime.init: $(CFILES)
+	cat `vpath_find $(CFILES)` | grep '^INIT ' > runtime.init
 
 mercury_conf.h.date: $(MERCURY_DIR)/config.status mercury_conf.h.in
 	CONFIG_FILES= CONFIG_HEADERS=mercury_conf.h $(MERCURY_DIR)/config.status
@@ -162,10 +157,10 @@
 	@true
 
 .PHONY: cs
-cs: $(MOD_CS)
+cs: $(CFILES)
 
-tags: $(MODS) $(ORIG_CS)
-	ctags $(MODS) $(ORIG_CS) $(HDRS)
+tags: $(CFILES) $(HDRS)
+	ctags $(CFILES) $(HDRS)
 
 .PHONY: check_headers
 check_headers:
@@ -204,23 +199,16 @@
 
 #-----------------------------------------------------------------------------#
 
-# prevent GNU make from removing these intermediate files
-dont_remove: engine.c wrapper.c call.c 
-
 # prevent Mmake from removing C files
 RM_C=:
 
 #-----------------------------------------------------------------------------#
 
-clean: clean_o clean_mod_c
+clean: clean_o
 
 .PHONY: clean_o
 clean_o:
-	rm -f $(MOD_OS) $(OBJS) $(PIC_OBJS) 
-
-.PHONY: clean_mod_c
-clean_mod_c:
-	rm -f $(MOD_OS)
+	rm -f $(OBJS) $(PIC_OBJS) 
 
 realclean:
 	rm -f libmer.a libmer.so runtime.init
Index: runtime/mercury_grade.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_grade.h,v
retrieving revision 1.4
diff -u -u -r1.4 mercury_grade.h
--- mercury_grade.h	1997/11/21 06:14:04	1.4
+++ mercury_grade.h	1997/11/24 22:01:58
@@ -75,15 +75,41 @@
 
 #ifdef PROFILE_TIME
   #ifdef PROFILE_CALLS
-    #define MR_GRADE_PART_4	_prof
+    #ifdef PROFILE_MEMORY
+      #define MR_GRADE_PART_4	_profall
+    #else
+      #define MR_GRADE_PART_4	_prof
+    #endif
   #else
-    #define MR_GRADE_PART_4	_proftime
+    #ifdef PROFILE_MEMORY
+      /*
+      ** Memory profiling interferes with time profiling,
+      ** so there's no point in allowing this.
+      */
+      #error "Invalid combination of profiling options"
+    #else
+      /* Currently useless, but... */
+      #define MR_GRADE_PART_4	_proftime
+    #endif
   #endif
 #else
   #ifdef PROFILE_CALLS
-    #define MR_GRADE_PART_4	_profcalls
+    #ifdef PROFILE_MEMORY
+      #define MR_GRADE_PART_4	_memprof
+    #else
+      #define MR_GRADE_PART_4	_profcalls
+    #endif
   #else
-    #define MR_GRADE_PART_4
+    #ifdef PROFILE_MEMORY
+      /*
+      ** Call-graph memory profiling requires call profiling,
+      ** and call profiling is reasonably cheap, so there's
+      ** no point in allowing this.
+      */
+      #error "Invalid combination of profiling options"
+    #else
+      #define MR_GRADE_PART_4
+    #endif
   #endif
 #endif
 
Index: runtime/mercury_heap.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_heap.h,v
retrieving revision 1.2
diff -u -u -r1.2 mercury_heap.h
--- mercury_heap.h	1997/11/23 07:21:24	1.2
+++ mercury_heap.h	1997/11/24 19:31:04
@@ -9,165 +9,209 @@
 #ifndef MERCURY_HEAP_H
 #define MERCURY_HEAP_H
 
-#include "mercury_types.h"	/* for `Word' */
-#include "mercury_context.h"	/* for min_heap_reclamation_point() */
+#include "mercury_types.h"		/* for `Word' */
+#include "mercury_context.h"		/* for min_heap_reclamation_point() */
+#include "mercury_heap_profile.h"	/* for MR_record_allocation() */
 
 #ifdef CONSERVATIVE_GC
 
-#include "gc.h"
+  #include "gc.h"
 
-#define	tag_incr_hp_n(dest,tag,count) \
-	((dest) = (Word)mkword((tag), (Word)GC_MALLOC((count) * sizeof(Word))))
-#define	tag_incr_hp_atomic(dest,tag,count) \
-	((dest) = (Word)mkword((tag), \
-			(Word)GC_MALLOC_ATOMIC((count) * sizeof(Word))))
+  #define tag_incr_hp_n(dest, tag, count) \
+	((dest) = (Word) mkword((tag), \
+			(Word) GC_MALLOC((count) * sizeof(Word))))
+  #define tag_incr_hp_atomic(dest, tag, count) \
+	((dest) = (Word) mkword((tag), \
+			(Word) GC_MALLOC_ATOMIC((count) * sizeof(Word))))
+
+  #ifdef INLINE_ALLOC
+
+    /*
+    ** The following stuff uses the macros in the `gc_inl.h' header file in the
+    ** Boehm garbage collector.  They improve performance a little for
+    ** highly allocation-intensive programs (e.g. the `nrev' benchmark).
+    ** You'll probably need to fool around with the `-I' options to get this
+    ** to work.  Also, you must make sure that you compile with the same
+    ** setting for -DSILENT that the boehm_gc directory was compiled with.
+    **
+    ** We only want to inline allocations if the allocation size is a
+    ** compile-time constant.  This should be true for almost all the code that
+    ** we generate, but with GCC we can use the `__builtin_constant_p()'
+    ** extension to find out.
+    **
+    ** The inline allocation macros are used only for allocating amounts
+    ** of less than 16 words, to avoid fragmenting memory by creating too
+    ** many distinct free lists.  The garbage collector also requires that
+    ** if we're allocating more than one word, we round up to an even number
+    ** of words.
+    */
+
+    #ifndef __GNUC__
+      /*
+      ** Without the gcc extensions __builtin_constant_p() and ({...}),
+      ** INLINE_ALLOC would probably be a performance _loss_.
+      */
+      #error "INLINE_ALLOC requires the use of GCC"
+    #endif
 
-#ifdef INLINE_ALLOC
-
-/*
-** The following stuff uses the macros in the `gc_inl.h' header file in the
-** Boehm garbage collector.  They improve performance a little for
-** highly allocation-intensive programs (e.g. the `nrev' benchmark).
-** You'll probably need to fool around with the `-I' options to get this
-** to work.  Also, you must make sure that you compile with the same
-** setting for -DSILENT that the boehm_gc directory was compiled with.
-**
-** We only want to inline allocations if the allocation size is a compile-time
-** constant.  This should be true for almost all the code that we generate,
-** but with GCC we can use the `__builtin_constant_p()' extension to find out.
-**
-** The inline allocation macros are used only for allocating amounts
-** of less than 16 words, to avoid fragmenting memory by creating too
-** many distinct free lists.  The garbage collector also requires that
-** if we're allocating more than one word, we round up to an even number
-** of words.
-*/
-
-#ifndef __GNUC__
-/*
-** Without the gcc extensions __builtin_constant_p() and ({...}),
-** INLINE_ALLOC would probably be a performance _loss_.
-*/
-#error "INLINE_ALLOC requires the use of GCC"
-#endif
-
-#include "gc_inl.h"
-#define	tag_incr_hp(dest,tag,count) 					\
+    #include "gc_inl.h"
+    #define tag_incr_hp(dest, tag, count) 				\
 	( __builtin_constant_p(count) && (count) < 16 			\
 	? ({ 	void * temp; 						\
 		/* if size > 1, round up to an even number of words */	\
-		Word num_words = ((count) == 1 ? 1 : 2 * (((count) + 1) / 2)); \
+		Word num_words = ((count) == 1 ? 1 : 2 * (((count) + 1) / 2));\
 		GC_MALLOC_WORDS(temp, num_words);			\
 		(dest) = (Word)mkword((tag), temp);			\
 	  })								\
-	: tag_incr_hp_n((dest),(tag),(count))				\
+	: tag_incr_hp_n((dest), (tag), (count))				\
 	)
 
-#else /* not INLINE_ALLOC */
+  #else /* not INLINE_ALLOC */
 
-#define	tag_incr_hp(dest,tag,count) \
-	tag_incr_hp_n((dest),(tag),(count))
+    #define tag_incr_hp(dest, tag, count) \
+	tag_incr_hp_n((dest), (tag), (count))
 
-#endif /* not INLINE_ALLOC */
+  #endif /* not INLINE_ALLOC */
 
-#define	mark_hp(dest)	((void)0)
-#define	restore_hp(src)	((void)0)
+  #define mark_hp(dest)		((void)0)
+  #define restore_hp(src)	((void)0)
 
 			/* we use `hp' as a convenient temporary here */
-#define hp_alloc(count) (incr_hp(MR_hp,(count)), MR_hp += (count), (void)0)
-#define hp_alloc_atomic(count) \
-			(incr_hp_atomic(MR_hp,(count)), MR_hp += (count), (void)0)
+  #define hp_alloc(count) \
+		(incr_hp(MR_hp, (count)), MR_hp += (count), (void)0)
+  #define hp_alloc_atomic(count) \
+		(incr_hp_atomic(MR_hp, (count)), MR_hp += (count), (void)0)
 
 #else /* not CONSERVATIVE_GC */
 
-#define	tag_incr_hp(dest,tag,count)	(			\
-				(dest) = (Word)mkword(tag, (Word)MR_hp),	\
-				debugincrhp(count, MR_hp),		\
-				MR_hp += (count),			\
-				heap_overflow_check(),		\
-				(void)0				\
-			)
-#define tag_incr_hp_atomic(dest,tag,count) tag_incr_hp((dest),(tag),(count))
-
-#define	mark_hp(dest)	(					\
-				(dest) = (Word)MR_hp,		\
-				(void)0				\
-			)
+  #define tag_incr_hp(dest, tag, count) 			\
+	(							\
+		(dest) = (Word) mkword(tag, (Word) MR_hp),	\
+		debugincrhp(count, MR_hp),			\
+		MR_hp += (count),				\
+		heap_overflow_check(),				\
+		(void)0						\
+	)
+  #define tag_incr_hp_atomic(dest, tag, count) \
+	tag_incr_hp((dest), (tag), (count))
 
-/*
-** When restoring hp, we must make sure that we don't truncate the heap
-** further than it is safe to. We can only truncate it as far as
-** min_heap_reclamation_point. See the comments in mercury_context.h next to
-** the set_min_heap_reclamation_point() macro.
-*/
-#define	restore_hp(src)	(						\
-			LVALUE_CAST(Word,MR_hp) =				\
-			  ( (Word) MR_min_hp_rec < (src) ?	\
-			  (src) : (Word) MR_min_hp_rec ),	\
-			(void)0						\
-		)
+  #define mark_hp(dest)						\
+	(							\
+		(dest) = (Word) MR_hp,				\
+		(void)0						\
+	)
 
-#define hp_alloc(count)  incr_hp(hp,count)
-#define hp_alloc_atomic(count) incr_hp_atomic(count)
+  /*
+  ** When restoring hp, we must make sure that we don't truncate the heap
+  ** further than it is safe to. We can only truncate it as far as
+  ** min_heap_reclamation_point. See the comments in mercury_context.h next
+  ** to the set_min_heap_reclamation_point() macro.
+  */
+  #define restore_hp(src)					\
+	(							\
+		LVALUE_CAST(Word, MR_hp) =			\
+			  ( 	(Word) MR_min_hp_rec < (src)	\
+			  ?	(src)				\
+			  :	(Word) MR_min_hp_rec		\
+			  ),					\
+		(void)0						\
+	)
+
+  #define hp_alloc(count)  incr_hp(hp, count)
+  #define hp_alloc_atomic(count) incr_hp_atomic(count)
 
 #endif /* not CONSERVATIVE_GC */
 
-#define	incr_hp(dest,count)	tag_incr_hp((dest),mktag(0),(count))
-#define	incr_hp_atomic(dest,count) \
-				tag_incr_hp_atomic((dest),mktag(0),(count))
+#ifdef	PROFILE_MEMORY
+  #define tag_incr_hp_msg(dest, tag, count, proclabel, type)		\
+	(								\
+		MR_record_allocation((count), LABEL(proclabel), 	\
+			MR_STRINGIFY(proclabel), (type)),		\
+		tag_incr_hp((dest), (tag), (count))			\
+	)
+  #define tag_incr_hp_atomic_msg(dest, tag, count, proclabel, type) 	\
+	(								\
+		MR_record_allocation((count), LABEL(proclabel), 	\
+			MR_STRINGIFY(proclabel), (type)),		\
+		tag_incr_hp_atomic((dest), (tag), (count))		\
+	)
+#else /* not PROFILE_MEMORY */
+  #define tag_incr_hp_msg(dest, tag, count, proclabel, type) \
+		tag_incr_hp((dest), (tag), (count))
+  #define tag_incr_hp_atomic_msg(dest, tag, count, proclabel, type) \
+		tag_incr_hp_atomic((dest), (tag), (count))
+#endif /* not PROFILE_MEMORY */
+
+/*
+** The incr_hp*() macros are defined in terms of the tag_incr_hp*() macros.
+*/
+#define	incr_hp(dest, count) \
+		tag_incr_hp((dest), mktag(0), (count))
+#define	incr_hp_msg(dest, count, proclabel, type) \
+		tag_incr_hp_msg((dest), mktag(0), (count), (proclabel), (type))
+#define	incr_hp_atomic(dest, count) \
+		tag_incr_hp_atomic((dest), mktag(0), (count))
+#define	incr_hp_atomic_msg(dest, count, proclabel, type) \
+		tag_incr_hp_atomic_msg((dest), mktag(0), (count), \
+			(proclabel), (type))
 
 /*
 ** Note that gcc optimizes `hp += 2; return hp - 2;'
 ** to `tmp = hp; hp += 2; return tmp;', so we don't need to use
-** gcc's expression statements here
+** gcc's expression statements in the code below.
 */
 
 /* used only by the hand-written example programs */
 /* not by the automatically generated code */
-#define create1(w1)	(					\
-				hp_alloc(1),			\
-				MR_hp[-1] = (Word) (w1),		\
-				debugcr1(MR_hp[-1], MR_hp),		\
-				/* return */ (Word) (MR_hp - 1)	\
-			)
+#define create1(w1)						\
+	(							\
+		hp_alloc(1),					\
+		MR_hp[-1] = (Word) (w1),			\
+		debugcr1(MR_hp[-1], MR_hp),			\
+		/* return */ (Word) (MR_hp - 1)			\
+	)
 
 /* used only by the hand-written example programs */
 /* not by the automatically generated code */
-#define create2(w1, w2)	(					\
-				hp_alloc(2),			\
-				MR_hp[-2] = (Word) (w1),		\
-				MR_hp[-1] = (Word) (w2),		\
-				debugcr2(MR_hp[-2], MR_hp[-1], MR_hp),	\
-				/* return */ (Word) (MR_hp - 2)	\
-			)
+#define create2(w1, w2)						\
+	(							\
+		hp_alloc(2),					\
+		MR_hp[-2] = (Word) (w1),			\
+		MR_hp[-1] = (Word) (w2),			\
+		debugcr2(MR_hp[-2], MR_hp[-1], MR_hp),		\
+		/* return */ (Word) (MR_hp - 2)			\
+	)
 
 /* used only by the hand-written example programs */
 /* not by the automatically generated code */
-#define create3(w1, w2, w3)	(				\
-				hp_alloc(3),			\
-				MR_hp[-3] = (Word) (w1),		\
-				MR_hp[-2] = (Word) (w2),		\
-				MR_hp[-1] = (Word) (w3),		\
-				/* return */ (Word) (MR_hp - 3)	\
-			)
+#define create3(w1, w2, w3)					\
+	(							\
+		hp_alloc(3),					\
+		MR_hp[-3] = (Word) (w1),			\
+		MR_hp[-2] = (Word) (w2),			\
+		MR_hp[-1] = (Word) (w3),			\
+		/* return */ (Word) (MR_hp - 3)			\
+	)
 
 /* used only by the hand-written example programs */
 /* not by the automatically generated code */
-#define create2_bf(w1)	(					\
-				MR_hp = MR_hp + 2,			\
-				MR_hp[-2] = (Word) (w1),		\
-				heap_overflow_check(),		\
-				/* return */ (Word) (MR_hp - 2)	\
-			)
+#define create2_bf(w1)						\
+	(							\
+		MR_hp = MR_hp + 2,				\
+		MR_hp[-2] = (Word) (w1),			\
+		heap_overflow_check(),				\
+		/* return */ (Word) (MR_hp - 2)			\
+	)
 
 /* used only by the hand-written example programs */
 /* not by the automatically generated code */
-#define create2_fb(w2)	(					\
-				MR_hp = MR_hp + 2,			\
-				MR_hp[-1] = (Word) (w2),		\
-				heap_overflow_check(),		\
-				/* return */ (Word) (MR_hp - 2)	\
-			)
+#define create2_fb(w2)						\
+	(							\
+		MR_hp = MR_hp + 2,				\
+		MR_hp[-1] = (Word) (w2),			\
+		heap_overflow_check(),				\
+		/* return */ (Word) (MR_hp - 2)			\
+	)
 
 /*
 ** Indended for use in handwritten C code where the Mercury registers
@@ -177,16 +221,18 @@
 ** restore_transient_registers() after.
 */
 
-#define incr_saved_hp(A,B)	do { 					\
-					restore_transient_registers();	\
-					incr_hp((A), (B));		\
-					save_transient_registers();	\
-				} while (0)
-
-#define incr_saved_hp_atomic(A,B) do { 					\
-					restore_transient_registers();	\
-					incr_hp_atomic((A), (B));	\
-					save_transient_registers();	\
-				} while (0)
+#define incr_saved_hp(A, B)					\
+	do { 							\
+		restore_transient_registers();			\
+		incr_hp((A), (B));				\
+		save_transient_registers();			\
+	} while (0)
+
+#define incr_saved_hp_atomic(A, B) 				\
+	do { 							\
+		restore_transient_registers();			\
+		incr_hp_atomic((A), (B));			\
+		save_transient_registers();			\
+	} while (0)
 
 #endif /* not MERCURY_HEAP_H */
Index: runtime/mercury_heap_profile.c
===================================================================
RCS file: mercury_heap_profile.c
diff -N mercury_heap_profile.c
--- /dev/null	Sun Nov 30 01:48:53 1997
+++ mercury_heap_profile.c	Tue Nov 25 06:23:58 1997
@@ -0,0 +1,123 @@
+/*
+** Copyright (C) 1997 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: mercury_heap_profile.c.
+** Main authors: zs, fjh
+**
+** This module records information about the allocations of cells on the heap.
+**
+** The information recorded by this module is used by code in
+** library/benchmarking.m.
+*/
+
+/*---------------------------------------------------------------------------*/
+
+#include "mercury_imp.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "mercury_prof_mem.h"
+#include "mercury_heap_profile.h"
+
+/* all fields of these variables are initialized to 0 */
+MR_memprof_counter	MR_memprof_overall;
+MR_memprof_table	MR_memprof_procs;
+MR_memprof_table	MR_memprof_types;
+
+/*
+** Initialize a heap profiling counter.
+*/
+static void
+MR_init_counter(MR_memprof_counter *counter)
+{
+	MR_zero_dword(counter->cells_at_period_start);
+	MR_zero_dword(counter->words_at_period_start);
+	MR_zero_dword(counter->cells_since_period_start);
+	MR_zero_dword(counter->words_since_period_start);
+}
+
+/*
+** Increment the fields in a heap profiling counter to record the allocation
+** of a single cell of `size' words.
+*/
+static void
+MR_increment_counter(MR_memprof_counter *counter, int size)
+{
+	MR_increment_dword(counter->cells_since_period_start, 1);
+	MR_increment_dword(counter->words_since_period_start, size);
+}
+
+/*
+** Search the specified `table' to find the entry for the given `name'
+** allocating one if there isn't one already, and then increment
+** the counters for that entry for an allocation of the specified `size'.
+*/
+static void
+MR_increment_table_entry(MR_memprof_table *table, const char *name,
+	Code *addr, int size)
+{
+	bool			found;
+	int			diff;
+	MR_memprof_record	**node_addr;
+	MR_memprof_record	*node;
+
+	/*
+	** Search the tree to find the node with this name.
+	*/
+	found = FALSE;
+	node_addr = &table->root;
+	while ((node = *node_addr) != NULL) {
+		diff = strcmp(name, node->name);
+		if (diff < 0) {
+			node_addr = &node->left;
+		} else if (diff > 0) {
+			node_addr = &node->right;
+		} else {
+			found = TRUE;
+			break;
+		}
+	}
+
+	/*
+	** If the tree didn't already contain a node with this name,
+	** create a new node for it.
+	*/
+	if (!found) {
+		node = MR_PROF_NEW(MR_memprof_record);
+		node->name = name;
+		node->addr = addr;
+		node->left = NULL;
+		node->right = NULL;
+		MR_init_counter(&node->counter);
+
+		*node_addr = node;
+
+		table->num_entries++;
+	}
+
+	/* Now record the counts in this node */
+	MR_increment_counter(&node->counter, size);
+}
+
+/*
+** Record heap profiling information for an allocation of size `size'
+** in procedure `proc' for an object of type `type'.
+*/
+void
+MR_record_allocation(int size, Code *proc_addr,
+	const char *proc_name, const char *type)
+{
+	/*
+	** Increment the overall totals,
+	** record the allocation in the per-procedure table, and
+	** record the allocation in the per-type table.
+	*/
+	MR_increment_counter(&MR_memprof_overall, size);
+	MR_increment_table_entry(&MR_memprof_procs, proc_name, proc_addr, size);
+	MR_increment_table_entry(&MR_memprof_types, type, NULL, size);
+}
Index: runtime/mercury_heap_profile.h
===================================================================
RCS file: mercury_heap_profile.h
diff -N mercury_heap_profile.h
--- /dev/null	Sun Nov 30 01:48:53 1997
+++ mercury_heap_profile.h	Tue Nov 25 06:23:30 1997
@@ -0,0 +1,174 @@
+/*
+** Copyright (C) 1997 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: mercury_heap_profile.h
+** Main authors: zs, fjh
+**
+** This module records information about the allocations of cells on the heap.
+*/
+
+/*---------------------------------------------------------------------------*/
+
+#ifndef MERCURY_HEAP_PROFILE_H
+#define MERCURY_HEAP_PROFILE_H
+
+/*---------------------------------------------------------------------------*/
+
+/*
+** Due to garbage collection, the total amount of memory allocated can
+** exceed the amount of real or even virtual memory available.  Hence
+** the total amount of memory allocated by a long-running Mercury program
+** might not fit into a single 32-bit `unsigned long'.
+** Hence we record memory usage counts using either `unsigned long long',
+** if available, or otherwise using a pair of unsigned longs (ugh).
+*/
+
+#ifdef MR_HAVE_LONG_LONG
+
+  /* nice and simple */
+
+  typedef unsigned long long MR_dword;
+
+  #define MR_convert_dword_to_double(dword_form, double_form) \
+		((double_form) = (double) (dword_form))
+
+  #define MR_zero_dword(dword) \
+		((dword) = 0)
+
+  #define MR_increment_dword(dword, inc) \
+		((dword) += (inc))
+
+  #define MR_add_two_dwords(src_dest_dword, src_dword) \
+		((src_dest_dword) += (src_dword))
+
+#else /* not MR_HAVE_LONG_LONG */
+
+  /* oh well, guess we have to do it the hard way :-( */
+
+  typedef struct MR_dword
+  {
+	unsigned long	low_word;
+	unsigned long	high_word;
+  } MR_dword;
+
+  #include <limits.h>
+
+  #define MR_HIGHWORD_TO_DOUBLE	(((double) ULONG_MAX) + 1.0)
+
+  #define MR_convert_dword_to_double(dword_form, double_form) 		\
+	do {								\
+		double_form = (MR_HIGHWORD_TO_DOUBLE			\
+			* (double) (dword_form).high_word) 		\
+			+ (double) (dword_form).low_word;		\
+	} while (0)
+
+  #define MR_zero_dword(dword) 						\
+	do { 								\
+		(dword).low_word = 0;					\
+		(dword).high_word = 0;					\
+	} while (0)
+
+  #define MR_increment_dword(dword, inc) 				\
+	do { 								\
+		unsigned long	old_low_word = (dword).low_word;	\
+		(dword).low_word += (inc);				\
+		if ((dword).low_word < old_low_word) {			\
+			(dword).high_word += 1;				\
+		}							\
+	} while (0)
+
+  #define MR_add_two_dwords(src_dest_dword, src_dword) 			\
+	do { 								\
+		unsigned long	old_low_word = (src_dest_dword).low_word; \
+		(src_dest_dword).low_word += (src_dword).low_word;	\
+		if ((src_dest_dword).low_word < old_low_word) {		\
+			(src_dest_dword).high_word += 1;		\
+		}							\
+		(src_dest_dword).high_word += (src_dword).high_word;	\
+	} while (0)
+
+#endif /* not MR_HAVE_LONG_LONG */
+
+/*---------------------------------------------------------------------------*/
+
+/* type declarations */
+
+/*
+** We count memory allocation in units of
+**	- cells (i.e. individual allocations), and
+**	- words
+**
+** We keep track of how much memory was allocated
+**	- by each procedure,
+**	- for objects of each type,
+**	- and an overall total
+**
+** The tables of counters for each procedure is represented
+** as a binary search tree.  Similarly for the table of counters
+** for each type.
+*/
+
+typedef	struct MR_memprof_counter
+{
+	MR_dword	cells_at_period_start;		/* ? what for? */
+	MR_dword	words_at_period_start;		/* ? what for? */
+	MR_dword	cells_since_period_start;
+	MR_dword	words_since_period_start;
+} MR_memprof_counter;
+
+/* type representing a binary tree node */
+typedef	struct MR_memprof_record
+{
+	const char			*name; /* of the type or procedure */
+	Code				*addr; /* for procedures only */
+	MR_memprof_counter		counter;
+	struct MR_memprof_record	*left;	/* left sub-tree */
+	struct MR_memprof_record	*right;	/* right sub-tree */
+} MR_memprof_record;
+
+/* type representing a binary tree */
+typedef	struct MR_memprof_table
+{
+	MR_memprof_record		*root;
+	int				num_entries;
+} MR_memprof_table;
+
+/*---------------------------------------------------------------------------*/
+
+/* global variables */
+
+extern	MR_memprof_counter	MR_memprof_overall;
+extern	MR_memprof_table	MR_memprof_procs;
+extern	MR_memprof_table	MR_memprof_types;
+
+/*---------------------------------------------------------------------------*/
+
+/* function declarations */
+
+/*
+** MR_record_allocation(size, proc_addr, proc_name, type):
+**	Record heap profiling information for an allocation of one cell
+**	of `size' words by procedure `proc_name' with address `proc_addr'
+**	for an object of type `type'.
+**	The heap profiling information is recorded in the three global
+**	variables above.
+*/
+extern void MR_record_allocation(int size, Code *proc_addr,
+		const char *proc_name, const char *type);
+
+/*
+** MR_prof_output_mem_tables():
+**	Write out the information recorded by MR_record_allocation()
+**	to a pair of files `Prof.MemoryWords' and `Prof.MemoryCells'.
+*/
+extern void MR_prof_output_mem_tables(void);
+
+/*---------------------------------------------------------------------------*/
+
+#endif /* MERCURY_HEAP_PROFILE_H */
+
+/*---------------------------------------------------------------------------*/
Index: runtime/mercury_label.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_label.c,v
retrieving revision 1.2
diff -u -u -r1.2 mercury_label.c
--- mercury_label.c	1997/11/23 07:21:26	1.2
+++ mercury_label.c	1997/11/24 23:32:33
@@ -9,6 +9,8 @@
 ** that map from procedure names to addresses and vice versa.
 */
 
+#include	"mercury_imp.h"	/* we need libmer_globals.h for Windows DLLs */
+
 #include	<stdio.h>
 #include	<string.h>
 
@@ -16,9 +18,8 @@
 
 #include	"mercury_label.h"
 
-#include	"mercury_imp.h"		/* we need libmer_globals.h for Windows DLLs */
 #include	"mercury_table.h"	/* for `Table' */
-#include	"mercury_prof.h"	/* for prof_output_addr_decls() */
+#include	"mercury_prof.h"	/* for prof_output_addr_decl() */
 #include	"mercury_engine.h"	/* for `progdebug' */
 #include	"mercury_wrapper.h"	/* for do_init_modules() */
 
@@ -61,7 +62,7 @@
 	entry->e_addr  = addr;
 
 #ifdef	PROFILE_CALLS
-	prof_output_addr_decls(name, addr);
+	if (MR_profiling) MR_prof_output_addr_decl(name, addr);
 #endif
 
 #ifndef	SPEED
Index: runtime/mercury_prof.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_prof.c,v
retrieving revision 1.3
diff -u -u -r1.3 mercury_prof.c
--- mercury_prof.c	1997/11/23 07:21:30	1.3
+++ mercury_prof.c	1997/11/29 10:05:57
@@ -18,9 +18,10 @@
 #include	<string.h>
 
 #include	"mercury_prof.h"
+#include	"mercury_heap_profile.h" /* for MR_prof_output_mem_tables() */
+#include	"mercury_prof_mem.h"	 /* for prof_malloc() */
 
 #include        "mercury_std.h"
-#include	"mercury_prof_mem.h"
 #include	"mercury_timing.h"
 
 #if defined(PROFILE_TIME)
@@ -38,11 +39,12 @@
 
 static int	MR_itimer_sig;
 static int	MR_itimer_type;
+static const char * MR_time_method;
 
 #endif	/* PROFILE_TIME */
 
 /*
-** Need to make these command line options
+** XXX Ought to make these command line options
 */
 #define CALL_TABLE_SIZE 4096
 #define TIME_TABLE_SIZE 4096
@@ -85,27 +87,47 @@
 ** Global Variables
 */
 
-Code *		volatile	prof_current_proc;
-static volatile	int		in_profiling_code = FALSE;
+Code *		volatile	MR_prof_current_proc;
 
 /* 
 ** Private global variables
 */
 
+static volatile	int		in_profiling_code = FALSE;
+
+
 #ifdef PROFILE_CALLS
-static	FILE	 	*declfptr = NULL;
-static	prof_call_node	*addr_pair_table[CALL_TABLE_SIZE] = {NULL};
-static	bool		profiling_on = FALSE;
+  static FILE 		*decl_fptr = NULL;
+  static prof_call_node	*addr_pair_table[CALL_TABLE_SIZE] = {NULL};
 #endif
 
 #ifdef PROFILE_TIME
-static	prof_time_node	*addr_table[TIME_TABLE_SIZE] = {NULL};
+  static bool		time_profiling_on = FALSE;
+  static prof_time_node	*addr_table[TIME_TABLE_SIZE] = {NULL};
 #endif
 
 /*
 ** Local function declarations
 */
-static	void prof_finish(void);
+
+#ifdef PROFILE_TIME
+  static void prof_init_time_profile_method(void);
+  static void prof_time_profile(int);
+  static void prof_output_addr_table(void);
+  static void print_time_node(FILE *fptr, prof_time_node *node);
+#endif
+
+#ifdef PROFILE_CALLS
+  static void print_addr_pair_node(FILE *fptr, prof_call_node *node);
+  static void prof_output_addr_pair_table(void);
+#endif
+
+#ifdef PROFILE_MEMORY
+  static void prof_output_mem_tables(void);
+  static void print_memory_node(FILE *words_fptr, FILE *cells_fptr,
+		MR_memprof_record *node);
+#endif
+
 
 /* ======================================================================== */
 
@@ -139,7 +161,7 @@
 
 /* utility routines for opening and closing files */
 
-#if defined(PROFILE_TIME) || defined(PROFILE_CALLS)
+#if defined(PROFILE_TIME) || defined(PROFILE_CALLS) || defined(PROFILE_MEMORY)
 
 static FILE *
 checked_fopen(const char *filename, const char *message, const char *mode)
@@ -180,7 +202,7 @@
 	}
 }
 
-#endif /* defined(PROFILE_TIME) || defined(PROFILE_CALLS) */
+#endif /* PROFILE_TIME or PROFILE_CALLS or PROFILE_MEMORY */
 
 #ifdef	PROFILE_TIME
 
@@ -234,15 +256,9 @@
 
 #ifdef PROFILE_TIME
 
-static void prof_init_time_profile_method(void);
-static void prof_time_profile(int);
-
 /*
-**	prof_init_time_profile:
-**		Writes the value of MR_CLOCK_TICKS_PER_SECOND and
-**		MR_CLOCK_TICKS_PER_PROF_SIG at the start of the file
-**		'Prof.Counts'.
-**		Then sets up the profiling timer and starts it up. 
+**	prof_turn_on_time_profiling:
+**		Sets up the profiling timer and starts it up. 
 **		At the moment it is after every MR_CLOCK_TICKS_PER_PROF_SIG
 **		ticks of the clock.
 **
@@ -252,30 +268,20 @@
 */
 
 void
-prof_init_time_profile(void)
+MR_prof_turn_on_time_profiling(void)
 {
 	FILE 	*fptr;
 	struct itimerval itime;
 	const long prof_sig_interval_in_usecs = MR_CLOCK_TICKS_PER_PROF_SIG *
 		(MR_USEC_PER_SEC / MR_CLOCK_TICKS_PER_SECOND);
 
-	/* output the value of MR_CLOCK_TICKS_PER_SECOND */
-	fptr = checked_fopen("Prof.Counts", "create", "w");
-	fprintf(fptr, "%d %d\n",
-		MR_CLOCK_TICKS_PER_SECOND, MR_CLOCK_TICKS_PER_PROF_SIG);
-	checked_fclose(fptr, "Prof.Counts");
-
-	checked_atexit(prof_finish);
-
-	profiling_on = TRUE;
+	time_profiling_on = TRUE;
 
 	itime.it_value.tv_sec = 0;
 	itime.it_value.tv_usec = prof_sig_interval_in_usecs;
 	itime.it_interval.tv_sec = 0;
 	itime.it_interval.tv_usec = prof_sig_interval_in_usecs;
 
-	prof_init_time_profile_method();
-
 	checked_signal(MR_itimer_sig, prof_time_profile);
 	checked_setitimer(MR_itimer_type, &itime);
 }
@@ -293,18 +299,21 @@
 		case MR_profile_real_time:
 			MR_itimer_type = ITIMER_REAL;
 			MR_itimer_sig  = SIGALRM;
+			MR_time_method = "real-time";
 			break;
 #endif
 #if defined(ITIMER_VIRTUAL) && defined(SIGVTALRM)
 		case MR_profile_user_time:
 			MR_itimer_type = ITIMER_VIRTUAL;
 			MR_itimer_sig  = SIGVTALRM;
+			MR_time_method = "user-time";
 			break;
 #endif
 #if defined(ITIMER_VIRTUAL) && defined(SIGVTALRM)
 		case MR_profile_user_plus_system_time:
 			MR_itimer_type = ITIMER_PROF;
 			MR_itimer_sig  = SIGPROF;
+			MR_time_method = "user-plus-system-time";
 			break;
 #endif
 		default:
@@ -324,7 +333,7 @@
 */
 
 void
-prof_call_profile(Code *Callee, Code *Caller)
+MR_prof_call_profile(Code *Callee, Code *Caller)
 {
 	prof_call_node	*node, **node_addr, *new_node;
 	int		 hash_value;
@@ -350,7 +359,7 @@
 		}
 	}
 
-	new_node = prof_make(prof_call_node);
+	new_node = MR_PROF_NEW(prof_call_node);
 	new_node->Callee = Callee;
 	new_node->Caller = Caller;
 	new_node->count  = 1;
@@ -380,6 +389,7 @@
 {
 	prof_time_node	*node, **node_addr, *new_node;
 	int		hash_value;
+	Code 		*current_proc;
 
 	/* Ignore any signals we get in this function or in prof_call_profile */
 	if (in_profiling_code) {
@@ -388,13 +398,14 @@
 
 	in_profiling_code = TRUE;
 
-	hash_value = hash_prof_addr(prof_current_proc);
+	current_proc = MR_prof_current_proc;
+	hash_value = hash_prof_addr(current_proc);
 
 	node_addr = &addr_table[hash_value];
 	while ((node = *node_addr) != NULL) {
-		if (node->Addr < prof_current_proc) {
+		if (node->Addr < current_proc) {
 			node_addr = &node->left;
-		} else if (node->Addr > prof_current_proc) {
+		} else if (node->Addr > current_proc) {
 			node_addr = &node->right;
 		} else {
 			node->count++;
@@ -403,8 +414,8 @@
 		}
 	}
 
-	new_node = prof_make(prof_time_node);
-	new_node->Addr  = prof_current_proc;
+	new_node = MR_PROF_NEW(prof_time_node);
+	new_node->Addr  = current_proc;
 	new_node->count = 1;
 	new_node->left  = NULL;
 	new_node->right = NULL;
@@ -422,11 +433,11 @@
 */
 
 void
-prof_turn_off_time_profiling(void)
+MR_prof_turn_off_time_profiling(void)
 {
 	struct itimerval itime;
 
-	if (profiling_on == FALSE)
+	if (time_profiling_on == FALSE)
 		return;
 
 	itime.it_value.tv_sec = 0;
@@ -449,35 +460,27 @@
 **		Caller then callee followed by count.
 */
 
-static	void	print_addr_pair_node(FILE *fptr, prof_call_node *node);
-
-void
+static void
 prof_output_addr_pair_table(void)
 {
-	static	bool	addr_pair_table_written = FALSE;
-	FILE		*fptr;
-	int		i;
-	if (addr_pair_table_written == TRUE)
-		return;
+	FILE	*fptr;
+	int	i;
 
 	fptr = checked_fopen("Prof.CallPair", "create", "w");
+
 	for (i = 0; i < CALL_TABLE_SIZE ; i++) {
 		print_addr_pair_node(fptr, addr_pair_table[i]);
 	}
 
 	checked_fclose(fptr, "Prof.CallPair");
-
-	addr_pair_table_written = TRUE;
 }
 
 static void
 print_addr_pair_node(FILE *fptr, prof_call_node *node)
 {
-	if (node != (prof_call_node *) NULL) {
+	if (node != NULL) {
 		fprintf(fptr, "%ld %ld %lu\n",
-			(long) node->Caller,
-			(long) node->Callee,
-			node->count);
+			(long) node->Caller, (long) node->Callee, node->count);
 		print_addr_pair_node(fptr, node->left);
 		print_addr_pair_node(fptr, node->right);
 	}
@@ -487,22 +490,22 @@
 
 /* ======================================================================== */
 
-#ifdef PROFILE_CALLS
+#if defined(PROFILE_CALLS)
 
 /*
-**	prof_output_addr_decls:
-**		Ouputs the main predicate labels as well as their machine
-**		addresses to a file called "Prof.Decl".
-**		This is called from insert_entry() in label.c.
+**	prof_output_addr_decl:
+**		Ouputs an entry label name and its corresponding machine
+**		address to a file called "Prof.Decl".
+**		This is called from insert_entry() in mercury_label.c.
 */
 
 void
-prof_output_addr_decls(const char *name, const Code *address)
+MR_prof_output_addr_decl(const char *name, const Code *address)
 {
-	if (!declfptr) {
-		declfptr = checked_fopen("Prof.Decl", "create", "w");
+	if (!decl_fptr) {
+		decl_fptr = checked_fopen("Prof.Decl", "create", "w");
 	}
-	fprintf(declfptr, "%ld\t%s\n", (long) address, name);
+	fprintf(decl_fptr, "%ld\t%s\n", (long) address, name);
 }
 
 #endif /* PROFILE_CALLS */
@@ -513,39 +516,45 @@
 
 /*
 **	prof_output_addr_table:
-**		Outputs the addresses saved whenever PROF_SIG is received to
-**		the file "Prof.Counts"
+**		Writes out the time profiling counts recorded
+**		by the profile signal handler to the file `Prof.Counts'.
 */
 
-static	void	print_time_node(FILE *fptr, prof_time_node *node);
-
-void
+static void
 prof_output_addr_table(void)
 {
-	static	bool	addr_table_written = FALSE;
 	FILE *fptr;
 	int  i;
+	double scale;
+	double rate;
 
-	if (addr_table_written == TRUE)
-		return;
+	fptr = checked_fopen("Prof.Counts", "create", "w");
 
-	fptr = checked_fopen("Prof.Counts", "append to", "a");
+	/*
+	** Write out header line indicating what we are profiling,
+	** the scale factor, and the units.
+	** The scale factor is the time per profiling interrupt.
+	** The units are seconds.
+	*/
+	scale = (double) MR_CLOCK_TICKS_PER_PROF_SIG /
+		(double) MR_CLOCK_TICKS_PER_SECOND;
+	fprintf(fptr, "%s %f %s\n", MR_time_method, scale, "seconds");
+
+	/*
+	** Write out the time profiling data: one one-line entry per node.
+	*/
 	for (i = 0; i < TIME_TABLE_SIZE ; i++) {
 		print_time_node(fptr, addr_table[i]);
 	}
 
 	checked_fclose(fptr, "Prof.Counts");
-
-	addr_table_written = TRUE;
 }
 
 static void
 print_time_node(FILE *fptr, prof_time_node *node)
 {
 	if (node != (prof_time_node *) NULL) {
-		fprintf(fptr, "%ld %lu\n",
-			(long) node->Addr,
-			node->count);
+		fprintf(fptr, "%ld %lu\n", (long) node->Addr, node->count);
 		print_time_node(fptr, node->left);
 		print_time_node(fptr, node->right);
 	}
@@ -553,16 +562,107 @@
 
 #endif /* PROFILE_TIME */
 
-void prof_finish(void)
+/* ======================================================================== */
+
+#ifdef PROFILE_MEMORY
+
+/*
+**	prof_output_addr_table:
+**		Writes the value of MR_CLOCK_TICKS_PER_SECOND and
+**		MR_CLOCK_TICKS_PER_PROF_SIG at the start of the file
+**		`Prof.Counts'.  Then outputs the addresses saved
+**		whenever PROF_SIG is received (also to `Prof.Counts').
+*/
+
+static void
+prof_output_mem_tables(void)
+{
+	FILE *words_fptr;
+	FILE *cells_fptr;
+	int  i;
+
+	words_fptr = checked_fopen("Prof.MemoryWords", "create", "w");
+	cells_fptr = checked_fopen("Prof.MemoryCells", "create", "w");
+
+	fprintf(words_fptr, "%s %f %s\n",
+		"memory-words", 0.001, "kilowords");
+	fprintf(cells_fptr, "%s %f %s\n",
+		"memory-cells", 0.001, "kilocells");
+
+	print_memory_node(words_fptr, cells_fptr, MR_memprof_procs.root);
+
+	checked_fclose(words_fptr, "Prof.MemoryWords");
+	checked_fclose(cells_fptr, "Prof.MemoryCells");
+}
+
+static void
+print_memory_node(FILE *words_fptr, FILE *cells_fptr, MR_memprof_record *node)
+{
+	if (node != NULL) {
+		MR_dword cells, words;
+
+		cells = node->counter.cells_at_period_start;
+		words = node->counter.words_at_period_start;
+
+		MR_add_two_dwords(cells,
+			node->counter.cells_since_period_start);
+		MR_add_two_dwords(words,
+			node->counter.words_since_period_start);
+
+		if (cells.high_word || words.high_word) {
+			fprintf(stderr, "Mercury runtime: memory profile "
+				"counter for `%s' overflowed\n",
+				node->name);
+		}
+		fprintf(words_fptr, "%ld %lu\n",
+			(long) node->addr, words.low_word);
+		fprintf(cells_fptr, "%ld %lu\n",
+			(long) node->addr, cells.low_word);
+
+		print_memory_node(words_fptr, cells_fptr, node->left);
+		print_memory_node(words_fptr, cells_fptr, node->right);
+	}
+}
+
+#endif /* PROFILE_MEMORY */
+
+/* ======================================================================== */
+
+void
+MR_prof_init(void)
 {
+#ifdef PROFILE_TIME
+	prof_init_time_profile_method();
+#endif
+
+#if defined(PROFILE_TIME) || defined(PROFILE_CALLS) || defined(PROFILE_MEMORY)
+	checked_atexit(MR_prof_finish);
+#endif
+}
+
+void
+MR_prof_finish(void)
+{
+	/* ensure this routine only gets run once, even if called twice */
+	static bool done = FALSE;
+	if (done) return;
+	done = TRUE;
 
 #ifdef PROFILE_TIME
-	prof_turn_off_time_profiling();
+	MR_prof_turn_off_time_profiling();
 	prof_output_addr_table();
 #endif
 
-#ifdef PROFILE_CALLS
+#if defined(PROFILE_CALLS)
+	if (decl_fptr) {
+		checked_fclose(decl_fptr, "Prof.Decl");
+	}
 	prof_output_addr_pair_table();
 #endif
+
+#ifdef PROFILE_MEMORY
+	prof_output_mem_tables();
+#endif
 }
 
+/* ======================================================================== */
Index: runtime/mercury_prof.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_prof.h,v
retrieving revision 1.2
diff -u -u -r1.2 mercury_prof.h
--- mercury_prof.h	1997/11/23 07:21:30	1.2
+++ mercury_prof.h	1997/11/24 19:23:30
@@ -4,7 +4,10 @@
 ** Public License - see the file COPYING.LIB in the Mercury distribution.
 */
 
-/* mercury_prof.h -- definitions for profiling */
+/*
+** mercury_prof.h -- definitions for profiling.
+** (See also mercury_heap_profiling.h.)
+*/
 
 #ifndef MERCURY_PROF_H
 #define MERCURY_PROF_H
@@ -12,38 +15,69 @@
 #include "mercury_types.h"	/* for `Code *' */
 
 /*
-** this variable holds the address of the "current" procedure so that
+** This variable holds the address of the "current" procedure so that
 ** when a profiling interrupt occurs, the profiler knows where we are,
 ** so that it can credit the time to the appropriate procedure.
 */
 
-extern	Code *	volatile	prof_current_proc;
+extern	Code *	volatile	MR_prof_current_proc;
 
 /*
-** the following two macros are used to ensure that the profiler can
+** The following two macros are used to ensure that the profiler can
 ** use `prof_current_proc' to determine what procedure is currently
-** being executed when a profiling interrupt occurs
+** being executed when a profiling interrupt occurs.
 */
 
 #ifdef PROFILE_TIME
-#define set_prof_current_proc(target)		(prof_current_proc = (target))
-#define update_prof_current_proc(target)	(prof_current_proc = (target))	
+  #define set_prof_current_proc(target)		\
+		(MR_prof_current_proc = (target))
+  #define update_prof_current_proc(target)	\
+		(MR_prof_current_proc = (target))	
 #else
-#define set_prof_current_proc(target)		((void)0)
-#define update_prof_current_proc(target)	((void)0)
+  #define set_prof_current_proc(target)		((void)0)
+  #define update_prof_current_proc(target)	((void)0)
 #endif
 
+/*
+** The PROFILE() macro is used (by mercury_calls.h) to record each call.
+*/
+
 #ifdef	PROFILE_CALLS
-#define	PROFILE(callee, caller)		prof_call_profile((callee), (caller))
+  #define PROFILE(callee, caller) MR_prof_call_profile((callee), (caller))
 #else
-#define	PROFILE(callee, caller)		((void)0)
+  #define PROFILE(callee, caller) ((void)0)
 #endif
 
-extern	void 	prof_init_time_profile(void);
-extern  void    prof_call_profile(Code *, Code *);
-extern	void	prof_turn_off_time_profiling(void);
-extern	void	prof_output_addr_pair_table(void);
-extern	void	prof_output_addr_decls(const char *, const Code *);
-extern	void	prof_output_addr_table(void);
+#ifdef PROFILE_CALLS
+  extern void	MR_prof_call_profile(Code *, Code *);
+#endif
+
+
+/*
+** The prof_output_addr_decl() function is used by insert_entry() in
+** mercury_label.c to record the address of each entry label.
+*/
+
+extern void	MR_prof_output_addr_decl(const char *name, const Code *address);
+
+
+/*
+** The following functions are used by mercury_wrapper.c to
+** initiate profiling, at the start of the the program,
+** and to finish up profiling (writing the profiling data to files)
+** at the end of the program.
+** Note that prof_init() calls atexit(prof_finish), so that it can handle
+** the case where the program exits by calling exit() rather than just
+** returning, so it is actually not necessary to call prof_finish()
+** explicitly.
+*/
+
+extern	void	MR_prof_init(void);
+extern	void	MR_prof_finish(void);
+
+#ifdef PROFILE_TIME
+  extern void 	MR_prof_turn_on_time_profiling(void);
+  extern void	MR_prof_turn_off_time_profiling(void);
+#endif
 
 #endif	/* not MERCURY_PROF_H */
Index: runtime/mercury_prof_mem.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_prof_mem.c,v
retrieving revision 1.2
diff -u -u -r1.2 mercury_prof_mem.c
--- mercury_prof_mem.c	1997/11/23 07:21:31	1.2
+++ mercury_prof_mem.c	1997/11/24 17:25:12
@@ -11,10 +11,10 @@
 **
 ** This module is needed to get around the problem that when a signal occurs
 ** it may be in a malloc.  The handling routine may also do a malloc which 
-** stuff's up the internal state of malloc and cause a seg fault.
-**
-** NB.	This shouldn't be needed anymore when native gc is implemented
-** 	as mercury will no longer use malloc anymore.
+** stuffs up the internal state of malloc and cause a seg fault.
+** To avoid this problem, we use our own version of malloc() which
+** allocates memory in large chunks, reducing the chance of this
+** problem occurring.
 */
 
 #include <stdio.h>
@@ -50,7 +50,7 @@
 
 
 void *
-prof_malloc(size_t size)
+MR_prof_malloc(size_t size)
 {
 	register void *p;
 
Index: runtime/mercury_prof_mem.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_prof_mem.h,v
retrieving revision 1.2
diff -u -u -r1.2 mercury_prof_mem.h
--- mercury_prof_mem.h	1997/11/23 07:21:32	1.2
+++ mercury_prof_mem.h	1997/11/24 19:23:30
@@ -23,8 +23,12 @@
 ** from a profiling interrupt that interrupted another call to newmem().
 ** Doing that is bad news, because newmem() is not re-entrant.
 */
-void *prof_malloc(size_t);
+extern void *MR_prof_malloc(size_t);
 
-#define prof_make(t)	((t *) prof_malloc(sizeof(t)))
+/*
+** Use the following macros rather than calling MR_prof_malloc() directly.
+*/
+#define MR_PROF_NEW(t)		((t *) MR_prof_malloc(sizeof(t)))
+#define MR_PROF_NEW_ARRAY(t,n)	((t *) MR_prof_malloc(sizeof(t) * (n)))
 
 #endif /* not MERCURY_PROF_MEM_H */
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.3
diff -u -u -r1.3 mercury_wrapper.c
--- mercury_wrapper.c	1997/11/23 07:21:44	1.3
+++ mercury_wrapper.c	1997/11/29 14:35:28
@@ -88,6 +88,8 @@
 char **		mercury_argv;
 int		mercury_exit_status = 0;
 
+bool		MR_profiling = TRUE;
+
 /*
 ** EXTERNAL DEPENDENCIES
 **
@@ -221,6 +223,9 @@
 	/* start up the Mercury engine */
 	init_engine();
 
+	/* initialize profiling */
+	if (MR_profiling) MR_prof_init();
+
 	/*
 	** We need to call save_registers(), since we're about to
 	** call a C->Mercury interface function, and the C->Mercury
@@ -427,7 +432,7 @@
 	unsigned long size;
 	int c;
 
-	while ((c = getopt(argc, argv, "acd:hLlP:p:r:s:tT:w:xz:1:2:3:")) != EOF)
+	while ((c = getopt(argc, argv, "acC:d:hLlP:pr:s:tT:w:xz:1:2:3:")) != EOF)
 	{
 		switch (c)
 		{
@@ -440,6 +445,14 @@
 			check_space = TRUE;
 			break;
 
+		case 'C':
+			if (sscanf(optarg, "%lu", &size) != 1)
+				usage();
+
+			pcache_size = size * 1024;
+
+			break;
+
 		case 'd':	
 			if (streq(optarg, "b"))
 				nondstackdebug = TRUE;
@@ -513,6 +526,10 @@
 			exit(0);
 		}
 
+		case 'p':
+			MR_profiling = FALSE;
+			break;
+
 #ifdef	PARALLEL
 		case 'P':
 				if (sscanf(optarg, "%u", &numprocs) != 1)
@@ -524,14 +541,6 @@
 				break;
 #endif
 
-		case 'p':
-			if (sscanf(optarg, "%lu", &size) != 1)
-				usage();
-
-			pcache_size = size * 1024;
-
-			break;
-
 		case 'r':	
 			if (sscanf(optarg, "%d", &repeats) != 1)
 				usage();
@@ -603,7 +612,7 @@
 		}
 		case 'x':
 #ifdef CONSERVATIVE_GC
-			GC_dont_gc = 1;
+			GC_dont_gc = TRUE;
 #endif
 
 			break;
@@ -656,17 +665,18 @@
 usage(void)
 {
 	printf("Mercury runtime usage:\n"
-		"MERCURY_OPTIONS=\"[-hclt] [-d[abcdghs]] [-[sz][hdn]#]\n"
-	"                 [-p#] [-r#] [-1#] [-2#] [-3#] [-w name]\"\n"
+		"MERCURY_OPTIONS=\"[-hclLtxp] [-T[rvp]] [-d[abcdghs]]\n"
+        "                  [-[szt][hdn]#] [-C#] [-r#]  [-w name] [-[123]#]\"\n"
 		"-h \t\tprint this usage message\n"
 		"-c \t\tcheck cross-function stack usage\n"
 		"-l \t\tprint all labels\n"
 		"-L \t\tcheck for duplicate labels\n"
 		"-t \t\ttime program execution\n"
+		"-x \t\tdisable garbage collection\n"
+		"-p \t\tdisable profiling\n"
 		"-Tr \t\tprofile real time (using ITIMER_REAL)\n"
 		"-Tv \t\tprofile user time (using ITIMER_VIRTUAL)\n"
 		"-Tp \t\tprofile user + system time (using ITIMER_PROF)\n"
-		"-x \t\tdisable garbage collection\n"
 		"-dg \t\tdebug gotos\n"
 		"-dc \t\tdebug calls\n"
 		"-db \t\tdebug backtracking\n"
@@ -690,9 +700,11 @@
 #ifdef MR_USE_TRAIL
 		"-zt<n> \t\tallocate n kb for the trail redzone\n"
 #endif
+		"-C<n> \t\tprimary cache size in kbytes\n"
+#ifdef PARALLEL
 		"-P<n> \t\tnumber of processes to use for parallel execution\n"
 		"\t\tapplies only if Mercury is configured with --enable-parallel\n"
-		"-p<n> \t\tprimary cache size in kbytes\n"
+#endif
 		"-r<n> \t\trepeat n times\n"
 		"-w<name> \tcall predicate with given name (default: main/2)\n"
 		"-1<x> \t\tinitialize register r1 with value x\n"
@@ -872,7 +884,7 @@
 	}
 
 #ifdef  PROFILE_TIME
-	prof_init_time_profile();
+	if (MR_profiling) MR_prof_turn_on_time_profiling();
 #endif
 
 	noprof_call(program_entry_point, LABEL(global_success));
@@ -904,12 +916,9 @@
 #endif
 
 Define_label(all_done);
+
 #ifdef  PROFILE_TIME
-	prof_turn_off_time_profiling();
-	prof_output_addr_table();
-#endif
-#ifdef  PROFILE_CALLS
-	prof_output_addr_pair_table();
+	if (MR_profiling) MR_prof_turn_off_time_profiling();
 #endif
 
 	MR_maxfr = (Word *) pop();
@@ -946,6 +955,8 @@
 	save_regs_to_mem(c_regs);
 
 	(*MR_library_finalizer)();
+
+	if (MR_profiling) MR_prof_finish();
 
 	terminate_engine();
 
Index: runtime/mercury_wrapper.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.h,v
retrieving revision 1.3
diff -u -u -r1.3 mercury_wrapper.h
--- mercury_wrapper.h	1997/11/23 07:21:44	1.3
+++ mercury_wrapper.h	1997/11/24 23:37:22
@@ -95,4 +95,6 @@
 extern	enum MR_TimeProfileMethod
 			MR_time_profile_method;
 
+extern  bool MR_profiling;
+
 #endif /* not MERCURY_WRAPPER_H */
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing scripts
Index: scripts/init_grade_options.sh-subr
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/init_grade_options.sh-subr,v
retrieving revision 1.1
diff -u -u -r1.1 init_grade_options.sh-subr
--- init_grade_options.sh-subr	1997/10/08 13:16:25	1.1
+++ init_grade_options.sh-subr	1997/11/24 20:39:13
@@ -19,6 +19,7 @@
 gc_method=conservative
 profile_time=false
 profile_calls=false
+profile_memory=false
 use_trail=false
 args_method=compact
 debug=false
Index: scripts/mgnuc.in
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/mgnuc.in,v
retrieving revision 1.44
diff -u -u -r1.44 mgnuc.in
--- mgnuc.in	1997/10/08 13:16:29	1.44
+++ mgnuc.in	1997/11/24 22:24:02
@@ -26,6 +26,7 @@
 	-p, --profiling
 	--profile-calls
 	--profile-time
+	--profile-memory
 	--debug
 	--use-trail
 	--args {simple, compact}
@@ -206,6 +207,11 @@
 	false)		PROF_CALLS_OPTS="" ;;
 esac
 
+case $profile_memory in
+	true)		PROF_MEMORY_OPTS="-DPROFILE_MEMORY" ;;
+	false)		PROF_MEMORY_OPTS="" ;;
+esac
+
 case $use_trail in
 	true)		TRAIL_OPTS="-DMR_USE_TRAIL" ;;
 	false)		TRAIL_OPTS="" ;;
@@ -338,17 +344,20 @@
 
 case $verbose in true)
 	echo $CC -I$C_INCL_DIR $ANSI_OPTS $CHECK_OPTS \
-		$GRADE_OPTS $GC_OPTS $PROF_TIME_OPTS $PROF_CALLS_OPTS \
+		$GRADE_OPTS $GC_OPTS \
+		$PROF_TIME_OPTS $PROF_CALLS_OPTS $PROF_MEMORY_OPTS \
 		$INLINE_ALLOC_OPTS $TRAIL_OPTS $SPLIT_OPTS \
 		$PICREG_OPTS $ARCH_OPTS $ARG_OPTS "$@" $OVERRIDE_OPTS ;;
 esac
 case $# in
 	0) exec $CC -I$C_INCL_DIR $ANSI_OPTS $CHECK_OPTS \
-		$GRADE_OPTS $GC_OPTS $PROF_TIME_OPTS $PROF_CALLS_OPTS \
+		$GRADE_OPTS $GC_OPTS \
+		$PROF_TIME_OPTS $PROF_CALLS_OPTS $PROF_MEMORY_OPTS \
 		$INLINE_ALLOC_OPTS $TRAIL_OPTS $SPLIT_OPTS \
 		$PICREG_OPTS $ARCH_OPTS $OVERRIDE_OPTS ;;
 	*) exec $CC -I$C_INCL_DIR $ANSI_OPTS $CHECK_OPTS \
-		$GRADE_OPTS $GC_OPTS $PROF_TIME_OPTS $PROF_CALLS_OPTS \
+		$GRADE_OPTS $GC_OPTS \
+		$PROF_TIME_OPTS $PROF_CALLS_OPTS $PROF_MEMORY_OPTS \
 		$INLINE_ALLOC_OPTS $TRAIL_OPTS $SPLIT_OPTS \
 		$PICREG_OPTS $ARCH_OPTS $ARG_OPTS "$@" $OVERRIDE_OPTS ;;
 esac
Index: scripts/ml.in
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/ml.in,v
retrieving revision 1.35
diff -u -u -r1.35 ml.in
--- ml.in	1997/10/12 13:46:45	1.35
+++ ml.in	1997/11/24 21:25:08
@@ -55,6 +55,7 @@
 	-p, --profiling
 	--profile-calls
 	--profile-time
+	--profile-memory
 	--debug
 	--use-trail
 	--args {simple, compact}
@@ -229,11 +230,18 @@
 	conservative)	GRADE="$GRADE.gc" ;;
 	accurate)	GRADE="$GRADE.agc" ;;
 esac
-case $profile_time,$profile_calls in
-	true,true)	GRADE="$GRADE.prof" ;;
-	true,false)	GRADE="$GRADE.proftime" ;;
-	false,true)	GRADE="$GRADE.profcalls" ;;
-	false,false)	;;
+case $profile_time,$profile_calls,$profile_memory in
+	true,true,false)	GRADE="$GRADE.prof" ;;
+	true,false,false)	GRADE="$GRADE.proftime" ;;
+	false,true,false)	GRADE="$GRADE.profcalls" ;;
+	true,true,true)		GRADE="$GRADE.profall" ;;
+	false,true,true)	GRADE="$GRADE.memprof" ;;
+	false,false,false)	;;
+	*)			progname=`basename $0`
+				echo \
+	"$progname: Error: invalid combination of profiling options." 1>&2
+				exit 1
+			;;
 esac
 case $use_trail in
 	true)		GRADE="$GRADE.tr" ;;
Index: scripts/mprof_merge_runs
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/mprof_merge_runs,v
retrieving revision 1.2
diff -u -u -r1.2 mprof_merge_runs
--- mprof_merge_runs	1997/10/15 16:44:33	1.2
+++ mprof_merge_runs	1997/11/29 14:11:45
@@ -6,7 +6,7 @@
 # Public License - see the file COPYING in the Mercury distribution.
 #---------------------------------------------------------------------------#
 #
-# mprof_merge_counts - 
+# mprof_merge_runs - 
 #
 # Merges the profiling counts from different runs of a profiled program.
 #
@@ -70,8 +70,9 @@
 esac
 
 #
-# The Prof.Counts file format is as follows:
-#	clock-frequency	tick-rate
+# The Prof.Counts, Prof.MemoryWords, and Prof.MemoryCells file format
+# is as follows:
+#	what_to_profile scale units
 #	address1 count1
 #	address2 count2
 #	...
@@ -80,17 +81,21 @@
 # To merge two different count files, we just need to
 # add up the counts for each address.
 #
-touch Prof.Counts.total &&
-awk '
-	FNR == 1 { clock = $1; rate = $2; }
-	FNR != 1 { counts[$1] += $2; }
-	END {
-		printf("%d %d\n", clock, rate); 
-		for (addr in counts) {
-			printf("%d %d\n", addr, counts[addr]);
-		}
-	}
-' Prof.Counts.total Prof.Counts > Prof.Counts.newtotal &&
+for prof_file in Prof.Counts Prof.MemoryWords Prof.MemoryCells; do
+	if [ -f $prof_file ]; then
+		touch $prof_file.total &&
+		awk '
+			FNR == 1 { what_to_profile = $1; scale = $2; units = $3; }
+			FNR != 1 { counts[$1] += $2; }
+			END {
+				printf("%s %f %s\n", what_to_profile, scale, units); 
+				for (addr in counts) {
+					printf("%d %d\n", addr, counts[addr]);
+				}
+			}
+		' $prof_file.total $prof_file > $prof_file.newtotal
+	fi
+done &&
 #
 # The Prof.CallPair file format is as follows:
 #	caller1 callee1 count1
Index: scripts/parse_grade_options.sh-subr
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/parse_grade_options.sh-subr,v
retrieving revision 1.1
diff -u -u -r1.1 parse_grade_options.sh-subr
--- parse_grade_options.sh-subr	1997/10/08 13:16:33	1.1
+++ parse_grade_options.sh-subr	1997/11/24 22:21:19
@@ -45,13 +45,20 @@
 		esac
 		;;
 
-	-p|--profiling)
+	-p|--profiling|--time-profiling)
 		profile_time=true
 		profile_calls=true
+		profile_memory=false
+		;;
+	--memory-profiling)
+		profile_time=false
+		profile_calls=true
+		profile_memory=true
 		;;
 	-p-|--no-profiling)
 		profile_time=false
 		profile_calls=false
+		profile_memory=false
 		;;
 	--profile-time)
 		profile_time=true ;;
@@ -61,6 +68,10 @@
 		profile_calls=true ;;
 	--no-profile-calls)
 		profile_calls=false ;;
+	--profile-memory)
+		profile_memory=true ;;
+	--no-profile-memory)
+		profile_memory=false ;;
 
 	--use-trail)
 		use_trail=true ;;
@@ -123,24 +134,40 @@
 		esac
 
 		case "$grade" in
+			*.memprof)
+				profile_time=false
+				profile_calls=true
+				profile_memory=true
+				grade="` expr $grade : '\(.*\).memprof' `"
+				;;
 			*.prof)
 				profile_time=true
 				profile_calls=true
+				profile_memory=false
 				grade="` expr $grade : '\(.*\).prof' `"
 				;;
 			*.proftime)	
 				profile_time=true
 				profile_calls=false
+				profile_memory=false
 				grade="` expr $grade : '\(.*\).proftime' `"
 				;;
 			*.profcalls)	
 				profile_time=false
 				profile_calls=true
+				profile_memory=false
 				grade="` expr $grade : '\(.*\).profcalls' `"
 				;;
+			*.profall)
+				profile_time=true
+				profile_calls=true
+				profile_memory=true
+				grade="` expr $grade : '\(.*\).profall' `"
+				;;
 			*)
 				profile_time=false
 				profile_calls=false
+				profile_memory=false
 				;;
 		esac
 
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/general
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trial
cvs diff: Diffing util

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   WWW: <http://www.cs.mu.oz.au/~fjh>  
Note: due to some buggy software and a (probably accidental)
denial-of-service attack, any mail sent to me between
	Tue Nov 25 20:00:00 UTC (6am Wed, local time)
and	Wed Nov 26 06:00:00 UTC (4pm, local time)
may have gone into the bit-bucket.  Please re-send it.



More information about the developers mailing list