测试环境:ccs10.4,编译优化级别o3,dsplib版本3.4 for c674x,编译器为TI7.4.24。
所有代码和数据均放在L2RAM中,L1P按默认值做cache用,L1D按默认值是做RAM用
现象:DSPF_sp_dotprod函数涉及两组float的相乘,两组系数均为32字节对齐时,测试将1024阶点乘执行1M次,测试结果表明其效率存在波动。
以下是dsplib中点乘函数的c代码:
#pragma CODE_SECTION(DSPF_sp_dotprod, ".text:optimized"); #include "DSPF_sp_dotprod.h" float DSPF_sp_dotprod(const float * x, const float * y, const int nx) { int i; float sum = 0; _nassert(nx > 0); _nassert(nx % 8 == 0); _nassert((int)x % 8 == 0); _nassert((int)y % 8 == 0); for(i = 0; i < nx; i++) sum += x[i]*y[i]; return (sum); }
测试用代码:
//#pragma DATA_SECTION(".far:optimized"); #pragma DATA_ALIGN(32) float x1[1024+100]; //#pragma DATA_SECTION(".far:optimized"); #pragma DATA_ALIGN(32) float x2[1024+100]; printf("==DotProd V0 test!==\n"); for(cur = 0; cur <32; cur++) { mTC.StartTimer(); for(i=0; i<cycles; i++) { sum+=dot_product_v0_align8(x1+cur<<1,x2, 1024);//起点每次移动2元素 } mTC.StopTimer(); printf("cur=%d, ",cur); mTC.PrintResult(); }
测试结果:
==DotProd V0 test!==
cur=0, 2.355 s @456MHz.
cur=1, 1.231 s @456MHz.
cur=2, 1.232 s @456MHz.
cur=3, 1.231 s @456MHz.
cur=4, 2.355 s @456MHz.
cur=5, 1.231 s @456MHz.
cur=6, 1.232 s @456MHz.
cur=7, 1.231 s @456MHz.
cur=8, 2.355 s @456MHz.
cur=9, 1.231 s @456MHz.
cur=10, 1.232 s @456MHz.
cur=11, 1.231 s @456MHz.
cur=12, 2.355 s @456MHz.
cur=13, 1.231 s @456MHz.
cur=14, 1.232 s @456MHz.
cur=15, 1.231 s @456MHz.
cur=16, 2.355 s @456MHz.
cur=17, 1.231 s @456MHz.
cur=18, 1.232 s @456MHz.
cur=19, 1.231 s @456MHz.
cur=20, 2.355 s @456MHz.
cur=21, 1.231 s @456MHz.
cur=22, 1.232 s @456MHz.
cur=23, 1.231 s @456MHz.
cur=24, 2.355 s @456MHz.
cur=25, 1.231 s @456MHz.
cur=26, 1.232 s @456MHz.
cur=27, 1.231 s @456MHz.
cur=28, 2.355 s @456MHz.
cur=29, 1.231 s @456MHz.
cur=30, 1.232 s @456MHz.
cur=31, 1.231 s @456MHz.
所以,为什么该代码在x和h都是32字节对齐的情况下,会出现效率明显的下降呢?按我推断是和储存器访问冲突有关,那么有什么办法可以消除此问题呢
另外,是否有不要求8字节对齐的高效点乘函数呢,我看dsplib里面只提供了8字节对齐的版本,如果我想每次将起点移动4字节的话,dsplib的点乘就不工作了
虽然我手写了一个,但是其效率跟库函数在32字节对齐处的效率相当,是否有办法进一步优化呢
float dot_product_v1(const float *restrict x, const float *restrict h, const unsigned int length) { int i; float sum1 = 0, sum2 = 0; _nassert(length > 0); _nassert(length % 4 == 0); // //数据已经对齐,提示编译器优化 //事实上float数组本身都是4字节对齐的,实测加不加效率相同 // _nassert(((int)(x) & 0x3) == 0); // _nassert(((int)(h) & 0x3) == 0); #pragma MUST_ITERATE(,1024,2)//最小8(去除后可使用分段),最大1024,执行次数是2的倍数【即滤波器长度为4的倍数】 for (i = 0; i < length; i+=2) { sum1 += x[i]*h[i]; sum2 += x[i+1]*h[i+1]; } return sum1 + sum2; }