并行化和矢量化性能瓶颈:AVX 和 MT 竞争吗?
Paralellization vs vectorization performance bottlenec: Does AVX and MT compete?
我试图计算一个大矩阵中所有元素的总和。以下是测试用例:
- MT 和 AVX 需要 37 秒
- MT 且无 AVX 需要 40 秒
- AVX 且无 MT 需要 49 秒
- 既不是 AVX 也不是 MT 105 s
在所有情况下,CPU 时钟固定为 3.0 GHz(由 cpufreq-info 声明):
current policy: frequency should be within 1.60 GHz and 3.40 GHz.
The governor "userspace" may decide which speed to use
within this range.
current CPU frequency is 3.00 GHz.
矩阵有 25000000 个类型为 double
且值为 1.0 的元素。并且在循环中重复计算总和 4096 次。在没有 AVX 的情况下,使用 MT 时速度提高了 2.6。对于 AVX,它只有 1.3。当运行 MT时,矩阵被分成4块,每个线程一个。如果我降低 CPU 频率,AVX 的 MT 改进更大,因此缓存未命中也可能存在一些问题,但这不能解释 (4)/(2) 和 (3)/( 1). AVX 和 MT 是否在某种程度上相互竞争?芯片是i3570K.
您的基准性能很可能受到执行延迟的限制,但是任何一种形式的并行化(MT 或矢量化)都可以让您打破它并达到下一个瓶颈,即您 CPU 的内存 BW .
检查您的 CPU 可以达到的峰值带宽并与您的数据进行比较,看起来您只是以 20.5GB/s 的速度饱和(25000000 个元素 * 4096 个循环 * 8 字节,假设这是您的系统使用的double / ~40 秒),这似乎有点低,因为 link 说它应该达到 25GB/s,但大致相同,所以这可能是由于其他低效率,如 DDR 类型、其他应用 / OS 在后台工作,由 CPU 完成频率缩放以节省电力/减少热量等。
您也可以尝试 运行 一些内存基准测试(lmbench、sandra 等),看看它们在相同环境下是否表现更好。
MT不应该和MT竞争,它们是两个不同的东西。虽然求和的想法很简单,但根据您的实现,您可以获得非常不同的数字。我建议您使用 Stream benchmarks 来测试性能,因为它们是标准的。我没有看到您的代码,但存在一些问题:
- 您正在用 1.0 为所有元素初始化矩阵。我认为这不是一个好主意。您应该使用随机数或至少根据索引进行初始化(例如 (i%10)/10.0)。
- 你如何衡量时间?您应该将计时器放在重复循环之外,并取重复次数的平均值。你也使用准确的计时器吗?
- 您确定您的代码实际上是矢量化的吗?您是否启用了任何编译器标志来显示此信息?您确定使用了代码的 AVX 版本吗?也许编译器选择使用标量版本。
- 你提到频率是固定的,你确定在任何时候都没有启用涡轮模式吗?
- 使用 MT 测量时线程亲和性如何?
我试图计算一个大矩阵中所有元素的总和。以下是测试用例:
- MT 和 AVX 需要 37 秒
- MT 且无 AVX 需要 40 秒
- AVX 且无 MT 需要 49 秒
- 既不是 AVX 也不是 MT 105 s
在所有情况下,CPU 时钟固定为 3.0 GHz(由 cpufreq-info 声明):
current policy: frequency should be within 1.60 GHz and 3.40 GHz.
The governor "userspace" may decide which speed to use
within this range.
current CPU frequency is 3.00 GHz.
矩阵有 25000000 个类型为 double
且值为 1.0 的元素。并且在循环中重复计算总和 4096 次。在没有 AVX 的情况下,使用 MT 时速度提高了 2.6。对于 AVX,它只有 1.3。当运行 MT时,矩阵被分成4块,每个线程一个。如果我降低 CPU 频率,AVX 的 MT 改进更大,因此缓存未命中也可能存在一些问题,但这不能解释 (4)/(2) 和 (3)/( 1). AVX 和 MT 是否在某种程度上相互竞争?芯片是i3570K.
您的基准性能很可能受到执行延迟的限制,但是任何一种形式的并行化(MT 或矢量化)都可以让您打破它并达到下一个瓶颈,即您 CPU 的内存 BW .
检查您的 CPU 可以达到的峰值带宽并与您的数据进行比较,看起来您只是以 20.5GB/s 的速度饱和(25000000 个元素 * 4096 个循环 * 8 字节,假设这是您的系统使用的double / ~40 秒),这似乎有点低,因为 link 说它应该达到 25GB/s,但大致相同,所以这可能是由于其他低效率,如 DDR 类型、其他应用 / OS 在后台工作,由 CPU 完成频率缩放以节省电力/减少热量等。
您也可以尝试 运行 一些内存基准测试(lmbench、sandra 等),看看它们在相同环境下是否表现更好。
MT不应该和MT竞争,它们是两个不同的东西。虽然求和的想法很简单,但根据您的实现,您可以获得非常不同的数字。我建议您使用 Stream benchmarks 来测试性能,因为它们是标准的。我没有看到您的代码,但存在一些问题:
- 您正在用 1.0 为所有元素初始化矩阵。我认为这不是一个好主意。您应该使用随机数或至少根据索引进行初始化(例如 (i%10)/10.0)。
- 你如何衡量时间?您应该将计时器放在重复循环之外,并取重复次数的平均值。你也使用准确的计时器吗?
- 您确定您的代码实际上是矢量化的吗?您是否启用了任何编译器标志来显示此信息?您确定使用了代码的 AVX 版本吗?也许编译器选择使用标量版本。
- 你提到频率是固定的,你确定在任何时候都没有启用涡轮模式吗?
- 使用 MT 测量时线程亲和性如何?