# Remarks

- Introduction to the LLVM remark diagnostics

- Enabling optimization remarks

  - Remark diagnostics

  - Serialized remarks

- YAML remarks

- opt-viewer

  - opt-viewer.py

  - opt-stats.py

  - opt-diff.py

- Emitting remark diagnostics in the object file

- C API

## 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 llc or opt.

`-pass-remarks``=<regex>`

  Enables optimization remarks from passes whose name match the given (POSIX) regular expression.

`-pass-remarks-missed``=<regex>`

  Enables missed optimization remarks from passes whose name match the given (POSIX) regular expression.

`-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 YAML, and it can be accompanied by a section in the object files to easily retrieve it.

llc and opt support the following options:

`Basic options`

> `-pass-remarks-output``=<filename>`

>   Enables the serialization of remarks to a file specified in <filename>.

>   By default, the output is serialized to YAML.

> `-pass-remarks-format``=<format>`

>   Specifies the output format of the serialized remarks.

>   Supported formats:

>   - yaml (default)

`Content configuration`

> `-pass-remarks-filter``=<regex>`

>   Only passes whose name match the given (POSIX) regular expression will be serialized to the final output.

> `-pass-remarks-with-hotness```

>   With PGO, include profile count in optimization remarks.

> `-pass-remarks-hotness-threshold```

>   The minimum profile count required for an optimization remark to be emitted.

Other tools that support remarks:

llvm-lto

> `-lto-pass-remarks-output``=<filename>`
> `-lto-pass-remarks-filter``=<regex>`
> `-lto-pass-remarks-format``=<format>`
> `-lto-pass-remarks-with-hotness```
> `-lto-pass-remarks-hotness-threshold```

gold-plugin and lld

> `-opt-remarks-filename``=<filename>`
> `-opt-remarks-filter``=<regex>`
> `-opt-remarks-format``=<format>`
> `-opt-remarks-with-hotness```

## YAML remarks

A typical remark serialized to YAML looks like this:

    --- !<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>`

## opt-viewer

The `opt-viewer` directory contains a collection of tools that visualize and summarize serialized remarks.

### 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 opt-viewer.py.

> 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

## Emitting remark diagnostics in the object file

A section containing metadata on remark diagnostics will be emitted when -remarks-section is passed. The section contains:

- 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

- the absolute file path to the serialized remark diagnostics: a null-terminated string.

The section is named:

- `__LLVM,__remarks` (MachO)

- `.remarks` (ELF)

## 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:

    LLVMRemarkParserRef Parser = LLVMRemarkParserCreateYAML(Buf, Size);
    LLVMRemarkEntryRef Remark = NULL;
    while ((Remark = LLVMRemarkParserGetNext(Parser))) {
       // use Remark
       LLVMRemarkEntryDispose(Remark); // Release memory.
    }
    bool HasError = LLVMRemarkParserHasError(Parser);
    LLVMRemarkParserDispose(Parser);