程序(提供的来源)在 Ivy Bridge Xeon 上运行的时间是旧款移动 Sandy Bridge 的两倍

Posted

技术标签:

【中文标题】程序(提供的来源)在 Ivy Bridge Xeon 上运行的时间是旧款移动 Sandy Bridge 的两倍【英文标题】:Program (source provided) takes twice as long to run on Ivy Bridge Xeon than older mobile 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 相处得并不融洽,所以这并不是非常有用。 【参考方案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 相比,后者产生了更好的实现。

【讨论】:

以上是关于程序(提供的来源)在 Ivy Bridge Xeon 上运行的时间是旧款移动 Sandy Bridge 的两倍的主要内容,如果未能解决你的问题,请参考以下文章

Apache Ivy:解决嵌入在安装程序中的依赖项

提供的 Ivy 依赖项

Maven 范围如何通过 ivy 映射到 ivy 配置

__bridge,__bridge_transfer和__bridge_retained的使用和区别转载

iOS开发之__bridge,__bridge_transfer和__bridge_retained

什么是常春藤?它与蚂蚁有什么关系?