首页 文章

OpenMP和核心/线程

提问于
浏览
5

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

现在我有一个标准的C矢量类,我的意思是一个不使用表达式模板的固定大小的双数组类 . 我仔细并行化了我 class 的所有方法,并获得了“预期”的加速 .

问题是:在这么简单的情况下,我能猜出预期的加速吗?例如,如果我添加两个没有并行化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如何在这个简单案例中完成工作的信息 . 我应该说我是并行计算的初学者 .

谢谢!

2 回答

  • 3

    EDIT : 现在已经添加了一些代码 .

    在该特定示例中,计算量很少并且存储器访问量很大 . 因此,性能将在很大程度上取决于:

    • 向量的大小 .

    • 你如何计时 . (你有一个外环用于计时)

    • 数据是否已存在于缓存中 .

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

    我拒绝提供硬数字,因为一般来说,“猜测”性能,特别是在多线程应用程序中是一个失败的原因,除非您具有先前的测试知识或对程序及其运行的系统的深入了解 .

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

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

    如果我使用 4 threads 运行,结果是:

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

    如果我使用 4 threads 并显式(使用任务管理器) pin the threads on 4 distinct physical cores 运行,结果是:

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

    所以这表明即使是一个非常简单和令人尴尬的并行应用程序也是多么不可预测 . 涉及大量内存使用和同步的应用程序变得更加丑陋......

  • 1

    添加到Mysticals的答案 . 你的问题纯粹是 memory bandwidth bounded . 看看STREAM benchmark . 在单线程和多线程情况下在您的计算机上运行它,并查看三元组结果 - 这是您的情况(好吧,差不多,因为您的输出向量同时是您的输入向量之一) . 计算您移动的数据量,您将确切知道预期的性能 .

    多线程是否适用于此问题?是 . 单个CPU内核很少能够使系统的整个内存带宽饱和 . 现代计算机 balancer 可用内存带宽与可用内核数量 . 根据我的经验,您需要大约一半的内核才能通过简单的memcopy操作来满足内存带宽 . 如果你在路上做一些计算,可能还需要一些 .

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

相关问题