C++11 我可以使用intrinsic加速类型转换吗?
我正在开发一个需要将数据转换为浮点的应用程序。 数据为无符号字符或无符号短字符 我在这段代码中使用了AVX2和其他SIMDs内部函数。 我这样写了转换: 无符号字符->浮点:C++11 我可以使用intrinsic加速类型转换吗?,c++11,simd,intrinsics,C++11,Simd,Intrinsics,我正在开发一个需要将数据转换为浮点的应用程序。 数据为无符号字符或无符号短字符 我在这段代码中使用了AVX2和其他SIMDs内部函数。 我这样写了转换: 无符号字符->浮点: #ifdef_uuavx2__ __m256i tmp_v=_mm256_lddqu_si256(重新解释铸造(src+j)); v16_avx[0]=_mm256_cvtepu8_epi16(_mm256_extractf128_si256(tmp_v,0x0)); v16_avx[1]=_mm256_cvtepu8_e
#ifdef_uuavx2__
__m256i tmp_v=_mm256_lddqu_si256(重新解释铸造(src+j));
v16_avx[0]=_mm256_cvtepu8_epi16(_mm256_extractf128_si256(tmp_v,0x0));
v16_avx[1]=_mm256_cvtepu8_epi16(_mm256_extractf128_si256(tmp_v,0x1));
v32_avx[0]=_mm256_cvtepi16_epi32(_mm256_extractf128_si256(v16_avx[0],0x0));
v32_avx[1]=_mm256_cvtepi16_epi32(_mm256_extractf128_si256(v16_avx[0],0x1));
v32_avx[2]=_mm256_cvtepi16_epi32(_mm256_extractf128_si256(v16_avx[1],0x0));
v32_avx[3]=_mm256_cvtepi16_epi32(_mm256_extractf128_si256(v16_avx[1],0x1));
对于(intl=0;l,我认为没有比已有的intrinsic更快的方法将无符号字符或无符号短字符转换为float
我尝试了其他几种使用位运算符的方法,但没有一种比这更快
因此,我认为让这个话题再继续下去是没有意思的。我认为没有比已有的内部函数更快的方法将无符号字符或无符号短字符转换为浮点
我尝试了其他几种使用位运算符的方法,但没有一种比这更快
因此,我认为让这个话题再拖下去是没有意思的。为什么不尝试测量一下?哪段代码?我这样做了,为什么我会问这个问题。我使用无符号短字符到浮点字符的转换的完整代码大约在15微秒内工作。函数convert_sse_intrinsic平均工作(超过10次迭代)在61纳秒的时间内,函数convert_sse_intrinsics2以58纳秒的速度运行。我想知道是否有加速转换的方法,以及如何进行转换。您是如何编译代码的?您使用了哪些命令行开关?此外,您是如何对其进行基准测试的?您用于基准测试的数据集大小是多少?我在Linux I c下使用-O1-O2-O3-Og选项编译代码。我使用头计时(C++11)的稳定时钟时间点进行基准测试。然后我以纳秒为单位进行持续时间转换。我用于基准测试的数据集的大小第一种算法是每种类型64 x 64的图像。我使用的是i7 Haswell系列,多亏了《英特尔intrisics指南》网站,我知道每一步的循环次数……等等每一步的理论处理时间。我要寻找的是更多的是一种“丑陋”但可移植的方式来加速从每种类型到浮点的转换。你为什么不尝试并测量一下?哪种代码?我这样做了,为什么我问这个问题。我使用从无符号短到浮点的转换的完整代码大约在15微秒内工作。函数convert_sse_intrinsic平均工作(超过10次迭代)在61纳秒的时间内,函数convert_sse_intrinsics2以58纳秒的速度运行。我想知道是否有加速转换的方法,以及如何进行转换。您是如何编译代码的?您使用了哪些命令行开关?此外,您是如何对其进行基准测试的?您用于基准测试的数据集大小是多少?我在Linux I c下使用-O1-O2-O3-Og选项编译代码。我使用头计时(C++11)的稳定时钟时间点进行基准测试。然后我以纳秒为单位进行持续时间转换。我用于基准测试的数据集的大小第一种算法是每种类型64 x 64的图像。我使用的是i7 Haswell系列,多亏了《英特尔intrisics指南》网站,我知道每一步的循环次数……等等每一步的理论处理时间。我要寻找的是这更像是一种“丑陋”但便携的方式,可以加速从每种类型到浮动的转换。
#ifdef __AVX2__
__m256i tmp_v =_mm256_lddqu_si256(reinterpret_cast<const __m256i*>(src+j));
v16_avx[0] = _mm256_cvtepu8_epi16(_mm256_extractf128_si256(tmp_v,0x0));
v16_avx[1] = _mm256_cvtepu8_epi16(_mm256_extractf128_si256(tmp_v,0x1));
v32_avx[0] = _mm256_cvtepi16_epi32(_mm256_extractf128_si256(v16_avx[0],0x0));
v32_avx[1] = _mm256_cvtepi16_epi32(_mm256_extractf128_si256(v16_avx[0],0x1));
v32_avx[2] = _mm256_cvtepi16_epi32(_mm256_extractf128_si256(v16_avx[1],0x0));
v32_avx[3] = _mm256_cvtepi16_epi32(_mm256_extractf128_si256(v16_avx[1],0x1));
for (int l=0; l<4; l++) {
__m256 vc1_ps = _mm256_cvtepi32_ps(_mm256_and_si256(v32_avx[l],m_lt_avx[l]));
__m256 vc2_ps = _mm256_cvtepi32_ps(_mm256_and_si256(v32_avx[l],m_ge_avx[l]));
/*
....
some processing there.
*/
}
#endif
#ifdef __SSE2__
#ifdef __SSE3__
__m128i tmp_v = _mm_lddqu_si128(reinterpret_cast<const __m128i*>(src+j));
#else
__m128i tmp_v = _mm_loadu_si128(reinterpret_cast<const __m128i*>(src+j));
#endif
#ifdef __SSE4_1__
v16[0] = _mm_cvtepu8_epi16(tmp_v);
tmp_v = _mm_shuffle_epi8(tmp_v,mask8);
v16[1] = _mm_cvtepu8_epi16(tmp_v);
v32[0] = _mm_cvtepi16_epi32(v16[0]);
v16[0] = _mm_shuffle_epi32(v16[0],0x4E);
v32[1] = _mm_cvtepi16_epi32(v16[0]);
v32[2] = _mm_cvtepi16_epi32(v16[1]);
v16[1] = _mm_shuffle_epi32(v16[1],0x4E);
v32[3] = _mm_cvtepi16_epi32(v16[1]);
#else
__m128i tmp_v_l = _mm_slli_si128(tmp_v,8);
__m128i tmp_v_r = _mm_srli_si128(tmp_v,8);
v16[0] = _mm_unpacklo_epi8(tmp_v,tmp_v_l);
v16[1] = _mm_unpackhi_epi8(tmp_v,tmp_v_r);
tmp_v_l = _mm_srli_epi16(v16[0],8);
tmp_v_r = _mm_srai_epi16(v16[0],8);
v32[0] = _mm_unpacklo_epi16(v16[0],tmp_v_l);
v32[1] = _mm_unpackhi_epi16(v16[0],tmp_v_r);
v16[0] = _mm_unpacklo_epi8(tmp_v,tmp_v_l);
v16[1] = _mm_unpackhi_epi8(tmp_v,tmp_v_r);
tmp_v_l = _mm_srli_epi16(v16[1],8);
tmp_v_r = _mm_srai_epi16(v16[1],8);
v32[2] = _mm_unpacklo_epi16(v16[1],tmp_v_l);
v32[3] = _mm_unpackhi_epi16(v16[1],tmp_v_r);
#endif
for (int l=0; l<4; l++) {
__m128 vc1_ps = _mm_cvtepi32_ps(_mm_and_si128(v32[l],m_lt[l]));
__m128 vc2_ps = _mm_cvtepi32_ps(_mm_and_si128(v32[l],m_ge[l]));
/*
...
some processing there.
*/
}
#endif
#ifdef __AVX2__
v32_avx[0] = _mm256_cvtepu16_epi32(_mm256_extractf128_si256(tmp_v,0x0));
v32_avx[1] = _mm256_cvtepu16_epi32(_mm256_extractf128_si256(tmp_v,0x1));
for(int l=0;l<2;l++) {
__m256 vc1_ps = _mm256_cvtepi32_ps(_mm256_and_si256(v32_avx[l],m_lt_avx[l]));
__m256 vc2_ps = _mm256_cvtepi32_ps(_mm256_and_si256(v32_avx[l],m_ge_avx[l]));
/*
...
some processing there.
*/
}
#endif
#ifdef __SSE2__
#ifdef __SSE3__
__m128i tmp_v = _mm_lddqu_si128(reinterpret_cast<const __m128i*>(src+j));
#else
__m128i tmp_v = _mm_loadu_si128(reinterpret_cast<const __m128i*>(src+j));
#endif
#ifdef __SSE4_1__
v32[0] = _mm_cvtepu16_epi32(tmp_v);
tmp_v = _mm_shuffle_epi32(tmp_v,0x4E);
v32[1] = _mm_cvtepu16_epi32(tmp_v);
#else
__m128i tmp_v_l = _mm_slli_si128(tmp_v,8);
__m128i tmp_v_r = _mm_srli_si128(tmp_v,8);
v32[0] = _mm_unpacklo_epi16(tmp_v,tmp_v_l);
v32[1] = _mm_unpackhi_epi16(tmp_v,tmp_v_r);
#endif
for(int l=0;l<2;l++) {
__m128 vc1_ps = _mm_cvtepi32_ps(_mm_and_si128(v32[l],m_lt[l]));
__m128 vc2_ps = _mm_cvtepi32_ps(_mm_and_si128(v32[l],m_ge[l]));
/*
...
some processing there.
*/
}
#endif
#include <immintrin.h>
#include <iterator>
#include <iostream>
#include <chrono>
void convert_sse_intrinsic(const ushort *source,const int len, int *destination)
{
__m128i zero2 = _mm_setzero_si128();
for (int i = 0; i < len; i+=4)
{
__m128i value = _mm_unpacklo_epi16(_mm_set_epi64x(0,*((long long*)(source+i)) /**ps*/), zero2);
value = _mm_srai_epi32(_mm_slli_epi32(value, 16), 16);
_mm_storeu_si128(reinterpret_cast<__m128i*>(destination+i),value);
}
}
void convert_sse_intrinsic2(const ushort *source,const int len, int *destination)
{
for (int i = 0; i < len; i+=8)
{
__m128i value = _mm_loadu_si128(reinterpret_cast<const __m128i*>(source+i));
_mm_storeu_si128(reinterpret_cast<__m128i*>(destination+i),_mm_cvtepu16_epi32(value));
value = _mm_shuffle_epi32(value,0x4E);
_mm_storeu_si128(reinterpret_cast<__m128i*>(destination+i+4),_mm_cvtepu16_epi32(value));
}
}
int main(int argc, char *argv[])
{
ushort CV_DECL_ALIGNED(32) toto[16] =
{0,500,1000,5000,
10000,15000,20000,25000,
30000,35000,40000,45000,
50000,55000,60000,65000};
int CV_DECL_ALIGNED(32) tutu[16] = {0};
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
convert_sse_intrinsic(toto,16,tutu);
std::chrono::steady_clock::time_point stop = std::chrono::steady_clock::now();
std::cout<<"processing time 1st method : "<<std::chrono::duration_cast<std::chrono::nanoseconds>(stop-start).count()<<" : ns"<<std::endl;
std::copy(tutu,tutu+16,std::ostream_iterator<int>(std::cout," "));
std::cout<<std::endl;
start = std::chrono::steady_clock::now();
convert_sse_intrinsic2(toto,16,tutu);
stop = std::chrono::steady_clock::now();
std::cout<<"processing time 2nd method : "<<std::chrono::duration_cast<std::chrono::nanoseconds>(stop-start).count()<<" : ns"<<std::endl;
std::copy(tutu,tutu+16,std::ostream_iterator<int>(std::cout," "));
std::cout<<std::endl;
return 0;
}