如果把一份AI模型编译成高效代码的过程,比作中央厨房做一桌菜,那么MLIR就是厨房的操作总规范:食材要经过洗切、腌制、爆炒、摆盘一道道工序,最后变成餐桌上的美味。这里的每一道工序,就对应MLIR里的一个Pass(可以翻译成“工序”),而食材的状态,就是IR(Intermediate Representation,中间表示)。当菜出了问题,厨师长要做的不是重做整桌菜,而是弄清楚是哪一道工序把菜做坏了——这,就是Pass调试。如果上菜速度变慢,他要给每位厨师计时,看谁在“磨洋工”——这,就是性能分析。本文将带你用“后厨巡检”的视角,学会打印中间IR、设置断点、验证优化是否生效,以及剖析每个Pass的耗时。掌握了这些方法,你就能在MLIR编译流水线里快速定位问题,而不是对着海量日志干瞪眼。

岗位关联

掌握Pass调试与性能分析,是AI编译器工程师高效排查优化问题的基本功,避免在庞杂流水线中大海捞针。

目录
  1. 可视化演示
  2. 调试准备:先看清流水线
  3. IR打印:端出半成品看看
  4. 断点调试:在灶台前喊停
  5. 优化验证:试菜确认效果
  6. 性能分析:给厨师戴上秒表
  7. 耗时剖析:工时的秘密账本
  8. 调试策略:二分法揪出“搞砸”的工序
  9. 实践要点:后厨管理手册
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示MLIR编译器Pass流水线中IR的逐步转换过程,含各Pass耗时柱状图,直观理解编译器优化流程和性能分析方法。

本节配有交互动效(进入视口后自动加载,约 3KB)。

MLIR Pass流水线调试 IR→Pass→Opt→IR→输出五阶段流水线,各Pass耗时柱状图 func→arith→llvm IR逐步降低,打印中间结果定位优化效果 AI编译器Pass调试与性能分析,高效定位优化问题

调试准备:先看清流水线

走进一家中央厨房,你肯定不会一上来就掀开锅盖。厨师长会先带你走一遍动线:食材从仓库进来,在洗切台预处理,到备料区调味,再到灶台烹饪,最后装盘出菜。MLIR编译器也是同样的逻辑:一个模型先被lowering成多层IR,再被一系列Pass逐段加工。调试的第一步,就是先看清这条流水线的全貌——哪些Pass先后执行,它们各自改了IR的哪一部分。

在MLIR中,Pass是独立的优化或转换单元,就像厨房里的“工序”;IR(Intermediate Representation,中间表示)是工序间传递的半成品。我们调试的大部分动作,都在问两个问题:某个Pass到底有没有跑?跑完后IR变成了什么?为此需要准备三样基础工具:一是知道Pass流水线的构建方式,二是会用mlir-opt这个“操作台”,三是能读懂IR文本格式。

mlir-opt是MLIR自带的瑞士军刀,它能加载一个.mlir文件,按照命令行提供的--pass-pipeline执行Pass序列,比如mlir-opt input.mlir --pass-pipeline='builtin.module(func.func(canonicalize, cse))' -o output.mlir。IR文本则以Module、Func、Block、Operation形成树状结构,打印出来的每一段都能对照源码找到位置。调试前建议先跑一个最小样例,确认工具链和Pass顺序。

就像厨师长先在图纸上标注每道工序的位置,调试前把Pass顺序和IR状态画在心里,后续不管是打印还是断点,都能精准找到那一截传送带。

Pipeline=P1∘P2∘⋯∘Pn\text{Pipeline} = P_1 \circ P_2 \circ \cdots \circ P_n
Pass流水线就是按顺序组合多个Pass,前一个Pass的输出会变成后一个Pass的输入。
  1. Pass序列把流水线看成一组有序工序,每个 \(P_i\) 是一次独立优化或转换。
    P1,P2,…,PnP_1, P_2, \ldots, P_n
  2. 复合应用\(\circ\) 表示先执行前面工序,再执行后面工序,前一个Pass的结果是后一个Pass的输入。
    (Pi+1∘Pi)(IR)=Pi+1(Pi(IR))(P_{i+1} \circ P_i)(\text{IR}) = P_{i+1}(P_i(\text{IR}))

IR打印:端出半成品看看

做菜讲究“边做边尝”。师傅炒到一半会用小勺舀一勺汤,看看颜色和咸淡。MLIR调试中最常用的招数也是这个:把IR这个“半成品”从流水线上端出来,看看它在某个Pass之后变成了什么样。

IR打印不是往代码里塞printf,而是MLIR内置的调试能力。它能在每个Pass执行前或执行后输出当前IR的完整快照。你不需要手动维护日志,只需要在mlir-opt命令上追加开关。

最常用的开关包括:--mlir-print-ir-before-all(每个Pass前打印)、--mlir-print-ir-after-all(每个Pass后打印)、--mlir-print-ir-after=canonicalize(只打印canonicalize这个Pass之后的结果)、--mlir-print-ir-module-scope(以module为单位整体打印)。如果输出量巨大,记得把结果用-o /dev/null或重定向到文件,再配合grep筛选。

打印IR就像是给每道工序拍照归档,照片越多,越容易对比出“食材从哪一步开始不对劲”。

IR::=Module (Func (Block (Operation)∗)∗)∗\text{IR} ::= \text{Module} \ (\text{Func} \ (\text{Block} \ (\text{Operation})^*)^*)^*
IR是层级嵌套的树状结构,打印时可以按模块、函数、块、操作不同粒度观察。
  1. Module一个编译单元的最外层容器,相当于整桌菜的总菜单。
    Module\text{Module}
  2. Func函数是菜的做法说明书,对应一个可调用过程。
    Func\text{Func}
  3. Block块是函数里的基础代码块,相当于连续操作的一段灶台流程。
    Block\text{Block}
  4. Operation操作是IR里最小的指令单元,相当于一次具体的翻炒动作。
    Operation\text{Operation}

断点调试:在灶台前喊停

如果只是拍照还不够,厨师长会直接喊“停”!让整条流水线定格,然后走到某个灶台前仔细检查锅里的菜。断点调试就是给编译器按下的暂停键。

在MLIR中调试Pass,可以借助调试器在Pass的执行函数处设置断点。Pass的核心逻辑通常写在runOnOperation方法里,在这里下断点就能拦下某个Pass,然后单步观察IR如何被改写。

MLIR本身是LLVM生态的一部分,所以常用gdb/lldb。此外也能在Pass源码中用llvm::dbgs()打印debug信息,并用-debug-only=...按关键字过滤。若想按“IR中出现某类操作”暂停,可以在条件断点写一个谓词,匹配当前Operation的名字和属性。

只在最关键的灶台前喊停,其余工序照常跑,调试才不至于影响整个后厨的节奏。

C(IR)=match(IR, pattern)C(\text{IR}) = \text{match}(\text{IR}, \ \text{pattern})
断点条件就是一个布尔函数,返回真才暂停;pattern可以是操作名、属性等。
  1. 条件函数\(C\) 表示断点是否触发的判断,IR 是输入,输出真则暂停。
    C(IR)→{0,1}C(\text{IR}) \to \{0,1\}
  2. 匹配规则match 检查当前 IR 是否满足某个 pattern,比如操作名为 transform.structured.pack。
    pattern={opName, attr}\text{pattern} = \{\text{opName}, \ \text{attr}\}

优化验证:试菜确认效果

一道菜做出来好不好,最终要试菜说了算。Pass也是一样:“运行过”不等于“生效了”。就像厨师把菜翻炒了两下,但食材可能压根没变化。

优化验证的目的是确认Pass是否真正改变了IR,并且在语义保持的前提下变得更优。MLIR提供了统计和测试机制帮助验证。

第一,直接对比Pass前后IR,看是否有预期中的模式出现或消失;第二,使用--mlir-pass-statistics统计每个Pass执行的次数、处理的Operation数量等信息;第三,写FileCheck测试,在IR文本上挂CHECK、CHECK-NOT、CHECK-LABEL等断言。比如编译器工程中常见的mlir-opt input.mlir --pass-pipeline='builtin.module(cse)' | FileCheck input.mlir。

只有试菜合格的工序才能继续,确认优化真正生效,流水线才值得继续跑下去。

ΔIR=IRafter−IRbefore\Delta \text{IR} = \text{IR}_{\text{after}} - \text{IR}_{\text{before}}
前后IR的差集表示Pass带来的变化;差集为空说明优化没有生效。
  1. 前快照和后快照取Pass执行前后的IR状态,分别记为 before 和 after。
    IRbefore, IRafter\text{IR}_{\text{before}}, \ \text{IR}_{\text{after}}
  2. 求差比较两棵IR树,找出增删的节点,得到变化集合。
    ΔIR=IRafter∖IRbefore\Delta \text{IR} = \text{IR}_{\text{after}} \setminus \text{IR}_{\text{before}}

性能分析:给厨师戴上秒表

当上菜越来越慢时,厨师长会给每位厨师发一个秒表,记录每道工序耗时。Pass性能分析做的就是这件事:给每个Pass计时,找出整个编译流水线里的时间黑洞。

MLIR内置了计时工具--mlir-timing,开启后每个Pass执行完都会记录自己的耗时,最后输出一份流水线耗时清单。

--mlir-timing支持不同的展示形式,比如--mlir-timing-display=tree按调用树展示,list按列表展示,json方便脚本解析。性能分析前先关掉调试输出和IR打印,因为它们会严重污染计时结果。也可以配合--mlir-pass-statistics,把“耗时”和“改动量”两张表放一起看,判断耗时高是因为改动大还是实现低效。

秒表一戴,哪个厨师在磨洋工一目了然。同样,性能分析会告诉你,到底是哪个Pass吃掉了大部分编译时间。

Ttotal=∑i=1nTPiT_{\text{total}} = \sum_{i=1}^{n} T_{P_i}
总编译时间近似为每个Pass耗时的总和,前提是默认串行执行。
  1. 求和把每个Pass的时间累加起来,\(\sum\) 下标表示从第1个到第n个。
    ∑i=1n\sum_{i=1}^{n}
  2. 每项含义\(T_{P_i}\) 表示第 i 个Pass的执行时间。
    TPiT_{P_i}

耗时剖析:工时的秘密账本

秒表只能告诉你每个环节的绝对用时,可真正决策要靠工时账本:洗菜只要2分钟,摆盘却要1小时,那摆盘就是优化重点。耗时剖析就是在算每个Pass的耗时占比。

只看单个Pass的绝对时间容易被误导。比如一个Pass耗时3秒,看着不多,但总编译时间只有5秒,那它就已经占了60%。所以要算占比、找热点Pass。

我们可以把--mlir-timing输出的json导入Python或jq,计算每个Pass的累计耗时、平均耗时和占比;也可以把多次运行的平均值作为基准。定位到热点Pass后,再结合--mlir-print-ir-before/after观察它到底在处理什么复杂结构,进一步优化。

账本越细,主厨越清楚该给哪个灶台添人手,而不是凭感觉乱抓药。

Ri=TiTtotal×100%R_i = \frac{T_i}{T_{\text{total}}} \times 100\%
第i个Pass的耗时占比,数值越大说明它越是性能热点。
  1. 分子单个Pass耗时 \(T_i\),来自--mlir-timing的输出。
    TiT_i
  2. 分母总耗时 \(T_{\text{total}}\),等于所有Pass耗时的和。
    TtotalT_{\text{total}}
  3. 百分比乘以100转成百分比,方便横向比较。
    ×100%\times 100\%

调试策略:二分法揪出“搞砸”的工序

如果顾客投诉菜味不对,厨师长不会从第一道工序开始怀疑,而是先尝中间的半成品:如果中间就已经坏了,说明问题在前面;如果中间没事,问题就在后面。这种折半查找的思路,就是二分定位。

当Pass流水线很长时,不要傻乎乎从第一个Pass挨个查。先把Pass序列分成前后两半,分别运行并观察IR坏在哪一半;不断对半切,很快就能定位到元凶Pass。

实际操作中,先用--pass-pipeline构造一个只包含前半段的流水线,再构造后半段,打印关键IR做对比。同时尽量使用最小复现:只保留触发问题的必要IR操作,去掉无关的Pass;再和基线(比如完全不优化、或只用单个Pass)对比,确认哪些Pass是必须的。

有了二分法,就不用从第一口菜开始尝到最后一盘,而是像拆盲盒一样精准锁定搞砸的那道工序。

Cmax⁡=⌈log⁡2n⌉C_{\max} = \lceil \log_2 n \rceil
n个Pass的流水线,二分定位最多比较这么多次即可找到问题Pass。
  1. 取对数n个Pass二分,每次排除一半,所以比较次数与 \(\log_2 n\) 相关。
    log⁡2n\log_2 n
  2. 向上取整次数必须是整数,用 \(\lceil \cdot \rceil\) 向上取整。
    ⌈⋅⌉\lceil \cdot \rceil

实践要点:后厨管理手册

成熟的后厨都有自己的管理手册:调料瓶贴标签、日志分级记录、每隔一段时间盘点。日常调试MLIR Pass也需要这样一套规范,才能避免在复杂流水线中迷失方向。

实践要点包括:用好日志级别、控制输出量、记住常见陷阱。LLVM/MLIR的调试日志用llvm::dbgs()打印,可以用-debug-only=pass名只输出某个Pass的日志;不要一上来就全量打印IR。

--mlir-print-ir-after-all的输出可能达到GB级别,一定要配合-o /dev/null或| grep按需查看。记住--mlir-pass-statistics输出的是统计信息,--mlir-timing输出的是时间信息,两者不要混用。多线程(Threading)开启时,IR打印和耗时统计的顺序可能不稳定,必要时关闭并行让结果可复现。

手册越规范,后厨越稳定;实践要点记心间,Pass调试和性能分析才能从“碰运气”变成“按图索骥”。

Lerror<Lwarning<Linfo<LdebugL_{\text{error}} < L_{\text{warning}} < L_{\text{info}} < L_{\text{debug}}
日志级别从低到高排列,级别越高信息越详细,生产环境通常只保留error和warning。
  1. 排序日志级别从错误到调试递增,低级别最严重、输出最少。
    Lerror<Lwarning<Linfo<LdebugL_{\text{error}} < L_{\text{warning}} < L_{\text{info}} < L_{\text{debug}}
  2. 级别含义error只报致命问题,debug打印最细的IR流转信息。
    debug:每条IR的变更记录\text{debug:每条IR的变更记录}

AI 应用场景

模型部署时定位性能回退

阶段:推理编译与优化阶段

解决的问题:传统方式只能看到最终性能变差,不知道是哪个Pass导致的;面对几十个Pass组成的流水线,工程师只能用笨办法逐个排查。使用IR打印和耗时分析可以快速定位未生效的优化。

具体案例:某团队在把开源LLM导出为MLIR推理流程时,发现端到端延迟增加20%。他们用--mlir-timing发现affine-loop-invariant-code-motion耗时异常,再用--mlir-print-ir-after对比IR,发现循环外提未生效,最终修复了Pass的匹配条件。

新Pass开发中的正确性校验

阶段:Pass开发与单元测试阶段

解决的问题:新写的Pass容易改错IR或跳过关键操作,传统方式依赖人工review和跑全套回归。调试加验证方法用IR打印和FileCheck断言,把开发闭环变快。

具体案例:编译器团队开发一个新的convert-triton-to-gpu Pass,每实现一个模式就打印IR,并用FileCheck断言新旧IR结构,最终一次集成即通过。

大规模编译的性能剖析

阶段:编译基础设施成本治理

解决的问题:大模型编译动辄几十分钟,传统方式只能等编译完再事后分析。通过Pass耗时剖析将热点Pass调整顺序或并行化,降低等待时间。

具体案例:某云厂商的AI编译服务每天执行数千次编译,用--mlir-timing --mlir-timing-display=json导出数据,发现某个算子泛化Pass平均耗时占比过高;通过改写Pass顺序,p99编译时间下降40%。

Python 演示

python58 行
import time  # 模拟MLIR Pass: 常量折叠def fold_constants(ir_text):    time.sleep(0.02)    return ir_text.replace("arith.constant 21", "arith.constant 21")  # 模拟MLIR Pass: 死代码消除def dead_code_eliminate(ir_text):    time.sleep(0.01)    return "\n".join(line for line in ir_text.splitlines() if "debug" not in line)  # 模拟MLIR Pass: 公共子表达式消除def common_subexpr(ir_text):    time.sleep(0.03)    return ir_text.replace("%z = arith.addi %y, %y", "%z = arith.addi %y, %y")  class PassPipeline:    def __init__(self, ir_text):        self.ir_text = ir_text        self.steps = []        self.timings = {}     def add_pass(self, pass_name, fn):        self.steps.append((pass_name, fn))     def run(self):        for pass_name, fn in self.steps:            start = time.perf_counter()            self.ir_text = fn(self.ir_text)            cost = time.perf_counter() - start            self.timings[pass_name] = cost            print("[IR] after %-12s\n%s" % (pass_name, self.ir_text))        return self.ir_text  if __name__ == "__main__":    input_ir = """module {  func.func @main() {    %x = arith.constant 21 : i32    %y = arith.muli %x, %x : i32    %z = arith.addi %y, %y : i32    return  }}"""    pipeline = PassPipeline(input_ir)    pipeline.add_pass("ConstFold", fold_constants)    pipeline.add_pass("DCE", dead_code_eliminate)    pipeline.add_pass("CSE", common_subexpr)    pipeline.run()    total = sum(pipeline.timings.values())    print("Total time: %.6f s" % total)    for name, t in pipeline.timings.items():        print("%s: %.6f s (%.1f%%)" % (name, t, t / total * 100))
目的:用一个简单的Python“Pass流水线”模拟MLIR的Pass执行和耗时分析,演示如何打印IR中间结果、统计每个Pass耗时与占比。
  1. pipeline.add_pass("ConstFold", fold_constants)把Pass名字和执行函数注册进流水线,相当于在mlir-opt里追加一个Pass。
  2. start = time.perf_counter()在Pass运行前启动高精度计时器,对应--mlir-timing的计时原理。
  3. self.ir_text = fn(self.ir_text)执行Pass并更新当前IR,模拟IR在流水线上流动。
  4. self.timings[pass_name] = cost记录每个Pass耗时,供最后占比分析用。
  5. t / total * 100计算单个Pass耗时占比,对应正文中的耗时剖析公式。

常见误区

误区我在mlir-opt命令的pass-pipeline里写了canonicalize,它肯定在IR上跑过一遍。

正解Pass执行是有条件的。如果IR没有匹配的Operation,Pass可能直接跳过runOnOperation。要确认是否生效,应该看--mlir-pass-statistics的计数,或对比Pass前后IR是否有变化。就像厨师安排了“焯水”这道工序,但有的菜本身不需要焯水,师傅自然会跳过。

为何常见:把“写了Pass”等同于“改了IR”,没有意识到Pass的处理基于模式匹配。

误区我习惯在Pass源码里到处加printf,这样就能看到中间结果。

正解MLIR内置了更优雅的打印方式:--mlir-print-ir-after-all、--mlir-print-ir-after=pass名可以在不改源码的情况下打印任意Pass后的IR,还能配合-o /dev/null和grep按需查看。自己加printf污染源码,且一次只能看一个点。

为何常见:不知道MLIR命令行已有成熟开关,沿用通用调试习惯。

误区编译总时间减去前后IO时间,平均分给每个Pass,就能得到耗时。

正解这种估算会被日志打印、文件IO、缓存状态严重干扰。正确做法是用--mlir-timing,它会记录每个Pass自身的CPU/user/sys时间,并以树形结构展示。就像你要给厨师计时,得用独立秒表而不是看整条流水线的打卡机。

为何常见:没有意识到编译过程包含大量非Pass开销,如解析、验证、打印、调度。

误区只有用真实大模型跑完整Pass流水线,timing结果才可信。

正解大模型编译很慢,且输出日志巨大。更高效的做法是先用最小IR样例跑一遍,拿到每个Pass的耗时画像和热点排名;再在完整模型上只针对热点Pass做详细分析。相当于先做小样品的试吃,再精算大锅菜的时间。

为何常见:把性能分析理解为终极验收而不是过程中的定位手段。

误区FileCheck是回归测试的东西,跟我平时调试Pass没关系。

正解FileCheck用文本模式断言IR是否包含某个结构,在调试时同样好用:你可以把某个Pass后的IR保存下来,用CHECK和CHECK-NOT快速判断预期优化是否出现。就像厨师用试纸测酸碱度,几秒钟就能判断菜有没有放对调料。

为何常见:把测试工具和调试工具割裂,没想过快速断言IR模式。

面试题

Q1. 在MLIR编译流水线中,Pass指的是?

单选题 · easy

  • A.解析输入文件的语法工具
  • B.对IR做变换优化的基本单元← 正确答案
  • C.管理设备显存的软件模块
  • D.生成调试日志的独立进程

答案:B。Pass就像一个工序,不是解析器、显存管理或日志进程。它是IR变换优化单元,可以对Operation做增删改。比喻:像是给食材改刀或焯水的工序,而不是采购冰箱。

Q2. 想要观察每个Pass运行后的IR,应选用哪种手段?

单选题 · mid

  • A.统计所有Pass耗时
  • B.打印所有Pass后IR← 正确答案
  • C.打印所有Pass前IR
  • D.打印Pass统计信息

答案:B。想观察Pass做完之后的IR状态,应该选“打印Pass后IR”。统计耗时、统计信息或打印前IR都不能看到运行结果,只有快照在Pass后才有意义,像试菜在出锅后而不是下锅前。

Q3. 下面哪些方法能确认Pass真正改变了IR?

多选题 · mid

  • A.对比Pass前后的IR← 正确答案
  • B.使用统计信息观察变化← 正确答案
  • C.用FileCheck断言模式← 正确答案
  • D.直接删除Pass不运行

答案:ABC。确认Pass真正改动IR,可以对比前后快照、看统计计数、用FileCheck断言模式。删除Pass只是回到没有优化的状态,不能证明该Pass没干活。比喻:尝菜前后对比才知道加盐是否有效,而不是把厨师赶走。

Q4. 在GDB中给MLIR Pass下断点,通常应放在哪个方法?

单选题 · mid

  • A.模块解析入口函数
  • B.Pass的runOnOperation← 正确答案
  • C.结果打印函数
  • D.命令行参数解析

答案:B。Pass的执行核心是runOnOperation,所以断点设在这里。解析、打印、命令行参数都发生在Pass执行之前或之后,拦截不到核心变换。比喻:要抓炒菜的动作,得守在锅边而不是大门口。

Q5. 关于--mlir-timing的作用,正确的是?

单选题 · mid

  • A.打印IR的语法树结构
  • B.统计每个Pass的执行耗时← 正确答案
  • C.生成Pass之间的依赖图
  • D.自动设置断点位置

答案:B。--mlir-timing就是给Pass计时,统计每个Pass的执行耗时;它不打印IR语法、不画依赖图、不设断点。比喻:秒表只负责计时,不负责拍照。

Q6. 耗时占比公式 R_i = T_i / T_total * 100% 用来计算?

单选题 · easy

  • A.Pass平均运行时间
  • B.Pass耗时占总体比例← 正确答案
  • C.Pass被调用次数
  • D.优化后加速倍数

答案:B。占比 = 单项耗时/总耗时×100%,所以它计算的是“某项耗时在总耗时中的比例”,不是平均数、次数或加速比。比喻:账本上记录的是这个环节占总工时的百分比,而不是平均每道菜花了多久。

Q7. 关于MLIR Pass调试,下列哪些说法正确?

多选题 · hard

  • A.Pass可能因IR不匹配被跳过← 正确答案
  • B.打印全部IR会产生海量数据← 正确答案
  • C.二分法可缩小问题Pass范围← 正确答案
  • D.--mlir-timing能直接输出IR

答案:ABC。A对,Pass按模式匹配跳过;B对,print-after-all可能输出海量IR;C对,二分法可缩小范围;D错,--mlir-timing只计时不打印IR。比喻:厨房里有的工序不适用于所有菜,拍照记录可能堆积成山,二分法能逐步缩小怀疑范围,但秒表不会告诉你菜色。

Q8. 想把Pass调试输出写到文件而不是刷屏,应使用?

单选题 · easy

  • A.-o指定输出文件← 正确答案
  • B.--help查看帮助
  • C.--version查看版本
  • D.--debug开启调试

答案:A。-o output.mlir把结果写到文件。--help、--version、--debug都不能将IR持久化输出。比喻:把半成品盛到盘子里而不是对着空气喊做法。

Q9. 流水线包含16个Pass,用二分定位最坏需要比较几次?

单选题 · hard

  • A.4次← 正确答案
  • B.8次
  • C.16次
  • D.32次

答案:A。log2(16)=4,二分比较最多4次就能定位。每次比较排除一半,16→8→4→2→1。比喻:从16个嫌疑工序中二分试菜,最多尝4轮。

Q10. 以下哪些做法能提升MLIR Pass调试效率?

多选题 · hard

  • A.使用最小复现IR样例← 正确答案
  • B.精确指定Pass后打印IR← 正确答案
  • C.直接跑完整大模型再分析
  • D.用FileCheck快速断言模式← 正确答案

答案:ABD。最小复现、精确打印、FileCheck都是高效调试手段;跑完整大模型会浪费大量时间,且输出巨大,不适合快速定位。比喻:先在灶台小样上找到问题,再回大锅复查,而不是一开始就蒸一锅全宴。