LLVM-MCA: docs

Introduction

LLVM Machine Code Analyzer 是一种性能分析工具,它使用llvm中可用的信息(如调度模型)静态测量特定CPU中机器代码的性能。

性能是根据吞吐量处理器资源消耗来衡量的。该工具目前适用于在后端中使用LLVM调度模型的处理器。

该工具的主要目标不仅是预测代码在目标上运行时的性能,还帮助诊断潜在的性能问题。

给定汇编代码,llvm-mca可以估计每个周期的指令数(IPC)以及硬件资源压力。分析和报告风格的灵感来自英特尔的IACA工具。

github

https://github.com/llvm/llvm-project/tree/main/llvm/tools/llvm-mca

docs

https://llvm.org/docs/CommandGuide/llvm-mca.html

options

architecture

1
2
3
4
5
6
-mtriple=<target triple>
eg. -mtriple=x86_64-unknown-unknown
-march=<arch>
Specify the architecture for which to analyze the code. It defaults to the host default target.
-march=<arch>
Specify the architecture for which to analyze the code. It defaults to the host default target.
1
2
3
4
# 查看支持的arch
llc --version
# 查看具体支持的CPU Architecture
llc -march=x86 -mattr=help

output-report

1
2
3
4
5
6
7
8
-output-asm-variant=<variant id>
为工具生成的报告指定输出程序集变量。???
-print-imm-hex
优先16进制输出。
-json
除了瓶颈分析,基本都支持json格式输出视图
-timeline
打印指令流水线情况

runtime options

1
2
3
4
5
6
7
8
9
10
11
12
13
-dispatch=<width>
为处理器指定不同的调度宽度。调度宽度默认为处理器调度模型中的“IssueWidth”字段。
-register-file-size=<size>
指定寄存器文件的大小。指定时,该项会限制可用于寄存器重命名的物理寄存器的数量。此标志的值为零意味着“无限数量的物理寄存器”。
-iterations=<number of iterations>
指定要运行的迭代次数。如果此标志设置为 0,则该工具会将迭代次数设置为默认值(即 100)。
-noalias=<bool>
loads and stores don’t alias
-lqueue=<load queue size>
-squeue=<store queue size>
在工具模拟的加载/存储单元中指定加载队列的大小。默认情况下,该工具假定加载队列中的条目数量不受限制。此标志的零值将被忽略,而是使用默认加载队列大小。
-disable-cb
强制使用通用的 CustomBehaviour 和 InstrPostProcess 类,而不是使用目标特定的实现。通用类从不检测任何自定义危险或对指令进行任何后处理修改。

more values/Info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-resource-pressure
Enable the resource pressure view. This is enabled by default.
-register-file-stats
启用注册文件使用统计。
-dispatch-stats
-scheduler-stats
-retire-stats
-instruction-info
启用额外的调度/发出/retire control unit统计。该视图收集和分析指令分派事件,以及静态/动态分派停顿事件。默认情况下禁用此视图。
-show-encoding
打印指令16进制
-all-stats
-all-views
-instruction-tables
这与资源压力视图不同,因为它不需要模拟代码。相反,它按顺序打印每个指令的资源压力的理论均匀分布。
-bottleneck-analysis
打印有关影响吞吐量的瓶颈的信息。这种分析可能很昂贵,并且默认情况下是禁用的。瓶颈在摘要视图中突出显示。具有有序后端的处理器目前不支持瓶颈分析。???

实现逻辑

样例分析

quick overview of the performance throughput

1
2
3
4
5
6
7
8
9
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
  1. IPC
    1. 理论最大值是$$\frac{OneLoopInstructions}{Block_RThroughput}=(OneLoopInstructions)*(Block_Throughput)$$
  2. uOps Per Cycle
    1. simulated micro opcodes (uOps)
    2. 每个周期的simulated micro opcodes数
    3. 在不考虑循环依赖的情况下,理论上最大值是$$\frac{OneLoopUOps}{Block_RThroughput}=(OneLoopUOps)*(Block_Throughput)$$
    4. A delta between Dispatch Width and this field is an indicator of a performance issue.
    5. 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.
  3. Dispatch Width
    1. 发射到乱序后端的最大微指令操作数(the maximum number of micro opcodes/uOps)?
  4. Block RThroughput (Block Reciprocal Throughput)
    1. 在不考虑循环依赖的情况下,理论上的每次循环的最大block或者iterations数
    2. 受限于dispatch rate和the availability of hardware resources.

Instruction info view

1
2
3
4
5
6
7
8
9
10
11
12
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

显示了指令里队列每条指令的延迟吞吐量的倒数

RThroughput是指令吞吐量的倒数。在不考虑循环依赖的情况下,吞吐量是单周期能执行的同类型指令的最大数量

Resource pressure view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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, %xmm4

每次循环或者每条指令执行,消耗的资源周期数。从而找到高资源占用的部分。

Timeline View

可打印流水线情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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's queue
[2]: Average time spent waiting in a scheduler's 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>

影响因素包括:

  1. 数据冲突/依赖:读后写,写后读依赖 。无法指令级并行,也可以通过寄存器重命名解决
  2. 结构冲突:占用发射位 或者 同一硬件
  3. 控制冲突:分支?
  4. instructions must retire in program order, so [1,0] has to wait for [0,2] to be retired first

Bottleneck Analysis

  • 可以分析出数据冲突/依赖和结构冲突的影响大小
  • 准确性取决于模拟和是否有对应CPU模型。
  • 暂时不支持有序后端。
1
2
3
4
5
6
7
8
9
Cycles with backend pressure increase [ 91.52% ]
Throughput Bottlenecks:
Resource Pressure [ 0.01% ]
- SBPort0 [ 0.01% ]
- SBPort1 [ 0.01% ]
- SBPort5 [ 0.01% ]
Data Dependencies: [ 91.51% ]
- Register Dependencies [ 91.51% ]
- Memory Dependencies [ 10.76% ]
  • 端口信息来自TableGen llvm/lib/Target/X86/X86SchedSandyBridge.td
  • 鲲鹏920的来自 llvm/lib/Target/AArch64/AArch64SchedTSV110.td

额外信息

  1. Dynamic Dispatch Stall Cycles
  2. Dispatch Logic
    1. 可以看出流水线发射满带宽或几条指令的时间占比
  3. Schedulers
    1. 每个周期微指令发射数占比
  4. Scheduler’s queue usage
    1. 执行时使用的平均或最大buffer entries (i.e., scheduler queue entries)

    2. AMD Jaguar

    3.   JALU01 - A scheduler for ALU instructions.
        JFPU01 - A scheduler floating point operations.
        JLSAGU - A scheduler for address generation.
        
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117

      5. Retire Control Unit
      1. 在一个周期里有多少指令retired的占比(好吧,感觉有语病)
      6. A re-order buffer (ROB) 的使用情况
      7. Register File statistics
      1. physical register file (PRF)
      2. floating-point registers (JFpuPRF)
      3. integer registers (JIntegerPRF)

      ## Instruction Flow

      llvm-mca 假设指令在模拟开始之前已经全部解码并放入队列中。因此,指令提取和解码阶段没有被计算。未考虑前端的性能瓶颈。此外,llvm-mca 不模拟分支预测。

      ### Instruction Dispatch

      处理器的默认 dispatch width值等于LLVM’s scheduling model里的IssueWidth值。

      An instruction can be dispatched if:

      * The size of the **dispatch group** is smaller than processor’s dispatch width.
      * There are enough entries in the **reorder buffer**.
      * There are enough **physical registers** to do register renaming.
      * The schedulers are **not full**.

      reorder buffer负责跟踪命令,使之按照程序顺序retired结束。其默认值为 MicroOpBufferSize 。

      各种Buffered resources 被视作scheduler resources.

      ### Instruction Issue

      每个处理器调度器实现一个指令缓冲区。指令必须在调度程序的缓冲区中等待,直到输入寄存器操作数可用。只有在那个时候,指令才符合执行的条件,并且可能会被发出(可能是乱序的)以供执行。 llvm-mca 在调度模型的帮助下计算指令延迟。

      llvm-mca 的调度器旨在模拟多处理器调度器。调度器负责跟踪数据依赖关系,并动态选择指令消耗哪些处理器资源。它将处理器资源单元和资源组的管理委托给资源管​​理器。资源管理器负责选择指令消耗的资源单元。例如,如果一条指令消耗了一个资源组的1cy,则资源管理器从该组中选择一个可用单元;默认情况下,资源管理器使用循环选择器来保证资源使用在组的所有单元之间均匀分配。

      llvm-mca’s scheduler internally groups instructions into three sets:

      * WaitSet: a set of instructions whose operands are not ready.
      * ReadySet: a set of instructions ready to execute.
      * IssuedSet: a set of instructions executing.

      ### Write-Back and Retire Stage

      retire control unit

      1. When instructions are executed,the flags the instruction as “ready to retire.”
      2. Instructions are retired in program order
      3. free the physical registers

      ### Load/Store Unit and Memory Consistency Model

      load/store unit (LSUnit)用来模拟乱序memory操作

      The rules are:

      1. A younger load is allowed to pass an older load only if there are no intervening stores or barriers between the two loads.
      2. A younger load is allowed to pass an older store provided that the load does not alias with the store.
      3. A younger store is not allowed to pass an older store.不能交换顺序的意思
      4. A younger store is not allowed to pass an older load.

      假设 loads do not alias (-noalias=true) store operations.Under this assumption, younger loads are always allowed to pass older stores. ???

      LSUnit不打算跑alias analysis来预测何时load与store不相互alias???

      in the case of write-combining memory, rule 3 could be relaxed to allow reordering of non-aliasing store operations.???

      LSUnit不管的其余三点:

      1. The LSUnit does not know when store-to-load forwarding may occur.
      2. The LSUnit does not know anything about cache hierarchy and memory types.
      3. The LSUnit does not know how to identify serializing operations and memory fences.
      4. The LSUnit does not attempt to predict if a load or store hits or misses the L1 cache(不考虑cache命中,默认是命中L1,产生the load-to-use latency的最乐观开销)

      llvm-mca 不知道序列化操作或内存屏障之类的指令。 LSUnit 保守地假设同时具有“MayLoad”和未建模副作用的指令的行为类似于“软”load-barrier。这意味着,它在不强制刷新load队列的情况下序列化加载。类似地,“MayStore”和具有未建模副作用的指令被视为store障碍。完整的memory-barrier是具有未建模副作用的“MayLoad”和“MayStore”指令。LLVM的实现是不准确的,但这是我们目前使用 LLVM 中可用的当前信息所能做的最好的事情。

      load/store barrier会占用在load/store 队列里占用一项。
      当load/store barrier是其队列里oldest项时,其会被执行

      ![](https://pic.shaojiemike.top/img/440472FD7AB14BC3C1F29BD2D565ACDF.png)

      ### In-order Issue and Execute

      有序处理器被建模为单个 InOrderIssueStage 阶段。它绕过 Dispatch、Scheduler 和 Load/Store 单元。一旦它们的操作数寄存器可用并且满足资源要求,就会发出指令。根据LLVM的调度模型中IssueWidth参数的值,可以在一个周期内发出多条指令。一旦发出,指令就会被移到 IssuedInst 集,直到它准备好retire。 llvm-mca 确保按顺序提交写入。但是,如果 RetireOOO 属性for at least one of its writes为真,则允许指令提交写入并无序retire???

      ## Custom Behaviour 自定义行为

      某些指令在该模型中并不能被准确的模拟。为了几条指令而修改模型不是个好的选择,一般通过**CustomBehaviour**类对某些指令进行特殊建模:自定义数据依赖,以及规避、单独处理特殊情况。

      为此,llvm-mca设置了一个通用的以及多个特殊的**CustomBehaviour**类。下面两种情况下会使用通用类:

      1. 开启了`-disable-cb`选项
      2. 不存在针对某目标的特殊类(通用类也做不了什么,我什么也做不到😥)

      但是注意目前只有in-order流水线实现了**CustomBehaviour**类,out-order流水线将来也会支持。

      该类主要通过`checkCustomHazard()`函数来实现,通过当前指令和真正流水线中执行的指令,来判断当前指令需要等待几个周期才能发射。

      如果想对没有实现的目标添加**CustomBehaviour**类,可以参考已有的实现,比如在`/llvm/lib/Target/AMDGPU/MCA/`目录下。

      ## Custom Views 自定义视图

      关于自定义的视图的添加路径,如果**没有输出**从未在MC layer classes (MCSubtargetInfo, MCInstrInfo, etc.)里出现过的**新后端值**,请把实现加入`/tools/llvm-mca/View/`。相反,请加入`/lib/Target/<TargetName>/MCA/`目录。

      关于Custom Views所需内容,需要写特殊的**CustomBehaviour**类来覆写`CustomBehaviour::getViews()`函数,根据位置的不同还有三种实现`getStartViews(), getPostInstrInfoViews(),getEndViews()`。

      ## 影响准确性的因素

      调度模型不仅用于计算指令延迟和吞吐量,还用于了解可用的处理器资源以及如何模拟它们。

      llvm mca进行分析的质量不可避免地受到**llvm中调度模型质量**的影响。

      ## 功能(能估计的值

      1. IPC
      2. 硬件资源压力resource-pressure
      3. 一些额外Info?
      1.

      register-file-stats -dispatch-stats -scheduler-stats -retire-stats -instruction-info instruction-tables
      1
      2
      3
      4
      5
      6
      7

      4. 吞吐量瓶颈?

      ### 支持对特定代码块的分析

      1. 汇编代码,支持命名和嵌套

    LLVM-MCA-BEGIN block-name

    add %eax, %eax

    LLVM-MCA-END

    1
    2
    3

    2. 高级语言,通过内联汇编实现

    int foo(int a, int b) {
    __asm volatile(“# LLVM-MCA-BEGIN foo”);
    a += 42;
    __asm volatile(“# LLVM-MCA-END”);
    a *= b;
    return a;
    }

    
    但是,这会干扰循环矢量化等优化,并可能对生成的代码产生影响。具体影响请对比汇编代码。
    

相关论文

Google学术搜llvm-mca,一堆论文。但是不急着看,因为没有预备知识,没有问题的去看论文。效率和收获很低的,而且会看不懂。

相关项目

mc-ruler

mc-ruler是整合了llvm-mca的cmake,可以打印指定部分的代码分析信息。如果之后要测试可能用得上。

需要进一步的研究学习

  1. 具体功能
  2. llvm如何实现的,要看代码。

遇到的问题

  1. (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.)
  2. ???的地方
  3. 大概看了一下功能,但是性能怎么对比呢。准确值是多少呢?
    1. arm kunpeng pmu-tools 实现
  4. 每次的估计值会波动吗?

如何和大神交流呢+提问的艺术

开题缘由、总结、反思、吐槽~~

参考文献

LLVM Mca : huawei HiSilicon's TSV110 work

几个对比图

x轴的含义是改变port值的意思,比如tsv110alu2是在tsv110的基础上将alu的值改成2

相关的 git commit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
commit c9ca3a3c66a493d72cf7afc7ee975e2de399f2e5
Author: Elvina Yakubova <[email protected]>
Date: Sat Nov 7 01:50:43 2020 +0300

[AArch64] Add driver tests for HiSilicon's TSV110

commit 93b99728b1676d23ab5dabc606344230d25e7f4b
Author: Elvina Yakubova <[email protected]>
Date: Sat Nov 7 01:22:35 2020 +0300

[AArch64] Add pipeline model for HiSilicon's TSV110

This patch adds the scheduling and cost model for TSV110.

Reviewed by: SjoerdMeijer, bryanpkc

Differential Revision: https://reviews.llvm.org/D89972

commit 123553921f86ac0fad7b742740aa45e8d380be02
Author: Bryan Chan <[email protected]>
Date: Fri Nov 9 19:32:08 2018 +0000

[AArch64] Support HiSilicon's TSV110 processor

Reviewers: t.p.northover, SjoerdMeijer, kristof.beyls

Reviewed By: kristof.beyls

Subscribers: olista01, javed.absar, kristof.beyls, kristina, llvm-commits

Differential Revision: https://reviews.llvm.org/D53908

llvm-svn: 346546

只有3个,感觉和2个功能很相关。

最近 Driver commit

类似的llvm check的设置

复现上面的图

要改的地方

应该每次都要重新编译安装

测试的汇编代码

  1. 判断llvm/test/MC/AArch64下的汇编能用吗?选个最大的,neon 不支持, armv8.2也并不支持。感觉有特别要求
    1
    cat neon-diagnostics.s|llvm-mca -timeline -show-encoding -all-stats -all-views
  2. 选择osaca的benchmark里的add.c

AArch64SchedTSV110.td

locate at llvm/lib/Target/AArch64/AArch64SchedTSV110.td

td file

tablegen(LLVM class) definitions

部分指令解释

1
def : InstRW<[TSV110Wr_2cyc_1MDU],   (instregex "^(AND|BIC|EON|EOR|ORN|ORR)[WX]rs$")>;

BIC (bit clear) EON (Exclusive OR) ORR (OR operations on the values in Rn and Operand2)

InstRW的定义

1
2
3
4
5
6
7
8
9
10
11
// Map a set of opcodes to a list of SchedReadWrite types. This allows
// the subtarget to easily override specific operations.
//
// SchedModel ties this opcode mapping to a processor.
class InstRW<list<SchedReadWrite> rw, dag instrlist> {
list<SchedReadWrite> OperandReadWrites = rw;
dag Instrs = instrlist;
SchedMachineModel SchedModel = ?;
// Allow a subtarget to mark some instructions as unsupported.
bit Unsupported = false;
}

TSV110Wr_2cyc_1MDU的定义

1
2
3
4
5
6
7
8
9
def TSV110Wr_2cyc_1MDU   : SchedWriteRes<[TSV110UnitMDU]>   { let Latency = 2; }

class SchedWriteRes<list<ProcResourceKind> resources> : SchedWrite,
ProcWriteResources<resources>;

//定义TSV110上可用的每种处理器资源和数量,
//它有8条pipeline管道,每个管道都有自己的队列,微操作在那里等待
//它们的operands和issue将无序地发送到八个执行管道之一。
def TSV110UnitMDU : ProcResource<1>; // Multi-Cycle

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

LLVM Mca :with BHive (2019)

BHive

一种新的profiler,可以profile没有用户干预的内存访问的基本块。

基于这种profiler创建了BHive,来验证llvm-mca等模型。

BHive是用来评价llvm-mca这些模型的,实验基于各种收集来的一个基本块各种评价

I. INTRODUCTION

Automatically Profiling Basic Blocks

困难在于现有的 没有考虑 memory crash ??? .默认命中L1 cache

A key technical challenge with collecting a large basic block dataset is that there is no existing approach to profile an arbitrary basic block that has been removed from its program
context.

(没懂?那为什么要removed from its program
context) 因为要把常用的应用拆成小例子来评判,这些模型的准确性。

原理

运用隐含狄利克雷分布LDA,基于cpu资源的利用率,来cluster benchmark suite里的基本块

通过对各种类型最基本的代码块来进行profile,从而形成针对各种performance model的数据库。

现在已经有超过30万的基本块分析,来源于各种方向的应用,包括数值计算OpenBLAS,数据库SQLite,机器学习TensorFlow,密码学OpenSSL。

这么多的数据产生了一个用于评估performance model的新benchmark。

作者说performance modeling 研究的未来在于与其他先进技术的大规模定量比较

内存访问的处理

通过把虚拟页面映射到单个物理页面,来合法内存访问同时避免cache miss

II. 背景

Existing Performance Models

有两种model

  1. 产生可以详细描述指令何时发射和退休的可解释执行路径的微架构模拟器,附带吞吐量预测。
  2. 每条指令都有延迟、吞吐量查找表,相当于一个被寄存器分配器使用的额外开销估计器

各种model, 写到另一篇里了

  1. IACA
  2. llvm-mca
  3. OSACA
  4. Ithemal

Machine Code Profilers

  1. 通过 Agner Fog’s script 测量真实的,有周期,cache miss 等等。https://www.agner.org/optimize/testp.zip
  2. nanoBench也是。https://github.com/andreas-abel/nanoBench 可以指定processor?和 kernel模式。
  3. Unrolling
    1. 测量吞吐量的基本方法就是展开一个基本块的代码多次,然后测重复多次的代码。把展开的基本块latency除以unroll factor(典型值是100)
    2. 目的:
      1. 边缘化前几次warm up的latency值的影响。
      2. 减少收起数据的开销影响
    3. unroll factor就是循环展开次数。
  4. 局限性是,必须人工给代码块,不能自动profile一堆任意的基本块来系统性验证。???

III. PROFILING ARBITRARY BASIC BLOCKS

目标是在不需要手动干预的情况下分析任意基本块,以便测量的吞吐量与性能模型通常假定的定义和不变量相对应。关键的挑战是使这些基本块能够在不崩溃的情况下访问任意内存地址

由于基本块只是正常程序的一部分,导致根本不能单独正常运行。BHive做的事情就是,让他正常运行。

Handling Arbitrary Memory Accesses


这个代码块只有执行代码分配在0x4110a时,才能正常运行

  1. Remapping Virtual Pages.
    1. 一个基本块的所有虚拟内存页重新映射到一个物理页上,所以全部数据访问都命中L1。这样就可以执行97%的基本块。
    2. 步骤
      1. 把原本虚拟页全部unmap
        1. 这会导致除了包含基本块指令的页之外的全部的连续的内存访问出问题???
        2. 在子进程里运行展开的基本块指令。
          1. 这时对每个unmap的虚拟页的访问都会出错,但是主进程一种监视着。一旦中断就重新映射出错地址,然后重新开始跑。
  2. Memory Initialization
    1. 初始化一个中等大小0x12345600的物理页,允许都虚拟页都映射
  3. Virtual page aliasing
    1. 因为不同的虚拟页映射在同一个物理页的同一项导致memory dependences,要等待
    2. 剔除6.28%的基本块
    3. 可以通过增大物理页,来减小发生的概率。

Overall Profiling Workflow

通过重复运行基本块来计算吞吐量

  1. Raw Measurement
    1. 先从基本块里,产生不会memory crash的可执行部分。
    2. unroll factor的选取。It uses 100 and 200 as the unroll factors for basic blocks smaller than 100 bytes; 50 and 100 for basic blocks between 100 bytes and 200 bytes; and finally 16 and 32 for basic blocks larger than 200 bytes
  2. Filtering
    1. 筛选执行代码满足理想化模型的执行结果,比如命中L1cache
    2. L1 Cache Misses
      1. 工具可以用硬件计数器监控指令和数据cache misses。拒绝所有cache miss的情况。
    3. Unaligned Loads
      1. 不连续的访存会很慢,解决方法就是去除所有有不连续的访存的。大约删除了0.18%的基本块
    4. Subnormal Floating Point
      1. 一些特殊的浮点数计算会比正常的浮点数计算慢20倍,去除了与MXCSR寄存器有关的0.1%的基本块。
      2. https://stackoverflow.com/questions/8341395/what-is-a-subnormal-floating-point-number
    5. Context Switches
      1. 上下文切换(英语:context switch),又称环境切换,电脑术语,是一个存储和重建CPU的状态 (内文),因此令多个进程(process)可以分享单一CPU资源的计算过程。要切换CPU上的进程时,必需先行存储目前进程的状态,再将欲运行的进程之状态读回CPU中。
    6. 可接受的评估公式 10%的误差???
  3. Throughput Calculation
    1. 如果通过了基本块的筛选,用有记录的最小延迟计算吞吐量
  4. Environment Variance
    1. 由于环境的影响,导致结果有个稳定的偏移。至少执行5次,展开16次的基本块。取最小的5次作为结果。

Portability to Other Architectures

只要架构满足以下几点要求

  1. 有将多个虚拟页面映射到几个物理页面的API。map
    multiple virtual pages to a few physical pages
    1. without incurring a performance penalty due to unnecessary cache invalidation. We therefore require that the target processor has a **physically tagged data cache(VIPT)**???
    2. we additionally require that the page size is small enough so the indexing bits are
      not affected by address translation.
  2. detecting cache misses,
  3. and detecting or disabling floating-point underflow.

IV. BASIC BLOCK DATASET

应用的选择

  1. 尽可能还原现实生活的各个方面,
  2. 而且是用户的典型用法。
  3. Clang/LLVM (compiler), Redis (inmemory database), SQLite (database), and Gzip 是用高级语言C或者C++编写的,算法和数据结构有复杂的设计。
  4. OpenSSL (cryptography), OpenBLAS , Eigen (scientific computing),TensorFlow (machine learning) 代表的是核心循环是手动汇编优化过的高性能库。
    1. 其中Embree是 用Intel ispc (a data-parallel language)编写的。

We compiled all applications with the highest optimization settings defined by their build systems. 如果可以用上了AVX2。

使用DynamoRIO动态分析来提炼基本块。可以实现在运行时记录每个运行的基本块。我们采用动态分析,而不是静态反汇编。因为静态反汇编无法区别padding bytes from instructions。???

应用的例子除了FFmpeg and Gzip都是选择的官方的benchmark。
Eigen 采用的是 two sparse linear algebra workloads: sparse matrix-matrix multiplication (SpMM) and sparse matrix-vector multiplication (SpMV).

V. BASIC BLOCK CLUSTERING

一些基本块比其他的更难建模,???(建什么模,VI-B说明了什么)有内存依赖的基本块预测错误率更高。

采用了一种技术???(是应用在提取上) 基于处理器的使用聚类基本块。
这个技术有助于性能模型的设计和使用者更细粒度了解performance model,让他们能集中以后新添加的资源在有困难的那一类基本块。

  1. Methodology
    1. 具体方法
      1. 找到每个基本块的硬件使用率的表示 port-mapping representation
      2. 根据其聚类
    2. 对每条指令结合port使用
      1. 运用 Abel and Reineke A. Abel and J. Reineke, “uops.info: Characterizing latency, throughput, and port usage of instructions on intel microarchitectures,” in ASPLOS, 2019的结果 ???
      2. 例如???
        1. xor %rax, %rbx in Haswell is {p0156 → 1}
    3. 使用Latent Dirichlet Allocation (LDA)来构建topic model 模型(python 训练模型)
      1. 在语言处理上的应用是基于统计词频
      2. 在实际运用的时候,微指令操作会根据使用的port而有小不同。
        1. topics是分类的类别,6类
        2. documents是基本块
        3. α = 1/6 and β = 1/13.
      3. 为了推断每个微指令操作所属的类别,我们使用了SciKit Learn transform对于LDA的随机变化推断的默认实现
      4. 计算每个基本块的最有可能的类别作为其分类结果
  2. Results
    1. LDA将结果聚类后,根据基本块的内容,手动进行注名以及说明
    2. example
    3. 根据运行时频率确定其权重, 基于sample-based profiler??? (A portable sampling-based profiler for java virtual machines,)确定。
    4. 高性能的库如预期一样,向量化的基本块占比较多。
    5. 其余的无向量化的较多。OpenSSL and Gzip有许多位操作的。
  3. Case Study on Data-Center Applications
    1. 目的:作为测试例子,看这个聚类方法能不能找得到隐藏的热点、工作负载
    2. Methodology
      1. 第一步:首先将其基本块分成之前的几类,还是使用LDA
      2. 第二步:分类结果标注
      3. 第三步:比较聚类结果的perplexity值???
      4. ???有没有结合google的应用
    3. Results
      1. 添加新应用后,该值只是略微增长。说明模型的代表性好。???

VI. PERFORMANCE MODEL EVALUATION

在3种Intel架构上验证4种已有的性能模型

  1. Methodology
    1. 说明各个测试软件的版本。
    2. Dataset
      1. basic block dataset discussed in Section IV
    3. Platform
      1. balabala 3种架构的 Intel cpus
    4. Evaluation Metrics
      1. 测量吞吐量t和预测吞吐量t’$$err(t,t’)=|\frac{t-t’}{t}|$$
      2. 不以预测精度,而是以预测结果的相对关系为评分标准。
    5. 额外能评估每个模型如何保持基本块吞吐量的顺序。使用Kendall’s tau系数(越大效果越好),而不是相对误差。测量的原因是使用者可能关心的不是绝对的数值精度,而是相对关系的准确率。比如优化软件的时候关心的不是具体耗时,而是哪个优化策略耗时更短。
  2. Results
    1. IACA 第二好的,在向量化类模拟的最好
    2. llvm-mca 最差的,尤其是和loads有关时。
    3. Ithemal 除了向量基本块都是最好的。在memory dependence (Ld/St)尤其好,但是向量基本块不好,可能与训练集没有向量基本块有关。
    4. OSACA 第三。由于还在开发中,使用还遇到5个bug。在遇到一些不认识的指令的时候,会直接按照nops空指令处理。
  3. Examples of Modeling Bugs
    1. 最后一个例子是由于模型错误调度微指令导致的
    2. Modeling bug due to unsigned division
      1. 例子是 a 64-bit by 32-bit unsigned division.
      2. ???
    3. Modeling bug due to zero-idioms
      1. 对这种结果固定的特殊指令的快速处理。
    4. Modeling bug due to mis-scheduling
      1. 对于数据依赖,上下指令的寄存器有写后读。
      2. Ithemal’s and OSACA忽略了该依赖
      3. llvm-mca 没有注意到(%rcx)是memory,没有依赖可以提前发射。

CONCLUSION

现有的静态分析器对内存依赖向量化块的建模还有困难。

github代码说明

  1. benchmark/sources下是各种软件的各个部分的16进制基本代码块和其出现概率,用csv格式(逗号分隔值 (Comma-separated values))存储
  2. benchmark/throughput是在各种架构下的各基本块的测量吞吐量,单位cycles per hundred-iterations.
  3. benchmark/disasm可以把16进制代码通过nasm变成汇编,
  4. timing-harness

    吞吐量的计算(猜的)Skylake microarchitecture$$\frac{6632-1030}{2333-100}*100=250.8 (cyc/hundred\ iters)$$

BHive 被质疑的局限性

uops 的文章, Accurate Throughput Prediction of Basic Blocks on Recent Intel Microarchitectures

4.2 Extending BHive

BHive 运行逻辑

  1. 读入16进制代码和循环次数
  2. hhex2bin转换为二进制
  3. create_shm_fd
    1. shm_open, shm_unlinkcreates and opens a new, or opens or unlink an existing, POSIX shared memory object. O_RDWR Open the object for read-write access.O_CREAT the shared memory object if it does not exist. 777是类似文件读写执行组权限的东西 On success, shm_open() returns a file descriptor (a nonnegative integer)

    2. POSIX可移植操作系统接口The Portable Operating System Interface 是IEEE为要在各种UNIX操作系统上运行软件,而定义API的一系列互相关联的标准的总称。

    3. ftruncate — truncate截短 a file to a specified length

    4. #define SIZE_OF_HARNESS_MEM (4096 * 3)

  4. measure开始测量
    1. int fds[2] ???
    2. pipe用于创建pipe,用来进程间通信的单向数据通路,传入变量用来返回引用自pipe末端的文件描述符file descriptors。第一个指向the read end of the pipe,第二个指向the write end of the pipe
    3. mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); munmap(void *addr, size_t length);- map or unmap files or devices into memory 在调用进程的虚拟地址空间里create a new mapping.
    4. fork()产生子进程
      1. fork()原理详解
        1. 复制之前的一模一样。
        2. fork() returns a zero to the newly created child process.
        3. fork() returns a positive value, the process ID of the child process, to the parent.
      2. 父进程
        1. #define OFFSET_TO_COUNTERS 32
        2. 为什么声明一个偏移地址指针???
          1. struct pmc_counters 由5个uint64_t组成。 uint64 will always take 8 bytes。一个结构体40bytes
        3. attach_to_child(pid, fds[1]); pid是子进程pid
          1. ptrace(enum __ptrace_request request, pid_t pid,void *addr, void *data) - process trace 提供一种进程tracer跟踪控制另一个进程tracee的方法,可以修改被控制者的memory and registers.
            1. PTRACE_SEIZE Attach to the process specified in pid, making it a tracee of the calling process. Unlike PTRACE_ATTACH, PTRACE_SEIZE does not stop the process
          2. 子进程从fds[0]里读到x里,父进程把x的值写入 fds[1] ???
        4. check Performance Monitoring Counters (PMCs) supports
          1. rdpmc_open_attr initialize a raw ring 3 ReaDable PerforMance Counter
        5. last_failing_inst 和 mapping_done
        6. To kill child
          1. #define MAX_FAULTS 1024 # 子进程产生的错误需要解决?
          2. wait挂起当前线程,直到有一个children结束,返回其PID
          3. WIFEXITEDWait_IF_EXITED 判断是否正常结束
          4. 如果错误打印出错信号(eg.11)指令指针寄存器RIP,指针寄存器RSP
          5. 函数是用汇编写的就离谱what is aux mem?
          6. 修改出错地方的寄存器,重新运行PTRACE_CONT Restart the stopped tracee process
          7. 最多执行MAX_FAULTS次
        7. 最后父进程杀死子进程
      3. 子进程
        1. 父进程测试是否支持PMCs,子进程使用
        2. harness.c :277

https://www.cnblogs.com/from-zero/p/13750852.html

需要进一步的研究学习

暂无

遇到的问题

  1. time 怎么算的the latency of the basic block?为什么打印15个呢?
  2. 还有中间的错误是怎么回事?
  3. 论文里的误差怎么算的?
    1. BHive整合了几个软件(整合了什么呢),应该是真实测量了得出真实吞吐量?还是也是模拟的?
    2. 和uops比怎么样
  4. 哪个数据是准确的,是BHive模拟的,还是真实测量的。
    1. 通过 Agner Fog’s script 测量真实的,有周期,cache miss 等等。https://www.agner.org/optimize/testp.zip
    2. nanoBench也是。https://github.com/andreas-abel/nanoBench 可以指定processor?和 kernel模式。
    3. 局限性是,必须人工给代码块,不能自动profile一堆任意的基本块来系统性验证。???
  5. BHvie的代码实现,移植到鲲鹏,然后根据PMU调准。

问题是x86的二进制或者汇编不能变成aarm64的二进制或者汇编。

开题缘由、总结、反思、吐槽~~

参考文献

https://github.com/ithemal/bhive

Kunpeng

多线程SMT (Simultaneous multithreading)


统一的调度器复杂度超级高,只有Intel实现了,但是效果很好。

什么是CPU Die


良品率会更高


自研OpenBLAS+ ,毕申编译器,自研MPI

片间一致性可以到达4P到16P???。Intel可以达到8P

问题

  1. 虽然说是保密的,但是鲲鹏930,950应该已经出来了
    1. 930,950是异构的核(是大小核吗?)

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://bbs.huaweicloud.com/blogs/268031

LLVM-MCA: Install&RunTests

github

https://github.com/llvm/llvm-project/tree/main/llvm/tools/llvm-mca

Quick Start

安装

下载可执行文件上传服务器,解压

安装遇到的问题

  1. cannot find libtinfo.so.5
    1. sudo apt install libncurses5
    2. ln -s /usr/lib/libncursesw.so.6 /usr/lib/libtinfo.so.5 或者类似的 ln -s /usr/lib/libncurses.so.5 /usr/lib/libtinfo.so.5
    3. 在/snap/core下找到了,但是这是什么目录?是之前Ubuntu的包管理工具,但是已经不用了。

从源码安装

node5

由于之后要写代码的,还是从头安装更好。

1
2
3
4
5
6
cd llvm-project
mkdir build
cmake -S llvm -B build -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang;llvm-mca" -DCMAKE_INSTALL_PREFIX="~/Install/llvm" -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_ASSERTIONS=On
cd build
make -j32
make install

kunpeng

1
2
cmake -S llvm -B build -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS=all -DCMAKE_INSTALL_PREFIX="~/Install/llvm" -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_ASSERTIONS=On
#change cmake or -DLLVM_ENABLE_PROJECTS="all"

error

1
2
3
g++: error: unrecognized command line option ‘-mllvm’
g++: error: unrecognized command line option ‘--tail-merge-threshold=0’
g++: error: unrecognized command line option ‘-combiner-global-alias-analysis’

change

1
cmake -S llvm -B build -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang;llvm-mca" -DCMAKE_INSTALL_PREFIX="~/Install/llvm" -DLLVM_TARGETS_TO_BUILD=AArch64 -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_ASSERTIONS=On

使用

1
clang foo.c -O2 -target x86_64-unknown-unknown -S -o - | llvm-mca -mcpu=btver2

由于不是X86,llc --version 查看到target是 aarch64-unknown-linux-gnu

1
clang /home/shaojiemike/Download/llvm-project-main/lldb/test/API/lang/c/forward/foo.c -O2 -target aarch64-unknown-linux-gnu -S -o -|llvm-mca -timeline -show-encoding -all-stats -all-views

生成汇编代码,并默认管道到llvm-mca,并开启所有输出。

可以看出是用TSV110Unit的port,默认cpu是tsv110

名词解释

ALU/BRU

算数逻辑单元 ALU 负责处理整数运算指令. 跳转处理单元BRU 负责处理跳转指令. BRU 可以与 ALU 合并, 复用 ALU 的逻辑来计算跳转指令的条件和跳转地址, 也可以作为一个单独的功能单元接入到流水线中.

MDU

乘除法单元 MDU (mult-divide unit)

需要进一步的研究学习

  1. llvm-mca微指令怎么实现的,怎么把汇编变成微指令
  2. 在view里加memory的实现
  3. 考虑了cache命中等影响 https://github.com/andreas-abel/uiCA uops
  4. 鲲鹏架构 https://bbs.huaweicloud.com/community/usersnew/id_1513665626477516

遇到的问题

  1. llvm-mca -mcpu=help竟然会卡住,不知道为什么
  2. 所以说是华为已经写了一个叫tsv110的,实现2个功能?

开题缘由、总结、反思、吐槽~~

参考文献

样例输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
Iterations:        100
Instructions: 200
Total Cycles: 70
Total uOps: 200

Dispatch Width: 4
uOps Per Cycle: 2.86
IPC: 2.86
Block RThroughput: 0.5


No resource or data dependency bottlenecks discovered.


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 1 0.33 4 20 00 80 52 mov w0, #1
1 1 0.50 U 4 c0 03 5f d6 ret


Dynamic Dispatch Stall Cycles:
RAT - Register unavailable: 0
RCU - Retire tokens unavailable: 0
SCHEDQ - Scheduler full: 0
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, 20 (28.6%)
4, 50 (71.4%)


Schedulers - number of cycles where we saw N micro opcodes issued:
[# issued], [# cycles]
0, 3 (4.3%)
2, 1 (1.4%)
3, 66 (94.3%)

Scheduler's queue usage:
No scheduler resources used.


Retire Control Unit - number of cycles where we saw N instructions retired:
[# retired], [# cycles]
0, 3 (4.3%)
2, 1 (1.4%)
3, 66 (94.3%)

Total ROB Entries: 128
Max Used ROB Entries: 59 ( 46.1% )
Average Used ROB Entries per cy: 32 ( 25.0% )


Register File statistics:
Total number of mappings created: 100
Max number of mappings used: 29


Resources:
[0.0] - TSV110UnitAB
[0.1] - TSV110UnitAB
[1] - TSV110UnitALU
[2] - TSV110UnitFSU1
[3] - TSV110UnitFSU2
[4.0] - TSV110UnitLdSt
[4.1] - TSV110UnitLdSt
[5] - TSV110UnitMDU


Resource pressure per iteration:
[0.0] [0.1] [1] [2] [3] [4.0] [4.1] [5]
0.66 0.67 0.67 - - - - -

Resource pressure by instruction:
[0.0] [0.1] [1] [2] [3] [4.0] [4.1] [5] Instructions:
0.33 - 0.67 - - - - - mov w0, #1
0.33 0.67 - - - - - - ret


Timeline view:
Index 0123456789

[0,0] DeER . . mov w0, #1
[0,1] DeER . . ret
[1,0] DeER . . mov w0, #1
[1,1] D=eER. . ret
[2,0] .DeER. . mov w0, #1
[2,1] .DeER. . ret
[3,0] .D=eER . mov w0, #1
[3,1] .D=eER . ret
[4,0] . DeER . mov w0, #1
[4,1] . D=eER . ret
[5,0] . D=eER . mov w0, #1
[5,1] . D=eER . ret
[6,0] . D=eER . mov w0, #1
[6,1] . D=eER . ret
[7,0] . D=eER . mov w0, #1
[7,1] . D==eER. ret
[8,0] . D=eER. mov w0, #1
[8,1] . D=eER. ret
[9,0] . D==eER mov w0, #1
[9,1] . D==eER ret


Average Wait times (based on the timeline view):
[0]: Executions
[1]: Average time spent waiting in a scheduler's queue
[2]: Average time spent waiting in a scheduler's queue while ready
[3]: Average time elapsed from WB until retire stage

[0] [1] [2] [3]
0. 10 1.7 1.7 0.0 mov w0, #1
1. 10 2.0 2.0 0.0 ret
10 1.9 1.9 0.0 <total>