HORUS/blog

2026年8月29日 · benchmarks · honesty · performance · ros2

我们撤回了那个 ROS 2 加速数字。这是我们能守住的那一个。

HORUS 曾经宣称比 ROS 2 快几十倍——那个数字是编造的。这里是我们撤回了什么、为什么撤回、以及那个你能在自己机器上复现的、真正被测量过的数字。

我们曾经把一个数字挂在 README 上:HORUS 比 ROS 2 快几十倍。

那个数字是错的。它不是测量出来的——它是编造的。

这篇文章讲三件事:我们撤回了什么、为什么撤回、以及那个你能在自己机器上跑出来的、真正被测量过的数字。

那个被撤回的数字,到底是怎么造出来的?

事情很简单,简单到难堪:我们把一个 HORUS 自己测出来的真实数字,除以一个没人跑出来过的 ROS 2 延迟。那个 ROS 2 的"几十微秒"在 HORUS 仓库里没有任何 benchmark、没有任何报告、没有任何来源——它是编出来的。然后我们用真实的 HORUS 数字除以它,得到了一个看起来很漂亮的倍数。

这个倍数流到了 README、文档、社交媒体卡片,甚至一整篇博客文章里,直到有人认真去查。

我们撤回了它。

我们能守住的 ROS 2 比较,只有一个

HORUS 仓库里真正存在的 ROS 2 数字只有一个:REP 2014 中引用的、64 字节消息约 5 µs 的参考值。这个数字来自文献,不是我们自己测的。

HORUS 自己测出来的端到端跨进程延迟是 171 ns(单向,RDTSC 时间戳嵌入 payload,CPU 绑核,5000 次预热迭代后采样)。用 5 µs 除以 171 ns,大约是 30×

30× 是我们能守住的上限。这也是我们唯一会用的数字。

# 在你自己的机器上复现 171 ns 这个数字
cargo run --release -p horus_benchmarks --bin all_paths_latency

注意:这个 171 ns 是端到端、单向的。它和我们另外一些数字不是同一类——比如同进程发布/订阅的 91 ns,那是生产者侧send() 开销,没有消费者在路径上。把 send() 开销和端到端延迟放在一起比较,是在拿苹果比橙子。

真正值得拿来比较的,是 iceoryx2

如果我们想让你看到一个两边都测过的比较,我们不会拿 ROS 2——我们会拿 iceoryx2。

原因很简单:ROS 2 那一侧我们没跑过,iceoryx2 这一侧我们跑了。同一个测试框架,同一台机器,同样的 RDTSC + bootstrap 95% CI 方法论。

场景HORUSiceoryx2倍数
同线程11 ns69 ns6.3×
跨进程170 ns361 ns2.1×
吞吐95M msg/s22M msg/s4.3×
# 复现 iceoryx2 比较
cargo run --release --bin iceoryx2_comparison --features iceoryx2

这才是我们敢放在首页的比较——因为两边都是我们自己跑出来的。

为什么内部测量表也被撤回了?

这里有两件完全独立的事情,不要混为一谈。

第一件: 那个 headline 倍数和它的比较表被撤回,因为 ROS 2 那一侧的数字是编造的。

第二件: 内部的"Measured Results"表格(1 kHz / 10 kHz / 100 kHz PASS 裁决)被撤回,原因和 ROS 2 毫无关系

  1. 列出来的后端名字已经不存在了。 表格里写了 DirectChannelSpscIntraSpmcIntraMpscIntraMpmcIntra——这些后端全部被移除了。现在每个 topic 都是 SHM 支撑的,Topic::backend_name() 只能返回 PodShmSpscShmSpmcShmMpscShmFanoutShmUnknown
  2. 尾部被代码截断了。 Statistics::from_samples 在计算 maxp99p99.9 之前先跑了一个 Tukey IQR 滤波,所以报告出来的"最差情况"不可能超过 `Q3 + 1.5×IQR"——不管机器实际卡顿得多厉害。那个"最差测量 885 ns"的数字,是代码保证不可能大的数字。

这两件事的撤回原因完全不同。写第一件,原因就是编造的 ROS 2 数字。写第二件,原因就是不存在的后端和 IQR 截断的尾部。永远不要反过来讲,也不要把它们混成一个故事。

那些 per-message 数字呢?

robotics_messages_benchmark 在 i7-10750H 上跑出来的 send-only 数字是真实的:

消息类型大小send-only 延迟
CmdVel16 B75 ns
Imu304 B121 ns
JointCommand928 B135 ns
LaserScan1,480 B210 ns

文档把这些数字换算成相对于 REP 2014 ~5 µs 参考值的约 67× / 41× / 37× / 24×。

但要注意: 这些是 send-only——它们测的是生产者把消息放进共享内存槽的开销,没有消费者在路径上。把它们和端到端延迟比较是指示性的,不是 benchmark 结果。如果你引用这些数字,请说清楚这一点。

所以 HORUS 到底快不快?

这个问题问错了。正确的问题是:对谁快、在什么场景下快、快在哪里?

你该相信我们吗?

不该。至少不该盲目相信。

去跑那个 benchmark。看它打印出来的数字。检查 measurement 列——sendone-way 不是同一件事。检查 backend 列——如果你看到任何 *Intra 的名字,说明二进制版本不对。

# 完整的延迟基准,包含统计分析和后端检查
cargo run --release -p horus_benchmarks --bin all_paths_latency

# iceoryx2 对比(需要 iceoryx2 feature)
cargo run --release --bin iceoryx2_comparison --features iceoryx2

# 机器人消息类型基准
cargo run --release -p horus_benchmarks --bin robotics_messages_benchmark

all_paths_latency 会为每个场景打印一行,包含 scenario、backend 和 measurement 三列。如果 live backend 和预期不符,它会打印 MISMATCH——这个检查本该在撤回之前就抓住问题。

自己验证

在你自己的机器上跑。用 sudo cpupower frequency-set -g performance 把 CPU governor 切到 performance 模式。结果会因硬件和内核调度而异——这就是为什么我们给你命令,而不是给你一个数字。

Found this useful? Share it:Discuss on HNShare on X