大佬教程收集整理的这篇文章主要介绍了c – 这个功能是英特尔SIMD的理想选择吗?,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
int f(int len,unsigned char *p) { int i = 0; while (i < len && p[i] >= 32 && p[i] <= 127) { i++; } return i; }
我认为可以使用向量指令进行优化,但是从一些研究来看,SSE似乎不适合在字节级工作.该程序仅针对OSX上的64位Intel cpu.有没有一个巧妙的比特伎俩,我没有看到它会让我一次只能处理64位? llvm与-O3没有做任何聪明的优化.
更新:
SIMD代码在我的基准测试中通常是最快的(取决于输入的大小),但由于某种原因,使用SIMD的应用程序总体上比使用简单的代码或比特笨拙的技巧更慢.对于上下文,应用程序在终端仿真器的输入流中查找ASCII字符串的子序列的长度. ASCII字符串得到特殊的“快速路径”处理.我只能将一个答案标记为正确,但两者都很棒.我确实做了一个改进的小改进,通过这样做删除if语句:
while (i < len - 8) { uint64_t bytes = *(uint64_t *)(p + i); uint64_t middleBits = bytes & 0x6060606060606060; uint64_t highBits = bytes & 0x8080808080808080; middleBits |= (middleBits >> 1); middleBits &= ~(highBits >> 2); if ((middleBits & 0x2020202020202020) != 0x2020202020202020) { break; } i += 8; }
然后,您可以对ANDing比较结果的结果使用movemask.如果movemask的结果是0xFFFF,那么所有比较都会通过.否则,您需要运行尾循环以找出未通过测试的正确位置.你可以从面具中找出这个,但是根据’len’的值,它可能不值得努力.
如果’len’不是16的倍数,则还需要原始的非尾部非循环循环.它可能会也可能不会更快 – 您需要对其进行分析以确定.
报废 – 比较对签名值进行操作,但不起作用..
下面的工作版本.
union UmmU8 { __m128i mm_; struct { unsigned char u8_; }; }; int f(int len,unsigned char *p) { int i = 0; __m128i A; __m128i B; __m128i c; UmmU8* pu = (UmmU8*)p; int const len16 = len / 16; while (i < len16) { A = pu[i].mm_; B = _mm_slli_epi32(A,1); C = _mm_slli_epi32(A,2); B = _mm_or_si128(B,C); A = _mm_andnot_si128(A,B); int mask = _mm_movemask_epi8(A); if (mask == 0xFFFF) { ++i; } else { if (mask == 0) { return i * 16; } break; } } i *= 16; while (i < len && p[i] >= 32 && p[i] <= 127) { i++; } return i; }
由于我在这台PC上没有64 OS,我不能进行适当的性能测试.
但是,分析运行给出了:
>天真循环:30.44
> 64位整数:15.22(在32位操作系统上)
> SSE impl:5.21
所以SSE版本比朴素循环版本快得多.我希望64位版本在64位系统上表现更好 – SSE和64位版本之间可能差别不大.
以上是大佬教程为你收集整理的c – 这个功能是英特尔SIMD的理想选择吗?全部内容,希望文章能够帮你解决c – 这个功能是英特尔SIMD的理想选择吗?所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。