mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 01:43:35 +00:00
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.
359 lines
14 KiB
Mathematica
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
|
|
).
|