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

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

本文关键字:应用程序 速度 任意 延迟 情况下 最坏 多少 QPI      更新时间:2023-10-16

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

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

HFT需要大量的资源,现在我意识到我想要更多的核心。此外,两台1U单CPU机器的主机代管比一台1U双CPU机器的成本高得多,因此即使假设我可以将程序"拆分"为两台,使用1U双CPU机器仍然是有意义的。

那么QPI/NUMA延迟有多可怕呢?如果我把我的应用程序从单CPU机器移到双CPU机器,它会慢多少?我最多可以承受几微秒的延迟,但不能超过。如果调谐不正确,QPI/Numa是否会引入显著的延迟,以及该延迟的严重程度?

有没有可能编写这样的应用程序,它在双CPU设置上比单CPU设置运行得慢得多(慢几微秒以上)?I.e在速度更快的电脑上运行得慢得多?(当然,假设我们有相同的处理器、内存、网卡和其他一切)

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

代码主要是读、写还是大致相等?在单独的CPU上运行的线程之间共享了多少数据?写入此类数据的频率是多少,从而强制刷新缓存?

任务是如何安排的,操作系统如何以及何时决定将线程从一个CPU插槽移动到下一个CPU插座?

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

这些只是将在"效果非常好"answers"表现非常差"之间显著改变结果的几个因素。

与所有与性能相关的事情一样,细节可能会产生巨大的影响,在互联网上阅读这样的答案不会给你一个适用于你的情况的可靠答案。对您的应用程序进行基准测试,检查性能计数器并在此基础上进行调整。[考虑到你在上面评论中描述的规格的机器的价格,我希望供应商会允许进行某种测试、演示、"先试后买"等]。

假设您有一个最坏的情况,内存访问将跨越两条缓存线(例如,8字节值的未对齐访问),这两条缓存在位置最差的CPU之间进行分配,MMU需要重新加载,这些页表条目中的每一个也都在可能最坏的CPU中,并且由于这对内存位置的内存位于不同的位置,两次4字节读取中的每一次都需要新的TLB条目来加载您的64位值。(每个TLB条目都是一个单独的位置)。

这意味着2 x 4 x n,其中n大约是50-100 ns。因此,至少在理论上,一次内存访问可能需要1600纳秒。所以是1.6微秒。你不太可能因为一次手术而变得更糟。与交换到磁盘相比,开销要小得多,这可能会增加几毫秒的执行时间。

编写在多个CPU上更新同一缓存行的代码并不困难,因此会导致性能大幅下降——我记得很久以前我第一次让Athlon SMP系统运行一个简单的基准测试时,作者为Dhrystone基准做了这件事

int numberOfRuns[MAX_CPUS];

现在,numberOfRuns是外循环计数器,在任何一个CPU上更新每个循环的计数器都会导致"错误共享"(因此每次更新计数器时,另一个CPU都必须刷新该缓存行)。

在2核SMP系统上运行此程序可获得单CPU性能的30%。所以比一个CPU慢3倍,而不是你所期望的更快。(这是大约12年前的事了,所以内存可能对确切的细节有点"偏离",但这个故事的本质仍然是真实的——与单核相比,一个写得不好的应用程序在多核上运行速度可能会较慢)。

我预计,在一个对常用变量进行错误共享的现代系统中,至少会有这种糟糕的性能。

相比之下,如果CPU内核之间很少或根本没有共享,那么写得好的代码运行速度应该快近N倍。我有一个CPU高度受限、多线程的奇怪数字计算器,它在家里的单插槽系统和工作中的双插槽系统上都能获得接近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%的开销。这就是共享一个变量[当前数],该变量在线程之间进行原子更新(使用C++标准原子)。不幸的是,我没有一个"写得不好的代码"的好例子来对比这一点。