首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么它比memcmp慢?

为什么它比memcmp慢?
EN

Stack Overflow用户
提问于 2013-02-10 18:01:52
回答 3查看 3.2K关注 0票数 3

我正在尝试比较两行pixel

pixel定义为包含4个float值(RGBA值)的RGBA值。

我不使用memcmp的原因是因为我需要返回第一个不同像素的位置,而memcmp不会这样做。

我的第一个实现使用SSE内部函数,比memcmp慢大约30%

代码语言:javascript
复制
inline int PixelMemCmp(const Pixel* a, const Pixel* b, int count)
{
    for (int i = 0; i < count; i++)
    {
        __m128 x = _mm_load_ps((float*)(a + i));
        __m128 y = _mm_load_ps((float*)(b + i));
        __m128 cmp = _mm_cmpeq_ps(x, y);
        if (_mm_movemask_ps(cmp) != 15) return i;
    }
    return -1;
}

然后我发现,将这些值作为整数而不是浮点数来处理会加快一些速度,并且现在只比memcmp慢大约20%。

代码语言:javascript
复制
inline int PixelMemCmp(const Pixel* a, const Pixel* b, int count)
{
    for (int i = 0; i < count; i++)
    {
        __m128i x = _mm_load_si128((__m128i*)(a + i));
        __m128i y = _mm_load_si128((__m128i*)(b + i));
        __m128i cmp = _mm_cmpeq_epi32(x, y);
        if (_mm_movemask_epi8(cmp) != 0xffff) return i; 
    }
    return -1;
}

根据我在其他问题上所读到的内容,memcmp的MS实现也是使用SSE实现的。我的问题是,MS实现还有什么我没有的窍门?即使它进行逐字节比较,它怎么还能更快呢?

对齐是一个问题吗?如果pixel包含4个浮点数,那么不是已经在16字节边界上分配了一个像素数组吗?

我使用/o2和所有的优化标志进行编译。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-02-10 19:25:29

我已经用SSE (和MMX/3DNow!)编写了strcmp/memcmp优化,第一步是确保数组尽可能对齐-你可能会发现你必须“一次一个”地处理第一个和/或最后一个字节。

如果您可以在数据到达循环之前对齐数据,如果您的代码执行分配,那么这将是理想的。

第二部分是展开循环,这样你就不会得到那么多“如果循环不在末尾,跳回到循环的开头”-假设循环相当长。

您可能会发现,在执行“我们现在离开”条件之前预加载输入的下一个数据也很有帮助。

编辑:最后一段可能需要一个例子。这段代码假设至少有两个展开的循环:

代码语言:javascript
复制
 __m128i x = _mm_load_si128((__m128i*)(a));
 __m128i y = _mm_load_si128((__m128i*)(b));

 for(int i = 0; i < count; i+=2)
 {
    __m128i cmp = _mm_cmpeq_epi32(x, y);

    __m128i x1 = _mm_load_si128((__m128i*)(a + i + 1));
    __m128i y1 = _mm_load_si128((__m128i*)(b + i + 1));

    if (_mm_movemask_epi8(cmp) != 0xffff) return i; 
    cmp = _mm_cmpeq_epi32(x1, y1);
    __m128i x = _mm_load_si128((__m128i*)(a + i + 2));
    __m128i y = _mm_load_si128((__m128i*)(b + i + 2));
    if (_mm_movemask_epi8(cmp) != 0xffff) return i + 1; 
}

大致是这样的。

票数 3
EN

Stack Overflow用户

发布于 2013-02-10 19:02:39

您可能想要检查此memcmp SSE implementation,特别是__sse_memcmp函数,它从一些健全性检查开始,然后检查指针是否对齐:

代码语言:javascript
复制
aligned_a = ( (unsigned long)a & (sizeof(__m128i)-1) );
aligned_b = ( (unsigned long)b & (sizeof(__m128i)-1) );

如果它们未对齐,则逐字节比较指针,直到对齐地址的开始:

代码语言:javascript
复制
 while( len && ( (unsigned long) a & ( sizeof(__m128i)-1) ) )
{
   if(*a++ != *b++) return -1;
   --len;
}

然后将剩余内存与类似于您的代码的SSE指令进行比较:

代码语言:javascript
复制
 if(!len) return 0;
while( len && !(len & 7 ) )
{
__m128i x = _mm_load_si128( (__m128i*)&a[i]);
__m128i y = _mm_load_si128( (__m128i*)&b[i]);
....
票数 3
EN

Stack Overflow用户

发布于 2013-02-10 18:12:57

我不能直接帮助你,因为我正在使用Mac,但有一个简单的方法可以弄清楚发生了什么:

您只需在调试模式下进入memcpy,然后切换到反汇编视图。由于memcpy是一个简单的小函数,您将很容易弄清楚所有的实现技巧。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14796562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档