快乐虾
http://blog.csdn.net/lights_joy/
本文适用于
ADSP-BF561
Visual DSP++ 5.0 (update 7)
x264-snapshot-20091118-2245
欢迎转载,但请保留作者信息
发现了一个疏忽,排名第二的x264_pixel_satd_8x4函数没有放到L1_code中,改正错误,再运行:
encoded 301 frames, 2.02 fps, 1081.88 kb/s
86802M的cycle,怎么可能?速度反而变慢了!下降了386M的cycle。
退回上一步再验证,还是如此,晕……………………..@#@
究竟是什么导致这样的结果??
想来这个结果只能和调用者有关。
当x264_pixel_satd_8x4和它的调用者位于同一块内存区域时(<64K),编译器只要生成4个字节的call指令:
call x264_pixel_satd_8x4
当把这个函数放到L1时时,编译器只能生成这样的指令:
P1.L = 0x330a;
P1.H = 0xffa0;
CALL (P1);
差距就在这里。
本来程序在L1里面和SDRAM里面执行应该是有很大区别的,但在启用cache的情况下,如果这段代码恰好就位于cache中,就变得没有什么区别了。
我们尝试将其中的一个调用函数x264_pixel_satd_16x16放到L1中,再执行:
encoded 301 frames, 2.02 fps, 1081.88 kb/s
总共86614M的cycle。
我们再尝试将其它调用者放到L1中,将下面的函数放到L3:
add4x4_idct
运行结果:
encoded 301 frames, 2.02 fps, 1081.88 kb/s
总共耗费了86599M的cycle。
运行结果证实了我们的猜测。
看来我们现在只能把x264_pixel_satd_8x4放到L3中,仍然把add4x4_idct放到L1,因为这样效率最高,哈哈。
下面我们再看看x264_pixel_satd_8x4这个函数本身有没有可以优化的地方:
#define HADAMARD4(d0,d1,d2,d3,s0,s1,s2,s3) {/
int t0 = s0 + s1;/
int t1 = s0 - s1;/
int t2 = s2 + s3;/
int t3 = s2 - s3;/
d0 = t0 + t2;/
d2 = t0 - t2;/
d1 = t1 + t3;/
d3 = t1 - t3;/
}
// in: a pseudo-simd number of the form x+(y<<16)
// return: abs(x)+(abs(y)<<16)
static ALWAYS_INLINE uint32_t abs2( uint32_t a )
{
uint32_t s = ((a>>15)&0x10001)*0xffff;
return (a+s)^s;
}
static NOINLINE int x264_pixel_satd_8x4( uint8_t *pix1, int i_pix1, uint8_t *pix2, int i_pix2 )
{
uint32_t tmp[4][4];
uint32_t a0,a1,a2,a3;
int sum=0, i;
for( i=0; i<4; i++, pix1+=i_pix1, pix2+=i_pix2 )
{
a0 = (pix1[0] - pix2[0]) + ((pix1[4] - pix2[4]) << 16);
a1 = (pix1[1] - pix2[1]) + ((pix1[5] - pix2[5]) << 16);
a2 = (pix1[2] - pix2[2]) + ((pix1[6] - pix2[6]) << 16);
a3 = (pix1[3] - pix2[3]) + ((pix1[7] - pix2[7]) << 16);
HADAMARD4( tmp[i][0], tmp[i][1], tmp[i][2], tmp[i][3], a0,a1,a2,a3 );
}
for( i=0; i<4; i++ )
{
HADAMARD4( a0,a1,a2,a3, tmp[0][i], tmp[1][i], tmp[2][i], tmp[3][i] );
sum += abs2(a0) + abs2(a1) + abs2(a2) + abs2(a3);
}
return (((uint16_t)sum) + ((uint32_t)sum>>16)) >> 1;
}
在这里,我们发现了一个叫abs2的内联函数,它用以将一个无符号整数分成高16位和低16位,分别取其绝对值。我们将它用561的向量指令重写:
// in: a pseudo-simd number of the form x+(y<<16)
// return: abs(x)+(abs(y)<<16)
static ALWAYS_INLINE uint32_t abs2( uint32_t a )
{
uint32_t s;
asm(
"%0 = abs %0 (v);"
:"=d"(s)
:"d"(a)
);
return s;
}
在改写之前,第二个for循环生成这样的指令:
改写之后,生成的汇编就变成了:
这里有个问题,采用向量计算与原算法相比,其计算结果略有差异:
比如0xffffffff,这个数它的高低16位都是-1,使用向量取绝对值可以得到0x00010001这样的结果,但如果是原算法则只能得到0x0000 0001这样的结果,累加下来之后的差距最大将达到4。不过这还在我们能忍受的范围之内,呵呵。
改写之后导致此函数的cycle数从340下降到248,再运行我们的程序:
encoded 301 frames, 2.20 fps, 1222.74 kb/s
总共消耗了79702M个cycle,效率提高了7%。
在这个函数中,使用了一个tmp[4][4]的数组,我们直接将之放入L1,再运行:
encoded 301 frames, 2.52 fps, 1131.15 kb/s
总共69572M cycle,效率提高了12%。
我们希望最终能够用汇编实现整个函数,但是依照先易后难的原则,目前暂且放下。
近日,我家6岁的小姑娘参加了第六届POP全国少儿英语风采大赛,拉票进行中(2011-6-15前)。
请帮忙点击新东方网站的链接:
http://popdasai.xdf.cn/toupiao.php?do=space&uid=4237
投她一票,谢谢!
在ADSP-BF561上使用x264(6):get_ref(2009-11-25)
在ADSP-BF561上使用x264(5):Writeback vs writethrough(2009-11-24)
在ADSP-BF561上使用x264(4):确认热点(2009-11-24)
在ADSP-BF561上使用x264(4):打开cache(2009-11-24)
在ADSP-BF561上使用x264(3):正确性验证(2009-11-24)
ADSP-BF561软件优化(2):移植x264(2009-11-19)
ADSP-BF561软件优化(1):开篇(2009-11-18)