Skip to content

Latest commit

 

History

History
86 lines (57 loc) · 4.05 KB

File metadata and controls

86 lines (57 loc) · 4.05 KB

Agent Instructions

零容错原则 — 暴露错误,禁止吞错

吞错误(fallback / silent failure / 返回假值)会导致查找一个很小的 ULP 问题耗费无穷漫长的时间和人力。

规则:

  1. 外部符号解析失败 → 立刻 throw std::runtime_error,进程退出。 不返回 nullptr,不 fallback 到纯 C++ 循环,不返回假值。

  2. 任何系统级前提条件不满足(动态库未加载、ABI 不匹配、 符号缺失)→ 立刻 throw,附带清晰的错误消息说明原因和修复方法。

  3. 禁止 silent failure。 一个静默错误浪费的排查时间远超一个清晰的 crash + stack trace。

  4. 数学意义上的失败(如奇异矩阵)也要 throw,不要 return false/zero。 调用方如果期望处理奇异矩阵,应当显式 catch。

C++ 绑定与 Python 库的对齐规则

核心原则:C++ 绑定的接口和实现必须与目标 Python 库完全一致。 测试代码是"黄金标准"——它反映 Python 库的真实行为。禁止通过修改测试来绕过 C++ 实现缺陷。

规则 1:参数顺序必须与目标库一致

  • 错误: C++ 绑定擅自调换参数顺序(如把数组放在 mask 前面)
  • 正确: 严格匹配目标库的参数位置
  • 实例: compress(arr, mask)compress(condition, a)

规则 2:默认值语义必须一致,禁止自定义哨兵值

  • 错误:-1 表示"未传入参数"——目标库用 None 表示
  • 正确: 使用 py::none() 匹配目标库的 None 语义
  • 实例: eye(N, M=-1, k=0)eye(N, M=py::none(), k=0)
  • 规则: 目标库用什么哨兵,C++ 就用什么。不要发明自己的。

规则 3:数学函数必须经 dlsym 桥接,禁止直接调用 std::

  • 禁止: std::pow() / std::atan2() / std::exp() 等 libm 函数直接调用
  • 原因: 目标库使用的 Intel SVML / 自定义多项式实现与 libm 差 1-3 ULP
  • 正确: 通过 dlsym 从目标库的 .so 中解析它实际使用的数学符号,在 C++ 侧调用

规则 4:dlsym 解析符号必须用目标库实际使用的版本

  • 错误: dlsym("npy_atan2") → 解析到 libm 的标量 atan2(差 1 ULP)
  • 正确: dlsym("__svml_atan28") → 解析到目标库实际使用的向量实现
  • 方法:nm -D <目标库.so> | grep <函数名> 查看目标库实际导出了什么符号, 选择与目标库运行时路径一致的版本

规则 5:头文件 include 顺序

内部实现头文件(如数学后端桥接)必须在所有依赖它的模块头文件之前加载。 否则深层模块无法使用桥接符号,可能静默 fallback 到 std::

规则 6:修复流程

当发现对齐测试失败时:

  1. 诊断: 用最小复现脚本确认差异量级(ULP)
  2. 定位根因: 追溯 C++ 调用链,找出哪一步使用了非等价的实现(参数错误、std:: 函数、错误的 dlsym 符号等)
  3. 修复 C++ 源码: 修改实现使其严格匹配目标库的等效路径
  4. 严禁改测试: 测试反映目标库的真实行为。修改测试来绕过 C++ 缺陷等同于作弊

规则 7:不重复造轮子

  • 在请求新增 API 前,先确认 目标库或 pybind11 是否已有等价功能
  • 示例:py::isinstance<py::array_t<float>>(arr) 可直接判断 dtype,不需要自己写 is_float32()
  • 示例:astype(arr, "float64") 已实现类型转换,不需要写 ensure_float64()

编译模式

精确模式(默认)

关键 flag:

  • -O2 -ffp-contract=off — 禁用 FMA 融合,确保每一步计算独立
  • -fno-builtin-{exp,log,sin,cos,tan,pow,atan2,sqrt,...} — 阻止编译器用内置实现替换 dlsym 路径
  • -march=native — 避免编译器自动矢量化改变计算顺序
  • 通过 dlsym 从目标库的 .so 解析数学符号

性能模式

  • -O3 -march=native — 允许编译器自由优化
  • -fno-builtin-* — 使用编译器内置数学函数
  • 与目标库预期差 0-2 ULP(可接受范围)