在最坏的情况下,多少 QPI 延迟会减慢任意应用程序的速度?

in a worst case how much QPI latency can slow-down arbitrary application?

我正在开发低延迟高频交易应用程序。

我用的是单机CPU。因为它更容易配置和维护,(无需调整 NUMA)。另外,很明显,假设我们有足够的资源,它绝对不会比双 CPU 设置慢,而且可能会快一点,导致没有 QPI/NUMA 延迟。

HFT 需要大量资源,现在我意识到我想要更多的内核。此外,托管两台 1U 单 CPU 机器比托管一台 1U 双 cpu 机器要昂贵得多,所以即使假设我可以 "split" 我的程序到两个它仍然有意义使用 1U 双-CPU 机器。

那么 QPI/NUMA 延迟有多可怕?如果我将我的应用程序从单CPU 机器移动到双CPU 机器,它会慢多少?我最多可以承受几微秒的延迟,但不能更多。如果未正确调整,QPI/Numa 是否会引入明显的延迟?这种延迟会有多严重?

是否可以编写在双CPU 设置上比单CPU 设置运行得更慢(慢超过几微秒)的应用程序?即在更快的计算机上运行得更慢? (当然假设我们有相同的处理器、内存、网卡和其他一切)

这不是简单的回答,因为它取决于很多因素。代码是为NUMA写的吗?

代码主要是读,主要是写还是差不多? 运行 在单独的 CPU 上的线程之间共享多少数据?此类数据多久写入一次,强制缓存刷新?

如何安排任务,OS 如何以及何时决定将线程从一个 CPU 套接字移动到下一个套接字?

代码和数据是否适合缓存?

这些只是将在 "works really well" 和 "gives really poor performance" 之间显着改变结果的几个因素。

与所有与性能相关的事物一样,细节可能会产生巨大的差异,在互联网上阅读此类答案不会为您提供适用于您的情况的可靠答案。对您的应用程序进行基准测试,检查性能计数器并据此进行调整。 [鉴于您在上面评论中描述的规格机器的价格,我希望供应商允许进行某种测试、演示、"try before you buy" 等]。

假设你有一个最坏的情况,内存访问将跨越两个缓存行(例如,8 字节值的未对齐访问),它被分配到你最糟糕的位置 CPUs , 并且 MMU 需要重新加载,每个 page-table 条目也处于最糟糕的 CPUs,并且由于那对内存位置的内存位于不同的位置,因此需要新的 TLB 条目对于两个 4 字节读取中的每一个,以加载您的 64 位值。 (每个 TLB 条目都是一个单独的位置)。

这意味着 2 x 4 x n,其中 n 类似于 50-100 ns。因此,至少在理论上,一次内存访问可能需要 1600 ns。所以 1.6 微秒。对于单个操作,您不太可能会比这更糟。开销比例如交换到磁盘要少得多,这会增加执行时间的毫秒数。

编写代码在多个 CPU 上更新同一个缓存行并因此导致性能急剧下降并不难 - 我记得很久以前我第一次拥有 Athlon SMP 系统时运行创建一个简单的基准测试,作者在其中为 Dhrystone 基准测试做了这个

int numberOfRuns[MAX_CPUS];

现在,numberOfRuns 是外部循环计数器,并且在 CPU 上为每个循环更新它会导致 "false sharing"(因此每次更新计数器时,另一个 CPU 必须刷新该缓存行)。

运行 这个在 2 核 SMP 系统上的性能是单个 CPU 的 30%。所以比 CPU 慢 3 倍,而不是像您期望的那样快。 (这是大约 12 年前的事了,所以在确切的细节上记忆可能有点 "off",但这个故事的本质仍然是真实的 - 一个写得不好的应用程序可以 运行 在多核上变慢与单核相比)。

我希望至少在现代系统上表现不佳,因为您错误地共享了常用变量。

相比之下,如果 CPU 核心之间几乎没有或没有共享,那么编写良好的代码应该 运行 快近 N 倍。我有一个高度 CPU 绑定的多线程计算器 weird numbers,它使我在家中的单路系统和工作中的双路系统的性能提高近 n 倍。

$ time ./weird -t 1 -e 100000

real    0m22.641s
user    0m22.660s
sys 0m0.003s

$ time ./weird -t 6 -e 100000

real    0m5.096s
user    0m25.333s
sys 0m0.005s

大约 11% 的开销。那就是共享一个变量 [current number],它在线程之间自动更新(使用 C++ 标准原子)。不幸的是,我没有 "badly written code" 的好例子来与之对比。