如何使用SSE指令提高FIR算法效率
来源:互联网 发布:网易房产数据准确吗 编辑:程序博客网 时间:2024/05/16 15:15
如何使用SSE指令提高FIR算法效率
在搭建好VC6.0 SSE环境后(请参考:如何使VC6支持内嵌SSE指令),菜菜这里就开始现学现卖了J。因为自己的机器较老,仅支持MMX/SSE/SSE2指令,所以这里的方法也仅仅局限于此。
好的,言归正传!一般的FIR算法如下:
static void ShowFIR( float *in, float *out, float *coeff, unsigned int count )
{
unsigned int i;
unsigned int j;
for ( i = 0; i < count - TAP; ++ i )
{
float sum;
sum = 0;
for ( j = 0; j < TAP; ++ j )
{
sum += in[ j ] * coeff[ j ];
}
*out ++ = sum;
++ in;
}
}
那么如何使用SSE指令来优化它呢?
SSE的指令在于它使用了向量计算,极大的提高了运算速度,所以在优化之前,我们首先要对原有的c代码进行向量构造。因为水平有限,构造了一个粗糙向量(如果有那位网友能够指导我进行优化,我将万分感谢!)。
这里假设相关的所有长度都是16个字节的倍数。
static void ShowFIR_O1( float *in, float *out, float *coeff, unsigned int count )
{
unsigned int i;
unsigned int j;
for ( i = 0; i < count - TAP; i += 4 )
{
out[ 0 ] = 0;
out[ 1 ] = 0;
out[ 2 ] = 0;
out[ 3 ] = 0;
for ( j = 0; j < TAP; j += 4 )
{
out[ 0 ] += in[ j ] * coeff[ j ];
out[ 0 ] += in[ j + 1 ] * coeff[ j + 1 ];
out[ 0 ] += in[ j + 2 ] * coeff[ j + 2 ];
out[ 0 ] += in[ j + 3 ] * coeff[ j + 3 ];
out[ 1 ] += in[ j + 1 ] * coeff[ j ];
out[ 1 ] += in[ j + 2 ] * coeff[ j + 1 ];
out[ 1 ] += in[ j + 3 ] * coeff[ j + 2 ];
out[ 1 ] += in[ j + 4 ] * coeff[ j + 3 ];
out[ 2 ] += in[ j + 2 ] * coeff[ j ];
out[ 2 ] += in[ j + 3 ] * coeff[ j + 1 ];
out[ 2 ] += in[ j + 4 ] * coeff[ j + 2 ];
out[ 2 ] += in[ j + 5 ] * coeff[ j + 3 ];
out[ 3 ] += in[ j + 3 ] * coeff[ j ];
out[ 3 ] += in[ j + 4 ] * coeff[ j + 1 ];
out[ 3 ] += in[ j + 5 ] * coeff[ j + 2 ];
out[ 3 ] += in[ j + 6 ] * coeff[ j + 3 ];
}
in += 4;
out += 4;
}
}
上面方法的主要思路是,在保持原有算法的基础上,对代码进行展开和重组,形成若干个向量组。在这个基础上,我们再使用SSE指令进行快速的矢量计算以获取高性能。从上的构建可以看出,我们有两组向量,分别用in和coeff指向。in指向的向量in[j]是16个字节地址对齐,而in[j+1], in[j+2], in[j+2]是不对齐的,故除了第一组能够使用movaps之外,其他都使用movups来装载。coeff仅使用一组向量和in的4组向量进行相乘,所以可以考虑将它放入xmm寄存器中提高运行效率。从上面的c代码可以看出,对于每组向量计算的结果将被放在4个单元中([127,96],[95,64],[63:32], [31:0]),所以在计算最后要将它们水平相加后再放入out数组中。
相关的汇编代码如下:
static void ShowFIR_O2( float *inPtr, float *outPtr, float *coeffPtr, unsigned int count )
{
__asm
{
xorps xmm0, xmm0
xorps xmm1, xmm1
xorps xmm2, xmm2
xorps xmm3, xmm3
xor eax, eax
xor ecx, ecx
mov ebx, DWORD PTR[ coeffPtr ]
mov esi, DWORD PTR[ inPtr ]
mov edx, DWORD PTR[ outPtr ]
jmp b2
b1:
movaps xmm4, XMMWORD PTR[ ebx + ecx * 4 ]
movaps xmm5, XMMWORD PTR[ esi + ecx * 4 ]
mulps xmm5, xmm4
addps xmm0, xmm5
movups xmm5, XMMWORD PTR[ esi + ecx * 4 + 4 ]
mulps xmm5, xmm4
addps xmm1, xmm5
movups xmm5, XMMWORD PTR[ esi + ecx * 4 + 8 ]
mulps xmm5, xmm4
addps xmm2, xmm5
movups xmm5, XMMWORD PTR[ esi + ecx * 4 + 12 ]
mulps xmm5, xmm4
addps xmm3, xmm5
add ecx, 4
cmp ecx, TAP
jb b1
movhlps xmm5, xmm0
addps xmm5, xmm0
movaps xmm6, xmm5
shufps xmm5, xmm5, 1
addps xmm5, xmm6
movss XMMWORD PTR[ edx + eax * 4 ], xmm5
movhlps xmm5, xmm1
addps xmm5, xmm1
movaps xmm6, xmm5
shufps xmm5, xmm5, 1
addps xmm5, xmm6
movss XMMWORD PTR[ edx + eax * 4 + 4 ], xmm5
movhlps xmm5, xmm2
addps xmm5, xmm2
movaps xmm6, xmm5
shufps xmm5, xmm5, 1
addps xmm5, xmm6
movss XMMWORD PTR[ edx + eax * 4 + 8 ], xmm5
movhlps xmm5, xmm3
addps xmm5, xmm3
movaps xmm6, xmm5
shufps xmm5, xmm5, 1
addps xmm5, xmm6
movss XMMWORD PTR[ edx + eax * 4 + 12 ], xmm5
add eax, 4
b2:
cmp eax, count - TAP
jb b1
}
}
为了防止与汇编保留字冲突,我将原有的C代码中的部分变量进行了重新命名。此外,汇编代码假设他们的首地址都是16字节对齐的。16字节地址对齐的方法很简单,只要在变相声明的前面加上“__declspec(align( 16 ) )”修饰,比如:
static __declspec( align( 16 ) ) float fin[ COUNT ];
static __declspec( align( 16 ) ) float fout1[ COUNT ];
static __declspec( align( 16 ) ) float fout2[ COUNT ];
static __declspec( align( 16 ) ) float fcoeff[ TAP ];
它告诉编译器,上面声明的变量必须16字节地址对齐J。
小结:
上面的汇编代码有几个较大的缺陷:
1. 没有对水平相加进行优化,SSE3有一个HADDPS的水平相加指令,它对性能的提升有重大作用,因为我现在无法调试(计算机仅仅支持SSE2)所以使用了上面一对难看的指令。
2. 没有对out向量进行一次向量写操作(在这个实现中,用了很傻的4次标量写操作)。主要原因是还没有充分理解所有相关的SSE指令,并将它们融会贯通。
3. 对原有代码的向量构造不够好,我想一定有一种方法可以避免最后的差劲的水平向量加操作和4次标量写操作。我的理想状态是没有水平向量相加和一次向量写操作。
我想,随着学习的深入,这些方面将会被逐一解决。我将在后继的文章中对这些遗憾的方面进行逐步探讨以获取更好的性能。如果有大侠能够出手相救,给我醍醐灌顶的提示,小弟在此叩拜了J!
- 如何使用SSE指令提高FIR算法效率
- 如何使用SSE指令提高FIR算法效率(进化一)
- 如何使用SSE指令提高FIR算法效率(进化二)
- SSE指令使用注意
- 如何在vs2010中使用SSE指令集
- 如何在vs2010中使用SSE指令集
- SSE指令的使用学习
- 在视频格式转换中使用MMX和SSE指令集提高性能
- 在视频格式转换中使用MMX和SSE指令集提高性能
- 在视频格式转换中使用MMX和SSE指令集提高性能
- 在视频格式转换中使用MMX和SSE指令集提高性能
- 如何熟练使用MyEclipse提高开发效率
- 如何使用google提高搜索效率
- 使用高级搜索指令提高搜索效率(百度,谷歌)
- SSE指令算法及应用----入门篇
- SSE指令
- sse指令
- SSE 指令
- 一种新的BootLoader启动引导方式研究
- java 一道线程面试题
- javascript事件解释
- 微软将 jQuery IntelliSense整合到Visual Studio
- ASP开发
- 如何使用SSE指令提高FIR算法效率
- 成熟恋情必经的四个阶段
- web项目经理手册-web项目经理成长之路
- How to add, modify, or delete registry subkeys and values by using a registration entries (.reg) file
- 简单的arp攻击
- JBuilder2006下载及破解
- Visual Studio 2005 Express Edition 简体中文正式版下载 - 已增加安装攻略
- 谈谈对攻读计算机研究生的看法(转载)----差距啊,都不敢说是研究生了
- HAHA