什么会导致软件在更好的硬件上 运行 变慢?

What Could Cause Software to Run Slower on Better Hardware?

我在 RHEL 7.4 上有一个 Java OSGi (Apache Felix) 应用程序 运行,它以 ~975 packets/second(长度为 1038 个八位字节)读取多播 UDP。然后它将数据转换为 XML,模拟跨越边界设备,并将其转换回 UDP 多播数据包。涉及多个线程,它的编写方式是如果模拟边界设备需要一段时间来处理一个有效载荷,它会缓冲它并在下一次发送更大的有效载荷。

通过此集成测试场景查看数据包延迟时,两台不同的桌面级机器明显快于我们期望部署的相当高端的服务器。

我只提到硬盘驱动器是为了完整性,因为此应用程序不写入磁盘。从理论上讲,服务器的运行速度至少应与两个台式机一样快。

我已经消除的东西:

ark.intel.com processor comparison

这里有两个示例图来说明这个问题。该测试在 4 分 10 秒内向多播地址 A 发送 260,960 个 UDP 数据包,在通过应用程序处理后,数据包被发送到多播地址 B。tcpdump 记录两者的时间戳,减法产生延迟。所有三个应用程序(发件人、应用程序、tcpdump 在同一台机器上)。

首先针对虚拟接口的服务器硬件

i7 桌面硬件对虚拟接口

注意 Y 轴比例差异。服务器是0-4秒,i7桌面是0-1秒。看起来难以阅读的 X 轴是数据包编号。

下次尝试

我是 运行 应用程序的本地集成版本。然后,我消除了应用程序开始完成的几乎 100% 的工作,并发现服务器硬件上的延迟越来越长。然后我尝试 -Xmx100G -Xms100G 基本上让垃圾收集器远离 运行 EVER 并看到以下结果(< 1 秒一致延迟)。

这导致我 Java 8's Available Garbage Collectors

服务器硬件上的默认垃圾收集器select 是新的:ParallelScavenge,旧的:ParallelOld。这是没有 XML 转换的结果延迟图,尽可能简单的测试来重现问题。

明确 select 垃圾优先垃圾收集器 -XX:+UseG1GC select编辑新的:G1New,旧的:G1Old,它产生的延迟图不是很好:

显式 select 并发标记清除垃圾收集器 -XX:+UseConcMarkSweepGC selected New: ParNew, Old: ConcurrentMarkSweep 其生成的延迟图看起来非常好:

看来问题已经解决了。将所有组件添加回原位后,我仍然遇到无法接受的延迟。我仍在 运行 测试以查看是否可以隔离问题。

Strace 结果

尝试 strace -c -o /path/to/file -f 产生了以下顶级系统调用

首先是 i7 的桌面 strace 报告(截断前 10 项)

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 93.71 1418.604132         959   1479659    134352 futex
  1.74   26.294223      730395        36           poll
  1.74   26.288786         314     83645         4 read
  1.41   21.373672          73    293618           epoll_pwait
  1.19   17.952475         120    149854         2 recvfrom
  0.10    1.448453           2    909731           getrusage
  0.06    0.896903           3    281407           sendto
  0.03    0.394695           2    198041           write
  0.01    0.182809          10     18246           mmap
  0.01    0.120735           6     20582           sched_yield

现在服务器的 strace 报告:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.46 2119.311196        2642    802183    131276 futex
  1.28   27.734136     6933534         4           poll
  0.59   12.840448          49    263597           epoll_wait
  0.41    8.885742         113     78387         2 recvfrom
  0.07    1.575401           6    263671           sendto
  0.07    1.515999           6    262256           epoll_ctl
  0.04    0.902788          54     16800           sched_yield
  0.03    0.743231          10     75455           write
  0.02    0.490052           6     84509         7 read
  0.01    0.170152           4     42732           lseek

我不清楚我应该从中得出什么结论。在 futexpoll 系统调用中,桌面都快很多倍。我仍然不明白为什么应用程序在更快的硬件上潜伏得更多。

分析

我已经分析了两种硬件上的软件,显示了相似的热点位置,这似乎排除了这种可能性。

我确认我在 RedHat 中使用 performance CPU 调控器:CPUfreq Coverners

我 运行 VMWare ESXi 报告有问题的 BIOS 设置 Virtual Machine Application runs slower than expected on EXSi

直接指向我的答案。此 Dell R630 的默认设置为 "Performance Per Watt (DAPC)"(DAPC:Dell Active Power Controller)。切换到 "Performance" 完全解决了这个问题。这台机器在控制台上感觉更加敏捷,并且延迟比桌面能够实现的延迟低得多,这是我预期的 CPU 差异。

在戴尔 R630(可能还有其他)启动时更改 BIOS 的步骤:

  1. F2 进入系统设置
  2. Select "System BIOS"
  3. Select "System Profile Settings"
  4. 确保第一个条目设置为 "Performance" 默认为 "Performance Per Watt"
  5. Select "Back"
  6. Select "Finish"
  7. Select "Yes" 在系统重置时保存更改
  8. Select "OK" 设置保存成功

这是生成的延迟图,它们使用相同的 1 秒刻度。

服务器上的默认 GC:

服务器上的并发标记清除 GC:

服务器上的第一代 GC:

G1GC 和 CMSGC 之间没有太大区别,但两者的延迟明显优于默认值(这是预期的)。

逻辑核心时钟速度图

符号很难看清,但这两个图上有32个不同的点。总体而言,您可以快速分辨出哪个是性能,哪个是 performance-per-watt-dapc.

每瓦性能 (DAPC):

性能

一起绘制。红色子弹中的性能,蓝色空心圆中的每瓦性能

这是在 300 秒的数据流中捕获的,并相应地设置了 BIOS。以下是我捕获数据的方式,以防有人想知道:

for i in `seq 300`; do
  paste /sys/devices/system/cpu/cpu[0-9]*/cpufreq/cpuinfo_cur_freq
  sleep 1
done > performance.log