mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-20 11:54:02 +00:00
deep_profiler/analysis_utils.m:
deep_profiler/autopar_find_best_par.m:
deep_profiler/autopar_reports.m:
deep_profiler/autopar_search_callgraph.m:
deep_profiler/autopar_search_goals.m:
deep_profiler/callgraph.m:
deep_profiler/canonical.m:
deep_profiler/cliques.m:
deep_profiler/coverage.m:
deep_profiler/dump.m:
deep_profiler/mdprof_cgi.m:
deep_profiler/mdprof_create_feedback.m:
deep_profiler/mdprof_dump.m:
deep_profiler/mdprof_procrep.m:
deep_profiler/mdprof_report_feedback.m:
deep_profiler/mdprof_test.m:
deep_profiler/profile.m:
deep_profiler/read_profile.m:
deep_profiler/recursion_patterns.m:
deep_profiler/startup.m:
deep_profiler/var_use_analysis.m:
Replace implicit streams with explicit streams.
In some places, simplify some code, often using constructs such as
string.format that either did not exist or were too expensive to use
when the original code was written.
Consistenly use the spelling StdErr over Stderr.
In mdbprof_dump.m, put filename and reason-for-failing-to-open-that-file
in the right order in an error message.
deep_profiler/DEEP_FLAGS.in:
Turn on --warn-implicit-stream-calls for the entire deep_profiler
directory.
mdbcomp/program_representation.m:
mdbcomp/trace_counts.m:
Replace implicit streams with explicit streams. These are the two mdbcomp
modules that (a) used to use implicit streams, and (2) are used by the
deep profiler.
mdbcomp/Mercury.options:
Turn on --warn-implicit-stream-calls for these two modules.
slice/mcov.m:
slice/mtc_union.m:
Conform to the changes in mdbcomp.
1120 lines
43 KiB
Mathematica
1120 lines
43 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2001-2002, 2004-2012 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: startup.m.
|
|
% Authors: conway, zs.
|
|
%
|
|
% This module contains the code for turning the raw list of nodes read in by
|
|
% read_profile.m into the data structure that mdprof_cgi.m needs to service
|
|
% requests for web pages. The algorithm it implements is documented in the
|
|
% deep profiling paper.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module startup.
|
|
:- interface.
|
|
|
|
:- import_module dump.
|
|
:- import_module profile.
|
|
|
|
:- import_module bool.
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred read_and_startup_default_deep_options(string::in, string::in,
|
|
string::in, bool::in, maybe(io.output_stream)::in, list(string)::in,
|
|
maybe_error(deep)::out, io::di, io::uo) is det.
|
|
|
|
:- pred read_and_startup(string::in, string::in,
|
|
string::in, bool::in, maybe(io.output_stream)::in, list(string)::in,
|
|
dump_options::in, maybe_error(deep)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module array_util.
|
|
:- import_module callgraph.
|
|
:- import_module canonical.
|
|
:- import_module exclude.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.program_representation.
|
|
:- import_module mdbcomp.shared_utilities.
|
|
:- import_module measurements.
|
|
:- import_module read_profile.
|
|
|
|
:- import_module array.
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
read_and_startup_default_deep_options(Machine, ScriptName, DataFileName,
|
|
Canonical, MaybeOutputStream, DumpStages, Res, !IO) :-
|
|
read_and_startup(Machine, ScriptName, DataFileName, Canonical,
|
|
MaybeOutputStream, DumpStages, default_dump_options, Res, !IO).
|
|
|
|
read_and_startup(Machine, ScriptName, DataFileName, Canonical,
|
|
MaybeOutputStream, DumpStages, DumpOptions, Result, !IO) :-
|
|
% Any limits on stack size bite mostly during startup, which is why
|
|
% this call is here. The alternative design would be to invoke
|
|
% unlimit_stack separately in every program in this directory.
|
|
% That would be error-prone, since adding the call would be easy to miss
|
|
% when adding a new program.
|
|
unlimit_stack(!IO),
|
|
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Reading graph data...\n", !IO),
|
|
read_call_graph(DataFileName, DataFileResult, !IO),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
(
|
|
DataFileResult = ok(InitDeep),
|
|
startup(Machine, ScriptName, DataFileName,
|
|
Canonical, MaybeOutputStream, DumpStages, DumpOptions,
|
|
InitDeep, Deep, !IO),
|
|
Result = ok(Deep)
|
|
;
|
|
DataFileResult = error(Error),
|
|
Result = error(Error)
|
|
).
|
|
|
|
:- func make_progrep_filename(string) = string.
|
|
|
|
make_progrep_filename(DataFileName) = ProgrepFileName :-
|
|
( if string.remove_suffix(DataFileName, ".data", BaseFileName) then
|
|
ProgrepFileName = BaseFileName ++ ".procrep"
|
|
else
|
|
error("Couldn't remove suffix from deep file name: " ++ DataFileName)
|
|
).
|
|
|
|
:- pred startup(string::in, string::in, string::in, bool::in,
|
|
maybe(io.output_stream)::in, list(string)::in, dump_options::in,
|
|
initial_deep::in, deep::out, io::di, io::uo) is det.
|
|
|
|
startup(Machine, ScriptName, DataFileName, Canonical, MaybeOutputStream,
|
|
DumpStages, DumpOptions, InitDeep0, !:Deep, !IO) :-
|
|
InitDeep0 = initial_deep(InitStats, Root,
|
|
CallSiteDynamics0, ProcDynamics, CallSiteStatics0, ProcStatics0),
|
|
maybe_dump(MaybeOutputStream, DataFileName, DumpStages, 0,
|
|
dump_initial_deep(InitDeep0, default_dump_options), !IO),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Mapping static call sites to containing procedures...\n", !IO),
|
|
array_foldl2_from_1(record_css_containers_module_procs, ProcStatics0,
|
|
u(CallSiteStatics0), CallSiteStatics, map.init, ModuleProcs),
|
|
ModuleDataMap0 = map.map_values_only(initialize_module_data, ModuleProcs),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Mapping dynamic call sites to containing procedures...\n", !IO),
|
|
array_foldl2_from_1(record_csd_containers_zeroed_pss, ProcDynamics,
|
|
u(CallSiteDynamics0), CallSiteDynamics, u(ProcStatics0), ProcStatics),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
InitDeep1 = initial_deep(InitStats, Root,
|
|
CallSiteDynamics, ProcDynamics, CallSiteStatics, ProcStatics),
|
|
maybe_dump(MaybeOutputStream, DataFileName, DumpStages, 10,
|
|
dump_initial_deep(InitDeep1, DumpOptions), !IO),
|
|
(
|
|
Canonical = no,
|
|
InitDeep = InitDeep1
|
|
;
|
|
Canonical = yes,
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Canonicalizing cliques...\n", !IO),
|
|
canonicalize_cliques(InitDeep1, InitDeep),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO)
|
|
),
|
|
maybe_dump(MaybeOutputStream, DataFileName, DumpStages, 20,
|
|
dump_initial_deep(InitDeep, DumpOptions), !IO),
|
|
|
|
array.max(InitDeep ^ init_proc_dynamics, PDMax),
|
|
NPDs = PDMax + 1,
|
|
array.max(InitDeep ^ init_call_site_dynamics, CSDMax),
|
|
NCSDs = CSDMax + 1,
|
|
array.max(InitDeep ^ init_proc_statics, PSMax),
|
|
NPSs = PSMax + 1,
|
|
array.max(InitDeep ^ init_call_site_statics, CSSMax),
|
|
NCSSs = CSSMax + 1,
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Finding cliques...\n", !IO),
|
|
find_cliques(InitDeep, CliqueList),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Constructing clique indexes...\n", !IO),
|
|
make_clique_indexes(NPDs, CliqueList, Cliques, CliqueIndex),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Constructing clique parent map...\n", !IO),
|
|
|
|
% For each CallSiteDynamic pointer, if it points to a ProcDynamic
|
|
% which is in a different clique to the one from which the
|
|
% CallSiteDynamic's parent came, then this CallSiteDynamic is the entry to
|
|
% the [lower] clique. We need to compute this information so that
|
|
% we can print clique-based timing summaries in the browser.
|
|
|
|
array.max(Cliques, CliqueMax),
|
|
NCliques = CliqueMax + 1,
|
|
array.init(NCliques, call_site_dynamic_ptr(-1), CliqueParents0),
|
|
array.init(NCSDs, no, CliqueMaybeChildren0),
|
|
array_foldl2_from_1(construct_clique_parents(InitDeep, CliqueIndex),
|
|
CliqueIndex,
|
|
CliqueParents0, CliqueParents,
|
|
CliqueMaybeChildren0, CliqueMaybeChildren),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Finding procedure callers...\n", !IO),
|
|
array.init(NPSs, [], ProcCallers0),
|
|
array_foldl_from_1(construct_proc_callers(InitDeep),
|
|
CallSiteDynamics, ProcCallers0, ProcCallers),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Constructing call site static map...\n", !IO),
|
|
array.init(NCSDs, call_site_static_ptr(-1), CallSiteStaticMap0),
|
|
array_foldl_from_1(construct_call_site_caller(InitDeep),
|
|
ProcDynamics, CallSiteStaticMap0, CallSiteStaticMap),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Finding call site calls...\n", !IO),
|
|
array.init(NCSSs, map.init, CallSiteCalls0),
|
|
array_foldl_from_1(construct_call_site_calls(InitDeep),
|
|
ProcDynamics, CallSiteCalls0, CallSiteCalls),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
ProgRepFileName = make_progrep_filename(DataFileName),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Reading program representation...\n", !IO),
|
|
read_prog_rep_file(ProgRepFileName, ProgRepResult, !IO),
|
|
(
|
|
ProgRepResult = ok(ProgRep),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
MaybeProcRepFile = yes(ok(ProgRep)),
|
|
|
|
ProgRep = prog_rep(ModuleMap),
|
|
map.keys(ModuleMap, ProgRepModules),
|
|
(
|
|
MaybeOutputStream = yes(OutputStream),
|
|
io.write(OutputStream, ProgRepModules, !IO),
|
|
io.nl(OutputStream, !IO)
|
|
;
|
|
MaybeOutputStream = no
|
|
),
|
|
list.foldl(ensure_module_has_module_data, ProgRepModules,
|
|
ModuleDataMap0, ModuleDataMap)
|
|
;
|
|
ProgRepResult = error(Error),
|
|
(
|
|
io.open_input(ProgRepFileName, OpenProgRepResult, !IO),
|
|
(
|
|
OpenProgRepResult = ok(ProgRepStream),
|
|
% The file exists, so the error message describes something
|
|
% wrong with the file.
|
|
io.close_input(ProgRepStream, !IO),
|
|
ErrorMessage = io.error_message(Error),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Error: " ++ ErrorMessage ++ "\n", !IO),
|
|
MaybeProcRepFile = yes(error(ErrorMessage)),
|
|
ModuleDataMap = ModuleDataMap0
|
|
;
|
|
OpenProgRepResult = error(_),
|
|
% The file does not exist.
|
|
MaybeProcRepFile = no,
|
|
ModuleDataMap = ModuleDataMap0
|
|
)
|
|
)
|
|
),
|
|
|
|
ContourFileName = contour_file_name(DataFileName),
|
|
string.format("%% Trying to read contour exclusion file `%s'...\n",
|
|
[s(ContourFileName)], TryMsg),
|
|
maybe_report_msg(MaybeOutputStream, TryMsg, !IO),
|
|
read_exclude_file(ContourFileName, ModuleDataMap, ExcludeFile, !IO),
|
|
ExcludeFile = exclude_file(_, ExcludeContents),
|
|
(
|
|
ExcludeContents = no_exclude_file,
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Couldn't open file.\n", !IO)
|
|
;
|
|
ExcludeContents = unreadable_exclude_file(ExcludeError),
|
|
string.format("%% File had unrecoverable errors:\n%% %s.\n",
|
|
[s(ExcludeError)], ExcludeErrorMsg),
|
|
maybe_report_msg(MaybeOutputStream, ExcludeErrorMsg, !IO)
|
|
;
|
|
ExcludeContents = readable_exclude_file(_, _),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO)
|
|
),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Propagating measurements up call graph...\n", !IO),
|
|
|
|
array.init(NCSDs, zero_inherit_prof_info, CSDDesc0),
|
|
array.init(NPDs, zero_own_prof_info, PDOwn0),
|
|
array_foldl_from_1(sum_call_sites_in_proc_dynamic,
|
|
CallSiteDynamics, PDOwn0, PDOwn),
|
|
array.init(NPDs, zero_inherit_prof_info, PDDesc0),
|
|
array.init(NPSs, zero_own_prof_info, PSOwn0),
|
|
array.init(NPSs, zero_inherit_prof_info, PSDesc0),
|
|
array.init(NCSSs, zero_own_prof_info, CSSOwn0),
|
|
array.init(NCSSs, zero_inherit_prof_info, CSSDesc0),
|
|
array.init(NPDs, map.init, PDCompTable0),
|
|
array.init(NCSDs, map.init, CSDCompTable0),
|
|
CoverageDataType = InitStats ^ prs_deep_flags ^ df_coverage_data_type,
|
|
(
|
|
CoverageDataType = no_coverage_data,
|
|
MaybeStaticCoverage0 = no
|
|
;
|
|
( CoverageDataType = static_coverage_data
|
|
; CoverageDataType = dynamic_coverage_data
|
|
),
|
|
array.init(NPSs, zero_static_coverage, StaticCoverage0),
|
|
MaybeStaticCoverage0 = yes(StaticCoverage0)
|
|
),
|
|
|
|
!:Deep = deep(InitStats, Machine, ScriptName, DataFileName, Root,
|
|
CallSiteDynamics, ProcDynamics, CallSiteStatics, ProcStatics,
|
|
CliqueIndex, Cliques, CliqueParents, CliqueMaybeChildren,
|
|
ProcCallers, CallSiteStaticMap, CallSiteCalls,
|
|
PDOwn, PDDesc0, CSDDesc0,
|
|
PSOwn0, PSDesc0, CSSOwn0, CSSDesc0,
|
|
PDCompTable0, CSDCompTable0, ModuleDataMap, MaybeStaticCoverage0,
|
|
ExcludeFile, MaybeProcRepFile, MaybeOutputStream),
|
|
|
|
array_foldl_from_1(propagate_to_clique, Cliques, !Deep),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
maybe_dump(MaybeOutputStream, DataFileName, DumpStages, 30,
|
|
dump_deep(!.Deep, DumpOptions), !IO),
|
|
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Summarizing information...\n", !IO),
|
|
(
|
|
( CoverageDataType = no_coverage_data
|
|
; CoverageDataType = static_coverage_data
|
|
),
|
|
(
|
|
CoverageDataType = static_coverage_data,
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"\t% Summarizing static coverage...\n", !IO),
|
|
summarize_proc_statics_coverage(!Deep)
|
|
;
|
|
CoverageDataType = no_coverage_data
|
|
),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"\t% Summarizing proc dynamics...\n", !IO),
|
|
summarize_proc_dynamics(!Deep)
|
|
;
|
|
CoverageDataType = dynamic_coverage_data,
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"\t% Summarizing proc dynamics with coverage...\n", !IO),
|
|
summarize_proc_dynamics_with_coverage_data(!Deep)
|
|
),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"\t% Summarizing call site dynamics...\n", !IO),
|
|
summarize_call_site_dynamics(!Deep),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"\t% Summarizing modules...\n", !IO),
|
|
summarize_modules(!Deep),
|
|
maybe_report_msg(MaybeOutputStream,
|
|
"% Done.\n", !IO),
|
|
maybe_report_stats(MaybeOutputStream, !IO),
|
|
|
|
maybe_dump(MaybeOutputStream, DataFileName, DumpStages, 40,
|
|
dump_deep(!.Deep, DumpOptions), !IO).
|
|
|
|
:- func contour_file_name(string) = string.
|
|
|
|
contour_file_name(DataFileName) = ContourFileName :-
|
|
( if string.remove_suffix(DataFileName, ".data", BaseFileName) then
|
|
ContourFileName = BaseFileName ++ ".contour"
|
|
else
|
|
error("Couldn't remove suffix from deep file name: " ++ DataFileName)
|
|
).
|
|
|
|
:- pred count_quanta(int::in, call_site_dynamic::in, int::in, int::out) is det.
|
|
|
|
count_quanta(_N, CSD, Quanta0, Quanta) :-
|
|
Quanta = Quanta0 + quanta(CSD ^ csd_own_prof).
|
|
|
|
:- func initialize_module_data(list(proc_static_ptr)) = module_data.
|
|
|
|
initialize_module_data(PSPtrs) =
|
|
module_data(zero_own_prof_info, zero_inherit_prof_info, PSPtrs).
|
|
|
|
:- pred ensure_module_has_module_data(string::in,
|
|
map(string, module_data)::in, map(string, module_data)::out) is det.
|
|
|
|
ensure_module_has_module_data(Module, !ModuleDataMap) :-
|
|
( if map.search(!.ModuleDataMap, Module, _) then
|
|
true
|
|
else
|
|
Data = module_data(zero_own_prof_info, zero_inherit_prof_info, []),
|
|
map.det_insert(Module, Data, !ModuleDataMap)
|
|
).
|
|
|
|
:- pred maybe_dump(maybe(io.text_output_stream)::in,
|
|
string::in, list(string)::in, int::in,
|
|
pred(io.text_output_stream, io, io)::in(pred(in, di, uo) is det),
|
|
io::di, io::uo) is det.
|
|
|
|
maybe_dump(MaybeOutputStream, BaseName, DumpStages, ThisStageNum,
|
|
Action, !IO) :-
|
|
string.int_to_string(ThisStageNum, ThisStageStr),
|
|
( if
|
|
( list.member("all", DumpStages)
|
|
; list.member(ThisStageStr, DumpStages)
|
|
)
|
|
then
|
|
FileName = BaseName ++ ".deepdump." ++ ThisStageStr,
|
|
io.open_output(FileName, OpenRes, !IO),
|
|
(
|
|
OpenRes = ok(FileStream),
|
|
Action(FileStream, !IO),
|
|
io.close_output(FileStream, !IO)
|
|
;
|
|
OpenRes = error(Error),
|
|
io.error_message(Error, Msg),
|
|
(
|
|
MaybeOutputStream = yes(OutputStream)
|
|
;
|
|
MaybeOutputStream = no,
|
|
io.stderr_stream(OutputStream, !IO)
|
|
),
|
|
io.format(OutputStream, "%s: %s\n", [s(FileName), s(Msg)], !IO)
|
|
)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred record_css_containers_module_procs(int::in, proc_static::in,
|
|
array(call_site_static)::array_di,
|
|
array(call_site_static)::array_uo,
|
|
map(string, list(proc_static_ptr))::in,
|
|
map(string, list(proc_static_ptr))::out) is det.
|
|
|
|
record_css_containers_module_procs(PSI, PS, !CallSiteStatics, !ModuleProcs) :-
|
|
CSSPtrs = PS ^ ps_sites,
|
|
PSPtr = proc_static_ptr(PSI),
|
|
array.max(CSSPtrs, MaxCS),
|
|
record_css_containers_2(MaxCS, PSPtr, CSSPtrs, !CallSiteStatics),
|
|
DeclModule = PS ^ ps_decl_module,
|
|
( if map.search(!.ModuleProcs, DeclModule, PSPtrs0) then
|
|
map.det_update(DeclModule, [PSPtr | PSPtrs0], !ModuleProcs)
|
|
else
|
|
map.det_insert(DeclModule, [PSPtr], !ModuleProcs)
|
|
).
|
|
|
|
:- pred record_css_containers_2(int::in, proc_static_ptr::in,
|
|
array(call_site_static_ptr)::in,
|
|
array(call_site_static)::array_di,
|
|
array(call_site_static)::array_uo) is det.
|
|
|
|
record_css_containers_2(SlotNum, PSPtr, CSSPtrs, !CallSiteStatics) :-
|
|
( if SlotNum >= 0 then
|
|
array.lookup(CSSPtrs, SlotNum, CSSPtr),
|
|
lookup_call_site_statics(!.CallSiteStatics, CSSPtr, CSS0),
|
|
CSS0 = call_site_static(PSPtr0, SlotNum0,
|
|
Kind, LineNumber, GoalPath),
|
|
require(unify(PSPtr0, proc_static_ptr(-1)),
|
|
"record_css_containers_2: real proc_static_ptr"),
|
|
require(unify(SlotNum0, -1),
|
|
"record_css_containers_2: real slot_num"),
|
|
CSS = call_site_static(PSPtr, SlotNum,
|
|
Kind, LineNumber, GoalPath),
|
|
update_call_site_statics(CSSPtr, CSS, !CallSiteStatics),
|
|
record_css_containers_2(SlotNum - 1, PSPtr, CSSPtrs, !CallSiteStatics)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred record_csd_containers_zeroed_pss(int::in, proc_dynamic::in,
|
|
array(call_site_dynamic)::array_di,
|
|
array(call_site_dynamic)::array_uo,
|
|
array(proc_static)::array_di, array(proc_static)::array_uo) is det.
|
|
|
|
record_csd_containers_zeroed_pss(PDI, PD, !CallSiteDynamics, !ProcStatics) :-
|
|
CSDArray = PD ^ pd_sites,
|
|
PDPtr = proc_dynamic_ptr(PDI),
|
|
flatten_call_sites(CSDArray, CSDPtrs, IsZeroed),
|
|
record_csd_containers_2(PDPtr, CSDPtrs, !CallSiteDynamics),
|
|
(
|
|
IsZeroed = zeroed,
|
|
PSPtr = PD ^ pd_proc_static,
|
|
lookup_proc_statics(!.ProcStatics, PSPtr, PS0),
|
|
PS = PS0 ^ ps_is_zeroed := zeroed,
|
|
update_proc_statics(PSPtr, PS, !ProcStatics)
|
|
;
|
|
IsZeroed = not_zeroed
|
|
).
|
|
|
|
:- pred record_csd_containers_2(proc_dynamic_ptr::in,
|
|
list(call_site_dynamic_ptr)::in,
|
|
array(call_site_dynamic)::array_di,
|
|
array(call_site_dynamic)::array_uo) is det.
|
|
|
|
record_csd_containers_2(_, [], !CallSiteDynamics).
|
|
record_csd_containers_2(PDPtr, [CSDPtr | CSDPtrs], !CallSiteDynamics) :-
|
|
lookup_call_site_dynamics(!.CallSiteDynamics, CSDPtr, CSD0),
|
|
CSD0 = call_site_dynamic(CallerPDPtr0, CalleePDPtr, Own),
|
|
require(unify(CallerPDPtr0, proc_dynamic_ptr(-1)),
|
|
"record_csd_containers_2: real proc_dynamic_ptr"),
|
|
CSD = call_site_dynamic(PDPtr, CalleePDPtr, Own),
|
|
update_call_site_dynamics(CSDPtr, CSD, !CallSiteDynamics),
|
|
record_csd_containers_2(PDPtr, CSDPtrs, !CallSiteDynamics).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred construct_clique_parents(initial_deep::in, array(clique_ptr)::in,
|
|
int::in, clique_ptr::in,
|
|
array(call_site_dynamic_ptr)::array_di,
|
|
array(call_site_dynamic_ptr)::array_uo,
|
|
array(maybe(clique_ptr))::array_di,
|
|
array(maybe(clique_ptr))::array_uo) is det.
|
|
|
|
construct_clique_parents(InitDeep, CliqueIndex, PDI, CliquePtr,
|
|
!CliqueParents, !CliqueMaybeChildren) :-
|
|
( if PDI > 0 then
|
|
flat_call_sites(InitDeep ^ init_proc_dynamics,
|
|
proc_dynamic_ptr(PDI), CSDPtrs),
|
|
array_list_foldl2(
|
|
construct_clique_parents_2(InitDeep, CliqueIndex, CliquePtr),
|
|
CSDPtrs, !CliqueParents, !CliqueMaybeChildren)
|
|
else
|
|
error("construct_clique_parents: invalid pdi")
|
|
).
|
|
|
|
:- pred construct_clique_parents_2(initial_deep::in, array(clique_ptr)::in,
|
|
clique_ptr::in, call_site_dynamic_ptr::in,
|
|
array(call_site_dynamic_ptr)::array_di,
|
|
array(call_site_dynamic_ptr)::array_uo,
|
|
array(maybe(clique_ptr))::array_di,
|
|
array(maybe(clique_ptr))::array_uo) is det.
|
|
|
|
construct_clique_parents_2(InitDeep, CliqueIndex, ParentCliquePtr, CSDPtr,
|
|
!CliqueParents, !CliqueMaybeChildren) :-
|
|
CSDPtr = call_site_dynamic_ptr(CSDI),
|
|
( if CSDI > 0 then
|
|
array.lookup(InitDeep ^ init_call_site_dynamics, CSDI, CSD),
|
|
ChildPDPtr = CSD ^ csd_callee,
|
|
ChildPDPtr = proc_dynamic_ptr(ChildPDI),
|
|
( if ChildPDI > 0 then
|
|
array.lookup(CliqueIndex, ChildPDI, ChildCliquePtr),
|
|
( if ChildCliquePtr \= ParentCliquePtr then
|
|
ChildCliquePtr = clique_ptr(ChildCliqueNum),
|
|
array.set(ChildCliqueNum, CSDPtr, !CliqueParents),
|
|
array.set(CSDI, yes(ChildCliquePtr), !CliqueMaybeChildren)
|
|
else
|
|
true
|
|
)
|
|
else
|
|
true
|
|
)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred construct_proc_callers(initial_deep::in, int::in,
|
|
call_site_dynamic::in,
|
|
array(list(call_site_dynamic_ptr))::array_di,
|
|
array(list(call_site_dynamic_ptr))::array_uo) is det.
|
|
|
|
construct_proc_callers(InitDeep, CSDI, CSD, !ProcCallers) :-
|
|
PDPtr = CSD ^ csd_callee,
|
|
( if valid_proc_dynamic_ptr_raw(InitDeep ^ init_proc_dynamics, PDPtr) then
|
|
lookup_proc_dynamics(InitDeep ^ init_proc_dynamics, PDPtr, PD),
|
|
PSPtr = PD ^ pd_proc_static,
|
|
lookup_proc_callers(!.ProcCallers, PSPtr, Callers0),
|
|
Callers = [call_site_dynamic_ptr(CSDI) | Callers0],
|
|
update_proc_callers(PSPtr, Callers, !ProcCallers)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred construct_call_site_caller(initial_deep::in, int::in, proc_dynamic::in,
|
|
array(call_site_static_ptr)::array_di,
|
|
array(call_site_static_ptr)::array_uo) is det.
|
|
|
|
construct_call_site_caller(InitDeep, _PDI, PD, !CallSiteStaticMap) :-
|
|
PSPtr = PD ^ pd_proc_static,
|
|
CSDArraySlots = PD ^ pd_sites,
|
|
lookup_proc_statics(InitDeep ^ init_proc_statics, PSPtr, PS),
|
|
CSSPtrs = PS ^ ps_sites,
|
|
array.max(CSDArraySlots, MaxCS),
|
|
construct_call_site_caller_2(MaxCS,
|
|
InitDeep ^ init_call_site_dynamics, CSSPtrs, CSDArraySlots,
|
|
!CallSiteStaticMap).
|
|
|
|
:- pred construct_call_site_caller_2(int::in, call_site_dynamics::in,
|
|
array(call_site_static_ptr)::in,
|
|
array(call_site_array_slot)::in,
|
|
array(call_site_static_ptr)::array_di,
|
|
array(call_site_static_ptr)::array_uo) is det.
|
|
|
|
construct_call_site_caller_2(SlotNum, Deep, CSSPtrs, CSDArraySlots,
|
|
!CallSiteStaticMap) :-
|
|
( if SlotNum >= 0 then
|
|
array.lookup(CSDArraySlots, SlotNum, CSDArraySlot),
|
|
array.lookup(CSSPtrs, SlotNum, CSSPtr),
|
|
(
|
|
CSDArraySlot = slot_normal(CSDPtr),
|
|
construct_call_site_caller_3(Deep, CSSPtr, -1, CSDPtr,
|
|
!CallSiteStaticMap)
|
|
;
|
|
CSDArraySlot = slot_multi(_, CSDPtrs),
|
|
array_foldl_from_0(construct_call_site_caller_3(Deep, CSSPtr),
|
|
CSDPtrs, !CallSiteStaticMap)
|
|
),
|
|
construct_call_site_caller_2(SlotNum - 1, Deep, CSSPtrs,
|
|
CSDArraySlots, !CallSiteStaticMap)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred construct_call_site_caller_3(call_site_dynamics::in,
|
|
call_site_static_ptr::in, int::in, call_site_dynamic_ptr::in,
|
|
array(call_site_static_ptr)::array_di,
|
|
array(call_site_static_ptr)::array_uo) is det.
|
|
|
|
construct_call_site_caller_3(CallSiteDynamics, CSSPtr, _Dummy, CSDPtr,
|
|
!CallSiteStaticMap) :-
|
|
( if valid_call_site_dynamic_ptr_raw(CallSiteDynamics, CSDPtr) then
|
|
update_call_site_static_map(CSDPtr, CSSPtr, !CallSiteStaticMap)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred construct_call_site_calls(initial_deep::in, int::in, proc_dynamic::in,
|
|
array(map(proc_static_ptr, list(call_site_dynamic_ptr)))::array_di,
|
|
array(map(proc_static_ptr, list(call_site_dynamic_ptr)))::array_uo)
|
|
is det.
|
|
|
|
construct_call_site_calls(InitDeep, _PDI, PD, !CallSiteCalls) :-
|
|
PSPtr = PD ^ pd_proc_static,
|
|
CSDArraySlots = PD ^ pd_sites,
|
|
array.max(CSDArraySlots, MaxCS),
|
|
PSPtr = proc_static_ptr(PSI),
|
|
array.lookup(InitDeep ^ init_proc_statics, PSI, PS),
|
|
CSSPtrs = PS ^ ps_sites,
|
|
CallSiteDynamics = InitDeep ^ init_call_site_dynamics,
|
|
ProcDynamics = InitDeep ^ init_proc_dynamics,
|
|
construct_call_site_calls_2(CallSiteDynamics, ProcDynamics, MaxCS,
|
|
CSSPtrs, CSDArraySlots, !CallSiteCalls).
|
|
|
|
:- pred construct_call_site_calls_2(call_site_dynamics::in, proc_dynamics::in,
|
|
int::in, array(call_site_static_ptr)::in,
|
|
array(call_site_array_slot)::in,
|
|
array(map(proc_static_ptr, list(call_site_dynamic_ptr)))::array_di,
|
|
array(map(proc_static_ptr, list(call_site_dynamic_ptr)))::array_uo)
|
|
is det.
|
|
|
|
construct_call_site_calls_2(CallSiteDynamics, ProcDynamics, SlotNum,
|
|
CSSPtrs, CSDArraySlots, !CallSiteCalls) :-
|
|
( if SlotNum >= 0 then
|
|
array.lookup(CSDArraySlots, SlotNum, CSDArraySlot),
|
|
array.lookup(CSSPtrs, SlotNum, CSSPtr),
|
|
(
|
|
CSDArraySlot = slot_normal(CSDPtr),
|
|
construct_call_site_calls_3(CallSiteDynamics,
|
|
ProcDynamics, CSSPtr, -1, CSDPtr, !CallSiteCalls)
|
|
;
|
|
CSDArraySlot = slot_multi(_, CSDPtrs),
|
|
array_foldl_from_0(
|
|
construct_call_site_calls_3(CallSiteDynamics,
|
|
ProcDynamics, CSSPtr),
|
|
CSDPtrs, !CallSiteCalls)
|
|
),
|
|
construct_call_site_calls_2(CallSiteDynamics, ProcDynamics,
|
|
SlotNum - 1, CSSPtrs, CSDArraySlots, !CallSiteCalls)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred construct_call_site_calls_3(call_site_dynamics::in, proc_dynamics::in,
|
|
call_site_static_ptr::in, int::in, call_site_dynamic_ptr::in,
|
|
array(map(proc_static_ptr, list(call_site_dynamic_ptr)))::array_di,
|
|
array(map(proc_static_ptr, list(call_site_dynamic_ptr)))::array_uo)
|
|
is det.
|
|
|
|
construct_call_site_calls_3(CallSiteDynamics, ProcDynamics, CSSPtr,
|
|
_Dummy, CSDPtr, !CallSiteCalls) :-
|
|
CSDPtr = call_site_dynamic_ptr(CSDI),
|
|
( if CSDI > 0 then
|
|
array.lookup(CallSiteDynamics, CSDI, CSD),
|
|
PDPtr = CSD ^ csd_callee,
|
|
PDPtr = proc_dynamic_ptr(PDI),
|
|
array.lookup(ProcDynamics, PDI, PD),
|
|
PSPtr = PD ^ pd_proc_static,
|
|
|
|
CSSPtr = call_site_static_ptr(CSSI),
|
|
array.lookup(!.CallSiteCalls, CSSI, CallMap0),
|
|
( if map.search(CallMap0, PSPtr, CallList0) then
|
|
CallList = [CSDPtr | CallList0],
|
|
map.det_update(PSPtr, CallList, CallMap0, CallMap)
|
|
else
|
|
CallList = [CSDPtr],
|
|
map.det_insert(PSPtr, CallList, CallMap0, CallMap)
|
|
),
|
|
array.set(CSSI, CallMap, !CallSiteCalls)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred sum_call_sites_in_proc_dynamic(int::in, call_site_dynamic::in,
|
|
array(own_prof_info)::array_di, array(own_prof_info)::array_uo) is det.
|
|
|
|
sum_call_sites_in_proc_dynamic(_, CSD, !PDOwnArray) :-
|
|
CalleeOwn = CSD ^ csd_own_prof,
|
|
PDPtr = CSD ^ csd_callee,
|
|
PDPtr = proc_dynamic_ptr(PDI),
|
|
( if PDI > 0 then
|
|
array.lookup(!.PDOwnArray, PDI, ProcOwn0),
|
|
ProcOwn = add_own_to_own(CalleeOwn, ProcOwn0),
|
|
array.set(PDI, ProcOwn, !PDOwnArray)
|
|
else
|
|
error("sum_call_sites_in_proc_dynamic: invalid pdptr")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred summarize_proc_dynamics(deep::in, deep::out) is det.
|
|
|
|
summarize_proc_dynamics(Deep0, Deep) :-
|
|
PSOwnArray0 = Deep0 ^ ps_own,
|
|
PSDescArray0 = Deep0 ^ ps_desc,
|
|
array_foldl2_from_1(
|
|
summarize_proc_dynamic(Deep0 ^ pd_own, Deep0 ^ pd_desc,
|
|
Deep0 ^ pd_comp_table),
|
|
Deep0 ^ proc_dynamics,
|
|
copy(PSOwnArray0), PSOwnArray,
|
|
copy(PSDescArray0), PSDescArray),
|
|
Deep = ((Deep0
|
|
^ ps_own := PSOwnArray)
|
|
^ ps_desc := PSDescArray).
|
|
|
|
:- pred summarize_proc_dynamic(array(own_prof_info)::in,
|
|
array(inherit_prof_info)::in, array(compensation_table)::in,
|
|
int::in, proc_dynamic::in,
|
|
array(own_prof_info)::array_di, array(own_prof_info)::array_uo,
|
|
array(inherit_prof_info)::array_di, array(inherit_prof_info)::array_uo)
|
|
is det.
|
|
|
|
summarize_proc_dynamic(PDOwnArray, PDDescArray, PDCompTableArray, PDI, PD,
|
|
PSOwnArray0, PSOwnArray, PSDescArray0, PSDescArray) :-
|
|
PSPtr = PD ^ pd_proc_static,
|
|
PDPtr = proc_dynamic_ptr(PDI),
|
|
lookup_pd_own(PDOwnArray, PDPtr, PDOwn),
|
|
lookup_pd_desc(PDDescArray, PDPtr, PDDesc0),
|
|
lookup_pd_comp_table(PDCompTableArray, PDPtr, PDCompTable),
|
|
( if map.search(PDCompTable, PSPtr, InnerTotal) then
|
|
PDDesc = subtract_inherit_from_inherit(InnerTotal, PDDesc0)
|
|
else
|
|
PDDesc = PDDesc0
|
|
),
|
|
lookup_ps_own(PSOwnArray0, PSPtr, PSOwn0),
|
|
lookup_ps_desc(PSDescArray0, PSPtr, PSDesc0),
|
|
add_own_to_own(PDOwn, PSOwn0) = PSOwn,
|
|
add_inherit_to_inherit(PDDesc, PSDesc0) = PSDesc,
|
|
update_ps_own(PSPtr, PSOwn, u(PSOwnArray0), PSOwnArray),
|
|
update_ps_desc(PSPtr, PSDesc, u(PSDescArray0), PSDescArray).
|
|
|
|
:- pred summarize_proc_dynamics_with_coverage_data(deep::in, deep::out) is det.
|
|
|
|
summarize_proc_dynamics_with_coverage_data(!Deep) :-
|
|
% These arrays are one based, the +1 here is necessary to allocate the
|
|
% correct amount of storage.
|
|
NPS = !.Deep ^ profile_stats ^ prs_num_ps + 1,
|
|
array_foldl3_from_1(
|
|
summarize_proc_dynamic_with_coverage(!.Deep ^ pd_own,
|
|
!.Deep ^ pd_desc, !.Deep ^ pd_comp_table),
|
|
!.Deep ^ proc_dynamics,
|
|
init(NPS, zero_own_prof_info), PSOwnArray,
|
|
init(NPS, zero_inherit_prof_info), PSDescArray,
|
|
init(NPS, zero_static_coverage), CoverageArray),
|
|
!Deep ^ ps_own := PSOwnArray,
|
|
!Deep ^ ps_desc := PSDescArray,
|
|
!Deep ^ maybe_static_coverage := yes(CoverageArray).
|
|
|
|
:- pred summarize_proc_dynamic_with_coverage(array(own_prof_info)::in,
|
|
array(inherit_prof_info)::in, array(compensation_table)::in,
|
|
int::in, proc_dynamic::in,
|
|
array(own_prof_info)::array_di, array(own_prof_info)::array_uo,
|
|
array(inherit_prof_info)::array_di, array(inherit_prof_info)::array_uo,
|
|
array(static_coverage_info)::array_di,
|
|
array(static_coverage_info)::array_uo)
|
|
is det.
|
|
|
|
summarize_proc_dynamic_with_coverage(PDOwnArray, PDDescArray, PDCompTableArray,
|
|
PDI, PD, !PSOwnArray, !PSDescArray, !CoverageArray) :-
|
|
summarize_proc_dynamic(PDOwnArray, PDDescArray, PDCompTableArray,
|
|
PDI, PD, !PSOwnArray, !PSDescArray),
|
|
PSPtr = PD ^ pd_proc_static,
|
|
MaybeDynamicCoverage = PD ^ pd_maybe_coverage_points,
|
|
(
|
|
MaybeDynamicCoverage = yes(DynamicCoverage),
|
|
some [!StaticCoverage] (
|
|
lookup_ps_coverage(!.CoverageArray, PSPtr, !:StaticCoverage),
|
|
add_coverage_arrays(DynamicCoverage, !StaticCoverage),
|
|
update_ps_coverage(PSPtr, !.StaticCoverage, !CoverageArray)
|
|
)
|
|
;
|
|
MaybeDynamicCoverage = no,
|
|
unexpected($pred, "no coverage point array in proc dynamic")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred summarize_call_site_dynamics(deep::in, deep::out) is det.
|
|
|
|
summarize_call_site_dynamics(!Deep) :-
|
|
CSSOwnArray0 = !.Deep ^ css_own,
|
|
CSSDescArray0 = !.Deep ^ css_desc,
|
|
array_foldl2_from_1(
|
|
summarize_call_site_dynamic(
|
|
!.Deep ^ call_site_static_map, !.Deep ^ call_site_statics,
|
|
!.Deep ^ csd_desc, !.Deep ^ csd_comp_table),
|
|
!.Deep ^ call_site_dynamics,
|
|
copy(CSSOwnArray0), CSSOwnArray,
|
|
copy(CSSDescArray0), CSSDescArray),
|
|
!Deep ^ css_own := CSSOwnArray,
|
|
!Deep ^ css_desc := CSSDescArray.
|
|
|
|
:- pred summarize_call_site_dynamic(call_site_static_map::in,
|
|
call_site_statics::in, array(inherit_prof_info)::in,
|
|
array(compensation_table)::in, int::in, call_site_dynamic::in,
|
|
array(own_prof_info)::array_di, array(own_prof_info)::array_uo,
|
|
array(inherit_prof_info)::array_di, array(inherit_prof_info)::array_uo)
|
|
is det.
|
|
|
|
summarize_call_site_dynamic(CallSiteStaticMap, CallSiteStatics,
|
|
CSDDescs, CSDCompTableArray, CSDI, CSD,
|
|
CSSOwnArray0, CSSOwnArray, CSSDescArray0, CSSDescArray) :-
|
|
CSDPtr = call_site_dynamic_ptr(CSDI),
|
|
lookup_call_site_static_map(CallSiteStaticMap, CSDPtr, CSSPtr),
|
|
CSSPtr = call_site_static_ptr(CSSI),
|
|
( if CSSI > 0 then
|
|
CSDOwn = CSD ^ csd_own_prof,
|
|
lookup_csd_desc(CSDDescs, CSDPtr, CSDDesc0),
|
|
lookup_csd_comp_table(CSDCompTableArray, CSDPtr, CSDCompTable),
|
|
lookup_call_site_statics(CallSiteStatics, CSSPtr, CSS),
|
|
( if map.search(CSDCompTable, CSS ^ css_container, InnerTotal) then
|
|
CSDDesc = subtract_inherit_from_inherit(InnerTotal, CSDDesc0)
|
|
else
|
|
CSDDesc = CSDDesc0
|
|
),
|
|
lookup_css_own(CSSOwnArray0, CSSPtr, CSSOwn0),
|
|
lookup_css_desc(CSSDescArray0, CSSPtr, CSSDesc0),
|
|
add_own_to_own(CSDOwn, CSSOwn0) = CSSOwn,
|
|
add_inherit_to_inherit(CSDDesc, CSSDesc0) = CSSDesc,
|
|
update_css_own(CSSPtr, CSSOwn, u(CSSOwnArray0), CSSOwnArray),
|
|
update_css_desc(CSSPtr, CSSDesc, u(CSSDescArray0), CSSDescArray)
|
|
else
|
|
error("summarize_call_site_dynamic: invalid css ptr")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred summarize_modules(deep::in, deep::out) is det.
|
|
|
|
summarize_modules(Deep0, Deep) :-
|
|
ModuleData0 = Deep0 ^ module_data,
|
|
ModuleData =
|
|
map.map_values_only(summarize_module_costs(Deep0), ModuleData0),
|
|
Deep = Deep0 ^ module_data := ModuleData.
|
|
|
|
:- func summarize_module_costs(deep, module_data) = module_data.
|
|
|
|
summarize_module_costs(Deep, ModuleData0) = ModuleData :-
|
|
ModuleData0 = module_data(Own0, Desc0, PSPtrs),
|
|
list.foldl2(accumulate_ps_costs(Deep), PSPtrs, Own0, Own, Desc0, Desc),
|
|
ModuleData = module_data(Own, Desc, PSPtrs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred summarize_proc_statics_coverage(deep::in, deep::out) is det.
|
|
|
|
summarize_proc_statics_coverage(!Deep) :-
|
|
NPS = !.Deep ^ profile_stats ^ prs_num_ps,
|
|
array_foldl_from_1(
|
|
summarize_proc_static_coverage,
|
|
!.Deep ^ proc_statics,
|
|
init(NPS, zero_static_coverage), CoverageArray),
|
|
!Deep ^ maybe_static_coverage := yes(CoverageArray).
|
|
|
|
:- pred summarize_proc_static_coverage(int::in, proc_static::in,
|
|
array(static_coverage_info)::array_di,
|
|
array(static_coverage_info)::array_uo) is det.
|
|
|
|
summarize_proc_static_coverage(Index, PS, !CoverageArray) :-
|
|
MaybeCoverage = PS ^ ps_maybe_coverage_points,
|
|
(
|
|
MaybeCoverage = yes(Coverage0),
|
|
array_to_static_coverage(Coverage0, Coverage),
|
|
array.set(Index, Coverage, !CoverageArray)
|
|
;
|
|
MaybeCoverage = no,
|
|
unexpected($pred, "no coverage data in proc static")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred accumulate_ps_costs(deep::in, proc_static_ptr::in,
|
|
own_prof_info::in, own_prof_info::out,
|
|
inherit_prof_info::in, inherit_prof_info::out) is det.
|
|
|
|
accumulate_ps_costs(Deep, PSPtr, Own0, Own, Desc0, Desc) :-
|
|
deep_lookup_ps_own(Deep, PSPtr, PSOwn),
|
|
deep_lookup_ps_desc(Deep, PSPtr, PSDesc),
|
|
Own = add_own_to_own(Own0, PSOwn),
|
|
Desc = add_inherit_to_inherit(Desc0, PSDesc).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred propagate_to_clique(int::in, list(proc_dynamic_ptr)::in,
|
|
deep::in, deep::out) is det.
|
|
|
|
propagate_to_clique(CliqueNumber, Members, !Deep) :-
|
|
array.lookup(!.Deep ^ clique_parents, CliqueNumber, ParentCSDPtr),
|
|
list.foldl3(propagate_to_proc_dynamic(CliqueNumber, ParentCSDPtr), Members,
|
|
!Deep, map.init, SumTable, map.init, OverrideMap),
|
|
( if valid_call_site_dynamic_ptr(!.Deep, ParentCSDPtr) then
|
|
deep_lookup_call_site_dynamics(!.Deep, ParentCSDPtr, ParentCSD),
|
|
ParentOwn = ParentCSD ^ csd_own_prof,
|
|
deep_lookup_csd_desc(!.Deep, ParentCSDPtr, ParentDesc0),
|
|
subtract_own_from_inherit(ParentOwn, ParentDesc0) = ParentDesc,
|
|
deep_update_csd_desc(ParentCSDPtr, ParentDesc, !Deep),
|
|
CSDCompTable = apply_override(OverrideMap, SumTable),
|
|
deep_update_csd_comp_table(ParentCSDPtr, CSDCompTable, !Deep)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred propagate_to_proc_dynamic(int::in, call_site_dynamic_ptr::in,
|
|
proc_dynamic_ptr::in, deep::in, deep::out,
|
|
compensation_table::in, compensation_table::out,
|
|
compensation_table::in, compensation_table::out) is det.
|
|
|
|
propagate_to_proc_dynamic(CliqueNumber, ParentCSDPtr, PDPtr, !Deep,
|
|
!SumTable, !OverrideTable) :-
|
|
flat_call_sites(!.Deep ^ proc_dynamics, PDPtr, CSDPtrs),
|
|
list.foldl2(propagate_to_call_site(CliqueNumber, PDPtr),
|
|
CSDPtrs, !Deep, map.init, PDCompTable),
|
|
deep_update_pd_comp_table(PDPtr, PDCompTable, !Deep),
|
|
|
|
deep_lookup_pd_desc(!.Deep, PDPtr, ProcDesc),
|
|
deep_lookup_pd_own(!.Deep, PDPtr, ProcOwn),
|
|
ProcTotal = add_own_to_inherit(ProcOwn, ProcDesc),
|
|
|
|
!:SumTable = add_comp_tables(!.SumTable, PDCompTable),
|
|
deep_lookup_proc_dynamics(!.Deep, PDPtr, PD),
|
|
PSPtr = PD ^ pd_proc_static,
|
|
deep_lookup_proc_statics(!.Deep, PSPtr, PS),
|
|
( if PS ^ ps_is_zeroed = zeroed then
|
|
!:OverrideTable = add_to_override(!.OverrideTable, PSPtr, ProcTotal)
|
|
else
|
|
true
|
|
),
|
|
|
|
( if valid_call_site_dynamic_ptr(!.Deep, ParentCSDPtr) then
|
|
deep_lookup_csd_desc(!.Deep, ParentCSDPtr, ParentDesc0),
|
|
ParentDesc = add_inherit_to_inherit(ParentDesc0, ProcTotal),
|
|
deep_update_csd_desc(ParentCSDPtr, ParentDesc, !Deep)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred propagate_to_call_site(int::in, proc_dynamic_ptr::in,
|
|
call_site_dynamic_ptr::in, deep::in, deep::out,
|
|
compensation_table::in, compensation_table::out) is det.
|
|
|
|
propagate_to_call_site(CliqueNumber, PDPtr, CSDPtr, !Deep, !PDCompTable) :-
|
|
deep_lookup_call_site_dynamics(!.Deep, CSDPtr, CSD),
|
|
CalleeOwn = CSD ^ csd_own_prof,
|
|
CalleePDPtr = CSD ^ csd_callee,
|
|
deep_lookup_clique_index(!.Deep, CalleePDPtr, ChildCliquePtr),
|
|
ChildCliquePtr = clique_ptr(ChildCliqueNumber),
|
|
( if ChildCliqueNumber = CliqueNumber then
|
|
% We don't propagate profiling measurements along intra-clique calls.
|
|
true
|
|
else
|
|
deep_lookup_pd_desc(!.Deep, PDPtr, ProcDesc0),
|
|
deep_lookup_csd_desc(!.Deep, CSDPtr, CalleeDesc),
|
|
CalleeTotal = add_own_to_inherit(CalleeOwn, CalleeDesc),
|
|
ProcDesc = add_inherit_to_inherit(ProcDesc0, CalleeTotal),
|
|
deep_update_pd_desc(PDPtr, ProcDesc, !Deep),
|
|
deep_lookup_csd_comp_table(!.Deep, CSDPtr, CSDCompTable),
|
|
!:PDCompTable = add_comp_tables(!.PDCompTable, CSDCompTable)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func add_comp_tables(compensation_table, compensation_table)
|
|
= compensation_table.
|
|
|
|
add_comp_tables(CompTableA, CompTableB) = CompTable :-
|
|
( if map.is_empty(CompTableA) then
|
|
CompTable = CompTableB
|
|
else if map.is_empty(CompTableB) then
|
|
CompTable = CompTableA
|
|
else
|
|
CompTable = map.union(add_inherit_to_inherit, CompTableA, CompTableB)
|
|
).
|
|
|
|
:- func apply_override(compensation_table, compensation_table)
|
|
= compensation_table.
|
|
|
|
apply_override(CompTableA, CompTableB) = CompTable :-
|
|
( if map.is_empty(CompTableA) then
|
|
CompTable = CompTableB
|
|
else if map.is_empty(CompTableB) then
|
|
CompTable = CompTableA
|
|
else
|
|
CompTable = map.union(select_override_comp, CompTableA, CompTableB)
|
|
).
|
|
|
|
:- func select_override_comp(inherit_prof_info, inherit_prof_info)
|
|
= inherit_prof_info.
|
|
|
|
select_override_comp(OverrideComp, _) = OverrideComp.
|
|
|
|
:- func add_to_override(compensation_table,
|
|
proc_static_ptr, inherit_prof_info) = compensation_table.
|
|
|
|
add_to_override(!.CompTable, PSPtr, PDTotal) = !:CompTable :-
|
|
( if map.search(!.CompTable, PSPtr, Comp0) then
|
|
Comp = add_inherit_to_inherit(Comp0, PDTotal),
|
|
map.det_update(PSPtr, Comp, !CompTable)
|
|
else
|
|
map.det_insert(PSPtr, PDTotal, !CompTable)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred flat_call_sites(proc_dynamics::in, proc_dynamic_ptr::in,
|
|
list(call_site_dynamic_ptr)::out) is det.
|
|
|
|
flat_call_sites(ProcDynamics, PDPtr, CSDPtrs) :-
|
|
lookup_proc_dynamics(ProcDynamics, PDPtr, PD),
|
|
CallSiteArray = PD ^ pd_sites,
|
|
flatten_call_sites(CallSiteArray, CSDPtrs, _).
|
|
|
|
:- pred flatten_call_sites(array(call_site_array_slot)::in,
|
|
list(call_site_dynamic_ptr)::out, is_zeroed::out) is det.
|
|
|
|
flatten_call_sites(CallSiteArray, CSDPtrs, IsZeroed) :-
|
|
array.to_list(CallSiteArray, CallSites),
|
|
list.foldl2(gather_call_site_csdptrs, CallSites, [], CSDPtrsList0,
|
|
not_zeroed, IsZeroed),
|
|
list.reverse(CSDPtrsList0, CSDPtrsList),
|
|
list.condense(CSDPtrsList, CSDPtrs).
|
|
|
|
:- pred gather_call_site_csdptrs(call_site_array_slot::in,
|
|
list(list(call_site_dynamic_ptr))::in,
|
|
list(list(call_site_dynamic_ptr))::out,
|
|
is_zeroed::in, is_zeroed::out) is det.
|
|
|
|
gather_call_site_csdptrs(Slot, CSDPtrs0, CSDPtrs1, IsZeroed0, IsZeroed) :-
|
|
(
|
|
Slot = slot_normal(CSDPtr),
|
|
CSDPtr = call_site_dynamic_ptr(CSDI),
|
|
( if CSDI > 0 then
|
|
CSDPtrs1 = [[CSDPtr] | CSDPtrs0]
|
|
else
|
|
CSDPtrs1 = CSDPtrs0
|
|
),
|
|
IsZeroed = IsZeroed0
|
|
;
|
|
Slot = slot_multi(IsZeroed1, PtrArray),
|
|
array.to_list(PtrArray, PtrList0),
|
|
list.filter((pred(CSDPtr::in) is semidet :-
|
|
CSDPtr = call_site_dynamic_ptr(CSDI),
|
|
CSDI > 0
|
|
), PtrList0, PtrList1),
|
|
CSDPtrs1 = [PtrList1 | CSDPtrs0],
|
|
(
|
|
IsZeroed1 = zeroed,
|
|
IsZeroed = zeroed
|
|
;
|
|
IsZeroed1 = not_zeroed,
|
|
IsZeroed = IsZeroed0
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred maybe_report_stats(maybe(io.output_stream)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% XXX: io.report_stats writes to stderr, which mdprof_cgi has closed.
|
|
% We want to write the report to _OutputStream, but the library doesn't
|
|
% support that yet.
|
|
%
|
|
% The stats are needed only when writing the deep profiling paper anyway.
|
|
|
|
maybe_report_stats(yes(_OutputStream), !IO).
|
|
% io.report_stats("standard", !IO).
|
|
maybe_report_stats(no, !IO).
|
|
|
|
:- pred maybe_report_msg(maybe(io.output_stream)::in, string::in,
|
|
io::di, io::uo) is det.
|
|
|
|
maybe_report_msg(yes(OutputStream), Msg, !IO) :-
|
|
io.write_string(OutputStream, Msg, !IO),
|
|
flush_output(OutputStream, !IO).
|
|
maybe_report_msg(no, _, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module startup.
|
|
%---------------------------------------------------------------------------%
|