【问题标题】:Program (source provided) takes twice as long to run on Ivy Bridge Xeon than older mobile Sandy Bridge程序(提供的来源)在 Ivy Bridge Xeon 上运行的时间是旧款移动 Sandy Bridge 的两倍
【发布时间】:2015-04-11 03:45:43
【问题描述】:

我有两台计算机正在尝试运行相同的程序。尽管该程序在系统 B 上的运行速度至少应该快一点,但实际上它在系统 A 上的速度是原来的两倍(或更好)。这对我来说毫无意义,如果有人能帮我弄清楚在世界正在导致这个奇怪的性能问题。我添加了第三个系统作为健全性检查,现在我更加困惑了。

系统A:

  • 2011 款配备 Sandy Bridge CPU 的 MacBook Pro
  • Intel(R) Core(TM) i7-2820QM CPU @ 2.30GHz
  • 英特尔功率计报告它在运行程序时以 3.1GHz 运行
  • 编译器为 clang++:Apple LLVM 版本 6.0 (clang-600.0.57)(基于 LLVM 3.5svn)

系统B:

  • 2-sockets, 12 cores/socket Ivy Bridge Xeon 服务器于 2013 年购买
  • Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz
  • turbostat 报告一个内核在运行程序时以 3.5GHz 运行
  • 编译器为 clang++:Ubuntu clang 版本 3.5-1ubuntu1(主干)(基于 LLVM 3.5)

系统 C:

  • 四核 Haswell Core i5
  • Intel(R) Core(TM) i5-4430 CPU @ 3.00GHz
  • turbostat 报告内核的最大输出频率为 3.2GHz
  • 编译器是 clang++:clang 版本 3.5.1 (tags/RELEASE_351/final)

您可以在以下位置找到该程序的源代码:http://www.cs.binghamton.edu/~millerti/test.tgz

我在两个系统上使用的编译器命令行如下:

  • 标量版本:clang++ -O3 -msse3 x.c 3_22_1b.c
  • 矢量版:clang++ -O3 -msse3 x.c 3_22_1.c

这有两件相当奇怪的事情。一是标量版本比向量版本稍快。但真正巨大的问题是,该程序在服务器(系统 B)上运行的时间是在笔记本电脑(系统 A)上运行时间的两倍多。

在系统 A 上:

$ time ./a.out
real    0m22.908s
user    0m22.853s
sys 0m0.038s

在系统 B 上:

$ time ./a.out
real    0m55.354s
user    0m55.310s
sys     0m0.000s

在系统 C 上:

$ time ./a.out
real    0m42.421s
user    0m42.400s
sys     0m0.000s

其他事实:

  • Sandy Bridge 和 Ivy Bridge 具有相同数量的 L1 缓存(总共 64KB)。实际上,Haswell 也是如此。
  • 系统 B 的二级缓存比其他系统多得多
  • 可执行文件非常小,至少应该大部分适合 L1I 缓存
  • 数据量为176个浮点数,所以L1D缓存命中率应该在100%左右
  • IVB 和 SB 微架构非常相似,差异大多有利于 IVB
  • 所有系统正在运行,否则将被卸载。笔记本(系统 A)确实有最少的其他东西。服务器(系统 B)和 Haswell(系统 C)完全卸载。没有其他用户或任何东西。
  • top 显示程序在所有系统中获得 100% CPU。 iotop 显示在此期间服务器上没有进行任何 I/O。
  • 在任何情况下,与 clang 相比,使用 g++ 并没有太大区别。
  • 作为参考,我添加了 Haswell,但它并没有照亮任何东西。这比 Ivy Bridge 快很多,但比 Sandy Bridge 慢,这毫无意义。
  • 操作系统不可能对这里产生任何影响,Apple 也不可能在他们没有共享的 LLVM 编译器中使用某种魔法来让程序运行得更快。
  • 我确实尝试过对 tanh 进行基准测试。事实证明,它在 MacOS X 上的速度大约是 Linux 的两倍。 1 亿次调用 tanh 在系统 A (Mac) 上需要 1.484 秒,而在系统 C (Haswell) 上需要 3.380 秒,在系统 B (IVB 服务器) 上需要 3.392 秒。但是,我做过 profiling,tanh 只占总运行时间的 35% 左右,因此无法解释整个性能差异。
  • -ffast-math 没有帮助。
  • 我正在 Mac 上的 VM 中安装 Linux。我将在 Mac 上的 Linux 上运行相同的代码,看看 glibc 的慢速数学有多少以及 CPU 有多少。 (因为这是计算密集型的,所以虚拟化无关紧要。)我稍后会添加结果。

【问题讨论】:

  • 我在 Mac 上的 Ubuntu VM 中运行它。大约花了65秒。但是,Parallels 与 Ubuntu 14.10 相处得并不融洽,所以这并不是非常有用。

标签: linux macos performance x86-64


【解决方案1】:

结果证明完全是tanh。由于分析开销,分析没有揭示这一点。我不知道为什么我昨晚没有想到这个,但是今天早上,我注释掉了 tanh,这就是我得到的:

系统A:

$ time ./a.out
real    0m4.443s
user    0m4.433s
sys 0m0.008s

系统B:

$ time ./a.out
real    0m3.373s
user    0m3.368s
sys     0m0.003s

系统 C:

$ time ./a.out
real    0m4.054s
user    0m4.050s
sys     0m0.000s

这些数字都很有意义。所以结论是 tanh 的 Linux 实现真的很糟糕。我必须自己实现或从 BSD libc 中获取 tanh 源代码。

【讨论】:

  • 使用-march= 选项查看结果会很有趣。理想情况下,您会以这种方式构建 libclibm
  • 差别不大。我在所有系统上添加了 -march=native。在系统 A (mac) 上,它是 22.4 秒。在系统 B (ivb) 上,它是 54.4 秒。在 System C (haswell) 上,它是 41.9s。结论是 Haswell 在架构上比 IVB 有一些优势,但是 Linux 的 tanh 很烂,所以 Mac 更快。与分析所说的相反,tanh 完全控制了运行时间。
  • Google 对 glibc 数学性能提出了一些建议。 news.ycombinator.com/item?id=8828936。显然 glibc 很慢,因为要确保所有内容都完美地四舍五入。我只是单步执行tanh 代码,它将浮点数移动到一个 int 寄存器,并进行大量比较和位测试。
【解决方案2】:

您需要检查程序集列表。一个编译器可能会生成 SISD 指令,而另一个编译器可能会生成 mulss xmm0、xmm7 而不是 mulps xmm0、xmm7,后者可以快四倍(在相同的 CPU GHz 下)。然后有AVX指令可以尝试。

您描述的问题通常是由较旧的编译器生成的最慢引起的,或者在我的情况下,使用最新的免费 Microsoft 编译器与最新的 GCC for Linux 相比,后者产生了更好的实现。

【讨论】:

    猜你喜欢
    • 2016-11-25
    • 1970-01-01
    • 2013-09-27
    • 2012-08-15
    • 2014-04-04
    • 2012-07-01
    • 2021-05-21
    • 2017-03-31
    • 1970-01-01
    相关资源
    最近更新 更多