【问题标题】:OpenMP and cores/threadsOpenMP 和内核/线程
【发布时间】:2012-02-15 11:07:55
【问题描述】:

我的 CPU 是具有 2 个内核和 4 个线程的 Core i3 330M。当我在终端中执行命令 cat /proc/cpuinfo 时,就像我有 4 个 CPUS。当我使用 OpenMP 函数 get_omp_num_procs() 时,我也得到 4。

现在我有一个标准的 C++ 向量类,我的意思是一个不使用表达式模板的固定大小的双精度数组类。我已经仔细地并行化了我班级的所有方法,并且得到了“预期的”加速。

问题是:在这种简单的情况下,我能猜出预期的加速吗?例如,如果我在没有并行化 for 循环的情况下添加两个向量,我会得到一些时间(使用 shell time 命令)。现在,如果我使用 OpenMP,我应该根据核心/线程数得到一个时间除以 2 还是 4?我强调我只是在问这个特别简单的问题,数据中没有相互依赖,一切都是线性的(向量加法)。

这里有一些代码:

Vector Vector::operator+(const Vector& rhs) const
{
    assert(m_size == rhs.m_size);
    Vector result(m_size);
    #pragma omp parallel for schedule(static)
    for (unsigned int i = 0; i < m_size; i++) 
            result.m_data[i] = m_data[i]+rhs.m_data[i];

    return result;
}

我已经阅读了这篇文章:OpenMP thread mapping to physical cores

我希望有人能告诉我更多关于 OpenMP 如何在这个简单的案例中完成工作的信息。我应该说我是并行计算的初学者。

谢谢!

【问题讨论】:

    标签: c++ parallel-processing cpu openmp memory-bandwidth


    【解决方案1】:

    编辑:现在已经添加了一些代码。

    在那个特定的示例中,计算量很少,内存访问量很大。所以性能在很大程度上取决于:

    • 矢量的大小。
    • 你是如何计时的。 (是否有用于计时目的的外循环)
    • 数据是否已经在缓存中。

    对于较大的矢量大小,您可能会发现性能受到内存带宽的限制。在这种情况下,并行性不会有太大帮助。对于较小的尺寸,线程的开销将占主导地位。如果您获得了“预期”的加速,那么您可能处于最佳结果之间。

    我拒绝给出确切的数字,因为一般来说,“猜测”性能,尤其是在多线程应用程序中,是一个失败的原因,除非您事先拥有测试知识或对程序和运行它的系统有深入了解。

    就像我在这里的回答中的一个简单示例:How to get 100% CPU usage from a C program

    在 Core i7 920 @ 3.5 GHz(4 核,8 线程)上:

    如果我用 4 个线程 运行,结果是:

    This machine calculated all 78498 prime numbers under 1000000 in 39.3498 seconds
    

    如果我使用 4 个线程 并明确地(使用任务管理器)将线程固定在 4 个不同的物理内核上,结果是:

    This machine calculated all 78498 prime numbers under 1000000 in 30.4429 seconds
    

    因此,这表明即使是非常简单且令人尴尬的并行应用程序也是如此不可预测。涉及大量内存使用和同步的应用程序变得更加丑陋...

    【讨论】:

      【解决方案2】:

      添加到神秘主义者的答案。您的问题纯粹是内存带宽受限。看看STREAM benchmark。在单线程和多线程情况下在您的计算机上运行它,并查看 Triad 结果 - 这是您的情况(嗯,几乎,因为您的输出向量同时是您的输入向量之一)。计算您移动了多少数据,您将确切知道预期的性能。

      多线程可以解决这个问题吗?是的。很少有单个 CPU 内核可以使系统的整个内存带宽饱和。现代计算机平衡了可用内存带宽和可用内核数量。根据我的经验,您将需要大约一半的内核来通过简单的 memcopy 操作使内存带宽饱和。如果您在途中进行一些计算,可能需要更多时间。

      请注意,在 NUMA 系统上,您需要将线程绑定到 cpu 内核并使用本地内存分配来获得最佳结果。这是因为在这样的系统上,每个 CPU 都有自己的本地内存,访问速度最快。您仍然可以像在通常的 SMP 上一样访问整个系统内存,但这会产生通信成本 - CPU 必须明确地交换数据。将线程绑定到 CPU 并使用本地分配非常重要。不这样做会破坏可伸缩性。如果您想在 Linux 上执行此操作,请检查 libnuma。

      【讨论】:

        猜你喜欢
        • 2023-04-03
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-29
        • 2016-04-23
        • 1970-01-01
        • 2016-04-13
        相关资源
        最近更新 更多