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