Paper: 2609.11923 Authors: Boning Li, Longbo Huang Categories: cs.DC, cs.AI, cs.GT, cs.MS, cs.PL

The Gap

Counterfactual regret minimization is one of the few large numerical workloads that still runs faster on CPUs than on GPUs. That is a striking exception, and the paper explains why it exists: each iteration sweeps a game tree with up to billions of states in millions of small, interdependent gather and scatter steps issued through a generic tree interface.

The mechanism of the failure is a gap between kernel duration and dispatch cost. On a GPU every kernel finishes in microseconds, so kernel launches and framework dispatch dominate the run time — the arithmetic is finished before the machinery to start it has wound down. That is why prior GPU implementations have lost to optimized CPU code: the GPU is not slower at the computation, it is slower at orchestrating a workload made of millions of tiny dependent steps.

   CFR: A STRIKING EXCEPTION

   CFR is ONE OF THE FEW LARGE NUMERICAL WORKLOADS THAT STILL RUNS
   FASTER ON CPUs THAN ON GPUs
        |
        v
   WHY: each iteration sweeps a game tree with UP TO BILLIONS OF STATES
        in MILLIONS of SMALL, INTERDEPENDENT GATHER AND SCATTER STEPS
        issued through a GENERIC TREE INTERFACE
        |
        v
   [THE MECHANISM OF THE FAILURE: KERNEL DURATION vs DISPATCH COST]
     on a GPU, EVERY KERNEL FINISHES IN MICROSECONDS
     -> KERNEL LAUNCHES and FRAMEWORK DISPATCH DOMINATE THE RUN TIME
     -> the ARITHMETIC is finished before the MACHINERY TO START IT
        has wound down
        |
        v
   -> that is why PRIOR GPU IMPLEMENTATIONS HAVE LOST TO OPTIMIZED
      CPU CODE
      <- the GPU is not slower at the COMPUTATION
      <- it is slower at ORCHESTRATING a workload made of MILLIONS OF
         TINY DEPENDENT STEPS

The Increment

One sentence: Before this paper, GPU CFR lost to CPUs because dispatch overhead dominated; after it, compiling the game into static dataflow and replaying it as one CUDA graph beats every baseline, and the compiled form alone already beats the GPU baseline on CPUs.

Core Mechanism

The insight is a single observation with large consequences: for a fixed game, everything about a CFR iteration except the numerical values is known before the first iteration runs. Shapes, indices, edge structure, depth levels, buffer addresses — all fixed by the game, not by the solve. And CFR’s update rule does not change, so nothing about the schedule varies between iterations. That is the condition under which compilation is possible at all.

So the game is compiled once into static dataflow: flat edge and information-set arrays, precomputed indices, and depth-level batched passes fix the entire operation sequence, and only solver state changes between iterations. The internal techniques each reduce a specific source of overhead — static chance folding, depth-level execution blocks, and a dual-lane reach buffer — and together they cut the number of framework operations by up to 18.1×. So the first gain is a genuine algorithmic-systems reduction, not merely a harness change: fewer operations means less to dispatch.

And then the payoff that only static shapes allow: because shapes, indices and buffer addresses never change, CUDA Graph Replay records the iteration once and replays it with a single graph launch. This is the step that directly attacks the diagnosis. If dispatch dominates, collapsing millions of launches into one is the right remedy, and it is only available because the compiled representation made the schedule invariant.

The results separate the two contributions, which is the most instructive part of the reporting. On one A100, across an eight-game suite spanning card games, dice games and board games:

  • 29.8–80.4× faster than the fastest prior GPU CFR on the same accelerator.
  • 14–258× faster than LiteEFG, one of the fastest open-source CPU implementations, on the four largest games.
  • And the attribution: the compiled representation carries most of that margin — on eight CPU threads with no accelerator it is already 2.2–51.1× faster than the GPU baseline.

That last figure is the one to dwell on. A CPU run beating a GPU baseline by up to 51× means the win is mostly not from using the GPU better — it is from doing far less orchestration work. The GPU then multiplies a gain that the compilation had already produced. Reporting the CPU-only number alongside the GPU result is what lets a reader see that decomposition.

Two further verifications are worth noting. On the CPU, the optimized path reproduces the reference iterates bitwise — so the compilation is semantics-preserving, not an approximation, which matters because CFR’s guarantees depend on the update rule. And tree construction and graph capture pay for themselves within the first solve, so the compilation cost is amortised within a single use rather than requiring many solves to justify.

The summary makes the scope explicit: GPU-CFR beats every CPU and GPU baseline on the mid-to-large games of the suite without changing the update rule. Both clauses matter — “mid-to-large” bounds where the win applies, and “without changing the update rule” bounds what was done to get it.

   THE INSIGHT: ONE OBSERVATION WITH LARGE CONSEQUENCES
     FOR A FIXED GAME, EVERYTHING ABOUT A CFR ITERATION EXCEPT THE
     NUMERICAL VALUES IS KNOWN BEFORE THE FIRST ITERATION RUNS
       <- SHAPES, INDICES, EDGE STRUCTURE, DEPTH LEVELS, BUFFER
          ADDRESSES: all fixed by the GAME, not by the SOLVE
       AND CFR's UPDATE RULE DOES NOT CHANGE
         -> nothing about the SCHEDULE varies between iterations
       <- that is the condition under which COMPILATION IS POSSIBLE
          AT ALL

   THE GAME IS COMPILED ONCE INTO STATIC DATAFLOW
     FLAT edge and information-set arrays
     PRECOMPUTED indices
     DEPTH-LEVEL BATCHED PASSES
       -> these FIX THE ENTIRE OPERATION SEQUENCE
     and ONLY SOLVER STATE CHANGES between iterations
     INTERNAL TECHNIQUES each reduce a SPECIFIC SOURCE OF OVERHEAD
       static chance folding | depth-level execution blocks |
       dual-lane reach buffer
       -> together they CUT THE NUMBER OF FRAMEWORK OPERATIONS BY UP TO
          18.1x
       <- the first gain is a GENUINE ALGORITHMIC-SYSTEMS REDUCTION,
          not merely a HARNESS CHANGE: FEWER OPERATIONS MEANS LESS TO
          DISPATCH

   THEN THE PAYOFF ONLY STATIC SHAPES ALLOW
     because shapes, indices and buffer addresses NEVER CHANGE,
     CUDA GRAPH REPLAY RECORDS THE ITERATION ONCE AND REPLAYS IT WITH A
     SINGLE GRAPH LAUNCH
       <- directly attacks the DIAGNOSIS: if DISPATCH DOMINATES,
          collapsing MILLIONS OF LAUNCHES INTO ONE is the right remedy
       <- ONLY available because the compiled representation made the
          SCHEDULE INVARIANT

   THE RESULTS SEPARATE THE TWO CONTRIBUTIONS -- the most instructive
   part of the reporting
     one A100, EIGHT-GAME SUITE (card, dice, board games)
       29.8-80.4x faster than the FASTEST PRIOR GPU CFR on the SAME
         ACCELERATOR
       14-258x faster than LiteEFG (a fastest open-source CPU
         implementation) ON THE FOUR LARGEST GAMES
     AND THE ATTRIBUTION:
       THE COMPILED REPRESENTATION CARRIES MOST OF THAT MARGIN -- on
       EIGHT CPU THREADS WITH NO ACCELERATOR it is ALREADY 2.2-51.1x
       FASTER THAN THE GPU BASELINE
       <- a CPU run beating a GPU baseline by up to 51x means the win is
          mostly NOT from USING THE GPU BETTER
       <- it is from DOING FAR LESS ORCHESTRATION WORK
       -> the GPU then MULTIPLIES a gain the COMPILATION had ALREADY
          produced
       <- reporting the CPU-ONLY number alongside the GPU result is what
          lets a reader SEE THAT DECOMPOSITION

   TWO FURTHER VERIFICATIONS WORTH NOTING
     on the CPU, the optimized path REPRODUCES THE REFERENCE ITERATES
     BITWISE
       <- the compilation is SEMANTICS-PRESERVING, not an approximation
       <- matters because CFR's GUARANTEES depend on the UPDATE RULE
     TREE CONSTRUCTION AND GRAPH CAPTURE PAY FOR THEMSELVES WITHIN THE
     FIRST SOLVE
       -> the COMPILATION COST is amortised within a SINGLE USE

   SCOPE MADE EXPLICIT
     beats every CPU and GPU baseline ON THE MID-TO-LARGE GAMES of the
     suite WITHOUT CHANGING THE UPDATE RULE
       <- "MID-TO-LARGE" bounds WHERE the win applies
       <- "WITHOUT CHANGING THE UPDATE RULE" bounds WHAT WAS DONE to
          get it

Think of it as a workshop where the tools are fine but fetching them takes longer than using them. Each operation takes microseconds; walking to the shelf takes longer. The fix is not a faster tool — it is arranging the workshop so that the whole sequence of operations is laid out in advance and can be executed without any fetching. Two details of the paper’s version map cleanly. First, the layout work is itself valuable independent of the fancy machinery: eight threads with no accelerator already beat the GPU version, which is the equivalent of saying the reorganisation alone paid for the upgrade. Second, the resulting sequence is identical every time, so you can record the entire session once and replay it — and that recording is only possible because nothing about the layout changes between runs.

Key Concepts

  • Dispatch-bound rather than compute-bound: microsecond kernels mean launch overhead dominates. It relocates the problem from arithmetic to orchestration, which is what makes a compiler the right tool.
  • Compilation enabled by schedule invariance: everything but the values is fixed before the first iteration. Without that invariance, static dataflow could not represent the iteration.
  • An 18.1× reduction in framework operations: static chance folding, depth-level blocks and a dual-lane reach buffer. It is a real reduction in work, which is why it matters independently of the GPU.
  • CUDA Graph Replay as the direct remedy: one launch instead of millions, available only because shapes and addresses never change.
  • The CPU-only attribution: 2.2–51.1× over the GPU baseline on eight threads. It decomposes the win and shows the compilation, not the accelerator, carries the margin.
  • Bitwise reproduction of reference iterates: semantics preserved exactly, which matters because the method’s guarantees depend on the update rule.

Framework Shift

Before (GPU CFR loses to CPU):
  millions of small interdependent steps through a generic interface
  -> microsecond kernels, dispatch dominates
  -> GPU slower at orchestration than CPU, despite faster arithmetic
  -> prior GPU implementations lost to optimized CPU code

After (compile the game, replay the iteration):
  everything but the values is known before iteration one
  -> static dataflow: flat arrays, precomputed indices, batched passes
  -> up to 18.1x fewer framework operations
  -> one recorded CUDA graph instead of millions of launches
  -> 29.8-80.4x over prior GPU CFR; 14-258x over fast CPU code
  -> and 2.2-51.1x over the GPU baseline on eight CPU threads alone

From trying to make a GPU faster at a workload it is bad at orchestrating, to compiling the workload so there is far less to orchestrate, the core shift is that the bottleneck was never the arithmetic — and the compiled representation, not the accelerator, carries most of the gain.

Expert Assessment

Problem choice: Excellent, and the framing is unusually well aimed. “One of the few workloads still faster on CPU” is a precise invitation to find out why, and the answer — dispatch overhead, not compute — immediately implies a compiler rather than a kernel. That is a diagnosis leading directly to the right class of solution.

Method maturity: The observation that everything but the values is fixed before the first iteration is the kind of insight that looks obvious once stated and had apparently not been exploited this way. The internal techniques each target a named overhead, and the 18.1× operation reduction is a real reduction rather than a harness trick. Using CUDA Graph Replay is the natural consequence of schedule invariance, not a separate optimisation. Most importantly, the reporting separates the two contributions by including the CPU-only number, which is the measurement that tells a reader where the gain actually comes from.

Experimental integrity: The comparisons are appropriately scoped: against the fastest prior GPU implementation on the same accelerator, against a fast open-source CPU implementation, and with the win bounded to mid-to-large games. Bitwise reproduction of reference iterates is the check that matters for a method with convergence guarantees, and it is reported on the CPU path where bitwise comparison is meaningful. The amortisation claim — construction and capture paid for within the first solve — removes the obvious objection about compilation cost. The limitation is that the win is conditional on games large enough to make the per-iteration orchestration significant, so small games, where the overhead ratio is less extreme, are outside the reported benefit.

Writing quality: The abstract states the diagnosis, the insight, the mechanism and the separated results in order, which makes the argument followable without the tables. Because the CPU-only figure is the most informative number in the paper, giving it prominence rather than burying it in a comparison table is the right editorial choice.

Verdict: strong accept — it diagnoses why GPUs lose at this workload, applies the compiler-shaped fix the diagnosis implies, and reports the results in a way that shows the compiled representation rather than the accelerator carries the gain.

Takeaways

  • Distinguish compute-bound from dispatch-bound. When kernels finish in microseconds, the fix is fewer operations rather than faster ones.
  • Look for schedule invariance before optimising. If nothing but the state changes between iterations, the iteration itself can be compiled.
  • Report the decomposed contribution. The CPU-only figure here shows the compilation, not the GPU, produced most of the speedup.
  • Verify semantics, not just speed. Bitwise agreement with reference iterates is what makes a compiled fast path usable for an algorithm with guarantees.

论文: 2609.11923 作者: Boning Li, Longbo Huang 分类: cs.DC, cs.AI, cs.GT, cs.MS, cs.PL

缺口

反事实遗憾最小化(CFR)是少数”在 CPU 上仍然比在 GPU 上更快”的大规模数值负载之一。这是一个引人注目的例外,而论文解释了它为何存在:每一轮迭代都要扫过一棵最多含数十亿状态的博弈树,方式是数百万个细小、彼此依赖的 gather/scatter 步骤,且通过一个通用的树接口发出。

失效机制在于内核时长与派发开销之间的落差。在 GPU 上每个内核都在微秒级完成,所以内核启动与框架派发主导了运行时间——算术早已算完,而启动它的那套机械还没停下来。这就是此前的 GPU 实现输给优化过的 CPU 代码的原因:GPU 在计算上并不慢,它慢在编排一个由数百万个微小依赖步骤构成的工作负载。

   CFR:一个引人注目的例外

   CFR 是「少数"在 CPU 上仍然比在 GPU 上更快"的大规模数值负载之一」
        |
        v
   原因:每一轮迭代都要扫过一棵「最多含数十亿状态」的博弈树,
        方式是「数百万个细小、彼此依赖的 GATHER/SCATTER 步骤」,
        且通过一个「通用的树接口」发出
        |
        v
   [失效机制:内核时长 vs 派发开销]
     在 GPU 上「每个内核都在微秒级完成」
     -> 「内核启动与框架派发主导了运行时间」
     -> 算术早已算完,而启动它的那套机械还没停下来
        |
        v
   -> 这就是「此前的 GPU 实现输给优化过的 CPU 代码」的原因
      <- GPU 在「计算」上并不慢
      <- 它慢在「编排」一个由「数百万个微小依赖步骤」构成的工作负载

增量

一句话: 在这篇论文之前,GPU 版 CFR 因为派发开销主导而输给 CPU;在这篇论文之后,把博弈编译成静态数据流、并以单次 CUDA 图重放,击败了所有基线——而仅凭编译后的表示,在 CPU 上就已经胜过 GPU 基线。

核心机制

洞见是一个单一观察,却带来很大后果:对于一个固定的博弈,CFR 一轮迭代中除数值之外的一切,在第一轮运行之前就都已知。 形状、索引、边结构、深度层级、缓冲地址——全部由博弈决定,而不是由求解过程决定。而且 CFR 的更新规则不变,所以调度中没有任何东西在迭代之间变化。这正是编译得以可能的条件。

于是博弈被一次性编译成静态数据流:扁平的边数组与信息集数组、预计算的索引、以及按深度分批的遍历,固定了整个操作序列,而迭代之间只有求解器状态在变。内部技术各自削减一类特定的开销来源——静态机会折叠、按深度的执行块、以及双通道 reach 缓冲——合起来把框架操作数最多减少 18.1 倍。所以第一份收益是算法—系统层面的真实削减,而不只是换了个外壳:操作更少,意味着要派发的更少。

接着是只有静态形状才允许的回报:由于形状、索引与缓冲地址从不改变,CUDA 图重放把这一轮迭代记录一次,然后用单次图启动重放。 这一步直接打击那个诊断。如果派发主导一切,那么把数百万次启动压缩成一次就是正确的补救——而它只有在编译后的表示使调度变得不变之后才可用。

结果把两份贡献分开了,而这是报告中最有教益的部分。 在一块 A100 上,跨越一个含卡牌、骰子与棋类的八博弈套件:

  • 相对同一加速器上此前最快的 GPU 版 CFR 快 29.8~80.4 倍。
  • 在四个最大的博弈上,相对 LiteEFG(最快的开源 CPU 实现之一)快 14~258 倍。
  • 以及那个归因:编译后的表示承载了这份差距的大部分——在八个 CPU 线程、不用任何加速器的情况下,它已经比 GPU 基线快 2.2~51.1 倍。

最后那个数字值得细看。一次 CPU 运行比 GPU 基线快最多 51 倍,意味着这份胜利主要不是来自”把 GPU 用得更好”——而是来自做了少得多的编排工作。GPU 随后是在放大一个编译早已产生的增益。把”仅 CPU”的数字与 GPU 结果并列报出,才让读者看到这份分解。

另外两项验证值得注意。 在 CPU 上,优化后的路径按位复现了参考迭代值——所以这次编译是保语义的,而不是近似;这一点要紧,因为 CFR 的保证依赖于更新规则。而树构建与图捕获在第一次求解之内就收回成本,所以编译代价在单次使用中就被摊掉了,而不需要多次求解来证明其必要。

总结把范围讲明白了:GPU-CFR 在该套件的中大型博弈上击败了每一个 CPU 与 GPU 基线,且没有改动更新规则。两个从句都要紧——“中大型”界定了胜利适用的范围,而”没有改动更新规则”界定了为拿到它做了什么。

   洞见:一个单一观察,却带来很大后果
     「对于一个固定的博弈,CFR 一轮迭代中除数值之外的一切,
       在第一轮运行之前就都已知」
       <- 形状、索引、边结构、深度层级、缓冲地址:
          全部由「博弈」决定,而不是由「求解过程」决定
       「而且 CFR 的更新规则不变」
         -> 调度中没有任何东西在迭代之间变化
       <- 这正是「编译得以可能」的条件

   「博弈被一次性编译成静态数据流」
     「扁平的」边数组与信息集数组
     「预计算的」索引
     「按深度分批的遍历」
       -> 这些「固定了整个操作序列」
     而「迭代之间只有求解器状态在变」
     「内部技术」各自削减一类特定的开销来源
       静态机会折叠 | 按深度的执行块 | 双通道 REACH 缓冲
       -> 合起来把「框架操作数最多减少 18.1 倍」
       <- 第一份收益是「算法—系统层面的真实削减」,
          而不只是换了个外壳:「操作更少,意味着要派发的更少」

   「接着是只有静态形状才允许的回报」
     由于形状、索引与缓冲地址「从不改变」,
     「CUDA 图重放」把这一轮迭代记录一次,
     然后用「单次图启动」重放
       <- 直接打击那个诊断:如果「派发」主导一切,
          把「数百万次启动压缩成一次」就是正确的补救
       <- 「只有」在编译后的表示使调度变得不变之后才可用

   「结果把两份贡献分开了」——报告中最有教益的部分
     一块 A100,「八博弈套件」(卡牌、骰子、棋类)
       相对同一加速器上「此前最快的 GPU 版 CFR」快 29.8~80.4 倍
       在「四个最大的博弈」上,相对 LITEEFG(最快的开源 CPU 实现之一)
         快 14~258 倍
     以及「归因」:
       「编译后的表示承载了这份差距的大部分」——在八个 CPU 线程、
       「不用任何加速器」的情况下,它已经比 GPU 基线快 2.2~51.1 倍
       <- 一次 CPU 运行比 GPU 基线快最多 51 倍,意味着这份胜利
          「主要不是」来自"把 GPU 用得更好"
       <- 而是来自「做了少得多的编排工作」
       -> GPU 随后是在「放大一个编译早已产生的增益」
       <- 把"仅 CPU"的数字与 GPU 结果并列报出,才让读者
          「看到这份分解」

   「另外两项验证」
     在 CPU 上,优化后的路径「按位复现了参考迭代值」
       <- 这次编译是「保语义」的,而不是近似
       <- 这一点要紧,因为 CFR 的「保证依赖于更新规则」
     「树构建与图捕获在第一次求解之内就收回成本」
       -> 编译代价在「单次使用」中就被摊掉了

   「范围被讲明白」
     在该套件的中大型博弈上击败了每一个 CPU 与 GPU 基线,
     「且没有改动更新规则」
       <- "中大型"界定了「胜利适用的范围」
       <- "没有改动更新规则"界定了「为拿到它做了什么」

可以用**“一个工坊:工具很好,但取工具的耗时比用工具还长”来理解这件事: 每次操作只要微秒,而走到架子那儿取它更久。修法不是”造更快的工具”,而是把工坊布置成”整串操作提前摆好、执行时不用取任何东西”。 论文版本里两个细节对得很整齐。 第一,布置工作本身就有价值、且独立于那套高级机械:八个线程、不用加速器,已经胜过 GPU 版本——这相当于说”光是重新组织就已经收回了升级成本”。 第二,得到的序列每次完全相同**,所以你可以把整场会话录一次然后重放——而这次录制之所以可能,正是因为两次运行之间布置没有任何变化。

关键概念

  • 受派发约束,而非受算力约束: 微秒级内核意味着启动开销主导。它把问题从”算术”挪到”编排”——这才让编译器成为正确的工具。
  • 由调度不变性使能的编译: 除数值之外的一切在第一轮之前就已固定。没有这种不变性,静态数据流无法表示这轮迭代。
  • 框架操作数减少 18.1 倍: 静态机会折叠、按深度的块、双通道 reach 缓冲。这是工作量的真实削减,也是它独立于 GPU 而有意义的原因。
  • 把 CUDA 图重放作为直接补救: 一次启动替代数百万次——仅因形状与地址从不改变而可用。
  • 仅 CPU 的归因: 八线程下比 GPU 基线快 2.2~51.1 倍。它分解了胜利,并表明承载差距的是编译、不是加速器。
  • 按位复现参考迭代值: 语义被精确保留;这要紧,因为该方法的保证依赖于更新规则。

框架转变

之前(GPU 版 CFR 输给 CPU):
  数百万个微小依赖步骤经通用接口发出
  -> 微秒级内核,派发主导
  -> GPU 在编排上比 CPU 慢,尽管算术更快
  -> 此前的 GPU 实现输给优化过的 CPU 代码

之后(编译博弈,重放迭代):
  除数值之外的一切在第一轮之前已知
  -> 静态数据流:扁平数组、预计算索引、分批遍历
  -> 框架操作数最多减少 18.1 倍
  -> 用一张录好的 CUDA 图替代数百万次启动
  -> 相对此前 GPU 版 CFR 快 29.8~80.4 倍;相对快速 CPU 代码快 14~258 倍
  -> 且仅凭八个 CPU 线程就比 GPU 基线快 2.2~51.1 倍

从”设法让 GPU 在一个它不擅编排的工作负载上更快”,转变为”把工作负载编译到’没什么需要编排’“,核心转变在于:瓶颈从来不在算术——而承载大部分增益的是编译后的表示,不是加速器。

专家评审

选题眼光: 极好,而且框定瞄得异常准。 “少数在 CPU 上仍然更快的工作负载之一”是一份精确的邀请——去弄清为什么;而答案(是派发开销、不是算力)立刻指向编译器而不是内核。这是一个直接推出正确解法类别的诊断。

方法成熟度: “除数值之外的一切在第一轮之前就已固定”这个观察,是那种一说破就显得显然、而此前显然没有被这样利用过的洞见。 内部技术各自针对一类被点名的开销;18.1 倍的操作削减是真实的削减、不是外壳把戏。使用 CUDA 图重放是”调度不变性”的自然推论,而不是一个单独的优化。 最重要的是:报告通过包含仅 CPU 的数字把两份贡献分开——而那正是告诉读者”增益实际来自哪里”的测量。

实验诚意: 比较的范围界定得当:对手是同一加速器上最快的既有 GPU 实现、以及一个快速的开源 CPU 实现;而胜利被限定在中大型博弈上。 对参考迭代值的按位复现,是对一个带收敛保证的方法最要紧的检查,而且它被报在”按位比较有意义”的 CPU 路径上。 “构建与捕获在第一次求解内收回成本”这一主张,消除了关于编译开销的那个显而易见的反对。 局限是:这个胜利以”博弈足够大、使每轮编排显著”为条件,所以那些开销比例不那么极端的小博弈不在所报收益之内。

写作功力: 摘要把诊断、洞见、机制与分开的结果按顺序陈述,让论证无需看表也能跟上。 由于”仅 CPU”那个数字是全文信息量最大的数,把它突出而不是埋进对照表里,是正确的编辑选择。

判决: 强接收(Strong Accept) — 它诊断出 GPU 为何在这个负载上落败,应用了诊断所暗示的”编译器形状”的修法,并以一种”显示承载增益的是编译后的表示而非加速器”的方式来报告结果。

要点总结

  • 区分受算力约束与受派发约束。当内核在微秒级完成时,修法是更少的操作,而不是更快的操作。
  • 优化之前先找调度不变性。如果迭代之间除状态之外什么都不变,那么这轮迭代本身就可以被编译。
  • 报告被分解的贡献。这里”仅 CPU”的数字表明:大部分提速来自编译,不是 GPU。
  • 验证语义,而不只是速度。与参考迭代值按位一致,才让一条编译出来的快路径可用于一个带保证的算法。