Files
mercury/mdbcomp/prim_data.m
Zoltan Somogyi 2dc982cfe4 Make a representation of the program available to the deep profiler.
Estimated hours taken: 50
Branches: main

Make a representation of the program available to the deep profiler. We do
this by letting the user request, via the option "--deep-procrep-file"
in MERCURY_OPTIONS, that when the Deep.data file is written, a Deep.procrep
file should be written alongside it.

The intended use of this information is the discovery of profitable
parallelism. When a conjunction contains two expensive calls, e.g. p(...) and
q(...) connected by some shared variables, the potential gain from executing
them in parallel is limited by how early p produces those variables and how
late q consumes them, and knowing this requires access to the code of p and q.

Since the debugger and the deep profiler both need access to program
representations, put the relevant data structures and the operations on them
in mdbcomp. The data structures are significantly expanded, since the deep
profiler deals with the whole program, while the debugger was interested only
in one procedure at a time.

The layout structures have to change as well. In a previous change, I changed
proc layout structures to make room for the procedure representation even in
non-debugging grades, but this isn't enough, since the procedure representation
refers to the module's string table. This diff therefore makes some parts of
the module layout structure, including of course the string table, also
available in non-debugging grades.

configure.in:
	Check whether the installed compiler can process switches on foreign
	enums correctly, since this diff depends on that.

runtime/mercury_stack_layout.[ch]:
runtime/mercury_types.h:
	Add a new structure, MR_ModuleCommonLayout, that holds the part of
	the module layout that is common to deep profiling and debugging.

runtime/mercury_deep_profiling.[ch]:
	The old "deep profiling token" enum type was error prone, since at
	each point in the data file, only a subset was applicable. This diff
	breaks up the this enum into several enums, each consisting of the
	choice applicable at a given point.

	This also allows some of the resulting enums to be used in procrep
	files.

	Rename some enums and functions to avoid ambiguities, and in one case
	to conform to our naming scheme.

	Make write_out_proc_statics take a second argument. This is a FILE *
	that (if not NULL) asks write_out_proc_statics to write the
	representation of the current module to specified stream.

	These module representations go into the middle part of the program
	representation file. Add functions to write out the prologue and
	epilogue of this file.

	Write out procedure representations if this is requested.

	Factor out some code that is now used in more than one place.

runtime/mercury_deep_profiling_hand.h:
	Conform to the changes to mercury_deep_profiling.h.

runtime/mercury_builtin_types.c:
	Pass the extra argument in the argument lists of invocations of
	write_out_proc_statics.

runtime/mercury_trace_base.[ch]:
	Conform to the name change from proc_rep to proc_defn_rep in mdbcomp.

runtime/mercury_grade.h:
	Due to the change to layout structures, increment the binary
	compatibility version numbers for both debug and deep profiling grades.

runtime/mercury_wrapper.[ch]:
	Provide two new MERCURY_OPTION options. The first --deep-procrep-file,
	allows the user to ask for the program representation to be generated.
	The second, --deep-random-write, allows tools/bootcheck to request that
	only a fraction of all program invocations should generate any deep
	profiling output.

	The first option will be documented once it is tested much more fully.
	The second option is deliberately not documented.

	Update the type of the variable that holds the address of the
	(mkinit-generated) write_out_proc_statics function to accept the second
	argument.

util/mkinit.c:
	Pass the extra argument in the argument list of write_out_proc_statics.

mdbcomp/program_representation.m:
	Extend the existing data structures for representing a procedure body
	to represent a procedure (complete with name), a module and a program.
	The name is implemented as string_proc_label, a form of proc_label that
	can be written out to files. This replaces the old proc_id type the
	deep profiler.

	Extend the representation of switches to record the identity of the
	variable being switched on, and the cons_ids of the arms. Without the
	former, we cannot be sure when a variable is first used, and the latter
	is needed for meaningful prettyprinting of procedure bodies.

	Add code for reading in files of bytecodes, and for making sense of the
	bytecodes themselves. (It is this code that uses foreign enums.)

mdbcomp/prim_data.m:
	Note the relationship of proc_label with string_proc_label.

mdbcomp/rtti_access.m:
	Add the access operations needed to find module string tables with the
	new organization of layout structures.

	Provide operations on bytecodes and string tables generally.

trace/mercury_trace_cmd_browsing.c:
	Conform to the change to mdbcomp/program_representation.m.

compiler/layout.m:
	Add support for a MR_ModuleCommonLayout.

	Rename some function symbols to avoid ambiguities.

compiler/layout_out.m:
	Handle the new structure.

compiler/stack_layout.m:
	Generate the new structure and the procedure representation bytecode
	in deep profiling grades.

compiler/llds_out.m:
	Generate the code required to write out the prologue and epilogue
	of program representation files.

	Pass the extra argument in the argument lists of invocations of
	write_out_proc_statics that tells those invocations to write out
	the module representations between the prologue and the epilogue.

compiler/prog_rep.m:
	When generating bytecodes, include the new information for switches.

compiler/continuation_info.m:
	Replace a bool with a more expressive type.

compiler/proc_rep.m:
	Conform to the change to continuation_info.m.

compiler/opt_debug.m:
	Conform to the change to layout.m.

deep_profiler/mdprof_procrep.m:
	A new test program to test the reading of program representations.

deep_profiler/DEEP_FLAGS.in:
deep_profiler/Mmakefile:
	Copy the contents of the mdbcomp module to this directory on demand,
	instead of linking to it. This is necessary now that the deep profiler
	depends directly on mdbcomp even if it is compiled in a non-debugging
	grade.

	The arrangements for doing this were copied from the slice directory,
	which has long done the same.

	Avoid a duplicate include of Mmake.deep.params.

	Add the new test program to the list of programs in this directory.

Mmakefile:
	Go through deep_profiler/Mmakefile when deciding whether to do "mmake
	depend" in the deep_profiler directory. The old actions won't work
	correctly now that we need to copy some files from mdbcomp before we
	can run "mmake depend".

deep_profiler/profile.m:
	Remove the code that was moved (in cleaned-up form) to mdbcomp.

deep_profiler/dump.m:
deep_profiler/profile.m:
	Conform to the changes above.

browser/declarative_execution.m:
browser/declarative_tree.m:
	Conform to the changes in mdbcomp.

doc/user_guide.texi:
	Add commented out documentation of the two new options.

slice/Mmakefile:
	Fix formatting, and a bug.

library/exception.m:
library/par_builtin.m:
library/thread.m:
library/thread.semaphore.m:
	Update all the handwritten modules to pass the extra argument now
	required by write_out_proc_statics.

tests/debugger/declarative/dependency.exp:
	Conform to the change from proc_rep to proc_defn_rep.

tools/bootcheck:
	Write out deep profiling data only from every 25th invocation, since
	otherwise the time for a bootcheck takes six times as long in deep
	profiling grades than in asm_fast.gc.

	However, do test the ability to write out program representations.

	Use the mkinit from the workspace, not the installed one.

	Don't disable line wrapping.
2007-09-12 06:21:20 +00:00

359 lines
14 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2005-2007 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: prim_data.m.
% Main authors: fjh, zs.
%
% This module contains some types and predicates that are, or are planned to
% be, shared between the compiler and the debugger.
%
%-----------------------------------------------------------------------------%
:- module mdbcomp.prim_data.
:- interface.
:- import_module list.
% This enumeration must be EXACTLY the same as the MR_PredFunc enum
% in runtime/mercury_stack_layout.h, and in the same order, since the
% code (in browser) assumes the representation is the same.
%
:- type pred_or_func
---> pf_predicate
; pf_function.
% The kinds of events with which MR_trace may be called, either
% by compiler-generated code, or by code in the standard library
% referring to compiler-generated data structures.
%
% This enumeration must be EXACTLY the same as the MR_trace_port enum
% in runtime/mercury_trace_base.h, and in the same order, since the
% code (in browser) assumes the representation is the same.
%
:- type trace_port
---> port_call
; port_exit
; port_redo
; port_fail
; port_exception
; port_ite_cond
; port_ite_then
; port_ite_else
; port_neg_enter
; port_neg_success
; port_neg_failure
; port_disj_first
; port_disj_later
; port_switch
; port_nondet_foreign_proc_first
; port_nondet_foreign_proc_later
; port_user.
% The order that the sym_name function symbols appear in can be significant
% for module dependency ordering.
%
:- type sym_name
---> unqualified(string)
; qualified(sym_name, string).
:- type module_name == sym_name.
% A proc_label is a data structure a backend can use to as the basis
% of the label used as the entry point of a procedure.
%
% The defining module is the module that provides the code for the
% predicate, the declaring module contains the `:- pred' declaration.
% When these are different, as for specialised versions of predicates
% from `.opt' files, the defining module's name may need to be added
% as a qualifier to the label.
%
% The type string_proc_label in program_representation.m parallels this
% type, but differs from it in being used not inside the compiler by
% outside, which means it needs to use different types for many fields.
%
:- type proc_label
---> ordinary_proc_label(
ord_defining_module :: module_name,
ord_p_or_f :: pred_or_func,
ord_declaring_module :: module_name,
ord_pred_name :: string,
ord_arity :: int,
ord_mode_number :: int
)
; special_proc_label(
spec_defining_module :: module_name,
spec_spec_id :: special_pred_id,
% The special_pred_id indirectly
% defines the predicate name.
spec_type_module :: module_name,
spec_type_name :: string,
spec_type_arity :: int,
spec_mode_number :: int
).
:- type special_pred_id
---> spec_pred_unify
; spec_pred_index
; spec_pred_compare
; spec_pred_init.
% special_pred_name_arity(SpecialPredId, GenericPredName, TargetName,
% Arity):
%
% True iff there is a special predicate of category SpecialPredId,
% called builtin.GenericPredName/Arity, and for which the name of the
% predicate in the target language is TargetName.
%
:- pred special_pred_name_arity(special_pred_id, string, string, int).
:- mode special_pred_name_arity(in, out, out, out) is det.
:- mode special_pred_name_arity(out, in, out, out) is semidet.
:- mode special_pred_name_arity(out, out, in, out) is semidet.
% get_special_pred_id_generic_name(SpecialPredId) = GenericPredName:
%
% The name of the generic predicate for SpecialPredId is
% builtin.GenericPredName.
%
:- func get_special_pred_id_generic_name(special_pred_id) = string.
% get_special_pred_id_target_name(SpecialPredId) = TargetName:
%
% The name of the predicate in the target language for SpecialPredId is
% TargetName.
%
:- func get_special_pred_id_target_name(special_pred_id) = string.
% get_special_pred_id_name(SpecialPredId) = Arity:
%
% The arity of the SpecialPredId predicate is Arity.
%
:- func get_special_pred_id_arity(special_pred_id) = int.
% string_to_sym_name_sep(String, Separator) = SymName:
%
% Convert a string, possibly prefixed with module qualifiers (separated
% by Separator), into a symbol name.
%
:- func string_to_sym_name_sep(string, string) = sym_name.
% string_to_sym_name(String) = SymName:
%
% Convert a string, possibly prefixed with module qualifiers (separated
% by the standard Mercury module qualifier separator), into a symbol name.
%
:- func string_to_sym_name(string) = sym_name.
% sym_name_to_string_sep(SymName, Separator) = String:
%
% Convert a symbol name to a string, with module qualifiers separated
% by Separator.
%
:- func sym_name_to_string_sep(sym_name, string) = string.
% sym_name_to_string(SymName) = String:
%
% Convert a symbol name to a string, with module qualifiers separated by
% the standard Mercury module qualifier operator.
%
:- func sym_name_to_string(sym_name) = string.
% is_submodule(SymName1, SymName2):
%
% True iff SymName1 is a submodule of SymName2.
% For example mod1.mod2.mod3 is a submodule of mod1.mod2.
%
:- pred is_submodule(module_name::in, module_name::in) is semidet.
% insert_module_qualifier(ModuleName, SymName0) = SymName:
%
% Prepend the specified ModuleName onto the module qualifiers in SymName0,
% giving SymName.
%
:- func insert_module_qualifier(string, sym_name) = sym_name.
% Returns all the modules which are automatically imported.
%
:- func all_builtin_modules = list(sym_name).
% Returns the name of the module containing public builtins;
% originally this was "mercury_builtin", but it later became
% just "builtin", and it may eventually be renamed "std.builtin".
% This module is automatically imported, as if via `import_module'.
%
:- func mercury_public_builtin_module = sym_name.
% Returns the name of the module containing private builtins;
% traditionally this was "mercury_builtin", but it later became
% "private_builtin", and it may eventually be renamed
% "std.private_builtin". This module is automatically imported,
% as if via `use_module'.
%
:- func mercury_private_builtin_module = sym_name.
% Returns the name of the module containing builtins for region-based
% memory management. This module is automatically imported iff
% RBMM is enabled.
%
:- func mercury_region_builtin_module = sym_name.
% Returns the name of the module containing builtins for software
% transactional memory.
% This module is automatically imported iff STM is used in a module.
%
:- func mercury_stm_builtin_module = sym_name.
% Returns the name of the module containing builtins for tabling;
% originally these were in "private_builtin", but were then moved into
% a separate module. This module is automatically imported iff any
% predicate is tabled.
%
:- func mercury_table_builtin_module = sym_name.
% Returns the name of the module containing the builtins for deep
% profiling. This module is automatically imported iff deep profiling
% is enabled.
%
:- func mercury_profiling_builtin_module = sym_name.
% Returns the name of the module containing the builtins for term size
% profiling. This module is automatically imported iff term size profiling
% is enabled.
%
:- func mercury_term_size_prof_builtin_module = sym_name.
% Returns the name of the module containing the builtins for parallelism.
% This module is automatically imported iff building in a .par grade.
%
:- func mercury_par_builtin_module = sym_name.
% Returns the sym_name of the module with the given name in the
% Mercury standard library.
%
:- func mercury_std_lib_module_name(sym_name) = sym_name.
:- pred is_std_lib_module_name(sym_name::in, string::out) is semidet.
% Succeeds iff the specified module is one of the builtin modules listed
% above which may be automatically imported.
%
:- pred any_mercury_builtin_module(sym_name::in) is semidet.
% Succeeds iff the specified module will never be traced.
%
:- pred non_traced_mercury_builtin_module(sym_name::in) is semidet.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module int.
:- import_module library.
:- import_module list.
:- import_module string.
%-----------------------------------------------------------------------------%
string_to_sym_name_sep(String, ModuleSeparator) = Result :-
% This would be simpler if we had a string.rev_sub_string_search/3 pred.
% With that, we could search for underscores right-to-left, and construct
% the resulting symbol directly. Instead, we search for them left-to-right,
% and then call insert_module_qualifier to fix things up.
(
string.sub_string_search(String, ModuleSeparator, LeftLength),
LeftLength > 0
->
string.left(String, LeftLength, ModuleName),
string.length(String, StringLength),
string.length(ModuleSeparator, SeparatorLength),
RightLength = StringLength - LeftLength - SeparatorLength,
string.right(String, RightLength, Name),
NameSym = string_to_sym_name_sep(Name, ModuleSeparator),
Result = insert_module_qualifier(ModuleName, NameSym)
;
Result = unqualified(String)
).
string_to_sym_name(String) = string_to_sym_name_sep(String, ".").
sym_name_to_string_sep(unqualified(Name), _Separator) = Name.
sym_name_to_string_sep(qualified(ModuleSym, Name), Separator) = QualName :-
ModuleName = sym_name_to_string_sep(ModuleSym, Separator),
string.append_list([ModuleName, Separator, Name], QualName).
sym_name_to_string(SymName) = sym_name_to_string_sep(SymName, ".").
insert_module_qualifier(ModuleName, unqualified(PlainName)) =
qualified(unqualified(ModuleName), PlainName).
insert_module_qualifier(ModuleName, qualified(ModuleQual0, PlainName)) =
qualified(ModuleQual, PlainName) :-
insert_module_qualifier(ModuleName, ModuleQual0) = ModuleQual.
is_submodule(SymName, SymName).
is_submodule(qualified(SymNameA, _), SymNameB) :-
is_submodule(SymNameA, SymNameB).
special_pred_name_arity(spec_pred_unify, "unify", "__Unify__", 2).
special_pred_name_arity(spec_pred_index, "index", "__Index__", 2).
special_pred_name_arity(spec_pred_compare, "compare", "__Compare__", 3).
special_pred_name_arity(spec_pred_init, "initialise", "__Initialise__", 1).
get_special_pred_id_generic_name(Id) = Name :-
special_pred_name_arity(Id, Name, _, _).
get_special_pred_id_target_name(Id) = Name :-
special_pred_name_arity(Id, _, Name, _).
get_special_pred_id_arity(Id) = Arity :-
special_pred_name_arity(Id, _, _, Arity).
all_builtin_modules = [
mercury_public_builtin_module,
mercury_private_builtin_module,
mercury_region_builtin_module,
mercury_stm_builtin_module,
mercury_table_builtin_module,
mercury_profiling_builtin_module,
mercury_term_size_prof_builtin_module,
mercury_par_builtin_module].
% We may eventually want to put the standard library into a package "std":
% mercury_public_builtin_module = qualified(unqualified("std"), "builtin").
% mercury_private_builtin_module(M) =
% qualified(unqualified("std"), "private_builtin"))).
mercury_public_builtin_module = unqualified("builtin").
mercury_private_builtin_module = unqualified("private_builtin").
mercury_region_builtin_module = unqualified("region_builtin").
mercury_stm_builtin_module = unqualified("stm_builtin").
mercury_table_builtin_module = unqualified("table_builtin").
mercury_profiling_builtin_module = unqualified("profiling_builtin").
mercury_term_size_prof_builtin_module = unqualified("term_size_prof_builtin").
mercury_par_builtin_module = unqualified("par_builtin").
mercury_std_lib_module_name(Name) = Name.
is_std_lib_module_name(SymName, Name) :-
Name = sym_name_to_string(SymName),
mercury_std_library_module(Name).
any_mercury_builtin_module(Module) :-
( Module = mercury_public_builtin_module
; Module = mercury_private_builtin_module
; Module = mercury_region_builtin_module
; Module = mercury_table_builtin_module
; Module = mercury_profiling_builtin_module
; Module = mercury_term_size_prof_builtin_module
; Module = mercury_par_builtin_module
).
non_traced_mercury_builtin_module(Module) :-
( Module = mercury_table_builtin_module
; Module = mercury_profiling_builtin_module
; Module = mercury_term_size_prof_builtin_module
; Module = mercury_par_builtin_module
).