7

V8 TurboFan 生成图简析

 2 years ago
source link: https://kiprey.github.io/2021/04/v8TurboFan_IR_intro/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

v8 turbolizer 有助于我们分析 JIT turbofan 的优化方式以及优化过程。但我们常常对于 turbolizer 生成的 IR 图一知半解,不清楚具体符号所代表的意思。以下为笔者阅读相关代码后所做的笔记。

二、TurboFan Json 格式

  • --trace-turbo 参数将会生成一个 JSON 格式的数据。通过在 turbolizer 上加载该 JSON,可以得到一个这样的IR图:
    img

  • 其中,该 JSON 的格式如下:

    {
    "function": "opt_me",
    "sourcePosition": 109,
    "source": [js source],
    "phases": [
    {
    "name": "Typed",
    "type": "graph",
    "data": {
    "nodes": [
    [...],
    {
    "id": 20,
    "label": "FrameState[INTERPRETED_FRAME, 11, Ignore, 0x1a5acd4aa5e9 <SharedFunctionInfo opt_me>]",
    "title": "FrameState[INTERPRETED_FRAME, 11, Ignore, 0x1a5acd4aa5e9 <SharedFunctionInfo opt_me>]",
    "live": true,
    "properties": "Idempotent, NoRead, NoWrite, NoThrow, NoDeopt",
    "pos": 178,
    "opcode": "FrameState",
    "control": false,
    "opinfo": "5 v 0 eff 0 ctrl in, 1 v 0 eff 0 ctrl out",
    "type": "Internal"
    },
    [...]
    ],
    "edges": [
    {
    "source": 100,
    "target": 101,
    "index": 0,
    "type": "control"
    },
    [...]
    ]
    }
    },
    [...]
    ],
    "nodePositions": {
    [...]
    }
    }

    简单的概括一下,就是:

    • function: 函数名称
    • sourcePosition:代码的起始位置。
    • source: 当前 turboFan 优化的 JS 代码
    • phases: turboFan 的各个优化阶段
      • 优化阶段1
        • name: 当前优化阶段的名称
        • type:显示的形式,是 graph IR 图还是 文本。
        • data: 当前阶段真正存放的结点与边的数据。
          • nodes: 结点数据
              • id: 结点ID,通常是一个数字

              • label:结点标签

              • title:结点主题

              • live: 当前结点是否是活结点,为 true / false

              • properties:当前结点的属性

              • pos:暂且不说

              • opcode:当前结点的操作码,例如End

              • control:当前是否是控制结点,为 true / false

              • opinfo:具体的结点信息,通常表示当前结点的ValueInputCount、EffectInputCount、ControlInputCount、ValueOutputCount、EffectOutputCount、ControlOutputCount

                表示方式如下:

                “<ValueInputCount> v
                <EffectInputCount> eff
                <ControlInputCount> ctrl in,
                <ValueOutputCount> v
                <EffectOutputCount> eff
                <ControlOutputCount> ctrl out”

                例如:“0 v 1 eff 1 ctrl in, 0 v 1 eff 0 ctrl out”

            • [其他结点]

          • edges:边的数据
            • 边1
              • source:边的源节点 ID
              • target:边的目标节点ID
              • index:当前边连接到目标节点的哪个输入
              • type:当前边的类型,例如 control、value、effect等等
            • [其他边]
      • [其他优化阶段]
    • nodePositions:每个结点在 JS 源码中所对应的代码位置

三、Node

a. 属性说明

以下是截取出的一个 Node 示例:

{
"id": 128,
"label": "LoadField[+16]",
"title": "LoadField[tagged base, 16, Internal, kRepTaggedPointer|kTypeAny, PointerWriteBarrier]",
"live": true,
"properties": "NoWrite, NoThrow, NoDeopt",
"pos": 388,
"opcode": "LoadField",
"control": false,
"opinfo": "1 v 1 eff 1 ctrl in, 1 v 1 eff 0 ctrl out",
"type": "Internal"
}

对应的结点如下:

img

一一对应以下便可以看出,其中的 id、label、title、properties、opinfo 以及 type 均显现在图中。

而 live、pos、opcode 以及 control 字段则是给 turbolizer.js 使用的。

注意到上图中的 “Inplace update in phase: Typed”,其中的 phase 则是 turbolizer.js 动态分析出的,不在 JSON 中记录。

我们可以注意到,IR图中的结点都有颜色,其中颜色貌似符合某种规律。

通过查阅 turbolizer.js 以及 在线 turbolizer 的 css 代码,turbolizer 将结点分为了以下几种结点,并设置了不同的颜色加以区分:

  • Control 结点:对于那些控制结点, 即 JSON 数据中 control 字段为 true 的结点,其颜色为黄色

    img

  • Input 结点:那些 opcode 为 Parameter 或 Constant 结点,其颜色为浅蓝色

    img

  • Live 结点(这其实不能算一类结点):即 live 字段为 true 的结点。其反向结点——DeadNode——的颜色会在原先颜色的基础上进行浅色化处理,例如以下图片。图片中的两个结点其类型相同,所不同的是左边的结点是 Dead,右边结点是 Live。

    img

  • JavaScript结点:那些 opcode 以 JS 开头的结点,其颜色为橙红色

    img

  • Simplified 结点:那些 opcode 包含 Phi、Boolean、Number、String、Change、Object、Reference、Any、ToNumber、AnyToBoolean、Load、Store,但不是 JavaScript类型的结点。其颜色如下所示:

    img

  • Machine 结点:除了上述四种结点以外,剩余的结点。颜色如下所示:

    img

四、Edge

Edge 中的 Type 共有五种,分别是 valuecontextframe-stateeffectcontrol 以及最后一个 unknown。

以下是这些边的一些例子:

a. value 边

对于该边:

{
"source": 80,
"target": 83,
"index": 4,
"type": "value"
}

其边的视觉效果如下:

img

可以看到,对于 Value 边来说,是一条实线

b. context 边

对于该边:

{
"source": 4,
"target": 49,
"index": 3,
"type": "context"
}

视觉效果如下:

img

可以看到,Context边也是一条实线。但在当前这个例子中,由于 Context 边只会由 Parameter[%context#4]结点发出,因此不会与 Value 边混淆

这里需要注意一下,Context 边只会存在于某个 Context 结点发出的所有边,即不会出现结点既发出 Context 边又发出 Value 边的情况。

如果有还请指正。

c. frame-state 边

{
"source": 50,
"target": 49,
"index": 4,
"type": "frame-state"
}

视觉效果:

img

可以看到,对于一条 frame-state 边,其视觉效果是一条 疏虚线

frame-state 边一定是由一个 FrameState 结点发出的。

上图的另一条虚线是密虚线,所不同的是虚线的疏密程度

d. effect 边

{
"source": 114,
"target": 49,
"index": 5,
"type": "effect"
}

视觉效果:

img

effect 边的显示效果是 密虚线

e. control 边

{
"source": 31,
"target": 49,
"index": 6,
"type": "control"
}

视觉效果:

img

注意:与 value 边相同,control 边的显示效果也是一条实线。这意味着单单只看 IR 图的话,是无法将 Control 边和 Value 边区分开的。

五、参考的源码

  • v8/tools/turbolizer/build/turbolizer.js
  • v8/src/compiler/graph-visualizer.cc

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK