【问题标题】:What could be some possible problems with this use of OpenMP?使用 OpenMP 可能会出现哪些问题?
【发布时间】:2012-02-10 20:01:17
【问题描述】:

我试图弄清楚如何在 OpenMP 中并行化一段代码,其中 for 循环的内部独立于它的其余部分。

该项目基本上是在处理粒子系统,但我认为这与代码的并行化无关。 for循环以一种方式划分线程,使得粒子没有以有效的方式缓存在每个核心中,这是否是一个缓存问题?

编辑:正如下面的答案所述,我想知道为什么我没有得到加速。

#pragma omp parallel for
for (unsigned i = 0; i < psize-n_dead; ++i)
{
    s->particles[i].pos = s->particles[i].pos + dt * s->particles[i].vel;
    s->particles[i].vel = (1 - dt*.1) * s->particles[i].vel + dt*s->force;
    //  printf("%d", omp_get_thread_num());

}

【问题讨论】:

  • 它随着时间的推移而增长,但它在 1000s 的数量级上。所以说在最简单的状态下是 4000,最大可能达到 200000。

标签: c parallel-processing openmp


【解决方案1】:

如果您询问它是否正确并行化,它看起来没问题。我没有看到任何可能破坏它的数据竞争或循环依赖。

但我想你想知道为什么并行性没有得到任何加速。

由于您提到了行程计数,psize-n_dead 将按4000 的顺序排列。考虑到循环中的工作量,我想说这实际上非常小。

换句话说,您没有太多值得并行化的工作。因此,线程开销可能正在消耗您应该获得的任何加速。如果可能,您应该尝试在更高级别进行并行化。


编辑:您更新了您的评论以包含多达 200000 个。

对于较大的值,您可能会以某种方式受到内存限制。您的循环只是遍历所有数据,做的工作很少。所以使用更多线程可能不会有太大帮助(如果有的话)。

【讨论】:

    【解决方案2】:

    这段代码不存在数据竞争等正确性问题。

    假设要处理的粒子数量足够大以保证并行性,我在此代码中看不到与 OpenMP 相关的性能问题。默认情况下,OpenMP 会在所有线程中将循环迭代静态地分成相等的部分,因此任何缓存冲突都可能只发生在这些部分的边界处,即仅在循环的几次迭代中发生。

    与 OpenMP(以及并行加速问题)无关,可能通过从结构数组切换到数组结构来提高性能,因为这可能有助于编译器对代码进行矢量化(即使用 SIMD目标处理器的指令):

    #pragma omp parallel for
    for (unsigned i = 0; i < psize-n_dead; ++i)
    {
        s->particles.pos[i] = s->particles.pos[i] + dt * s->particles.vel[i];
        s->particles.vel[i] = (1 - dt*.1) * s->particles.vel[i] + dt*s->force;
    }
    

    这种重组假设大多数时候所有粒子都在这样的循环中处理。使用单个粒子需要加载更多的缓存行,但如果您在一个循环中处理它们,加载的缓存行的净数量几乎相同。

    【讨论】:

    • +1 用于建议 Struct-of-Arrays。因为我只关注并行部分,所以我从来没有想过这个问题。
    【解决方案3】:

    你有多确定你没有得到加速?

    尝试两种方式 - 结构数组和数组结构,使用 gcc -O3 (gcc 4.6) 编译,在双四核 nehalem 上,我得到 psize-n_dead = 200000,运行 100 次迭代以获得更好的计时器精度:

    数组结构(报告时间以毫秒为单位)

    $ for t in 1 2 4 8; do export OMP_NUM_THREADS=$t; time ./foo; done
    Took time 90.984000
    Took time 45.992000
    Took time 22.996000
    Took time 11.998000
    

    结构数组:

    $ for t in 1 2 4 8; do export OMP_NUM_THREADS=$t; time ./foo; done
    Took time 58.989000
    Took time 28.995000
    Took time 14.997000
    Took time 8.999000
    

    但是,由于操作时间很短(亚毫秒),由于计时器的准确性,如果不进行 100 次迭代,我没有看到任何加速。此外,您必须拥有一台具有良好内存带宽的机器才能获得这种行为;您只需要执行约 3 个 FMA 以及每读取两条数据的另一个乘法。

    结构数组的代码如下。

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    
    typedef struct particle_struct {
        double pos;
        double vel;
    } particle;
    
    typedef struct simulation_struct {
        particle *particles;
        double force;
    } simulation;
    
    void tick(struct timeval *t) {
        gettimeofday(t, NULL);
    }
    
    /* returns time in seconds from now to time described by t */
    double tock(struct timeval *t) {
        struct timeval now;
        gettimeofday(&now, NULL);
        return (double)(now.tv_sec - t->tv_sec) + ((double)(now.tv_usec - t->tv_usec)/1000000.);
    }
    
    
    void update(simulation *s, unsigned psize, double dt) {
    #pragma omp parallel for
        for (unsigned i = 0; i < psize; ++i)
        {
            s->particles[i].pos = s->particles[i].pos+ dt * s->particles[i].vel;
            s->particles[i].vel = (1 - dt*.1) * s->particles[i].vel + dt*s->force;
        }
    }
    
    void init(simulation *s, unsigned np) {
        s->force = 1.;
        s->particles = malloc(np*sizeof(particle));
        for (unsigned i=0; i<np; i++) {
            s->particles[i].pos = 1.;
            s->particles[i].vel = 1.;
    }
    
    int main(void)
    {
        const unsigned np=200000;
        simulation s;
        struct timeval clock;
    
        init(&s, np);
        tick(&clock);
        for (int iter=0;iter< 100; iter++) 
            update(&s, np, 0.75);
        double elapsed=tock(&clock)*1000.;
        printf("Took time %lf\n", elapsed);
    
        free(s.particles);
    }
    

    【讨论】:

    • 我意识到主要问题是做这组操作的成本与整体时间成本相比太小了,所以我增加了粒子的数量以增加整体影响并展示并行效率。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 2011-01-28
    • 2011-06-12
    • 1970-01-01
    • 2011-08-19
    • 2014-02-27
    相关资源
    最近更新 更多