6

我目前正在为需要一些性能改进的 Java 应用程序开发 C 模块(请参阅背景改进网络编码编码的性能)。我尝试使用 SSE-intrinsics 优化代码,它的执行速度比 Java 版本快一些(~20%)。但是,它仍然不够快。

不幸的是,我在优化 C 代码方面的经验有些有限。因此,我很想获得一些关于如何改进当前实施的想法。

构成热点的内部循环如下所示:

for (i = 0; i < numberOfGFVectorsInFragment; i++)   {

        // Load the 4 GF-elements from the message-fragment and add the log of the coefficeint to them.
        __m128i currentMessageFragmentVector = _mm_load_si128 (currentMessageFragmentPtr);
        __m128i currentEncodedResult = _mm_load_si128(encodedFragmentResultArray);

        __m128i logSumVector = _mm_add_epi32(coefficientLogValueVector, currentMessageFragmentVector);

        __m128i updatedResultVector = _mm_xor_si128(currentEncodedResult, valuesToXor);
        _mm_store_si128(encodedFragmentResultArray, updatedResultVector);

        encodedFragmentResultArray++;
        currentMessageFragmentPtr++;
    }
4

2 回答 2

7

即使不查看程序集,我也可以立即判断出瓶颈来自 4 元素聚集内存访问和_mm_set_epi32打包操作。在内部,_mm_set_epi32, 在您的情况下可能会被实现为一系列unpacklo/hi指令。

此循环中的大部分“工作”来自打包这 4 个内存访问。在没有 SSE4.1 的情况下,我会说循环可以更快非矢量化,但展开。

如果你愿意使用 SSE4.1,你可以试试这个。它可能会更快,也可能不会:

    int* logSumArray = (int*)(&logSumVector);

    __m128i valuesToXor = _mm_cvtsi32_si128(expTable[*(logSumArray++)]);
    valuesToXor = _mm_insert_epi32(valuesToXor, expTable[*(logSumArray++)], 1);
    valuesToXor = _mm_insert_epi32(valuesToXor, expTable[*(logSumArray++)], 2);
    valuesToXor = _mm_insert_epi32(valuesToXor, expTable[*(logSumArray++)], 3);

我建议将循环展开至少 4 次迭代并交错所有指令,以使此代码有任何表现良好的机会。

您真正需要的是英特尔的 AVX2 收集/分散指令。但那是几年后的事了……

于 2011-10-17T14:28:53.607 回答
1

也许试试http://web.eecs.utk.edu/~plank/plank/papers/CS-07-593/。名称中带有“区域”的功能据说速度很快。他们似乎没有使用任何类型的特殊指令集,但也许他们已经在其他方面进行了优化......

于 2011-10-17T18:40:41.530 回答