GPU并行虚拟机:用线性代数实现百万程序并发评估

发布时间:2026/5/28 20:31:25

GPU并行虚拟机:用线性代数实现百万程序并发评估 1. 项目概述当线性代数遇上GPU虚拟机在程序合成、超级优化和数组编程这些前沿领域我们常常面临一个核心挑战如何高效地评估海量、形态各异的程序变体。传统思路是串行执行一个接一个地跑但这在面对数以百万计的可能性空间时无异于杯水车薪。GPU这个为图形渲染而生的怪兽凭借其成千上万个流处理器的SIMD单指令多数据架构本应是处理这类“令人愉悦的并行”任务的绝佳平台。然而通用程序的执行通常充满了分支和复杂的数据依赖与GPU擅长的规则数据并行模式格格不入导致其潜力在程序分析这类负载中远未被充分挖掘。我最近深入研究了Breandan Considine的一篇工作它提出了一种非常巧妙的思路将抽象计算模型的状态转换彻底“翻译”成线性代数运算。具体来说他选择了RASP随机访问存储程序模型作为基础。这个模型本身很简单就是一个包含指令计数器、累加器、内存、输入和输出的状态机。但妙就妙在当我们将这个状态机的每一步操作比如加载、加法、存储、条件跳转都表示为有限域特别是F2即模2的整数域上的多元多项式时整个计算过程就变成了一系列矩阵和向量的运算。而GPU恰恰是进行大规模线性代数计算的专家。这样一来我们就能构建一个“超大规模并行虚拟机”。想象一下你不是在模拟一个程序而是同时模拟数百万个不同的程序实例。每个实例的状态被编码为一个向量所有实例的状态向量堆叠成一个巨大的状态矩阵。GPU的每个线程块负责处理这个矩阵的一个切片通过高度优化的张量核心执行统一的线性代数操作即那个多元多项式表示的状态转换函数一步就能推进所有虚拟机的状态。这不再是简单的“一个GPU线程对应一个虚拟机”的粗粒度映射而是更本质的、基于计算模型的数学抽象实现的细粒度并行。实测下来这种方法的加速比可以轻松突破百倍为程序搜索、算法探索甚至一些经验数学研究打开了新的大门。2. RASP模型从抽象机器到多项式映射要理解这个并行虚拟机的核心必须先吃透RASP模型。它不是什么新东西但正是其简洁性使其成为线性代数化的理想目标。2.1 RASP模型的核心定义RASP可以定义为一个四元组 ℛ ⟨, 0, →, ⟩。我们拆开来看 (配置空间)代表了机器的完整状态。它是一个五元组 ⟨, , , , ⟩。(Instruction Counter): 指令指针指向下一条要执行的指令在内存中的位置。(Accumulator): 累加器用于存储临时计算结果。(Memory): 内存数组同时存储程序指令和数据。这是RASP与后来更常见的RAM随机访问机器的关键区别之一RAM将程序与数据内存分开。(Unread Input): 待读取的输入流。(Output): 已产生的输出流。0 (初始配置)给定一个程序本质上是一个(操作码 操作数)对的序列和输入初始化机器状态。通常是把程序写入内存开头输入放在特定位置指令指针、累加器清零输出为空。→ (单步转换函数)这是核心定义了机器如何从当前状态演进到下一个状态‘。它基于当前指令指针处的操作码和操作数从内存中读取来决定行为。论文中给出了一个经典的指令集包括LOD j(加载): M[j]ADD j(加法): M[j]SUB j(减法): - M[j]STO j(存储):M[j] BPA j(累加器为正则跳转): 如果 0则 j否则 2指令通常占两个字。RD j(读输入): 从输入流读取一个字符到M[j]。PRI j(打印输出): 将M[j]的内容追加到输出流。 (停机配置)所有满足 → 的状态集合即转换到自身的状态固定点。通常通过执行一个无效指令如操作码0来实现停机。这个模型虽然简单但图灵完备足以表达任何可计算函数。它的状态空间是离散且有限的如果我们限定内存和字长。2.2 关键跃迁从状态机到多项式函数传统的虚拟机实现无论是解释器还是JIT编译本质上是在CPU上模拟这个状态机取指、解码、根据操作码分支跳转到对应的处理函数、更新状态。这个过程充满了条件判断和内存访问在GPU上并行化时会导致严重的线程分化——不同虚拟机执行不同的指令路径迫使GPU的SIMD单元如NVIDIA的Warp串行执行不同分支极大降低效率。本文的突破点在于将单步转换函数→表示为一个有限域上的多元多项式函数Φ。怎么做到的呢状态编码首先将整个配置空间映射到一个有限域比如F2^即位二进制向量的集合上的向量。每个状态变量, , 内存的每个字等都成为这个向量中的一个或多个分量。操作编码每个RASP指令如ADD, STO以及条件判断如 0都可以表示为对状态向量分量的布尔函数或算术函数。多项式化一个关键的理论基础是任何定义在有限域上的布尔函数都可以唯一地表示为一个多元线性多项式在F2上或更一般的多元多项式。这意味着像“如果操作码是ADD则将累加器分量更新为 ⊕ M[j]否则保持不变”这样的条件更新逻辑可以写成一系列多项式项的和其中每一项都包含一个“指示函数”当条件满足时值为1否则为0乘以对应的更新多项式。统一形式最终整个单步转换‘ Φ()被写成一个统一的多项式函数。对于有多个分支的指令其形式类似于Φ() Σ_ψ [η_ψ() * Φ_ψ()]其中ψ遍历所有可能的指令分支如LOD分支、ADD分支等η_ψ()是一个多元线性指示函数当且仅当当前状态满足分支ψ的条件如操作码等于某个值且累加器满足某条件时值为1否则为0。Φ_ψ()是该分支对应的状态更新多项式。由于在任何状态下有且仅有一个分支的条件为真所以这些指示函数的和恒为1。这样做的巨大优势在于Φ是一个确定性的、无分支的数学函数。给定输入状态向量输出状态向量是唯一确定的并且计算过程完全由算术运算加法、乘法组成。这完美契合了GPU的SIMD架构成千上万个线程可以同步地对各自的状态向量执行完全相同的多项式计算序列无需任何条件分支从而实现极高的吞吐量。注意这里说的“无分支”是指虚拟机实现层面GPU内核代码本身没有if/else或switch。分支逻辑被编码在了多项式的系数和结构里通过算术运算来实现“选择”效果。这是实现高效GPU并行的关键技巧。2.3 字长RASP的扩展论文进一步定义了“字长RASP”Word RASP引入了固定字长如32位、有限内存、有限输入长度ℓ和输出缓冲区大小。这使模型更贴近实际硬件。操作也调整为基于固定字长的模运算⊕ 表示模2^加法⊗ 表示模2^乘法。条件跳转BPA变为BNZ非零跳转用累加器是否为零来判断这在二进制域上更容易用多项式表示例如 ≠ 0的指示函数可以用1 - δ()来近似构造其中δ是某种“是否为零”的函数的多项式近似。这个扩展模型ℛ(,,ℓ,)的配置空间是有限的F_2^(*(ℓ4))。有限性至关重要它保证了状态转换函数可以被一个有限域上的多项式精确表示这是整个数学框架成立的前提。3. 实现策略GPU上的超大规模并行虚拟机有了理论框架接下来就是如何将其映射到GPU硬件上实现真正的超大规模并行。这部分的工程实现充满了权衡与技巧。3.1 整体架构与数据布局核心目标是同时运行个独立的RASP虚拟机实例。我们有一个全局的状态矩阵其维度为 × (状态向量长度)。每个虚拟机实例的状态向量就是矩阵中的一行。数据布局策略 为了优化GPU内存访问合并访问通常采用结构体数组的方式。即在GPU全局内存中分配一个一维数组数组的每个元素是一个结构体包含了某个虚拟机实例的完整状态, , [0..n-1], [0..ℓ], [0..]。虽然“数组结构体”在某些访问模式下可能更优但“结构体数组”更符合我们以虚拟机实例为并行单元的操作模式便于每个线程处理自己对应的那个结构体。内存约束考量 论文提到由于CUDA架构每个线程最多只能使用255个寄存器为了将整个虚拟机状态尤其是内存尽可能放入寄存器以获得最快访问速度他们限制了内存大小 ≈ 250个32位字约1KB。这是一个典型的性能与容量权衡。如果程序需要更大内存状态就必须部分存储在更慢的全局内存或共享内存中会增加访问延迟。在实际应用中需要根据目标程序的特点来调整这个参数。3.2 内核设计与无分支策略这是实现高效并行的核心。GPU内核函数的核心任务就是计算c_new Φ(c_old)。内核函数签名内核接收指向全局状态数组的指针以及当前的时间步或最大步数限制τ_max。线程映射最直观的映射是一个GPU线程对应一个虚拟机实例。这样我们有个线程并行工作。每个线程读取自己对应的状态结构体到寄存器或共享内存执行多项式函数Φ然后将新状态写回全局内存。无分支计算实现这是最精妙的部分。如何在没有if语句的情况下实现条件更新以ADD j指令为例其逻辑是如果当前操作码 2则 _新 _旧 ⊕ M[j]否则 _新 _旧。我们可以为每个操作码x计算一个选择掩码mask_x。mask_x是一个与状态向量同宽度的向量或标量作用于特定分量当 x时其对应分量为全1二进制否则为全0。在F2域上全1掩码与任何值进行按位与运算结果不变全0掩码与任何值进行按位与运算结果为0。那么_新可以计算为_新 _旧 ⊕ (mask_ADD (_旧 ⊕ M[j]))。解释(_旧 ⊕ M[j])是ADD操作的结果。mask_ADD ...意味着只有当 2时这个结果才被保留否则结果为0。最后再与_旧进行异或在F2上加法和减法都是异或等价于如果掩码为全1则_新 _旧 ⊕ (_旧 ⊕ M[j]) M[j]这里似乎有误原意应为累加实际上经典RASP的ADD是 M[j]在F2上就是_新 _旧 ⊕ M[j]。所以更准确的计算是_新 (mask_ADD (_旧 ⊕ M[j])) | (~mask_ADD _旧)但F2上可以用选择函数实现。实际上论文中通过多元线性指示函数η_ψ()来精确实现这个“选择”逻辑。多项式求值优化Φ()是一个多元多项式。直接展开计算可能项数很多。我们需要利用多项式的结构进行优化公共子表达式消除计算[]需要根据当前从内存中取操作数和操作码等公共部分。利用位并行由于是在F2^上运算我们可以利用GPU的位操作指令一次性处理整个字长的比特位。预计算常数多项式的许多系数是常数可以在编译时或内核启动前计算好作为常量内存或直接硬编码在指令中。3.3 调度与停机处理并非所有虚拟机都会同步运行。有些程序可能很快停机进入固定点而有些则会运行很久。我们需要一个调度策略来避免活跃线程等待停机线程。论文附录A给出了一个条带化轮询调度算法启动个持久化的工作线程对应GPU上的线程块或网格大小。将全局的个虚拟机实例条带化分配给这些工作线程。例如线程负责处理索引为, , 2, ...的虚拟机。每个工作线程在其负责的条带上进行轮询。在每一轮中线程依次访问条带上的每个虚拟机。对于每个访问的虚拟机线程检查其是否已停机状态是否在中。如果未停机则为其执行个时间步的模拟即连续应用Φ函数次然后将更新后的状态写回。是一个“时段”参数用于平摊线程启动和状态加载/存储的开销。这个过程重复进行直到所有虚拟机停机或达到全局最大步数τ_max。这种调度方式的好处是负载均衡。即使不同虚拟机的运行时间差异很大每个工作线程负责的条带内总会有一些活跃的任务可以保持GPU计算单元的利用率。的选择是个权衡太小则调度开销大太大则可能导致某些线程过早空闲。停机检测在每一步应用Φ后需要判断新状态c_new是否等于旧状态c_old即是否为固定点。由于状态是离散的可以直接比较。在实现上可以计算两个状态向量的差或异或检查是否全为零。这个比较操作也可以向量化。4. 前端语言与编译将高级构造映射到RASP直接编写RASP机器码是极其繁琐的。为了实用我们需要一个高级语言作为前端并将其编译或解释成RASP程序。论文第2.2节介绍了一个简单的无堆数组语言并给出了将其操作语义编译到RASP指令序列的规则。4.1 语言概览这个语言非常精简但包含了核心的编程结构函数只有一个函数f0接受一个输入数组ipt返回一个输出数组opt。类型只有一种类型W位字的数组。语句赋值scr[z] E或opt[z] E条件语句ife G {B1} {B2}(if-else)循环语句whl G {B}(while)停机hlt表达式支持数组元素ipt[z],scr[z],opt[z]、常量、加法()、乘法(*)。scr是一个临时“便签”数组用于存储中间结果。语言设计为“无堆”的意味着所有数组ipt,opt,scr的大小在编译时确定并映射到RASP内存的固定区域。这简化了内存管理也符合RASP模型内存静态分配的特点。4.2 编译规则详解编译过程Γ ⊢ B ⇒ C将语言的一个语句块B编译成一个RASP指令序列C。Γ是编译上下文记录了变量到内存地址的映射。关键编译规则与地址分配内存布局RASP内存M被划分为几个连续区域M[0..2m-1]: 存储程序指令本身每个指令占两个字操作码和操作数。M[2m..2mℓ-1]: 映射输入数组ipt。M[2mℓ..2mℓs-1]: 映射输出数组opt。M[2mℓs..2mℓsμ-1]: 映射便签数组scr。此外还会预留一个特殊的临时地址ν用于计算表达式时存放中间结果。表达式编译表达式编译规则Γ ⊢ E ⇒a A生成指令序列A该序列执行后会将表达式E的值留在累加器a中。变量/常量加载Γ ⊢ ipt[z] ⇒a A编译为LOD addr(ipt[z])其中addr计算该数组元素在内存中的绝对地址考虑模数组长度。二元运算以加法I1 I2为例。Γ ⊢ I1 ⇒a J1 Γ ⊢ I2 ⇒a J2 ------------------------------ Γ ⊢ I1 I2 ⇒a J1 STO ν J2 ADD ν解释先编译I1结果在a中。然后执行STO ν将a即I1的值存入临时地址ν。接着编译I2结果会覆盖a得到I2的值。最后执行ADD ν将aI2与内存ν处的值I1相加结果存回a。这样就实现了a I1 I2。控制流编译这是编译的难点因为RASP只有条件跳转指令BNZ非零跳转。条件语句ife I {B1} {B2}:Γ ⊢ I ⇒a J Γ ⊢ B1 ⇒ C1 Γ ⊢ B2 ⇒ C2 ------------------------------------------ Γ ⊢ ife I {B1} {B2} ⇒ J BNZ lt C2 JMP le lt: C1 le:解释先计算条件I值在a中。J是计算I的指令序列。然后执行BNZ lt如果a ! 0条件为真跳转到标签lt处执行C1B1的代码否则顺序执行后面的C2B2的代码。执行完C2后用JMP le跳过C1。JMP可以用LOD 1; BNZ le来实现加载一个非零值然后无条件跳转。循环语句whl I {B}:Γ ⊢ I ⇒a J Γ ⊢ B ⇒ C --------------------------------------------------------- Γ ⊢ whl I {B} ⇒ lh: J BNZ lb JMP le lb: C JMP lh le:解释lh是循环头标签先计算条件IJ。BNZ lb条件为真则跳转到lb执行循环体C。循环体执行完后JMP lh跳回循环头重新判断条件。如果条件为假则JMP le跳出循环。函数与停机函数fun f0(...) {...}的编译结果其最后会附加指令PRI q_ii从0到输出数组长度-1来输出结果然后跟一个HLT指令例如0 0使虚拟机停机。通过这套规则我们可以将高级语言编写的数组处理程序自动翻译成RASP机器码。这个RASP程序连同其输入数据就可以被我们之前实现的并行虚拟机加载和执行了。实操心得在设计这类编译规则时一个常见的坑是标签地址的解析。RASP的跳转指令BNZ的操作数是一个绝对内存地址存放目标指令的地址。在编译时我们可能还不知道C1、C2或循环体的具体长度因此无法立即确定lt、le、lh、lb的绝对地址。通常需要两遍扫描第一遍生成指令但用符号标签占位并记录指令位置第二遍将符号标签替换为计算出的绝对地址。这在实现编译器时需要仔细处理。5. 性能评估与结果分析理论很美好但实际效果如何论文在第3节给出了详细的评估其方法和结果对我们理解系统性能边界极具参考价值。5.1 实验设置实现平台基线Kotlin/JVM实现运行在Apple M4 Max CPU上。分别测试了单线程×1和16线程×16版本。GPU平台NVIDIA CUDA实现。测试了两种GPUA10G一款面向数据中心的通用计算GPU。B200NVIDIA最新的Blackwell架构旗舰GPU计算能力更强。虚拟机参数字长32位内存250个字输入缓冲区ℓ10输出缓冲区2最大模拟步数τ_max 10^6。工作负载生成了 8 × 10^6八百万个随机的数组程序。这些程序采样自一个定义良好的“无堆数组语言”的语法空间每个程序长度固定为 100条语句或指令文中指代码片段长度。使用了一个已知的“单词采样器”来确保采样的程序在语法上是有效的。评估指标总运行时间评估所有八百万个程序直到停机或达到τ_max步所花费的墙上时钟时间。停机分布统计这些程序实际停机所需的步数τ_h的分布情况。5.2 性能结果解读根据论文中的图1a运行时对比GPU带来数量级加速这是最显著的结论。在八百万程序规模下即使是A10G GPU其运行时间也远低于M4 Max的16线程版本。而B200 GPU的性能更为惊人。具体加速比论文提到观察到了最高147倍的加速相对于串行评估。这个加速比是相对于单线程CPU执行而言的。即使对比16线程的CPUGPU的加速比依然非常可观可能达到数十倍。性能差异来源并行规模GPU如B200可以同时启动数万个线程论文提到B200在峰值理论占用率下可维持约37,888个常驻线程而CPU核心数通常只有几十个。这是并行能力的基本差距。SIMD效率本文的“无分支多项式求值”内核确保了同一个Warp通常是32个线程内的所有线程执行完全相同的指令流最大化利用了GPU的SIMD吞吐量。这是相比传统基于解释执行的GPU虚拟机的关键优势。内存带宽GPU拥有远超CPU的显存带宽。虽然每个虚拟机的状态访问是随机的但通过合理的布局结构体数组和大量的并发线程可以有效地掩盖内存访问延迟饱和内存带宽。根据论文中的图1b停机分布大多数程序很快停机分布图显示大量程序在远少于τ_max10^6步内就停机了。这符合直觉随机生成的大多数程序要么很快进入死循环或固定点要么很快执行完毕。存在长尾分布也有一小部分程序运行了非常多的步骤才停机甚至可能不停机在τ_max步内未观测到停机。这对应了程序空间中的“复杂”或“潜在不可判定”的程序。研究意义这个分布对于程序合成和超级优化至关重要。如果我们是在搜索具有某种特性的程序例如计算某个特定函数我们需要评估海量候选程序。如果大多数程序很快被判定为“不符合要求”例如输出错误或超时那么这种并行虚拟机就能以极高的吞吐量快速过滤掉这些无效候选将计算资源集中在少数有潜力的程序上。5.3 实际应用场景与扩展这项工作不仅仅是学术演示它有明确的应用前景加速程序搜索在程序合成中我们需要在巨大的程序空间中寻找满足输入输出示例的程序。并行虚拟机可以同时评估数百万个候选程序快速淘汰错误答案。经验数学研究例如寻找“忙碌海狸”程序在给定状态下能输出最多1的停机程序。论文附录B就展示了用该系统在20分钟内搜索长度为120的程序找到的几个运行步数很长的“忙碌海狸”候选。这种穷举或随机搜索需要巨大的计算量GPU并行化能极大加速进程。算法探索与优化作者提到未来希望将其用于加速搜索快速矩阵乘法的直连程序straight-line program和上下文无关文法分析算法。这些都是计算密集型且可以高度并行化评估候选方案的任务。教学与原型验证RASP模型本身是计算机科学中一个经典的抽象模型。这个并行实现可以作为一个生动的教学工具展示如何将理论计算模型映射到现代并行硬件以及线性代数在计算中的基础性作用。6. 常见问题与实现避坑指南在尝试复现或借鉴这个思路时你可能会遇到一些典型问题。以下是我基于经验总结的排查清单和技巧。6.1 性能瓶颈分析与优化问题现象可能原因排查与优化建议GPU内核运行速度远低于预期甚至不如多线程CPU。1.线程分化严重虚拟机执行路径不同导致Warp内串行执行。2.全局内存访问未合并每个线程访问的状态数据在内存中不连续。3.寄存器溢出每个线程状态太大寄存器放不下使用本地内存慢。4.指令吞吐量低多项式Φ的实现过于复杂使用了大量低速运算。1.确保无分支检查内核代码绝对避免if、switch、?:运算符。分支逻辑必须通过算术掩码实现。2.优化数据布局使用struct封装单个VM状态并以struct VMState vm_states[N];方式分配。确保线程i访问vm_states[i]访问是连续的。3.减少状态大小压缩状态表示。例如如果输入/输出缓冲区很小可以考虑与内存合并。使用更小的数据类型如uint16_t如果字长允许。4.简化多项式分析Φ函数合并同类项预计算常数部分。考虑使用查表法如果条件组合有限来加速指示函数η_ψ的计算。当虚拟机数量非常大时性能提升不明显甚至下降。1.全局内存带宽成为瓶颈每个时间步都需要读写全部状态数据量巨大。2.调度开销过大轮询调度中时段设置太小频繁加载/存储状态。3.GPU资源限制活动线程数超过硬件限制导致频繁上下文切换。1.增加计算强度增大时段让每个线程在加载状态后执行更多步计算减少内存访问频率。2.使用共享内存将一批虚拟机的状态加载到线程块的共享内存中块内线程协作处理这批VM。这能极大减少对全局内存的访问。3.调整网格/块大小根据GPU的SM数量、每个SM的最大线程数等参数调整线程块大小和网格大小以达到最佳占用率。使用cudaOccupancyMaxPotentialBlockSize等工具辅助。部分虚拟机结果不正确。1.多项式Φ实现有误某个指令或条件对应的多项式项系数错误。2.内存访问越界RASP程序访问了未分配的内存地址。3.编译规则错误前端语言到RASP的翻译逻辑有bug。4.整数溢出处理字长RASP使用模运算而高级语言可能期望普通整数语义。1.单元测试为每个RASP指令单独编写小的测试程序在CPU上实现一个简单的解释器作为黄金标准对比GPU并行虚拟机的结果。2.边界检查在调试版本中可以在内核中加入断言检查内存访问索引是否在[0, n-1]范围内。虽然会影响性能但有助于定位问题。3.交叉验证用一个小型编译器将高级程序编译成RASP码同时用Python或C写一个同功能的程序对比最终输出。4.明确语义在文档和代码中清晰定义所有运算加、乘、比较是在模2^意义下确保前后端理解一致。6.2 扩展性与功能增强支持更大的内存如果程序需要超过250个字的内存可以考虑将内存M的一部分存储在全局内存中只将最频繁访问的部分如当前指令附近的数据、累加器放在寄存器或共享内存。这需要设计一个缓存策略。支持更丰富的指令集当前RASP指令集是极简的。要支持更实用的虚拟机如教学用的RISC-V子集需要定义更多的指令和对应的多项式。关键是保持指令译码的无分支性。可以为每个可能的操作码-操作数组合预计算一个更新掩码和更新值模板。输入/输出交互当前的模型是批处理的所有输入预先加载输出最后收集。要支持交互式或流式I/O需要修改状态模型可能引入“中断”或“外部事件”的概念这会使多项式Φ变得复杂可能破坏无分支性。一个折中方案是定期让虚拟机暂停由主机CPU处理I/O。调试支持在并行环境中调试数百万个虚拟机是噩梦。可以添加一个“调试掩码”只记录被标记的虚拟机的执行轨迹。或者实现一个“单步模式”虽然慢但用于调试关键程序。6.3 工程实践要点从简单开始不要一开始就实现完整的RASP和编译器。先从实现一个只有LOD、ADD、STO、HLT指令的微型虚拟机开始验证多项式映射和无分支内核的正确性。使用CUDA数学函数对于模2^32的加法和乘法可以直接使用和*因为CUDA中无符号整数的溢出行为就是模运算。对于其他字长或有限域运算可能需要自己实现或使用库。性能剖析工具善用nvprof或Nsight Compute来剖析内核性能。重点关注指标Achieved Occupancy占用率、Global Memory Load/Store Efficiency全局内存访问效率、Branch Divergence分支分化。主机-设备通信初始化八百万个虚拟机的状态程序、输入是一个大数据传输。使用cudaMemcpyAsync进行异步拷贝并与内核执行重叠以隐藏传输延迟。随机程序生成生成有意义的随机测试程序本身是个挑战。论文中提到的“单词采样器”确保生成的是语法有效的程序。你也可以定义自己的概率上下文无关文法来生成程序。这个基于线性代数和GPU的并行虚拟机方案为我们处理超大规模程序评估问题提供了一个全新的工具箱。它将计算问题转化为纯粹的数学变换从而释放了GPU的原始算力。虽然实现起来需要克服无分支编程、状态编码和调度等挑战但其带来的百倍级性能提升在程序合成、算法搜索等需要“暴力”评估的场景下价值是决定性的。

相关新闻