我已经阅读了有关此主题的其他一些问题。 但是,他们还是没有解决我的问题。

我写的代码如下,我得到的pthread版本和omp版本都比串行版本慢。 我很困惑

在以下环境下编译:

Ubuntu 12.04 64bit 3.2.0-60-generic
g++ (Ubuntu 4.8.1-2ubuntu1~12.04) 4.8.1

CPU(s):                2
On-line CPU(s) list:   0,1
Thread(s) per core:    1
Vendor ID:             AuthenticAMD
CPU family:            18
Model:                 1
Stepping:              0
CPU MHz:               800.000
BogoMIPS:              3593.36
L1d cache:             64K
L1i cache:             64K
L2 cache:              512K
NUMA node0 CPU(s):     0,1

编译命令:

g++ -std=c++11 ./eg001.cpp -fopenmp

#include <cmath>
#include <cstdio>
#include <ctime>
#include <omp.h>
#include <pthread.h>

#define NUM_THREADS 5
const int sizen = 256000000;

struct Data {
    double * pSinTable;
    long tid;
};

void * compute(void * p) {
    Data * pDt = (Data *)p;
    const int start = sizen * pDt->tid/NUM_THREADS;
    const int end = sizen * (pDt->tid + 1)/NUM_THREADS;
    for(int n = start; n < end; ++n) {
        pDt->pSinTable[n] = std::sin(2 * M_PI * n / sizen);
    }
    pthread_exit(nullptr);
}

int main()
{
    double * sinTable = new double[sizen];
    pthread_t threads[NUM_THREADS];
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    clock_t start, finish;

    start = clock();
    int rc;
    Data dt[NUM_THREADS];
    for(int i = 0; i < NUM_THREADS; ++i) {
        dt[i].pSinTable = sinTable;
        dt[i].tid = i;
        rc = pthread_create(&threads[i], &attr, compute, &dt[i]);
    }//for
    pthread_attr_destroy(&attr);
    for(int i = 0; i < NUM_THREADS; ++i) {
        rc = pthread_join(threads[i], nullptr);
    }//for
    finish = clock();
    printf("from pthread: %lf\n", (double)(finish - start)/CLOCKS_PER_SEC);

    delete sinTable;
    sinTable = new double[sizen];

    start = clock();
#   pragma omp parallel for
    for(int n = 0; n < sizen; ++n)
        sinTable[n] = std::sin(2 * M_PI * n / sizen);
    finish = clock();
    printf("from omp: %lf\n", (double)(finish - start)/CLOCKS_PER_SEC);

    delete sinTable;
    sinTable = new double[sizen];

    start = clock();
    for(int n = 0; n < sizen; ++n)
        sinTable[n] = std::sin(2 * M_PI * n / sizen);
    finish = clock();
    printf("from serial: %lf\n", (double)(finish - start)/CLOCKS_PER_SEC);

    delete sinTable;

    pthread_exit(nullptr);
    return 0;
}

输出:

from pthread: 21.150000
from omp: 20.940000
from serial: 20.800000

我想知道这是否是我的代码的问题,所以我用pthread做了同样的事情。

但是,我完全错了,我想知道这是否可能是Ubuntu在OpenMP / pthread上的问题。

我有一个朋友也拥有AMD CPU和Ubuntu 12.04,并且在那里遇到了相同的问题,因此我可能有理由相信该问题不仅限于我。

如果有人和我有相同的问题,或者对这个问题有一些线索,请事先感谢。


如果代码不够好,我会运行一个基准测试并将结果粘贴到此处:

http://pastebin.com/RquLPREc

基准网址: http : //www.cs.kent.edu/~farrell/mc08/lectures/progs/openmp/microBenchmarks/src/download.html


新信息:

我使用VS2012在Windows(无pthread版本)上运行代码。

我使用sizen的1/10,因为Windows不允许我分配很大的内存主干,结果是:

from omp: 1.004
from serial: 1.420
from FreeNickName: 735 (this one is the suggestion improvement by @FreeNickName)

这是否表明这可能是Ubuntu OS的问题?



通过使用可在操作系统之间移植的omp_get_wtime函数来解决问题。 请参阅Hristo Iliev的答案。


FreeNickName对有争议的主题进行了一些测试。

(对不起,我需要在Ubuntu上对其进行测试,因为Windows是我的朋友之一。)

--1--从delete变为delete [] :(但不包括memset)(-std = c ++ 11 -fopenmp)

from pthread: 13.491405
from omp: 13.023099
from serial: 20.665132
from FreeNickName: 12.022501

--2--在新之后立即使用memset:(-std = c ++ 11 -fopenmp)

from pthread: 13.996505
from omp: 13.192444
from serial: 19.882127
from FreeNickName: 12.541723

--3--在新之后立即使用memset:(-std = c ++ 11 -fopenmp -march = native -O2)

from pthread: 11.886978
from omp: 11.351801
from serial: 17.002865
from FreeNickName: 11.198779

--4--在新版本之后立即使用memset,并将FreeNickName的版本放在OMP之前的版本中:(-std = c ++ 11 -fopenmp -march = native -O2)

from pthread: 11.831127
from FreeNickName: 11.571595
from omp: 11.932814
from serial: 16.976979

--5--在新版本之后立即使用memset,并将FreeNickName的版本放在OMP之前的版本中,并将NUM_THREADS设置为5而不是2(我是双核)。

from pthread: 9.451775
from FreeNickName: 9.385366
from omp: 11.854656
from serial: 16.960101

===============>>#1 票数:6 已采纳

您的情况下,OpenMP没错。 错误的是您测量经过时间的方式。

在Linux(以及大多数其他类似Unix的操作系统)上使用clock()衡量多线程应用程序的性能是一个错误,因为它不会返回挂钟(真实)时间,而是所有进程线程(和其他线程)的累计CPU时间。在某些Unix版本上,甚至所有子进程的累积CPU时间)。 您的并行代码在Windows上显示出更好的性能,因为那里的clock()返回的是实时时间,而不是累计的CPU时间。

防止此类差异的最佳方法是使用可移植的OpenMP计时器例程omp_get_wtime()

double start = omp_get_wtime();
#pragma omp parallel for
for(int n = 0; n < sizen; ++n)
    sinTable[n] = std::sin(2 * M_PI * n / sizen);
double finish = omp_get_wtime();
printf("from omp: %lf\n", finish - start);

对于非OpenMP应用程序,应将clock_gettime()CLOCK_REALTIME时钟一起使用:

struct timespec start, finish;
clock_gettime(CLOCK_REALTIME, &start);
#pragma omp parallel for
for(int n = 0; n < sizen; ++n)
    sinTable[n] = std::sin(2 * M_PI * n / sizen);
clock_gettime(CLOCK_REALTIME, &finish);
printf("from omp: %lf\n", (finish.tv_sec + 1.e-9 * finish.tv_nsec) -
                          (start.tv_sec + 1.e-9 * start.tv_nsec));

===============>>#2 票数:0

在没有任何信息的情况下,Linux调度程序将倾向于在同一内核上的进程中调度线程,以便由相同的缓存和内存总线为它们提供服务。 它无法知道您的线程将访问不同的内存,因此不会因为位于不同的内核上而受到帮助而不会受到伤害。

使用sched_setaffinity函数将每个线程设置为不同的核心掩码。

===============>>#3 票数:-2

警告:您的答案是有争议的。 下面描述的技巧取决于实现方式,并且可能导致性能下降。 尽管如此,它可能也会增加它。 我强烈建议您看一下对此答案的评论。


这并不能真正回答问题,但是如果您更改并行化代码的方式,则可能会提高性能。 现在,您可以这样操作:

#pragma omp parallel for
for(int n = 0; n < sizen; ++n)
    sinTable[n] = std::sin(2 * M_PI * n / sizen);

在这种情况下,每个线程将计算一项。 由于您有2个核心,因此OpenMP默认会创建两个线程。 要计算线程的每个值,必须:

  1. 初始化。
  2. 计算值。

第一步相当昂贵。 而且您的两个线程都必须执行sizen/2次。 尝试执行以下操作:

    int workloadPerThread = sizen / NUM_THREADS;
    #pragma omp parallel for
    for (int thread = 0; thread < NUM_THREADS; ++thread)
    {
        int start = thread * workloadPerThread;
        int stop = start + workloadPerThread;
        if (thread == NUM_THREADS - 1)
                stop += sizen % NUM_THREADS;
        for (int n = start; n < stop; ++n)
            sinTable[n] = std::sin(2 * M_PI * n / sizen);
    }

这样,您的线程将仅初始化一次。

  ask by Adam translate from so

未解决问题?本站智能推荐:

1回复

openMP直方图比较

我正在研究比较图像直方图,购买计算相关性,交集,ChiSquare和其他一些方法的代码。 这些功能的一般外观彼此非常相似。 通常我使用pthreads,但这次我决定使用openMP构建小型原型(由于它简单),看看我会得到什么样的结果。 这是通过相关性进行比较的示例,除了单行open
1回复

作为OpenMP pragma的结果的中间代码

有没有办法获得OpenMP pragma生成的中间源代码? 我想看看每种编译指示是如何翻译的。 干杯。
1回复

Pthreads,MPI和OpenMP中的C ++

美好的一天。 我当时参加了有关并行和分布式编程的课程,我的一项任务是要求我们使用并行编程扩展(例如Pthreads,MPI和OpenMP)以C语言进行编程。 问题是,我对C ++有更多了解,我想知道C ++是否也与那些并行扩展兼容? 如果C ++不兼容,是否有任何简短的速查表或有关在短
2回复

为函数创建openmp线程

我看到的所有openmp教程示例都是为for循环创建线程。 但是我需要为可能聚集到函数中的普通语句组创建线程。 例如,如下所示: 在上面的代码中,我希望每个函数仅在不同的线程中执行一次。 (因此,在上述代码中使用指令可能是错误的,请根据需要对其进行更正。) 我该如何用open
1回复

使用OpenMP处理程序中的GUI线程

我有一个C ++程序,使用OpenMP并行执行一些冗长的计算。 现在该程序还必须响应用户输入并更新一些图形。 到目前为止,我一直在从主/ GUI线程开始我的计算,仔细平衡工作负载,这样既不会短路来掩盖OpenMP线程开销也不会很长,因此GUI变得无法响应。 显然,我想通过同时运行所有内
1回复

如何使用OpenMP函数强制在QThread中使用多核

我有一个在OpenMP中非常并行化的功能,当从简单的控制台可执行文件启动时,它会使机器的每个核心饱和,并在处理器数量上以线性方式更快地返回结果。 现在这个函数也在我的Qt程序中的QThread中使用。 问题是我必须在调用updateStateWithAParallelAlgorithm
2回复

pthread vs intel TBB及其与OpenMP的关系?

对于多线程编程,考虑到与HPC应用程序(MPI)的组合,哪一个更好,我们可以说,在功能方面,英特尔TBB(线程构建块)是否与pthread相当? 我只有开放式操作系统的经验,但我听说TBB和Pthread提供比开放式mp更精细的线程控制,但TBB或TBB + OpenMP与pthread相比能
1回复

Ubuntu 14.04 LTS对Eigen openmp的支持

我得到有关一个丑陋链接错误openmp (未定义参照omp_get_max_threads_ , omp_get_num_threads_等)试图建立,其包括代码,当Eigen 3.2使用矩阵库头g++ 4.8.2 。 目标操作系统是Ubuntu 14.04 。 我在编译时使用-fopenm
1回复

如何在C ++程序中使用openmp

我想使用OpenMP在c ++程序中并行化某些函数。 我在具有4核的Intel i5上使用ubuntu 12.04。 但是,按照某些步骤操作后,我看不到性能有任何改善。 我可以看到只使用了一个CPU内核。 (ubuntu中的系统监视器) 我做了什么.. 添加了#inclu
1回复

Multi2sim v4.0.1上简单OpenMP程序的奇怪输出

我正在尝试使用OpenMP运行一个简单的程序 该程序如下 现在当我使用 g++ test.cpp -fopenmp -o test 并在ubuntu终端上运行 ./test 输出正确-我认为-如下 但是当我尝试使用这两个文件使用Multi2sim运行