之前讲了很多的理论,之后会结合一些代码讲解一些优化的方法,今天刚对AVS熵解码的一部分内存访问进行优化
在熵编码和熵解码这样的底层函数因为调用次数是非常多的,有时候只要减少一个clock都会优化很多的内容
做DSP优化,和C语言优化有一些不同,除了一些常规的注意嵌套循环,减少判断语句之类的操作外,
对dsp优化必须非常注意减少内存的访问和程序运行的并行化处理
同时对于所采用的硬件也应该注意其自带的一些内联指令,这些内联指令对于一些运算是十分有用的,这个在我做DCT和IDCT优化的时候有明显的感觉,优化达到了80%以上,之后会慢慢介绍一些内联指令
我所提及的指令大部分都是针对TI 6678,对于别的型号可以作为参考用:
言归正传:
在AVS熵解码的一个函数
if (--Dbits_to_go < 0) { //<如果当前缓冲区没有数据
get_byte();//<从码流中获得一个字节的数据存入缓冲区
}
// Shift in next bit and add to value
value_t = (value_t << 1) | ((Dbuffer >> Dbits_to_go) & 0x01);//<将value_t和当前缓冲区数据中拿出来一个bit进行运算
value_t = 256 + value_t - t2;这里没有循环,只有一次操作
while (t_rlps < 256) {//t_rlps不为0,这是一个循环操作
t_rlps = t_rlps << 1;
if (--Dbits_to_go < 0) {
get_byte();
}
// Shift in next bit and add to value
value_t = (value_t << 1) | ((Dbuffer >> Dbits_to_go) & 0x01);//<和上面类似
}
while (value_t < 256) {//> Dbits_to_go) & 0x01); //<和上面类似
value_s++;
}
在这个函数中主要对这三部分进行优化,因为他们在大量的访问内存,并且做循环操作
1 get_byte()函数使用得可以更加充分,我们不取一个字节,在保证边界条件的情况下我们一次先取出来4个字节
#define get_byte(){
Dbuffer = Dcodestrm[(*Dcodestrm_len)++];
Dbits_to_go = 7;
}
修改为:
void Get_Byte2(DecodingEnvironmentPtr dep) {
Dbuffer = _mem4(Dcodestrm + *Dcodestrm_len);
Dbuffer = _packlh2(Dbuffer,Dbuffer);
Dbuffer = _swap4(Dbuffer);
Dbits_to_go = 31;
*Dcodestrm_len +=4;
}
这里用到了一些内联函数,具体可以参考6678的操作手册
上面的代码不仅取出来了4个字节的数据,还让码流顺序进行了交换,这个是代码中所需要的
(Dbuffer >> Dbits_to_go)
表示每次都是从高位中读出的,因此当Dbits_to_go从7变为31的时候也需要将码流适当做顺序处理
通过一次访问4个字节就会减少对内存的访问次数
2 计算一个循环的最大循环次数,为其准备充分的数据,减少循环内部判断
第一部分的代码最多循环1次
第二部分的代码最多循环8次
第三部分的代码循环次数不一定,但是根据分析我们可以知道value_t如果不为0,那么他的循环次数最多8次,如果为0,那么就需要根据缓冲区中的数据进行判断了,因此为了投机运算,我们开分支进行处理
if (Dbits_to_go < 16)
{
Get_Byte2_(dep);
}
在函数一开始将数据准备好,之后就不再有判断了,对应三部分的代码
dep->value_t = (dep->value_t << 1) | ((Dbuffer >>(--Dbits_to_go)) & 0x01);
dep->value_t = 256 + dep->value_t - t2;
tempi = _lmbd(1,t_rlps)-23;//<_lmbd is searching for the number of 0 befor 1
//< tempi refers to the cyclenum of while (t_rlps < 256),because the max number is 8
dep->value_t <<= tempi;
if (tempi != 0)
{
dep->value_t = dep->value_t | _extu(Dbuffer,32-Dbits_to_go,32-tempi);//<_extu get the bit of Dbuffer between 32-Dbits_to_go and 32-tempi
}
Dbits_to_go-=tempi;
t_rlps<<=tempi;
if (dep->value_t)
{
tempi = _lmbd(1,dep->value_t)-23;
dep->value_t <<= tempi;
if (tempi != 0)
{
dep->value_t = dep->value_t | _extu(Dbuffer,32-Dbits_to_go,32-tempi);
}
Dbits_to_go-=tempi;
dep->value_s +=tempi;
}
else
{
while (dep->value_t < QUARTER)
{
if (--Dbits_to_go < 0)
{
Get_Byte2(dep);
}
dep->value_t = (dep->value_t << 1) | ((Dbuffer >> Dbits_to_go) & 0x01);
dep->value_s++;
}
}
还有需要注意的就是使用恰当的DSP对应的内联函数