Synthesizing Performance Constraints for Evaluating and Improving Code Efficiency¶
会议: NeurIPS 2025
arXiv: 2505.23471
代码: https://github.com/UChiSeclab/perfforge
领域: AIGC检测
关键词: 性能约束合成, 代码效率评估, Fuzzing, LLM代码优化, PerfForge
一句话总结¶
提出Wedge框架——通过LLM合成性能刻画约束(performance-characterizing constraints)指导约束感知模糊测试,生成能暴露代码性能瓶颈的压力测试输入,构建PerfForge基准,使LLM代码优化器(如Effi-Learner)多减24% CPU指令。
研究背景与动机¶
领域现状:LLM在代码优化上表现出色,但评估其效果缺乏能真正暴露性能瓶颈的测试输入。现有方法要么用随机输入,要么用简单的大规模输入,无法针对性地触发特定代码路径的性能问题。
现有痛点:LLM难以直接推理"什么输入触发什么性能瓶颈",因为这涉及从程序输入到局部执行路径的复杂映射。现有性能测试生成方法(EvalPerf、TG-prompt)效果有限。
核心矛盾:需要找到让"未优化代码极慢但优化后代码快"的输入,但这种输入的构造需要理解代码的内部性能特征。
切入角度:将问题分解——LLM擅长推理局部代码行为("这个循环什么条件下迭代最多次"),fuzzing擅长搜索满足约束的输入。
核心idea:LLM合成性能约束 → 约束插桩到程序 → 约束感知fuzzing自动搜索满足约束的压力输入。
方法详解¶
整体框架¶
三阶段pipeline:(1)对比执行profiling——比较快/慢输入的per-statement执行次数找瓶颈;(2)性能约束合成——LLM两阶段推理(NL描述→checker code)生成约束并插桩;(3)约束引导fuzzing——修改版AFL++使用LLM生成的约束感知mutator搜索压力输入。
关键设计¶
-
对比执行Profiling:
- 功能:从已有正确性测试中挖掘对比输入对(相似输入但执行成本差异大)
- 核心思路:运行程序收集每个输入的 CPU 指令数,用匹配率+Jaccard相似度衡量输入相似度,用执行成本比衡量性能差异,选排名最高的 \((i_{slow}, i_{fast})\) 对。然后收集两次执行的 per-line hit count 差异
- 设计动机:对比执行提供的诊断线索比单次执行更丰富,高相似度确保差异确实来自性能特征而非输入本身
-
性能约束合成(两阶段):
- Phase 1(自然语言推理):LLM 比较快慢执行的 hit count,定位热点代码,推理"什么条件让这些行执行更多次",输出 NL 描述的约束集 \(\mathbb{C}\)
- Phase 2(代码实现):LLM 将自然语言约束转化为可执行的 checker 代码(如
all(l[i] > l[i+1] for i in range(len(l)-1))),插桩到程序中作为新的分支 - 设计动机:两阶段分解避免了直接要求 LLM 生成压力输入的困难——LLM 擅长局部行为推理,不擅长全程序输入→行为映射
-
约束感知Mutator:
- 功能:替换 AFL++ 的默认 bit-flip mutator,生成理解输入语法和性能约束的自定义 mutator
- 核心思路:LLM 根据问题描述(输入语法)、性能约束 \(\mathbb{C}\)、对比输入对,生成 Python mutator 函数。迭代 generate-and-fix 保证鲁棒性
- AFL++ 的 coverage-guided 机制天然将插桩的 checker 分支作为覆盖目标——覆盖新 checker 分支 = 找到满足性能约束的输入
- 去掉约束感知 mutator 后指令数降 3.9×(消融最关键组件)
实验关键数据¶
主实验¶
| 方法 | 平均指令数(×10⁸) | Win rate | 平均Slowdown |
|---|---|---|---|
| Wedge | 5.96 | 60% | 363× |
| TG-prompt | 3.87 (↓1.5×) | 12% | 275× |
| PerfFuzz | 3.29 (↓1.8×) | 11% | 149× |
| EvalPerf_slow | 3.23 (↓1.8×) | 8% | 146× |
代码优化驱动效果(Effi-Learner + GPT-4o)¶
| 输入源 | 执行时间减少 | CPU指令减少 |
|---|---|---|
| 无 | 15.66% | 31.39% |
| CC_default | 22.57% | 39.89% |
| PerfForge | 26.47% | 49.31% |
消融实验¶
| 配置 | 平均指令数(×10⁸) | vs Full |
|---|---|---|
| Full Wedge | 5.96 | - |
| WedgeNoInstr(去掉checker插桩) | 4.02 | ↓1.5× |
| WedgeDefaultMut(用AFL++默认mutator) | 1.54 | ↓3.9× |
| AFL++(无约束无插桩) | 1.49 | ↓4.0× |
Pie 代码优化公平评估¶
PerfForge 评测发现 Pie 优化的实际加速比比其声称的(基于正确性测试)更高:指令数加速 24%-149%,物理时间加速 5%-27%。7%-48% 更多的程序实际被有意义地优化。
关键发现¶
- 约束满足输入比违反输入慢 38.6×,在 92.84% 的程序上显著更慢——验证了约束的性能刻画能力
- 约束感知 mutator 贡献最大(去掉后指令数降 3.9×),checker 插桩次之(去掉降 1.5×)
- 小输入 (<1KB) 优势更大 (3× slowdown over baselines),证明性能压力来自实现瓶颈而非纯粹输入长度
- 评测数据集:CodeContests 154 个问题、33,020 个 C++ 程序,fuzzing 每个解 1 小时
亮点与洞察¶
- LLM+Fuzzing的精妙分工:LLM做"理解"(约束推理),fuzzing做"搜索"(满足约束的输入生成),各自发挥优势。
- PerfForge作为代码优化的加速器:不仅是评测工具,更能反馈驱动LLM优化器找到更好的优化——形成evaluation→improvement闭环。
局限与展望¶
- 依赖 LLM 生成正确的约束 checker 代码,复杂程序可能失败
- 仅在竞赛题上验证(CodeContests),工业代码和仓库级代码的适用性未测
- fuzzing 每个解 1 小时的开销较大,实际部署需考虑效率
- 约束质量完全依赖 LLM 的代码理解能力,对未见过的算法模式可能表现不佳
相关工作与启发¶
- vs EvalPerf:EvalPerf 通过 scale 参数控制输入大小,本质是长度压力测试;Wedge 针对具体代码实现生成结构化约束,更精准
- vs PerfFuzz:PerfFuzz 用 edge hit count 引导 fuzzing,但没有显式的性能约束,最终还是生成长度压力输入
- vs TG-prompt:直接提示 LLM 生成压力输入,要求端到端推理全程序行为,对 LLM 来说太难
- 对 LLM agent 的代码优化能力评测有重要参考价值——好的评测输入能驱动更好的优化
评分¶
- 新颖性: ⭐⭐⭐⭐⭐ 性能约束合成+约束引导fuzzing的组合全新
- 实验充分度: ⭐⭐⭐⭐ 多基准、多消融、闭环验证
- 写作质量: ⭐⭐⭐⭐ 动机清晰,方法描述系统
- 价值: ⭐⭐⭐⭐⭐ 对代码效率评测和LLM代码优化都有直接价值