用profile跑了下,这块的代码如何进一步优化

shiter
人工智能领域优质创作者
博客专家认证
2016-01-20 11:28:55



static inline void histogram_add( const uint16_t x[16], uint16_t y[16] )
{
int i;

for ( i = 0; i < 16; ++i ) {
y[i] += x[i];
}
}


这块的时间大约占到运行时间的30%
...全文
570 25 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2016-01-22
  • 打赏
  • 举报
回复
引用 24 楼 DelphiGuy 的回复:
y[i] += a * x[i];这种运算,理论上用FMA指令最合适,可以直接算y=ax+b这种形式,可惜现在的FMA指令(vfmadd*)只能执行浮点运算,如果先把整数转成浮点,最后把结果再转成整数,精度可能损失了。 PMULHW 操作数是有符号数,结果只保留高16位,不适合 PMULHUW 虽然操作数是无符号数,但是结果只保留高16位,也不适合 PMULLW 操作数是有符号数,不适合 PMULUDQ 可以用,每次只能算两对数(128位指令)或者4对数,拆分操作数、合并结果也很繁琐。
依我看楼主干脆在应用层改浮点数,使用FMA算了。
  • 打赏
  • 举报
回复
y[i] += a * x[i];这种运算,理论上用FMA指令最合适,可以直接算y=ax+b这种形式,可惜现在的FMA指令(vfmadd*)只能执行浮点运算,如果先把整数转成浮点,最后把结果再转成整数,精度可能损失了。 PMULHW 操作数是有符号数,结果只保留高16位,不适合 PMULHUW 虽然操作数是无符号数,但是结果只保留高16位,也不适合 PMULLW 操作数是有符号数,不适合 PMULUDQ 可以用,每次只能算两对数(128位指令)或者4对数,拆分操作数、合并结果也很繁琐。
赵4老师 2016-01-21
  • 打赏
  • 举报
回复
引用 19 楼 DelphiGuy 的回复:
实际测试,用256位操作比128位操作没快多少,因为现在大部分电脑还是双通道内存64-bit x 2,三通道、四通道的很少,256位指令load/store的性能体现不出来。
Orz
赵4老师 2016-01-21
  • 打赏
  • 举报
回复
请参考7楼回复中的: …… _mm_mulhi_epi16 PMULHW Multiplication _mm_mulhi_epu16 PMULHUW Multiplication _mm_mullo_epi16 PMULLW Multiplication _mm_mul_su32 PMULUDQ Multiplication _mm_mul_epu32 PMULUDQ Multiplication ……
赵4老师 2016-01-21
  • 打赏
  • 举报
回复
参考:《The Intel 64 and IA-32 Architectures Software Developer's Manual》
shiter 2016-01-21
  • 打赏
  • 举报
回复
引用 19 楼 DelphiGuy 的回复:
实际测试,用256位操作比128位操作没快多少,因为现在大部分电脑还是双通道内存64-bit x 2,三通道、四通道的很少,256位指令load/store的性能体现不出来。
引用 20 楼 zhao4zhong1 的回复:
[quote=引用 19 楼 DelphiGuy 的回复:] 实际测试,用256位操作比128位操作没快多少,因为现在大部分电脑还是双通道内存64-bit x 2,三通道、四通道的很少,256位指令load/store的性能体现不出来。
Orz[/quote] 请问大牛下面这种能行么?

static inline void histogram_muladd( const uint16_t a, const uint16_t x[16],
        uint16_t y[16] )
{
    int i;
	
    for ( i = 0; i < 16; ++i ) {
        y[i] += a * x[i];
    }
}

mLee79 2016-01-20
  • 打赏
  • 举报
回复
这段肯定应该 SIMD, 调用者函数的地方多不, 一起来想想办法。
www_adintr_com 2016-01-20
  • 打赏
  • 举报
回复
1. 手动把循环展开看 2. 传入的 x, y 地址尽量在一起 这么点代码执行的时间恐怕还没有创建线程的开销大.
shiter 2016-01-20
  • 打赏
  • 举报
回复
能否改成并行的?
  • 打赏
  • 举报
回复
实际测试,用256位操作比128位操作没快多少,因为现在大部分电脑还是双通道内存64-bit x 2,三通道、四通道的很少,256位指令load/store的性能体现不出来。
shiter 2016-01-20
  • 打赏
  • 举报
回复
引用 17 楼 DelphiGuy 的回复:
__declspec(align(32)) WORD x[16]; __declspec(align(32)) WORD y[16]; histogram_add_Intrinsic_AVX2(x, y); 我用VC++ 2010、2013测试了一下,编译是没有问题的,只是2010不识别_mm256_add_epi16,这个是AVX2中的指令。
我还有个问题,这些simd指令那些速度更快,还是都差不多
  • 打赏
  • 举报
回复
__declspec(align(32)) WORD x[16]; __declspec(align(32)) WORD y[16]; histogram_add_Intrinsic_AVX2(x, y); 我用VC++ 2010、2013测试了一下,编译是没有问题的,只是2010不识别_mm256_add_epi16,这个是AVX2中的指令。
shiter 2016-01-20
  • 打赏
  • 举报
回复
引用 12 楼 DelphiGuy 的回复:

#include <intrin.h>
typedef unsigned __int16 WORD;

__inline void histogram_add_Intrinsic_SSE2(const WORD x[16], WORD y[16])
{
  __m128i b2 = _mm_load_si128((__m128i *)&y[8]);
  __m128i b1 = _mm_load_si128((__m128i *)y);
  __m128i a2 = _mm_load_si128((__m128i *)&x[8]);
  __m128i a1 = _mm_load_si128((__m128i *)x);

  a1 = _mm_add_epi16(a1, b1);
  a2 = _mm_add_epi16(a2, b2);

  _mm_store_si128((__m128i *)&y[8], a2);
  _mm_store_si128((__m128i *)y, a1);
}

__inline void histogram_add_Intrinsic_AVX2(const WORD x[16], WORD y[16])
{
  __m256i b = _mm256_load_si256((__m256i *)y);
  __m256i a = _mm256_load_si256((__m256i *)x);

  a = _mm256_add_epi16(a, b);

  _mm256_store_si256((__m256i *)y, a);
}
注意两个版本传入数据需要16字节、32字节对齐,否则要使用非对齐指令。
请问大牛这个:

1>ctmf.c(169): error C2718: “__m256i”: 具有 __declspec(align('32')) 的实参将不被对齐
1>ctmf.c(169): error C2718: “__m256i”: 具有 __declspec(align('32')) 的实参将不被对齐
1>ctmf.c(169): error C2440: “=”: 无法从“int”转换为“__m256i”
1>

应该怎么修改
shiter 2016-01-20
  • 打赏
  • 举报
回复
elif defined(__ALTIVEC__) 这个是哪里的指令,为何包含头文件#include <altivec.h>也用不了?
shiter 2016-01-20
  • 打赏
  • 举报
回复
引用 11 楼 wangyaninglm 的回复:
[quote=引用 9 楼 yshuise 的回复:] 用下intel的TBB
请问具体怎么用? 请问vs里面如何使用这些指令?


#if defined(__SSE2__)
static inline void histogram_add( const uint16_t x[16], uint16_t y[16] )
{
    *(__m128i*) &y[0] = _mm_add_epi16( *(__m128i*) &y[0], *(__m128i*) &x[0] );
    *(__m128i*) &y[8] = _mm_add_epi16( *(__m128i*) &y[8], *(__m128i*) &x[8] );
}
#elif defined(__MMX__)
static inline void histogram_add( const uint16_t x[16], uint16_t y[16] )
{
    *(__m64*) &y[0]  = _mm_add_pi16( *(__m64*) &y[0],  *(__m64*) &x[0]  );
    *(__m64*) &y[4]  = _mm_add_pi16( *(__m64*) &y[4],  *(__m64*) &x[4]  );
    *(__m64*) &y[8]  = _mm_add_pi16( *(__m64*) &y[8],  *(__m64*) &x[8]  );
    *(__m64*) &y[12] = _mm_add_pi16( *(__m64*) &y[12], *(__m64*) &x[12] );
}
#elif defined(__ALTIVEC__)
static inline void histogram_add( const uint16_t x[16], uint16_t y[16] )
{
    *(vector unsigned short*) &y[0] = vec_add( *(vector unsigned short*) &y[0], *(vector unsigned short*) &x[0] );
    *(vector unsigned short*) &y[8] = vec_add( *(vector unsigned short*) &y[8], *(vector unsigned short*) &x[8] );
}
#else

[/quote] 我这个从0.07s提升到0.05了不知道算不算提升。。。release下面提示了0.01s
赵4老师 2016-01-20
  • 打赏
  • 举报
回复
引用 12 楼 DelphiGuy 的回复:

#include <intrin.h>
typedef unsigned __int16 WORD;

__inline void histogram_add_Intrinsic_SSE2(const WORD x[16], WORD y[16])
{
  __m128i b2 = _mm_load_si128((__m128i *)&y[8]);
  __m128i b1 = _mm_load_si128((__m128i *)y);
  __m128i a2 = _mm_load_si128((__m128i *)&x[8]);
  __m128i a1 = _mm_load_si128((__m128i *)x);

  a1 = _mm_add_epi16(a1, b1);
  a2 = _mm_add_epi16(a2, b2);

  _mm_store_si128((__m128i *)&y[8], a2);
  _mm_store_si128((__m128i *)y, a1);
}

__inline void histogram_add_Intrinsic_AVX2(const WORD x[16], WORD y[16])
{
  __m256i b = _mm256_load_si256((__m256i *)y);
  __m256i a = _mm256_load_si256((__m256i *)x);

  a = _mm256_add_epi16(a, b);

  _mm256_store_si256((__m256i *)y, a);
}
注意两个版本传入数据需要16字节、32字节对齐,否则要使用非对齐指令。
  • 打赏
  • 举报
回复

#include <intrin.h>
typedef unsigned __int16 WORD;

__inline void histogram_add_Intrinsic_SSE2(const WORD x[16], WORD y[16])
{
  __m128i b2 = _mm_load_si128((__m128i *)&y[8]);
  __m128i b1 = _mm_load_si128((__m128i *)y);
  __m128i a2 = _mm_load_si128((__m128i *)&x[8]);
  __m128i a1 = _mm_load_si128((__m128i *)x);

  a1 = _mm_add_epi16(a1, b1);
  a2 = _mm_add_epi16(a2, b2);

  _mm_store_si128((__m128i *)&y[8], a2);
  _mm_store_si128((__m128i *)y, a1);
}

__inline void histogram_add_Intrinsic_AVX2(const WORD x[16], WORD y[16])
{
  __m256i b = _mm256_load_si256((__m256i *)y);
  __m256i a = _mm256_load_si256((__m256i *)x);

  a = _mm256_add_epi16(a, b);

  _mm256_store_si256((__m256i *)y, a);
}
注意两个版本传入数据需要16字节、32字节对齐,否则要使用非对齐指令。
shiter 2016-01-20
  • 打赏
  • 举报
回复
引用 9 楼 yshuise 的回复:
用下intel的TBB
请问具体怎么用? 请问vs里面如何使用这些指令?


#if defined(__SSE2__)
static inline void histogram_add( const uint16_t x[16], uint16_t y[16] )
{
    *(__m128i*) &y[0] = _mm_add_epi16( *(__m128i*) &y[0], *(__m128i*) &x[0] );
    *(__m128i*) &y[8] = _mm_add_epi16( *(__m128i*) &y[8], *(__m128i*) &x[8] );
}
#elif defined(__MMX__)
static inline void histogram_add( const uint16_t x[16], uint16_t y[16] )
{
    *(__m64*) &y[0]  = _mm_add_pi16( *(__m64*) &y[0],  *(__m64*) &x[0]  );
    *(__m64*) &y[4]  = _mm_add_pi16( *(__m64*) &y[4],  *(__m64*) &x[4]  );
    *(__m64*) &y[8]  = _mm_add_pi16( *(__m64*) &y[8],  *(__m64*) &x[8]  );
    *(__m64*) &y[12] = _mm_add_pi16( *(__m64*) &y[12], *(__m64*) &x[12] );
}
#elif defined(__ALTIVEC__)
static inline void histogram_add( const uint16_t x[16], uint16_t y[16] )
{
    *(vector unsigned short*) &y[0] = vec_add( *(vector unsigned short*) &y[0], *(vector unsigned short*) &x[0] );
    *(vector unsigned short*) &y[8] = vec_add( *(vector unsigned short*) &y[8], *(vector unsigned short*) &x[8] );
}
#else

shiter 2016-01-20
  • 打赏
  • 举报
回复
引用 6 楼 zhao4zhong1 的回复:
换Intel的编译器,优化全开试试看。
换成intel的内嵌到vs 2010中,提升了0.01秒,哈哈
yshuise 2016-01-20
  • 打赏
  • 举报
回复
用下intel的TBB
加载更多回复(5)

65,182

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧