【问题标题】:Cilk_for returns wrong data in arrayCilk_for 在数组中返回错误数据
【发布时间】:2014-05-29 04:17:42
【问题描述】:

我是多线程编程的新手。最近,我有一个项目,我将 cilk_for 应用到其中。这是代码:。

void myfunction(short *myarray)
{
m128i *array = (m128i*) myarray
cilk_for(int i=0; i<N_LOOP1; i++)
    {
        for(int z = 0; z<N_LOOP2; z+=8)
        {
            array[z]        =  _mm_and_si128(array[z],mym128i);
            array[z+1]        =  _mm_and_si128(array[z+1],mym128i);
            array[z+2]        =  _mm_and_si128(array[z+2],mym128i);
            array[z+3]        =  _mm_and_si128(array[z+3],mym128i);
            array[z+4]        =  _mm_and_si128(array[z+4],mym128i);
            array[z+5]        =  _mm_and_si128(array[z+5],mym128i);
            array[z+6]        =  _mm_and_si128(array[z+6],mym128i);
            array[z+7]        =  _mm_and_si128(array[z+7],mym128i);
            array+=8;
        }
    }
}

在上面的代码运行之后,发生了荒谬的事情。数组中的数据未正确更新。例如,如果我有一个包含 1000 个元素的数组,则该数组有可能被正确更新(1000 个元素是 AND-ed)。但也有可能会省略数组的某些部分(第一个元素到第 300 个元素是 AND-ed,第 301 个元素到第 505 个元素不是 AND-ed,第 506 个元素到第 707 个元素是 AND-ed,等等, ...)。这些省略的部分在每次运行中都是随机的,所以我认为这里的问题是关于缓存未命中。我对吗?请告诉我,任何帮助表示赞赏。 :)

【问题讨论】:

    标签: parallel-processing intel cilk-plus


    【解决方案1】:

    问题是 cilk 产生的线程之间的数组指针不同步,并且您的数组变量在每次循环迭代中递增。这仅适用于线性执行。在您的代码 sn-p 中,多个线程正在访问数组中的相同元素,而根本不处理数组的其他部分。

    为了解决这个问题,我建议在外循环中计算索引,以便每个使用 Cilk 生成的线程都能够独立计算地址。也许你可以这样做:

    void myfunction(short *myarray)
        {
        cilk_for (int i=0; i<N_LOOP1; i++)
            {
                m128i *array = (m128i*) myarray + i * N_LOOP2 * 8;
                for(int z = 0; z<N_LOOP2; z+=8)
                {
                    array[z]        =  _mm_and_si128(array[z],mym128i);
                    array[z+1]        =  _mm_and_si128(array[z+1],mym128i);
                    array[z+2]        =  _mm_and_si128(array[z+2],mym128i);
                    array[z+3]        =  _mm_and_si128(array[z+3],mym128i);
                    array[z+4]        =  _mm_and_si128(array[z+4],mym128i);
                    array[z+5]        =  _mm_and_si128(array[z+5],mym128i);
                    array[z+6]        =  _mm_and_si128(array[z+6],mym128i);
                    array[z+7]        =  _mm_and_si128(array[z+7],mym128i);
                    array+=8;
                }
            }
        }
    

    顺便说一句:为什么需要在这里手动展开循环?编译器应该自动执行此操作。

    【讨论】:

    • 你是对的。通过您的修改,cilk_for 运行正常。但它比正常的 for 循环慢(大约 1.5 倍)。
    • 这里手动展开是因为我认为它会分摊cilk_for的开销。也许我错了,因为 unroll-version 的运行时间与普通版本相同。如果编译器自动展开循环,我应该删除这个手动展开吗?
    • 根据阵列的大小,您会受到内存带宽而不是 CPU 的限制。使用多个线程的速度变慢可能是因为线程正在访问不同的内存位置但共享 L3 缓存。运行 VTune 将有助于理解这一点。
    • 如果编译器自动展开,则很容易为英特尔® 至强融核™ 等不同架构进行编译。如果您手动展开,您可能需要在这种情况下采用(手动)展开。
    猜你喜欢
    • 2014-03-31
    • 1970-01-01
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 2020-08-04
    • 2017-08-22
    • 2017-05-23
    相关资源
    最近更新 更多