. . .nr rst2man-indent-level 0 . \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .rstReportMargin pre:
. RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .rstReportMargin post:
.. . RE indent \\n[an-margin]
old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1 new: \\n[rst2man-indent\\n[rst2man-indent-level]]
..
$ clang foo.c -O2 -target x86_64-unknown-unknown -S -o - | llvm-mca -mcpu=btver2NINDENT NINDENT Or for Intel syntax: NDENT 0.0 NDENT 3.5
$ clang foo.c -O2 -target x86_64-unknown-unknown -mllvm -x86-asm-syntax=intel -S -o - | llvm-mca -mcpu=btver2NINDENT NINDENT (llvm-mca detects Intel syntax by the presence of an .intel_syntax directive at the beginning of the input. By default its output syntax matches that of its input.) Scheduling models are not just used to compute instruction latencies and throughput, but also to understand what processor resources are available and how to simulate them. By design, the quality of the analysis conducted by llvm-mca is inevitably affected by the quality of the scheduling models in LLVM. If you see that the performance report is not accurate for a processor, please \%file a bug against the appropriate backend.
-help Print a summary of command line options. NINDENT NDENT 0.0
-o <filename> Use <filename> as the output filename. See the summary above for more details. NINDENT NDENT 0.0
-mtriple=<target triple> Specify a target triple string. NINDENT NDENT 0.0
-march=<arch> Specify the architecture for which to analyze the code. It defaults to the host default target. NINDENT NDENT 0.0
-mcpu=<cpuname> Specify the processor for which to analyze the code. By default, the cpu name is autodetected from the host. NINDENT NDENT 0.0
-output-asm-variant=<variant id> Specify the output assembly variant for the report generated by the tool. On x86, possible values are [0, 1]. A value of 0 (vic. 1) for this flag enables the AT&T (vic. Intel) assembly format for the code printed out by the tool in the analysis report. NINDENT NDENT 0.0
-print-imm-hex Prefer hex format for numeric literals in the output assembly printed as part of the report. NINDENT NDENT 0.0
-dispatch=<width> Specify a different dispatch width for the processor. The dispatch width defaults to field \(aqIssueWidth\(aq in the processor scheduling model. If width is zero, then the default dispatch width is used. NINDENT NDENT 0.0
-register-file-size=<size> Specify the size of the register file. When specified, this flag limits how many physical registers are available for register renaming purposes. A value of zero for this flag means \(dqunlimited number of physical registers\(dq. NINDENT NDENT 0.0
-iterations=<number of iterations> Specify the number of iterations to run. If this flag is set to 0, then the tool sets the number of iterations to a default value (i.e. 100). NINDENT NDENT 0.0
-noalias=<bool> If set, the tool assumes that loads and stores don\(aqt alias. This is the default behavior. NINDENT NDENT 0.0
-lqueue=<load queue size> Specify the size of the load queue in the load/store unit emulated by the tool. By default, the tool assumes an unbound number of entries in the load queue. A value of zero for this flag is ignored, and the default load queue size is used instead. NINDENT NDENT 0.0
-squeue=<store queue size> Specify the size of the store queue in the load/store unit emulated by the tool. By default, the tool assumes an unbound number of entries in the store queue. A value of zero for this flag is ignored, and the default store queue size is used instead. NINDENT NDENT 0.0
-timeline Enable the timeline view. NINDENT NDENT 0.0
-timeline-max-iterations=<iterations> Limit the number of iterations to print in the timeline view. By default, the timeline view prints information for up to 10 iterations. NINDENT NDENT 0.0
-timeline-max-cycles=<cycles> Limit the number of cycles in the timeline view, or use 0 for no limit. By default, the number of cycles is set to 80. NINDENT NDENT 0.0
-resource-pressure Enable the resource pressure view. This is enabled by default. NINDENT NDENT 0.0
-register-file-stats Enable register file usage statistics. NINDENT NDENT 0.0
-dispatch-stats Enable extra dispatch statistics. This view collects and analyzes instruction dispatch events, as well as static/dynamic dispatch stall events. This view is disabled by default. NINDENT NDENT 0.0
-scheduler-stats Enable extra scheduler statistics. This view collects and analyzes instruction issue events. This view is disabled by default. NINDENT NDENT 0.0
-retire-stats Enable extra retire control unit statistics. This view is disabled by default. NINDENT NDENT 0.0
-instruction-info Enable the instruction info view. This is enabled by default. NINDENT NDENT 0.0
-show-encoding Enable the printing of instruction encodings within the instruction info view. NINDENT NDENT 0.0
-show-barriers Enable the printing of LoadBarrier and StoreBarrier flags within the instruction info view. NINDENT NDENT 0.0
-all-stats Print all hardware statistics. This enables extra statistics related to the dispatch logic, the hardware schedulers, the register file(s), and the retire control unit. This option is disabled by default. NINDENT NDENT 0.0
-all-views Enable all the view. NINDENT NDENT 0.0
-instruction-tables Prints resource pressure information based on the static information available from the processor model. This differs from the resource pressure view because it doesn\(aqt require that the code is simulated. It instead prints the theoretical uniform distribution of resource pressure for every instruction in sequence. NINDENT NDENT 0.0
-bottleneck-analysis Print information about bottlenecks that affect the throughput. This analysis can be expensive, and it is disabled by default. Bottlenecks are highlighted in the summary view. Bottleneck analysis is currently not supported for processors with an in-order backend. NINDENT NDENT 0.0
-json Print the requested views in valid JSON format. The instructions and the processor resources are printed as members of special top level JSON objects. The individual views refer to them by index. However, not all views are currently supported. For example, the report from the bottleneck analysis is not printed out in JSON. All the default views are currently supported. NINDENT NDENT 0.0
-disable-cb Force usage of the generic CustomBehaviour and InstrPostProcess classes rather than using the target specific implementation. The generic classes never detect any custom hazards or make any post processing modifications to instructions. NINDENT NDENT 0.0
-disable-im Force usage of the generic InstrumentManager rather than using the target specific implementation. The generic class creates Instruments that provide no extra information, and InstrumentManager never overrides the default schedule class for a given instruction. NINDENT
# LLVM-MCA-BEGIN ... # LLVM-MCA-ENDNINDENT NINDENT If no user-defined region is specified, then llvm-mca assumes a default region which contains every instruction in the input file. Every region is analyzed in isolation, and the final performance report is the union of all the reports generated for every analysis region. Analysis regions can have names. For example: NDENT 0.0 NDENT 3.5
# LLVM-MCA-BEGIN A simple example add %eax, %eax # LLVM-MCA-ENDNINDENT NINDENT The code from the example above defines a region named \(dqA simple example\(dq with a single instruction in it. Note how the region name doesn\(aqt have to be repeated in the LLVM-MCA-END directive. In the absence of overlapping regions, an anonymous LLVM-MCA-END directive always ends the currently active user defined region. Example of nesting regions: NDENT 0.0 NDENT 3.5
# LLVM-MCA-BEGIN foo add %eax, %edx # LLVM-MCA-BEGIN bar sub %eax, %edx # LLVM-MCA-END bar # LLVM-MCA-END fooNINDENT NINDENT Example of overlapping regions: NDENT 0.0 NDENT 3.5
# LLVM-MCA-BEGIN foo add %eax, %edx # LLVM-MCA-BEGIN bar sub %eax, %edx # LLVM-MCA-END foo add %eax, %edx # LLVM-MCA-END barNINDENT NINDENT Note that multiple anonymous regions cannot overlap. Also, overlapping regions cannot have the same name. There is no support for marking regions from high-level source code, like C or C++. As a workaround, inline assembly directives may be used: NDENT 0.0 NDENT 3.5
int foo(int a, int b) { __asm volatile(\(dq# LLVM-MCA-BEGIN foo\(dq:::\(dqmemory\(dq); a += 42; __asm volatile(\(dq# LLVM-MCA-END\(dq:::\(dqmemory\(dq); a *= b; return a; }NINDENT NINDENT However, this interferes with optimizations like loop vectorization and may have an impact on the code generated. This is because the __asm statements are seen as real code having important side effects, which limits how the code around them can be transformed. If users want to make use of inline assembly to emit markers, then the recommendation is to always verify that the output assembly is equivalent to the assembly generated in the absence of markers. The \%Clang options to emit optimization reports can also help in detecting missed optimizations.
# LLVM-MCA-<INSTRUMENT_TYPE> <data> ... ## asmNINDENT NINDENT where INSTRUMENT_TYPE is a type defined by the target and expects to use data. A comment starting with substring LLVM-MCA-<INSTRUMENT_TYPE> brings data into scope for llvm-mca to use in its analysis for all following instructions. If a comment with the same INSTRUMENT_TYPE is found later in the instruction list, then the original InstrumentRegion will be automatically ended, and a new InstrumentRegion will begin. If there are comments containing the different INSTRUMENT_TYPE, then both data sets remain available. In contrast with an AnalysisRegion, an InstrumentRegion does not need a comment to end the region. Comments that are prefixed with LLVM-MCA- but do not correspond to a valid INSTRUMENT_TYPE for the target cause an error, except for BEGIN and END, since those correspond to AnalysisRegions. Comments that do not start with LLVM-MCA- are ignored by :program llvm-mca. An instruction (a MCInst) is added to an InstrumentRegion R only if its location is in range [R.RangeStart, R.RangeEnd]. On RISCV targets, vector instructions have different behaviour depending on the LMUL. Code can be instrumented with a comment that takes the following form: NDENT 0.0 NDENT 3.5
# LLVM-MCA-RISCV-LMUL <M1|M2|M4|M8|MF2|MF4|MF8>NINDENT NINDENT The RISCV InstrumentManager will override the schedule class for vector instructions to use the scheduling behaviour of its pseudo-instruction which is LMUL dependent. It makes sense to place RISCV instrument comments directly after vset{i}vl{i} instructions, although they can be placed anywhere in the program. Example of program with no call to vset{i}vl{i}: NDENT 0.0 NDENT 3.5
# LLVM-MCA-RISCV-LMUL M2 vadd.vv v2, v2, v2NINDENT NINDENT Example of program with call to vset{i}vl{i}: NDENT 0.0 NDENT 3.5
vsetvli zero, a0, e8, m1, tu, mu # LLVM-MCA-RISCV-LMUL M1 vadd.vv v2, v2, v2NINDENT NINDENT Example of program with multiple calls to vset{i}vl{i}: NDENT 0.0 NDENT 3.5
vsetvli zero, a0, e8, m1, tu, mu # LLVM-MCA-RISCV-LMUL M1 vadd.vv v2, v2, v2 vsetvli zero, a0, e8, m8, tu, mu # LLVM-MCA-RISCV-LMUL M8 vadd.vv v2, v2, v2NINDENT NINDENT Example of program with call to vsetvl: NDENT 0.0 NDENT 3.5
vsetvl rd, rs1, rs2 # LLVM-MCA-RISCV-LMUL M1 vadd.vv v12, v12, v12 vsetvl rd, rs1, rs2 # LLVM-MCA-RISCV-LMUL M4 vadd.vv v12, v12, v12NINDENT NINDENT
$ llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=300 dot-product.sNINDENT NINDENT NDENT 0.0 NDENT 3.5
Iterations: 300 Instructions: 900 Total Cycles: 610 Total uOps: 900 Dispatch Width: 2 uOps Per Cycle: 1.48 IPC: 1.48 Block RThroughput: 2.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 2 1.00 vmulps %xmm0, %xmm1, %xmm2 1 3 1.00 vhaddps %xmm2, %xmm2, %xmm3 1 3 1.00 vhaddps %xmm3, %xmm3, %xmm4 Resources: [0] - JALU0 [1] - JALU1 [2] - JDiv [3] - JFPA [4] - JFPM [5] - JFPU0 [6] - JFPU1 [7] - JLAGU [8] - JMul [9] - JSAGU [10] - JSTC [11] - JVALU0 [12] - JVALU1 [13] - JVIMUL Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] - - - 2.00 1.00 2.00 1.00 - - - - - - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] Instructions: - - - - 1.00 - 1.00 - - - - - - - vmulps %xmm0, %xmm1, %xmm2 - - - 1.00 - 1.00 - - - - - - - - vhaddps %xmm2, %xmm2, %xmm3 - - - 1.00 - 1.00 - - - - - - - - vhaddps %xmm3, %xmm3, %xmm4NINDENT NINDENT According to this report, the dot-product kernel has been executed 300 times, for a total of 900 simulated instructions. The total number of simulated micro opcodes (uOps) is also 900. The report is structured in three main sections. The first section collects a few performance numbers; the goal of this section is to give a very quick overview of the performance throughput. Important performance indicators are IPC, uOps Per Cycle, and Block RThroughput (Block Reciprocal Throughput). Field DispatchWidth is the maximum number of micro opcodes that are dispatched to the out-of-order backend every simulated cycle. For processors with an in-order backend, DispatchWidth is the maximum number of micro opcodes issued to the backend every simulated cycle. IPC is computed dividing the total number of simulated instructions by the total number of cycles. Field Block RThroughput is the reciprocal of the block throughput. Block throughput is a theoretical quantity computed as the maximum number of blocks (i.e. iterations) that can be executed per simulated clock cycle in the absence of loop carried dependencies. Block throughput is superiorly limited by the dispatch rate, and the availability of hardware resources. In the absence of loop-carried data dependencies, the observed IPC tends to a theoretical maximum which can be computed by dividing the number of instructions of a single iteration by the Block RThroughput. Field \(aquOps Per Cycle\(aq is computed dividing the total number of simulated micro opcodes by the total number of cycles. A delta between Dispatch Width and this field is an indicator of a performance issue. In the absence of loop-carried data dependencies, the observed \(aquOps Per Cycle\(aq should tend to a theoretical maximum throughput which can be computed by dividing the number of uOps of a single iteration by the Block RThroughput. Field uOps Per Cycle is bounded from above by the dispatch width. That is because the dispatch width limits the maximum size of a dispatch group. Both IPC and \(aquOps Per Cycle\(aq are limited by the amount of hardware parallelism. The availability of hardware resources affects the resource pressure distribution, and it limits the number of instructions that can be executed in parallel every cycle. A delta between Dispatch Width and the theoretical maximum uOps per Cycle (computed by dividing the number of uOps of a single iteration by the Block RThroughput) is an indicator of a performance bottleneck caused by the lack of hardware resources. In general, the lower the Block RThroughput, the better. In this example, uOps per iteration/Block RThroughput is 1.50. Since there are no loop-carried dependencies, the observed uOps Per Cycle is expected to approach 1.50 when the number of iterations tends to infinity. The delta between the Dispatch Width (2.00), and the theoretical maximum uOp throughput (1.50) is an indicator of a performance bottleneck caused by the lack of hardware resources, and the Resource pressure view can help to identify the problematic resource usage. The second section of the report is the instruction info view. It shows the latency and reciprocal throughput of every instruction in the sequence. It also reports extra information related to the number of micro opcodes, and opcode properties (i.e., \(aqMayLoad\(aq, \(aqMayStore\(aq, and \(aqHasSideEffects\(aq). Field RThroughput is the reciprocal of the instruction throughput. Throughput is computed as the maximum number of instructions of a same type that can be executed per clock cycle in the absence of operand dependencies. In this example, the reciprocal throughput of a vector float multiply is 1 cycles/instruction. That is because the FP multiplier JFPM is only available from pipeline JFPU1. Instruction encodings are displayed within the instruction info view when flag -show-encoding is specified. Below is an example of -show-encoding output for the dot-product kernel: NDENT 0.0 NDENT 3.5
Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [7]: Encoding Size [1] [2] [3] [4] [5] [6] [7] Encodings: Instructions: 1 2 1.00 4 c5 f0 59 d0 vmulps %xmm0, %xmm1, %xmm2 1 4 1.00 4 c5 eb 7c da vhaddps %xmm2, %xmm2, %xmm3 1 4 1.00 4 c5 e3 7c e3 vhaddps %xmm3, %xmm3, %xmm4NINDENT NINDENT The Encoding Size column shows the size in bytes of instructions. The Encodings column shows the actual instruction encodings (byte sequences in hex). The third section is the Resource pressure view. This view reports the average number of resource cycles consumed every iteration by instructions for every processor resource unit available on the target. Information is structured in two tables. The first table reports the number of resource cycles spent on average every iteration. The second table correlates the resource cycles to the machine instruction in the sequence. For example, every iteration of the instruction vmulps always executes on resource unit [6] (JFPU1 - floating point pipeline #1), consuming an average of 1 resource cycle per iteration. Note that on AMD Jaguar, vector floating-point multiply can only be issued to pipeline JFPU1, while horizontal floating-point additions can only be issued to pipeline JFPU0. The resource pressure view helps with identifying bottlenecks caused by high usage of specific hardware resources. Situations with resource pressure mainly concentrated on a few resources should, in general, be avoided. Ideally, pressure should be uniformly distributed between multiple resources.
$ llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=3 -timeline dot-product.sNINDENT NINDENT NDENT 0.0 NDENT 3.5
Timeline view: 012345 Index 0123456789 [0,0] DeeER. . . vmulps %xmm0, %xmm1, %xmm2 [0,1] D==eeeER . . vhaddps %xmm2, %xmm2, %xmm3 [0,2] .D====eeeER . vhaddps %xmm3, %xmm3, %xmm4 [1,0] .DeeE-----R . vmulps %xmm0, %xmm1, %xmm2 [1,1] . D=eeeE---R . vhaddps %xmm2, %xmm2, %xmm3 [1,2] . D====eeeER . vhaddps %xmm3, %xmm3, %xmm4 [2,0] . DeeE-----R . vmulps %xmm0, %xmm1, %xmm2 [2,1] . D====eeeER . vhaddps %xmm2, %xmm2, %xmm3 [2,2] . D======eeeER vhaddps %xmm3, %xmm3, %xmm4 Average Wait times (based on the timeline view): [0]: Executions [1]: Average time spent waiting in a scheduler\(aqs queue [2]: Average time spent waiting in a scheduler\(aqs queue while ready [3]: Average time elapsed from WB until retire stage [0] [1] [2] [3] 0. 3 1.0 1.0 3.3 vmulps %xmm0, %xmm1, %xmm2 1. 3 3.3 0.7 1.0 vhaddps %xmm2, %xmm2, %xmm3 2. 3 5.7 0.0 0.0 vhaddps %xmm3, %xmm3, %xmm4 3 3.3 0.5 1.4 <total>NINDENT NINDENT The timeline view is interesting because it shows instruction state changes during execution. It also gives an idea of how the tool processes instructions executed on the target, and how their timing information might be calculated. The timeline view is structured in two tables. The first table shows instructions changing state over time (measured in cycles); the second table (named Average Wait times) reports useful timing statistics, which should help diagnose performance bottlenecks caused by long data dependencies and sub-optimal usage of hardware resources. An instruction in the timeline view is identified by a pair of indices, where the first index identifies an iteration, and the second index is the instruction index (i.e., where it appears in the code sequence). Since this example was generated using 3 iterations: -iterations=3, the iteration indices range from 0-2 inclusively. Excluding the first and last column, the remaining columns are in cycles. Cycles are numbered sequentially starting from 0. From the example output above, we know the following: NDENT 0.0
Cycles with backend pressure increase [ 48.07% ] Throughput Bottlenecks: Resource Pressure [ 47.77% ] - JFPA [ 47.77% ] - JFPU0 [ 47.77% ] Data Dependencies: [ 0.30% ] - Register Dependencies [ 0.30% ] - Memory Dependencies [ 0.00% ] Critical sequence based on the simulation: Instruction Dependency Information +----< 2. vhaddps %xmm3, %xmm3, %xmm4 | | < loop carried > | | 0. vmulps %xmm0, %xmm1, %xmm2 +----> 1. vhaddps %xmm2, %xmm2, %xmm3 ## RESOURCE interference: JFPA [ probability: 74% ] +----> 2. vhaddps %xmm3, %xmm3, %xmm4 ## REGISTER dependency: %xmm3 | | < loop carried > | +----> 1. vhaddps %xmm2, %xmm2, %xmm3 ## RESOURCE interference: JFPA [ probability: 74% ]NINDENT NINDENT According to the analysis, throughput is limited by resource pressure and not by data dependencies. The analysis observed increases in backend pressure during 48.07% of the simulated run. Almost all those pressure increase events were caused by contention on processor resources JFPA/JFPU0. The critical sequence is the most expensive sequence of instructions according to the simulation. It is annotated to provide extra information about critical register dependencies and resource interferences between instructions. Instructions from the critical sequence are expected to significantly impact performance. By construction, the accuracy of this analysis is strongly dependent on the simulation and (as always) by the quality of the processor model in llvm. Bottleneck analysis is currently not supported for processors with an in-order backend.
Dynamic Dispatch Stall Cycles: RAT - Register unavailable: 0 RCU - Retire tokens unavailable: 0 SCHEDQ - Scheduler full: 272 (44.6%) LQ - Load queue full: 0 SQ - Store queue full: 0 GROUP - Static restrictions on the dispatch group: 0 Dispatch Logic - number of cycles where we saw N micro opcodes dispatched: [# dispatched], [# cycles] 0, 24 (3.9%) 1, 272 (44.6%) 2, 314 (51.5%) Schedulers - number of cycles where we saw N micro opcodes issued: [# issued], [# cycles] 0, 7 (1.1%) 1, 306 (50.2%) 2, 297 (48.7%) Scheduler\(aqs queue usage: [1] Resource name. [2] Average number of used buffer entries. [3] Maximum number of used buffer entries. [4] Total number of buffer entries. [1] [2] [3] [4] JALU01 0 0 20 JFPU01 17 18 18 JLSAGU 0 0 12 Retire Control Unit - number of cycles where we saw N instructions retired: [# retired], [# cycles] 0, 109 (17.9%) 1, 102 (16.7%) 2, 399 (65.4%) Total ROB Entries: 64 Max Used ROB Entries: 35 ( 54.7% ) Average Used ROB Entries per cy: 32 ( 50.0% ) Register File statistics: Total number of mappings created: 900 Max number of mappings used: 35 * Register File #1 -- JFpuPRF: Number of physical registers: 72 Total number of mappings created: 900 Max number of mappings used: 35 * Register File #2 -- JIntegerPRF: Number of physical registers: 64 Total number of mappings created: 0 Max number of mappings used: 0NINDENT NINDENT If we look at the Dynamic Dispatch Stall Cycles table, we see the counter for SCHEDQ reports 272 cycles. This counter is incremented every time the dispatch logic is unable to dispatch a full group because the scheduler\(aqs queue is full. Looking at the Dispatch Logic table, we see that the pipeline was only able to dispatch two micro opcodes 51.5% of the time. The dispatch group was limited to one micro opcode 44.6% of the cycles, which corresponds to 272 cycles. The dispatch statistics are displayed by either using the command option -all-stats or -dispatch-stats. The next table, Schedulers, presents a histogram displaying a count, representing the number of micro opcodes issued on some number of cycles. In this case, of the 610 simulated cycles, single opcodes were issued 306 times (50.2%) and there were 7 cycles where no opcodes were issued. The Scheduler\(aqs queue usage table shows that the average and maximum number of buffer entries (i.e., scheduler queue entries) used at runtime. Resource JFPU01 reached its maximum (18 of 18 queue entries). Note that AMD Jaguar implements three schedulers: NDENT 0.0
.