这种悲伤教学的奇怪行为的原因是啥?

Posted

技术标签:

【中文标题】这种悲伤教学的奇怪行为的原因是啥?【英文标题】:What is the reason for this weird behavior of sad instruction?这种悲伤教学的奇怪行为的原因是什么? 【发布时间】:2017-02-05 17:59:35 【问题描述】:

我已经使用 SSE2 实现了 program 来分别比较 AVX2 和 SSE2 的 vpsadbw 指令和 psadbw。以下代码为SSE2程序:

#define MAX1 4096
#define MAX2 MAX1
#define MAX3 MAX1

#define NUM_LOOP 1000000000

double pTime = 0, mTime = 5; 

//global data for sequentila matrix operations
unsigned char a_char[MAX1][MAX2] __attribute__(( aligned(16)));
unsigned char b_char[MAX2][MAX3] __attribute__(( aligned(16)));
unsigned char c_char[MAX1][MAX3] __attribute__(( aligned(16)));
unsigned short int temp[8];


int main()

    int i, j, w=0, sad=0;
    struct timespec tStart, tEnd;
    double tTotal , tBest=10000;
    __m128i vec1, vec2, vecT, sad_total;
    sad_total= _mm_setzero_si128();

    do
        clock_gettime(CLOCK_MONOTONIC,&tStart);

        for(i=0; i<MAX1; i++)
            for(j=0; j<MAX2; j+=16)

                vec1 = _mm_load_si128((__m128i *)&a_char[i][j]);
                vec2 = _mm_load_si128((__m128i *)&b_char[i][j]);
                vecT = _mm_sad_epu8( vec1 , vec2);
                sad_total = _mm_add_epi64(vecT, sad_total);

                
            
        _mm_store_si128((__m128i *)&temp[0], sad_total);
        sad=temp[0]+temp[2]+temp[4]+temp[6];    

        clock_gettime(CLOCK_MONOTONIC,&tEnd);
        tTotal = (tEnd.tv_sec - tStart.tv_sec);
        tTotal += (tEnd.tv_nsec - tStart.tv_nsec) / 1000000000.0;
        if(tTotal<tBest)
            tBest=tTotal;
        pTime += tTotal;

     while(w++ < NUM_LOOP && pTime < mTime);
    printf(" The best time: %lf sec in %d repetition for %dX result is %d matrix\n",tBest,w, MAX1, sad);

    return 0;

我使用gccskylakeLinux mint 当我生成汇编代码时,内部循环包含一些不需要的移动操作,如下所示:

.L26:
    vmovdqa xmm1, XMMWORD PTR a_char[rcx+rax]
    vpsadbw xmm1, xmm1, XMMWORD PTR b_char[rcx+rax]
    add rax, 16
    vpaddq  xmm3, xmm1, XMMWORD PTR [rsp]
    cmp rax, 4096
    vmovaps XMMWORD PTR [rsp], xmm3
    jne .L26

由于 AVX2 生成此汇编代码:

.L26:
    vmovdqa ymm1, YMMWORD PTR a_char[rcx+rax]
    vpsadbw ymm1, ymm1, YMMWORD PTR b_char[rcx+rax]
    add rax, 32
    vpaddq  ymm2, ymm2, ymm1
    cmp rax, 4096
    jne .L26

我不知道这 2 条移动指令显着违反性能的原因。

【问题讨论】:

好的,我不知道它无法访问。 【参考方案1】:

原因是这样的:

_mm_store_si128((__m128i *)&temp[0], sad_total);

Clang 不介意并编写了很好的代码,但 GCC 不喜欢它(可能是启发式失败?)

将其替换为不会触发“这应该一直在堆栈上”的东西——启发式,GCC 可以生成更好的代码,例如:(未测试)

    __m128i sad_total = _mm_setzero_si128();
    for(i = 0; i < MAX1; i++) 
        for(j = 0; j < MAX2; j += 16) 
            __m128i vec1 = _mm_load_si128((__m128i *)&a_char[i][j]);
            __m128i vec2 = _mm_load_si128((__m128i *)&b_char[i][j]);
            __m128i vecT = _mm_sad_epu8( vec1 , vec2);
            sad_total = _mm_add_epi64(sad_total, vecT);
        
    
    __m128i hsum = _mm_add_epi64(sad_total, _mm_bsrli_si128(sad_total, 8));
    sad = _mm_cvtsi128_si32(hsum);

内部循环现在看起来像

.L2:
    vmovdqa xmm1, XMMWORD PTR a_char[rdx+rax]
    vpsadbw xmm1, xmm1, XMMWORD PTR b_char[rdx+rax]
    add     rax, 16
    vpaddq  xmm2, xmm1, xmm2
    cmp     rax, 4096
    jne     .L2

【讨论】:

【参考方案2】:

您直接绕过编译器并通过_mm_load_si128 告诉它使用movdqa。它正在做你告诉它做的事情。这里有什么问题?我还注意到您沿 16 字节边界对齐,如果我错了,请随时纠正我(我不确定 attribute 在您的编译器上是如何实现的)但您可能会得到填充结果,以便每个元素将在 16 字节边界上对齐;如果是这样,这将影响您展开的影响。如果没有,请随时纠正我。

【讨论】:

无论如何都必须加载那些东西,所以我认为问题是累加器溢出到堆栈中 对齐属性only对齐first字节(即没有填充)。也就是说,链接器/加载器将保证变量具有地址,例如(((unsigned long) &amp;x[0][0]) % 16) == 0。保持这种对齐[当索引到数组时]取决于使用情况(即程序代码)。为了正常工作,给定unsigned char a_char[MAX1][MAX2]MAX2 必须是 16 的倍数,并且在使用a_char[i][j] 进行索引时,必须使用for (j = 0; j &lt; MAX2; j += 16) [或等效]。实际增量可能是 16 的倍数(例如 16、32、...) 干杯克雷格。我在这里担心的是,如果您将其用于结构的每个成员(即 __attribute__(aligned(16) ) ),那么在结构上执行 sizeof() 报告的大小是否会随着对齐参数的更改而增加(不能现在测试)?虽然不确定它如何影响静态声明的数组 - 我猜这是你的观点所在。无法确定这一点,但我使用 VS 的“等效”并且有填充。只是认为这可能值得提出警告。

以上是关于这种悲伤教学的奇怪行为的原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 MacOs 下使用 pygt5 或 pyside2 的简单 QTimer 示例中,是啥导致了这种奇怪的 UI 行为?

为啥 Number.parseInt('111AAA') 像它在 JS 中那样工作?这种行为背后的原因是啥?

应用程序仅在安装了 Visual Studio 的 PC 上启动。这种行为的原因可能是啥?

AudioServicesPlaySystemSound 奇怪的行为

教学目标的表述方式──行为目标的ABCD表述法

当数组是函数参数时,矩阵乘法中的 Gcc 自动向量化奇怪行为