mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-08 18:34:00 +00:00
Estimated hours taken: 1
Not all the address in the hlc.gc profiling grades are recorded in the
Prof.Addr file. This can cause map__lookups to fail when processing the
Prof.CallPair file.
process_file.m:
When ever an unknown address is seen while processing the
Prof.CallPair file create a structure named unknown__<addr> to hold
information about the unknown address.
426 lines
14 KiB
Mathematica
426 lines
14 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995-1997,2000 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% process_file.m
|
|
%
|
|
% Main author: petdr.
|
|
%
|
|
% Processs the files that contain the label declarations, label counts and
|
|
% the caller-callee pairs, also builds the dynamic call graph if the option
|
|
% set.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module process_file.
|
|
|
|
:- interface.
|
|
|
|
:- import_module prof_info.
|
|
:- import_module io, relation.
|
|
|
|
:- pred process_file__main(prof, relation(string), io__state, io__state).
|
|
:- mode process_file__main(out, out, di, uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module read.
|
|
:- import_module globals, options.
|
|
:- import_module bool, int, require, std_util, string.
|
|
:- import_module list, map.
|
|
|
|
|
|
process_file__main(Prof, DynamicCallGraph) -->
|
|
globals__io_lookup_bool_option(very_verbose, VVerbose),
|
|
globals__io_lookup_string_option(declfile, DeclFile),
|
|
globals__io_lookup_string_option(countfile, CountFile),
|
|
globals__io_lookup_string_option(pairfile, PairFile),
|
|
% globals__io_lookup_string_option(libraryfile, LibFile),
|
|
globals__io_lookup_bool_option(dynamic_cg, Dynamic),
|
|
|
|
% process the decl file
|
|
maybe_write_string(VVerbose, "\n\t% Processing "),
|
|
maybe_write_string(VVerbose, DeclFile),
|
|
maybe_write_string(VVerbose, "..."),
|
|
process_addr_decl(AddrDeclMap0, ProfNodeMap0),
|
|
maybe_write_string(VVerbose, " done.\n"),
|
|
|
|
% process the timing counts file
|
|
maybe_write_string(VVerbose, "\t% Processing "),
|
|
maybe_write_string(VVerbose, CountFile),
|
|
maybe_write_string(VVerbose, "..."),
|
|
process_addr(ProfNodeMap0, ProfNodeMap1, WhatToProfile, Scale, Units,
|
|
TotalCounts),
|
|
maybe_write_string(VVerbose, " done.\n"),
|
|
|
|
% process the call pair counts file
|
|
maybe_write_string(VVerbose, "\t% Processing "),
|
|
maybe_write_string(VVerbose, PairFile),
|
|
maybe_write_string(VVerbose, "..."),
|
|
process_addr_pair(ProfNodeMap1, AddrDeclMap0, DynamicCallGraph,
|
|
ProfNodeMap, AddrDeclMap),
|
|
maybe_write_string(VVerbose, " done.\n"),
|
|
|
|
{ map__init(CycleMap) },
|
|
{ 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 }
|
|
->
|
|
% maybe_write_string(VVerbose, "\t% Processing "),
|
|
% maybe_write_string(VVerbose, LibFile),
|
|
% maybe_write_string(VVerbose, "..."),
|
|
% process_library_callgraph(_, _),
|
|
% maybe_write_string(VVerbose, " done.\n"),
|
|
{ true }
|
|
|
|
;
|
|
{ true }
|
|
).
|
|
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
|
|
% process_addr_decl:
|
|
% Reads in the Prof.Decl file.
|
|
% Builds the addrdecl map which associates label names(key) with
|
|
% label addresses.
|
|
% Also builds the prof_node_map which associates label addresses with
|
|
% the prof_node structure. Initialises and inserts the label name into
|
|
% the structure at the same time.
|
|
%
|
|
:- pred process_addr_decl(addrdecl, prof_node_map, io__state, io__state).
|
|
:- mode process_addr_decl(out, out, di, uo) is det.
|
|
|
|
process_addr_decl(AddrDeclMap, ProfNodeMap) -->
|
|
{ map__init(AddrDeclMap0) },
|
|
{ map__init(ProfNodeMap0) },
|
|
globals__io_lookup_string_option(declfile, DeclFile),
|
|
io__see(DeclFile, Result),
|
|
(
|
|
{ Result = ok },
|
|
process_addr_decl_2(AddrDeclMap0, ProfNodeMap0, AddrDeclMap,
|
|
ProfNodeMap),
|
|
io__seen
|
|
;
|
|
{ Result = error(Error) },
|
|
{ io__error_message(Error, ErrorMsg) },
|
|
|
|
{ string__append("error opening declaration file `", DeclFile,
|
|
Str0) },
|
|
{ string__append(Str0, "': ", Str1) },
|
|
{ string__append(Str1, ErrorMsg, Str2) },
|
|
{ string__append(Str2, "\n", ErrorStr) },
|
|
{ error(ErrorStr) }
|
|
).
|
|
|
|
:- pred process_addr_decl_2(addrdecl, prof_node_map, addrdecl, prof_node_map,
|
|
io__state, io__state).
|
|
:- mode process_addr_decl_2(in, in, out, out, di, uo) is det.
|
|
|
|
process_addr_decl_2(AddrDecl0, ProfNodeMap0, AddrDecl, ProfNodeMap) -->
|
|
maybe_read_label_addr(MaybeLabelAddr),
|
|
(
|
|
{ MaybeLabelAddr = yes(LabelAddr) },
|
|
read_label_name(LabelName),
|
|
{ prof_node_init(LabelName, ProfNode) },
|
|
{ map__det_insert(AddrDecl0, LabelName, LabelAddr, AddrDecl1) },
|
|
|
|
% Labels with different names but the same addresses.
|
|
(
|
|
{ map__insert(ProfNodeMap0, LabelAddr, ProfNode,
|
|
ProfNodeMap1) }
|
|
->
|
|
{ AddrDecl2 = AddrDecl1 },
|
|
{ ProfNodeMap2 = ProfNodeMap1 }
|
|
;
|
|
{ lookup_addr(ProfNodeMap0, AddrDecl1, LabelAddr,
|
|
ProfNode0, ProfNodeMap1, AddrDecl2) },
|
|
{ prof_node_concat_to_name_list(LabelName, ProfNode0,
|
|
NewProfNode) },
|
|
{ map__det_update(ProfNodeMap1, LabelAddr, NewProfNode,
|
|
ProfNodeMap2) }
|
|
),
|
|
process_addr_decl_2(AddrDecl2, ProfNodeMap2, AddrDecl,
|
|
ProfNodeMap)
|
|
;
|
|
{ MaybeLabelAddr = no },
|
|
{ AddrDecl = AddrDecl0 },
|
|
{ ProfNodeMap = ProfNodeMap0 }
|
|
).
|
|
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
|
|
% process_addr:
|
|
% 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,
|
|
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, WhatToProfile, Scale, Units,
|
|
TotalCounts) -->
|
|
globals__io_lookup_string_option(countfile, CountFile),
|
|
io__see(CountFile, Result),
|
|
(
|
|
{ Result = ok },
|
|
read_what_to_profile(WhatToProfile),
|
|
read_float(Scale),
|
|
read_string(Units),
|
|
process_addr_2(0, ProfNodeMap0, TotalCounts, ProfNodeMap),
|
|
io__seen
|
|
;
|
|
{ Result = error(Error) },
|
|
{ io__error_message(Error, ErrorMsg) },
|
|
io__write_string("\nWarning: error opening `"),
|
|
io__write_string(CountFile),
|
|
io__write_string("': "),
|
|
io__write_string(ErrorMsg),
|
|
io__write_string("\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 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,
|
|
io__state, io__state).
|
|
:- mode process_addr_2(in, in, out, out, di, uo) is det.
|
|
|
|
process_addr_2(TotalCounts0, ProfNodeMap0, TotalCounts, ProfNodeMap) -->
|
|
maybe_read_label_addr(MaybeLabelAddr),
|
|
(
|
|
{ MaybeLabelAddr = yes(LabelAddr) },
|
|
read_int(Count),
|
|
|
|
% Add to initial counts if we have a ProfNode structure
|
|
% for the address otherwise ignore it.
|
|
(
|
|
{map__search(ProfNodeMap0,LabelAddr, ProfNode0)}
|
|
->
|
|
{ prof_node_get_initial_counts(ProfNode0,
|
|
InitCount0) },
|
|
{ InitCount is InitCount0 + Count },
|
|
{ prof_node_set_initial_counts(InitCount,
|
|
ProfNode0, ProfNode) },
|
|
{ map__set(ProfNodeMap0, LabelAddr, ProfNode,
|
|
ProfNodeMap1) },
|
|
{ TC1 is TotalCounts0 + Count }
|
|
;
|
|
{ TC1 = TotalCounts0 },
|
|
{ ProfNodeMap1 = ProfNodeMap0 },
|
|
{ string__format("\nWarning address %d not found! Ignoring address and continuing computation.\n", [ i(LabelAddr) ], String) },
|
|
io__write_string(String)
|
|
),
|
|
|
|
process_addr_2(TC1, ProfNodeMap1, TotalCounts, ProfNodeMap)
|
|
;
|
|
{ MaybeLabelAddr = no },
|
|
{ ProfNodeMap = ProfNodeMap0 },
|
|
{ TotalCounts = TotalCounts0 }
|
|
).
|
|
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
|
|
% process_addr_pair:
|
|
% Reads in the Prof.CallPair file and stores the data in the relevant
|
|
% lists of the prof_node structure. Also calculates the number of times
|
|
% a predicate is called.
|
|
%
|
|
:- pred process_addr_pair(prof_node_map, addrdecl, relation(string),
|
|
prof_node_map, addrdecl, io__state, io__state).
|
|
:- mode process_addr_pair(in, in, out, out, out, di, uo) is det.
|
|
|
|
process_addr_pair(ProfNodeMap0, AddrDecl0, DynamicCallGraph,
|
|
ProfNodeMap, AddrDecl) -->
|
|
{ relation__init(DynamicCallGraph0) },
|
|
globals__io_lookup_bool_option(dynamic_cg, Dynamic),
|
|
globals__io_lookup_string_option(pairfile, PairFile),
|
|
io__see(PairFile, Result),
|
|
(
|
|
{ Result = ok },
|
|
process_addr_pair_2(DynamicCallGraph0, ProfNodeMap0, AddrDecl0,
|
|
Dynamic, DynamicCallGraph,
|
|
ProfNodeMap, AddrDecl),
|
|
io__seen
|
|
;
|
|
{ Result = error(Error) },
|
|
{ io__error_message(Error, ErrorMsg) },
|
|
{ string__append("error opening pair file `", PairFile,
|
|
Str0) },
|
|
{ string__append(Str0, "': ", Str1) },
|
|
{ string__append(Str1, ErrorMsg, Str2) },
|
|
{ string__append(Str2, "\n", ErrorStr) },
|
|
{ error(ErrorStr) }
|
|
).
|
|
|
|
:- pred process_addr_pair_2(relation(string), prof_node_map, addrdecl, bool,
|
|
relation(string), prof_node_map, addrdecl,
|
|
io__state, io__state).
|
|
:- mode process_addr_pair_2(in, in, in, in, out, out, out, di, uo) is det.
|
|
|
|
process_addr_pair_2(DynamicCallGraph0, ProfNodeMap0, AddrDecl0,
|
|
Dynamic, DynamicCallGraph, ProfNodeMap, AddrDecl) -->
|
|
maybe_read_label_addr(MaybeLabelAddr),
|
|
(
|
|
{ MaybeLabelAddr = yes(CallerAddr) },
|
|
read_label_addr(CalleeAddr),
|
|
read_int(Count),
|
|
|
|
% Get child and parent information
|
|
{ lookup_addr(ProfNodeMap0, AddrDecl0, CallerAddr,
|
|
CallerProfNode0, ProfNodeMap0a, AddrDecl1) },
|
|
{ lookup_addr(ProfNodeMap0a, AddrDecl1, CalleeAddr,
|
|
CalleeProfNode0, ProfNodeMap0b, AddrDecl2) },
|
|
{ prof_node_get_pred_name(CallerProfNode0, CallerName) },
|
|
{ prof_node_get_pred_name(CalleeProfNode0, CalleeName) },
|
|
|
|
% Insert child information
|
|
|
|
{ prof_node_concat_to_child(CalleeName, Count, CallerProfNode0,
|
|
CallerProfNode) },
|
|
{map__set(ProfNodeMap0b, CallerAddr, CallerProfNode,
|
|
PNodeMap1)},
|
|
|
|
% Update the total calls field if not self recursive
|
|
({
|
|
CalleeAddr \= CallerAddr
|
|
->
|
|
prof_node_get_total_calls(CalleeProfNode0, TotalCalls0),
|
|
TotalCalls is TotalCalls0 + Count,
|
|
prof_node_set_total_calls(TotalCalls, CalleeProfNode0,
|
|
CalleeProfNode1),
|
|
prof_node_concat_to_parent(CallerName, Count,
|
|
CalleeProfNode1, CalleeProfNode)
|
|
;
|
|
prof_node_set_self_calls(Count, CalleeProfNode0,
|
|
CalleeProfNode)
|
|
}),
|
|
|
|
% Insert parent information
|
|
{ map__set(PNodeMap1, CalleeAddr, CalleeProfNode, PNodeMap2) },
|
|
|
|
% Add edge to call graph if generating dynamic call graph.
|
|
({
|
|
Dynamic = yes
|
|
->
|
|
relation__add_element(DynamicCallGraph0,
|
|
CallerName, CallerKey, DynamicCallGraph1),
|
|
relation__add_element(DynamicCallGraph1,
|
|
CalleeName, CalleeKey, DynamicCallGraph2),
|
|
relation__add(DynamicCallGraph2, CallerKey,
|
|
CalleeKey, DynamicCallGraph99)
|
|
;
|
|
DynamicCallGraph99 = DynamicCallGraph0
|
|
}),
|
|
|
|
process_addr_pair_2(DynamicCallGraph99, PNodeMap2, AddrDecl2,
|
|
Dynamic, DynamicCallGraph, ProfNodeMap,
|
|
AddrDecl)
|
|
;
|
|
{ MaybeLabelAddr = no },
|
|
{ DynamicCallGraph = DynamicCallGraph0 },
|
|
{ ProfNodeMap = ProfNodeMap0 },
|
|
{ AddrDecl = AddrDecl0 }
|
|
).
|
|
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% process_library_callgraph:
|
|
% XXX
|
|
%
|
|
:- pred process_library_callgraph(list(string), map(string, unit),
|
|
io__state, io__state).
|
|
:- mode process_library_callgraph(out, out, di, uo) is det.
|
|
|
|
process_library_callgraph(LibraryATSort, LibPredMap) -->
|
|
globals__io_lookup_string_option(libraryfile, LibFile),
|
|
{ map__init(LibPredMap0) },
|
|
io__see(LibFile, Result),
|
|
(
|
|
{ Result = ok },
|
|
process_library_callgraph_2([], LibraryATSort, LibPredMap0,
|
|
LibPredMap),
|
|
io__seen
|
|
;
|
|
{ Result = error(Error) },
|
|
{ io__error_message(Error, ErrorMsg) },
|
|
io__stderr_stream(StdErr),
|
|
io__write_strings(StdErr, ["mprof: error opening pair file `",
|
|
LibFile, "': ", ErrorMsg, "\n"]),
|
|
{ LibraryATSort = [] },
|
|
{ LibPredMap = LibPredMap0 }
|
|
).
|
|
|
|
:- pred process_library_callgraph_2(list(string), list(string),
|
|
map(string, unit), map(string, unit), io__state, io__state).
|
|
:- mode process_library_callgraph_2(in, out, in, out, di, uo) is det.
|
|
|
|
process_library_callgraph_2(LibATSort0, LibATSort, LibPredMap0, LibPredMap) -->
|
|
maybe_read_label_name(MaybeLabelName),
|
|
(
|
|
{ MaybeLabelName = yes(LabelName) },
|
|
|
|
{ map__det_insert(LibPredMap0, LabelName, unit, LibPredMap1) },
|
|
{ LibATSort1 = [ LabelName | LibATSort0 ] },
|
|
|
|
process_library_callgraph_2(LibATSort1, LibATSort, LibPredMap1,
|
|
LibPredMap)
|
|
;
|
|
{ MaybeLabelName = no },
|
|
|
|
{ LibPredMap = LibPredMap0 },
|
|
{ LibATSort = LibATSort0 }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
|
|
% Attempt to lookup the addr in the prof_node_map, if it doesn't exist
|
|
% record the name as unknown__<address> in the relevant data structures.
|
|
|
|
:- pred lookup_addr(prof_node_map, addrdecl, int, prof_node,
|
|
prof_node_map, addrdecl).
|
|
:- mode lookup_addr(in, in, in, out, out, out) is det.
|
|
|
|
lookup_addr(ProfNodeMap0, AddrDeclMap0, Addr, ProfNode,
|
|
ProfNodeMap, AddrDeclMap) :-
|
|
(
|
|
map__search(ProfNodeMap0, Addr, ProfNode0)
|
|
->
|
|
ProfNodeMap = ProfNodeMap0,
|
|
AddrDeclMap = AddrDeclMap0,
|
|
ProfNode = ProfNode0
|
|
;
|
|
Str = string__format("unknown__%d", [i(Addr)]),
|
|
prof_node_init(Str, ProfNode),
|
|
map__det_insert(ProfNodeMap0, Addr, ProfNode, ProfNodeMap),
|
|
map__det_insert(AddrDeclMap0, Str, Addr, AddrDeclMap)
|
|
).
|