【问题标题】:8 logical threads at 4 cores will at a maximum run 4 times faster in parallel?4 个核心的 8 个逻辑线程并行运行的速度最高会快 4 倍吗?
【发布时间】:2012-05-01 19:35:52
【问题描述】:

我正在使用我的所有 8 个“逻辑”线程在 Intel 2670QM 上执行比我的串行版本快 4 倍的基准测试软件。我想就我对基准测试结果的看法获得一些社区反馈。

当我在 4 个内核上使用 4 个线程时,我的速度提高了 4 倍,整个算法是并行执行的。这对我来说似乎是合乎逻辑的,因为“阿姆达尔定律”预测了这一点。 Windows 任务管理器告诉我我正在使用 50% 的 CPU。

但是,如果我在所有 8 个线程上执行相同的软件,我将再次获得 4 倍的加速,而不是 8 倍的加速。

如果我理解正确的话:我的 CPU 有 4 个内核,频率分别为 2.2GHZ,但是当应用于 8 个“逻辑”线程时,频率分为 1.1GHZ,其余组件也一样,例如高速缓存?如果这是真的,那为什么任务管理器声称我的 CPU 只使用了 50%?

#define NumberOfFiles 8
...
char startLetter ='a';
#pragma omp parallel for shared(startLetter)
for(int f=0; f<NumberOfFiles; f++){
    ...
}

我不包括使用磁盘 I/O 的时间。我只对 STL 调用所需的时间(STL 排序)感兴趣,而不是磁盘 I/O。

【问题讨论】:

  • 根据我的经验,4 核意味着您可以同时做 4 件事而不受惩罚。 8 个线程只是意味着两个线程共享一个内核(假设它们是均匀分布的),因此除非您的代码内置了一些并行性,否则您可能看不到 threads == cores 以上的任何速度提升。您的结果还取决于您的算法是受处理器限制还是受 I/O 限制。总之,事情没有你想的那么简单。
  • 在某些硬件上,每个线程都有一些处理器单元的多个实例,但不是全部(例如只有一个 FPU)。取决于硬件,尽管额外的“线程”将比在更大的可运行进程集之间进行上下文切换更便宜(您不必在每次切换时都复制所有状态)。

标签: multithreading openmp multicore hyperthreading


【解决方案1】:

i7-2670QM 处理器有 4 个内核。但它可以并行运行 8 个线程。 这意味着它只有 4 个处理单元(核心),但硬件支持并行运行 8 个线程。这意味着在核心上最多运行四个作业,如果其中一个作业由于例如内存访问而停止,另一个线程可以非常快速地开始在空闲核心上执行而几乎没有损失。 Read more on Hyper threading。在现实中,很少有超线程能够大幅提升性能的场景。更现代的处理器比旧处理器更好地处理超线程。

您的基准测试表明它受 CPU 限制,即管道中几乎没有停顿,这会给超线程带来优势。 50% CPU 是正确的,其中 4 个内核正在工作,而额外的 4 个内核没有做任何事情。在 BIOS 中打开超线程,您将看到 100% CPU。

【讨论】:

  • 感谢您的回答,我想我现在对此有了更多的把握:) 尽管在我的 DELL l702.x 的 BIOS 中,我只发现禁用/启用升压可以强制我的频率没有禁用/启用超线程,你认为我应该再看看吗?
  • 在 BIOS 中可能被称为“intel ht 技术”。不确定您是否可以在戴尔 1702x 上更改它(戴尔网站上一无所获)
  • 英特尔超线程只是开关机停止。它实际上在核心上混合了来自两个逻辑线程的指令,因此即使两个线程都没有因缓存未命中而停滞,它也可以提高吞吐量,而只是运行具有低 IPC 的代码,避免出现延迟瓶颈。请参阅 lighterra.com/papers/modernmicroprocessorsCan a hyper-threaded processor core execute two threads at the exact same time?。对于单线程已经可以让 ALU 在内核上保持忙碌的高吞吐量代码,您确实不会从 HT 中获得吞吐量。
  • 对于经过良好调整的数字运算代码,与禁用 HT 相比,2 个线程竞争内核上的 L1d / L2 缓存占用空间实际上具有更差 吞吐量的情况并不少见。这就是为什么您的答案与这里的实验数据相匹配,尽管不准确。
【解决方案2】:

这是对超线程的快速总结

线程切换很慢,不得不停止执行,将一堆值复制到内存中,将一堆值从内存中复制到 CPU 中,然后用新线程重新开始。

这就是你的 4 个虚拟内核的用武之地。你有 4 个内核,就是这样,但超线程允许 CPU 做的是在一个内核上有 2 个线程。

一次只能执行 1 个线程,但是当 1 个线程需要停止执行内存访问、磁盘访问或其他需要一些时间的操作时,它可以切换到另一个线程并运行一段时间少量。在旧处理器上,他们这段时间基本上睡了一会儿。

所以你的四核有 4 个核,每个核一次可以做一件事,但当他们需要在计算机的另一部分等待时,可以有第二个工作待命。

如果您的任务占用大量内存和大量 CPU,您应该会看到总执行时间略有减少,但如果您几乎完全受 CPU 限制,则最好坚持使用 4 个线程

【讨论】:

  • HyperTransport 与超线程完全无关(英特尔对SMT 的实现)。它是 AMD 在物理 CPU 内核之间的互连。他们只是碰巧在名字中都有“hyper”,因为它听起来很快。
【解决方案3】:

这里要理解的重要信息是物理线程和逻辑线程之间的区别。
如果您的 CPU 上有 4 个物理内核,这意味着您有物理资源可以并行执行 4 个不同的执行线程。因此,如果您的线程没有数据争用,与单线程的速度相比,您通常可以测量出 x4 的性能提升。
我还假设操作系统(或您:))正确设置了线程关联,因此每个线程都在每个物理核心上运行。
当您在 CPU 上启用 HT(超线程)时,核心频率不会被修改。 :)
发生的情况是硬件管道的部分(在核心内部和周围(非核心、缓存等))被复制,但其中一部分仍然在逻辑线程之间共享。 这就是您不测量 x8 性能提升的原因。根据我启用所有逻辑核心的经验,您可以获得每个物理核心 x1.5 - x1.7 的性能提升,具体取决于您正在执行的代码、缓存使用情况(请记住,L1 缓存在两个逻辑核心/1 个物理核心之间共享,例如)、线程亲和性等等。 希望这会有所帮助。

【讨论】:

  • 我的代码使用一百万个元素/向量的 std::sort() 对向量进行排序,你能猜一下超线程会在那里给我买多少吗?
  • 老实说我不是,对此感到抱歉。很难猜测这种改进,因为正如我所说,影响最终性能的因素很多。基准测试永远是最好的方法。 (但请确保您在 BIOS 中启用了 HT,正如 Nys 所记得的那样)
【解决方案4】:

HT 在大多数 BIOS 中称为 SMT(同时多线程)或 HTT(超线程技术)。 HT 的效率取决于所谓的计算与获取比率,即您的代码在从慢速主内存或 I/O 内存中获取或存储之前执行了多少内核(或寄存器/缓存)操作。对于高速缓存效率和 CPU 密集型代码,HT 几乎没有提供明显的性能提升。对于更多的内存绑定代码,由于所谓的“延迟隐藏”,HT 可以真正有利于执行。这就是为什么大多数非 x86 服务器 CPU 为每个内核提供 4 个(例如 IBM POWER7)到 8 个(例如 UltraSPARC T4)硬件线程。这些 CPU 通常用于数据库和事务处理系统,在这些系统中一次处理许多并发的内存绑定请求。

顺便说一下,Amdhal 定律指出并行加速的上限是代码串行分数的 1 倍。通常,如果线程之间存在(可能隐藏在运行时中的)通信或其他同步,则串行部分会随着处理元素的数量而增加,尽管有时缓存效果会导致超线性加速,有时缓存垃圾会大大降低性能。

【讨论】:

    【解决方案5】:

    一些实际数字:

    我的 i7 上的 CPU 密集型任务(将 1-1000000000 的数字添加到 int var 中,16 次),平均超过 8 次测试:

    总结,线程/滴答声:

    1/26414
    4/8923
    8/6659
    12/6592
    16/6719
    64/6811
    128/6778
    

    请注意,在下面报告中的“使用 X 线程”行中,X 比可用于执行任务的线程数大一 - 一个线程提交任务并等待倒计时锁存器 evnet 完成 -它不处理任何 CPU 密集型任务,也不使用 CPU。

    8 tests,
    16 tasks,
    counting to 1000000000,
    using 2 threads:
    Ticks: 26286
    Ticks: 26380
    Ticks: 26317
    Ticks: 26474
    Ticks: 26442
    Ticks: 26426
    Ticks: 26474
    Ticks: 26520
    Average: 26414 ms
    
    8 tests,
    16 tasks,
    counting to 1000000000,
    using 5 threads:
    Ticks: 8799
    Ticks: 9157
    Ticks: 8829
    Ticks: 9002
    Ticks: 9173
    Ticks: 8720
    Ticks: 8830
    Ticks: 8876
    Average: 8923 ms
    
    8 tests,
    16 tasks,
    counting to 1000000000,
    using 9 threads:
    Ticks: 6615
    Ticks: 6583
    Ticks: 6630
    Ticks: 6599
    Ticks: 6521
    Ticks: 6895
    Ticks: 6848
    Ticks: 6583
    Average: 6659 ms
    
    8 tests,
    16 tasks,
    counting to 1000000000,
    using 13 threads:
    Ticks: 6661
    Ticks: 6599
    Ticks: 6552
    Ticks: 6630
    Ticks: 6583
    Ticks: 6583
    Ticks: 6568
    Ticks: 6567
    Average: 6592 ms
    
    8 tests,
    16 tasks,
    counting to 1000000000,
    using 17 threads:
    Ticks: 6739
    Ticks: 6864
    Ticks: 6599
    Ticks: 6693
    Ticks: 6676
    Ticks: 6864
    Ticks: 6646
    Ticks: 6677
    Average: 6719 ms
    
    8 tests,
    16 tasks,
    counting to 1000000000,
    using 65 threads:
    Ticks: 7223
    Ticks: 6552
    Ticks: 6879
    Ticks: 6677
    Ticks: 6833
    Ticks: 6786
    Ticks: 6739
    Ticks: 6802
    Average: 6811 ms
    
    8 tests,
    16 tasks,
    counting to 1000000000,
    using 129 threads:
    Ticks: 6771
    Ticks: 6677
    Ticks: 6755
    Ticks: 6692
    Ticks: 6864
    Ticks: 6817
    Ticks: 6849
    Ticks: 6801
    Average: 6778 ms
    

    【讨论】:

    • Nice post thx hehe :) 在划分你的 4 线程和 8 线程测试时,我得到大约 1.34 倍,如果我理解正确的话,这就是 HT 比常规 4 核额外提供的东西?
    • 我想是的,是的。 'add-up-numbers' CPU 密集型任务不会占用太多缓存,所以我猜这些数字有点“人为”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-04
    • 1970-01-01
    • 2019-10-17
    相关资源
    最近更新 更多