mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
57aee84cb1
This extends the RemarkStreamer to allow for other emitters (e.g. frontends, SIL, etc.) to emit remarks through a common interface. See changes in llvm/docs/Remarks.rst for motivation and design choices. Differential Revision: https://reviews.llvm.org/D73676
651 lines
19 KiB
ReStructuredText
651 lines
19 KiB
ReStructuredText
=======
|
|
Remarks
|
|
=======
|
|
|
|
.. contents::
|
|
:local:
|
|
|
|
Introduction to the LLVM remark diagnostics
|
|
===========================================
|
|
|
|
LLVM is able to emit diagnostics from passes describing whether an optimization
|
|
has been performed or missed for a particular reason, which should give more
|
|
insight to users about what the compiler did during the compilation pipeline.
|
|
|
|
There are three main remark types:
|
|
|
|
``Passed``
|
|
|
|
Remarks that describe a successful optimization performed by the compiler.
|
|
|
|
:Example:
|
|
|
|
::
|
|
|
|
foo inlined into bar with (cost=always): always inline attribute
|
|
|
|
``Missed``
|
|
|
|
Remarks that describe an attempt to an optimization by the compiler that
|
|
could not be performed.
|
|
|
|
:Example:
|
|
|
|
::
|
|
|
|
foo not inlined into bar because it should never be inlined
|
|
(cost=never): noinline function attribute
|
|
|
|
``Analysis``
|
|
|
|
Remarks that describe the result of an analysis, that can bring more
|
|
information to the user regarding the generated code.
|
|
|
|
:Example:
|
|
|
|
::
|
|
|
|
16 stack bytes in function
|
|
|
|
::
|
|
|
|
10 instructions in function
|
|
|
|
Enabling optimization remarks
|
|
=============================
|
|
|
|
There are two modes that are supported for enabling optimization remarks in
|
|
LLVM: through remark diagnostics, or through serialized remarks.
|
|
|
|
Remark diagnostics
|
|
------------------
|
|
|
|
Optimization remarks can be emitted as diagnostics. These diagnostics will be
|
|
propagated to front-ends if desired, or emitted by tools like :doc:`llc
|
|
<CommandGuide/llc>` or :doc:`opt <CommandGuide/opt>`.
|
|
|
|
.. option:: -pass-remarks=<regex>
|
|
|
|
Enables optimization remarks from passes whose name match the given (POSIX)
|
|
regular expression.
|
|
|
|
.. option:: -pass-remarks-missed=<regex>
|
|
|
|
Enables missed optimization remarks from passes whose name match the given
|
|
(POSIX) regular expression.
|
|
|
|
.. option:: -pass-remarks-analysis=<regex>
|
|
|
|
Enables optimization analysis remarks from passes whose name match the given
|
|
(POSIX) regular expression.
|
|
|
|
Serialized remarks
|
|
------------------
|
|
|
|
While diagnostics are useful during development, it is often more useful to
|
|
refer to optimization remarks post-compilation, typically during performance
|
|
analysis.
|
|
|
|
For that, LLVM can serialize the remarks produced for each compilation unit to
|
|
a file that can be consumed later.
|
|
|
|
By default, the format of the serialized remarks is :ref:`YAML
|
|
<yamlremarks>`, and it can be accompanied by a :ref:`section <remarkssection>`
|
|
in the object files to easily retrieve it.
|
|
|
|
:doc:`llc <CommandGuide/llc>` and :doc:`opt <CommandGuide/opt>` support the
|
|
following options:
|
|
|
|
|
|
``Basic options``
|
|
|
|
.. option:: -pass-remarks-output=<filename>
|
|
|
|
Enables the serialization of remarks to a file specified in <filename>.
|
|
|
|
By default, the output is serialized to :ref:`YAML <yamlremarks>`.
|
|
|
|
.. option:: -pass-remarks-format=<format>
|
|
|
|
Specifies the output format of the serialized remarks.
|
|
|
|
Supported formats:
|
|
|
|
* :ref:`yaml <yamlremarks>` (default)
|
|
* :ref:`yaml-strtab <yamlstrtabremarks>`
|
|
* :ref:`bitstream <bitstreamremarks>`
|
|
|
|
``Content configuration``
|
|
|
|
.. option:: -pass-remarks-filter=<regex>
|
|
|
|
Only passes whose name match the given (POSIX) regular expression will be
|
|
serialized to the final output.
|
|
|
|
.. option:: -pass-remarks-with-hotness
|
|
|
|
With PGO, include profile count in optimization remarks.
|
|
|
|
.. option:: -pass-remarks-hotness-threshold
|
|
|
|
The minimum profile count required for an optimization remark to be
|
|
emitted.
|
|
|
|
Other tools that support remarks:
|
|
|
|
:program:`llvm-lto`
|
|
|
|
.. option:: -lto-pass-remarks-output=<filename>
|
|
.. option:: -lto-pass-remarks-filter=<regex>
|
|
.. option:: -lto-pass-remarks-format=<format>
|
|
.. option:: -lto-pass-remarks-with-hotness
|
|
.. option:: -lto-pass-remarks-hotness-threshold
|
|
|
|
:program:`gold-plugin` and :program:`lld`
|
|
|
|
.. option:: -opt-remarks-filename=<filename>
|
|
.. option:: -opt-remarks-filter=<regex>
|
|
.. option:: -opt-remarks-format=<format>
|
|
.. option:: -opt-remarks-with-hotness
|
|
|
|
Serialization modes
|
|
===================
|
|
|
|
There are two modes available for serializing remarks:
|
|
|
|
``Separate``
|
|
|
|
In this mode, the remarks and the metadata are serialized separately. The
|
|
client is responsible for parsing the metadata first, then use the metadata
|
|
to correctly parse the remarks.
|
|
|
|
``Standalone``
|
|
|
|
In this mode, the remarks and the metadata are serialized to the same
|
|
stream. The metadata will always come before the remarks.
|
|
|
|
The compiler does not support emitting standalone remarks. This mode is
|
|
more suited for post-processing tools like linkers, that can merge the
|
|
remarks for one whole project.
|
|
|
|
.. _yamlremarks:
|
|
|
|
YAML remarks
|
|
============
|
|
|
|
A typical remark serialized to YAML looks like this:
|
|
|
|
.. code-block:: yaml
|
|
|
|
--- !<TYPE>
|
|
Pass: <pass>
|
|
Name: <name>
|
|
DebugLoc: { File: <file>, Line: <line>, Column: <column> }
|
|
Function: <function>
|
|
Hotness: <hotness>
|
|
Args:
|
|
- <key>: <value>
|
|
DebugLoc: { File: <arg-file>, Line: <arg-line>, Column: <arg-column> }
|
|
|
|
The following entries are mandatory:
|
|
|
|
* ``<TYPE>``: can be ``Passed``, ``Missed``, ``Analysis``,
|
|
``AnalysisFPCommute``, ``AnalysisAliasing``, ``Failure``.
|
|
* ``<pass>``: the name of the pass that emitted this remark.
|
|
* ``<name>``: the name of the remark coming from ``<pass>``.
|
|
* ``<function>``: the mangled name of the function.
|
|
|
|
If a ``DebugLoc`` entry is specified, the following fields are required:
|
|
|
|
* ``<file>``
|
|
* ``<line>``
|
|
* ``<column>``
|
|
|
|
If an ``arg`` entry is specified, the following fields are required:
|
|
|
|
* ``<key>``
|
|
* ``<value>``
|
|
|
|
If a ``DebugLoc`` entry is specified within an ``arg`` entry, the following
|
|
fields are required:
|
|
|
|
* ``<arg-file>``
|
|
* ``<arg-line>``
|
|
* ``<arg-column>``
|
|
|
|
.. _yamlstrtabremarks:
|
|
|
|
YAML with a string table
|
|
------------------------
|
|
|
|
The YAML serialization supports the usage of a string table by using the
|
|
``yaml-strtab`` format.
|
|
|
|
This format replaces strings in the YAML output with integers representing the
|
|
index in the string table that can be provided separately through metadata.
|
|
|
|
The following entries can take advantage of the string table while respecting
|
|
YAML rules:
|
|
|
|
* ``<pass>``
|
|
* ``<name>``
|
|
* ``<function>``
|
|
* ``<file>``
|
|
* ``<value>``
|
|
* ``<arg-file>``
|
|
|
|
Currently, none of the tools in :ref:`the opt-viewer directory <optviewer>`
|
|
support this format.
|
|
|
|
.. _optviewer:
|
|
|
|
YAML metadata
|
|
-------------
|
|
|
|
The metadata used together with the YAML format is:
|
|
|
|
* a magic number: "REMARKS\\0"
|
|
* the version number: a little-endian uint64_t
|
|
* the total size of the string table (the size itself excluded):
|
|
little-endian uint64_t
|
|
* a list of null-terminated strings
|
|
|
|
Optional:
|
|
|
|
* the absolute file path to the serialized remark diagnostics: a
|
|
null-terminated string.
|
|
|
|
When the metadata is serialized separately from the remarks, the file path
|
|
should be present and point to the file where the remarks are serialized to.
|
|
|
|
In case the metadata only acts as a header to the remarks, the file path can be
|
|
omitted.
|
|
|
|
.. _bitstreamremarks:
|
|
|
|
LLVM bitstream remarks
|
|
======================
|
|
|
|
This format is using :doc:`LLVM bitstream <BitCodeFormat>` to serialize remarks
|
|
and their associated metadata.
|
|
|
|
A bitstream remark stream can be identified by the magic number ``"RMRK"`` that
|
|
is placed at the very beginning.
|
|
|
|
The format for serializing remarks is composed of two different block types:
|
|
|
|
.. _bitstreamremarksmetablock:
|
|
|
|
META_BLOCK
|
|
----------
|
|
|
|
The block providing information about the rest of the content in the stream.
|
|
|
|
Exactly one block is expected. Having multiple metadata blocks is an error.
|
|
|
|
This block can contain the following records:
|
|
|
|
.. _bitstreamremarksrecordmetacontainerinfo:
|
|
|
|
``RECORD_META_CONTAINER_INFO``
|
|
|
|
The container version and type.
|
|
|
|
Version: u32
|
|
|
|
Type: u2
|
|
|
|
.. _bitstreamremarksrecordmetaremarkversion:
|
|
|
|
``RECORD_META_REMARK_VERSION``
|
|
|
|
The version of the remark entries. This can change independently from the
|
|
container version.
|
|
|
|
Version: u32
|
|
|
|
.. _bitstreamremarksrecordmetastrtab:
|
|
|
|
``RECORD_META_STRTAB``
|
|
|
|
The string table used by the remark entries. The format of the string table
|
|
is a sequence of strings separated by ``\0``.
|
|
|
|
.. _bitstreamremarksrecordmetaexternalfile:
|
|
|
|
``RECORD_META_EXTERNAL_FILE``
|
|
|
|
The external remark file path that contains the remark blocks associated
|
|
with this metadata. This is an absolute path.
|
|
|
|
.. _bitstreamremarksremarkblock:
|
|
|
|
REMARK_BLOCK
|
|
------------
|
|
|
|
The block describing a remark entry.
|
|
|
|
0 or more blocks per file are allowed. Each block will depend on the
|
|
:ref:`META_BLOCK <bitstreamremarksmetablock>` in order to be parsed correctly.
|
|
|
|
This block can contain the following records:
|
|
|
|
``RECORD_REMARK_HEADER``
|
|
|
|
The header of the remark. This contains all the mandatory information about
|
|
a remark.
|
|
|
|
+---------------+---------------------------+
|
|
| Type | u3 |
|
|
+---------------+---------------------------+
|
|
| Remark name | VBR6 (string table index) |
|
|
+---------------+---------------------------+
|
|
| Pass name | VBR6 (string table index) |
|
|
+---------------+---------------------------+
|
|
| Function name | VBR6 (string table index) |
|
|
+---------------+---------------------------+
|
|
|
|
``RECORD_REMARK_DEBUG_LOC``
|
|
|
|
The source location for the corresponding remark. This record is optional.
|
|
|
|
+--------+---------------------------+
|
|
| File | VBR7 (string table index) |
|
|
+--------+---------------------------+
|
|
| Line | u32 |
|
|
+--------+---------------------------+
|
|
| Column | u32 |
|
|
+--------+---------------------------+
|
|
|
|
``RECORD_REMARK_HOTNESS``
|
|
|
|
The hotness of the remark. This record is optional.
|
|
|
|
+---------------+---------------------+
|
|
| Hotness | VBR8 (string table index) |
|
|
+---------------+---------------------+
|
|
|
|
``RECORD_REMARK_ARG_WITH_DEBUGLOC``
|
|
|
|
A remark argument with an associated debug location.
|
|
|
|
+--------+---------------------------+
|
|
| Key | VBR7 (string table index) |
|
|
+--------+---------------------------+
|
|
| Value | VBR7 (string table index) |
|
|
+--------+---------------------------+
|
|
| File | VBR7 (string table index) |
|
|
+--------+---------------------------+
|
|
| Line | u32 |
|
|
+--------+---------------------------+
|
|
| Column | u32 |
|
|
+--------+---------------------------+
|
|
|
|
``RECORD_REMARK_ARG_WITHOUT_DEBUGLOC``
|
|
|
|
A remark argument with an associated debug location.
|
|
|
|
+--------+---------------------------+
|
|
| Key | VBR7 (string table index) |
|
|
+--------+---------------------------+
|
|
| Value | VBR7 (string table index) |
|
|
+--------+---------------------------+
|
|
|
|
The remark container
|
|
--------------------
|
|
|
|
Bitstream remarks are designed to be used in two different modes:
|
|
|
|
``The separate mode``
|
|
|
|
The separate mode is the mode that is typically used during compilation. It
|
|
provides a way to serialize the remark entries to a stream while some
|
|
metadata is kept in memory to be emitted in the product of the compilation
|
|
(typically, an object file).
|
|
|
|
``The standalone mode``
|
|
|
|
The standalone mode is typically stored and used after the distribution of
|
|
a program. It contains all the information that allows the parsing of all
|
|
the remarks without having any external dependencies.
|
|
|
|
In order to support multiple modes, the format introduces the concept of a
|
|
bitstream remark container type.
|
|
|
|
.. _bitstreamremarksseparateremarksmeta:
|
|
|
|
``SeparateRemarksMeta: the metadata emitted separately``
|
|
|
|
This container type expects only a :ref:`META_BLOCK <bitstreamremarksmetablock>` containing only:
|
|
|
|
* :ref:`RECORD_META_CONTAINER_INFO <bitstreamremarksrecordmetacontainerinfo>`
|
|
* :ref:`RECORD_META_STRTAB <bitstreamremarksrecordmetastrtab>`
|
|
* :ref:`RECORD_META_EXTERNAL_FILE <bitstreamremarksrecordmetaexternalfile>`
|
|
|
|
Typically, this is emitted in a section in the object files, allowing
|
|
clients to retrieve remarks and their associated metadata directly from
|
|
intermediate products.
|
|
|
|
``SeparateRemarksFile: the remark entries emitted separately``
|
|
|
|
This container type expects only a :ref:`META_BLOCK <bitstreamremarksmetablock>` containing only:
|
|
|
|
* :ref:`RECORD_META_CONTAINER_INFO <bitstreamremarksrecordmetacontainerinfo>`
|
|
* :ref:`RECORD_META_REMARK_VERSION <bitstreamremarksrecordmetaremarkversion>`
|
|
|
|
This container type expects 0 or more :ref:`REMARK_BLOCK <bitstreamremarksremarkblock>`.
|
|
|
|
Typically, this is emitted in a side-file alongside an object file, and is
|
|
made to be able to stream to without increasing the memory consumption of
|
|
the compiler. This is referenced by the :ref:`RECORD_META_EXTERNAL_FILE
|
|
<bitstreamremarksrecordmetaexternalfile>` entry in the
|
|
:ref:`SeparateRemarksMeta <bitstreamremarksseparateremarksmeta>` container.
|
|
|
|
When the parser tries to parse a container that contains the metadata for the
|
|
separate remarks, it should parse the version and type, then keep the string
|
|
table in memory while opening the external file, validating its metadata and
|
|
parsing the remark entries.
|
|
|
|
The container versions from the separate container should match in order to
|
|
have a well-formed file.
|
|
|
|
``Standalone: the metadata and the remark entries emitted together``
|
|
|
|
This container type expects only a :ref:`META_BLOCK <bitstreamremarksmetablock>` containing only:
|
|
|
|
* :ref:`RECORD_META_CONTAINER_INFO <bitstreamremarksrecordmetacontainerinfo>`
|
|
* :ref:`RECORD_META_REMARK_VERSION <bitstreamremarksrecordmetaremarkversion>`
|
|
* :ref:`RECORD_META_STRTAB <bitstreamremarksrecordmetastrtab>`
|
|
|
|
This container type expects 0 or more :ref:`REMARK_BLOCK <bitstreamremarksremarkblock>`.
|
|
|
|
A complete output of :program:`llvm-bcanalyzer` on the different container types:
|
|
|
|
``SeparateRemarksMeta``
|
|
|
|
.. code-block:: none
|
|
|
|
<BLOCKINFO_BLOCK/>
|
|
<Meta BlockID=8 NumWords=13 BlockCodeSize=3>
|
|
<Container info codeid=1 abbrevid=4 op0=5 op1=0/>
|
|
<String table codeid=3 abbrevid=5/> blob data = 'pass\\x00key\\x00value\\x00'
|
|
<External File codeid=4 abbrevid=6/> blob data = '/path/to/file/name'
|
|
</Meta>
|
|
|
|
``SeparateRemarksFile``
|
|
|
|
.. code-block:: none
|
|
|
|
<BLOCKINFO_BLOCK/>
|
|
<Meta BlockID=8 NumWords=3 BlockCodeSize=3>
|
|
<Container info codeid=1 abbrevid=4 op0=0 op1=1/>
|
|
<Remark version codeid=2 abbrevid=5 op0=0/>
|
|
</Meta>
|
|
<Remark BlockID=9 NumWords=8 BlockCodeSize=4>
|
|
<Remark header codeid=5 abbrevid=4 op0=2 op1=0 op2=1 op3=2/>
|
|
<Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>
|
|
<Remark hotness codeid=7 abbrevid=6 op0=999999999/>
|
|
<Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 op3=11 op4=66/>
|
|
</Remark>
|
|
|
|
``Standalone``
|
|
|
|
.. code-block:: none
|
|
|
|
<BLOCKINFO_BLOCK/>
|
|
<Meta BlockID=8 NumWords=15 BlockCodeSize=3>
|
|
<Container info codeid=1 abbrevid=4 op0=5 op1=2/>
|
|
<Remark version codeid=2 abbrevid=5 op0=30/>
|
|
<String table codeid=3 abbrevid=6/> blob data = 'pass\\x00remark\\x00function\\x00path\\x00key\\x00value\\x00argpath\\x00'
|
|
</Meta>
|
|
<Remark BlockID=9 NumWords=8 BlockCodeSize=4>
|
|
<Remark header codeid=5 abbrevid=4 op0=2 op1=1 op2=0 op3=2/>
|
|
<Remark debug location codeid=6 abbrevid=5 op0=3 op1=99 op2=55/>
|
|
<Remark hotness codeid=7 abbrevid=6 op0=999999999/>
|
|
<Argument with debug location codeid=8 abbrevid=7 op0=4 op1=5 op2=6 op3=11 op4=66/>
|
|
</Remark>
|
|
|
|
opt-viewer
|
|
==========
|
|
|
|
The ``opt-viewer`` directory contains a collection of tools that visualize and
|
|
summarize serialized remarks.
|
|
|
|
The tools only support the ``yaml`` format.
|
|
|
|
.. _optviewerpy:
|
|
|
|
opt-viewer.py
|
|
-------------
|
|
|
|
Output a HTML page which gives visual feedback on compiler interactions with
|
|
your program.
|
|
|
|
:Examples:
|
|
|
|
::
|
|
|
|
$ opt-viewer.py my_yaml_file.opt.yaml
|
|
|
|
::
|
|
|
|
$ opt-viewer.py my_build_dir/
|
|
|
|
|
|
opt-stats.py
|
|
------------
|
|
|
|
Output statistics about the optimization remarks in the input set.
|
|
|
|
:Example:
|
|
|
|
::
|
|
|
|
$ opt-stats.py my_yaml_file.opt.yaml
|
|
|
|
Total number of remarks 3
|
|
|
|
|
|
Top 10 remarks by pass:
|
|
inline 33%
|
|
asm-printer 33%
|
|
prologepilog 33%
|
|
|
|
Top 10 remarks:
|
|
asm-printer/InstructionCount 33%
|
|
inline/NoDefinition 33%
|
|
prologepilog/StackSize 33%
|
|
|
|
opt-diff.py
|
|
-----------
|
|
|
|
Produce a new YAML file which contains all of the changes in optimizations
|
|
between two YAML files.
|
|
|
|
Typically, this tool should be used to do diffs between:
|
|
|
|
* new compiler + fixed source vs old compiler + fixed source
|
|
* fixed compiler + new source vs fixed compiler + old source
|
|
|
|
This diff file can be displayed using :ref:`opt-viewer.py <optviewerpy>`.
|
|
|
|
:Example:
|
|
|
|
::
|
|
|
|
$ opt-diff.py my_opt_yaml1.opt.yaml my_opt_yaml2.opt.yaml -o my_opt_diff.opt.yaml
|
|
$ opt-viewer.py my_opt_diff.opt.yaml
|
|
|
|
.. _remarkssection:
|
|
|
|
Emitting remark diagnostics in the object file
|
|
==============================================
|
|
|
|
A section containing metadata on remark diagnostics will be emitted for the
|
|
following formats:
|
|
|
|
* ``yaml-strtab``
|
|
* ``bitstream``
|
|
|
|
This can be overridden by using the flag ``-remarks-section=<bool>``.
|
|
|
|
The section is named:
|
|
|
|
* ``__LLVM,__remarks`` (MachO)
|
|
|
|
C API
|
|
=====
|
|
|
|
LLVM provides a library that can be used to parse remarks through a shared
|
|
library named ``libRemarks``.
|
|
|
|
The typical usage through the C API is like the following:
|
|
|
|
.. code-block:: c
|
|
|
|
LLVMRemarkParserRef Parser = LLVMRemarkParserCreateYAML(Buf, Size);
|
|
LLVMRemarkEntryRef Remark = NULL;
|
|
while ((Remark = LLVMRemarkParserGetNext(Parser))) {
|
|
// use Remark
|
|
LLVMRemarkEntryDispose(Remark); // Release memory.
|
|
}
|
|
bool HasError = LLVMRemarkParserHasError(Parser);
|
|
LLVMRemarkParserDispose(Parser);
|
|
|
|
Remark streamers
|
|
================
|
|
|
|
The ``RemarkStreamer`` interface is used to unify the serialization
|
|
capabilities of remarks across all the components that can generate remarks.
|
|
|
|
All remark serialization should go through the main remark streamer, the
|
|
``llvm::remarks::RemarkStreamer`` set up in the ``LLVMContext``. The interface
|
|
takes remark objects converted to ``llvm::remarks::Remark``, and takes care of
|
|
serializing it to the requested format, using the requested type of metadata,
|
|
etc.
|
|
|
|
Typically, a specialized remark streamer will hold a reference to the one set
|
|
up in the ``LLVMContext``, and will operate on its own type of diagnostics.
|
|
|
|
For example, LLVM IR passes will emit ``llvm::DiagnosticInfoOptimization*``
|
|
that get converted to ``llvm::remarks::Remark`` objects. Then, clang could set
|
|
up its own specialized remark streamer that takes ``clang::Diagnostic``
|
|
objects. This can allow various components of the frontend to emit remarks
|
|
using the same techniques as the LLVM remarks.
|
|
|
|
This gives us the following advantages:
|
|
|
|
* Composition: during the compilation pipeline, multiple components can set up
|
|
their specialized remark streamers that all emit remarks through the same
|
|
main streamer.
|
|
* Re-using the remark infrastructure in ``lib/Remarks``.
|
|
* Using the same file and format for the remark emitters created throughout the
|
|
compilation.
|
|
|
|
at the cost of an extra layer of abstraction.
|
|
|
|
.. FIXME: add documentation for llvm-opt-report.
|
|
.. FIXME: add documentation for Passes supporting optimization remarks
|
|
.. FIXME: add documentation for IR Passes
|
|
.. FIXME: add documentation for CodeGen Passes
|