首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

【推荐】C6XX优化经验总结 [转帖]

十六、C6X优化inline举例:

1、原程序:
for (i = LO_CHAN; i <= HI_CHAN; i++)
{

norm_shift = norm_l(st->ch_noise);
Ltmp = L_shl(st->ch_noise, norm_shift);

norm_shift1 = norm_l(st->ch_enrg);
Ltmp3 = L_shl1(st->ch_enrg, norm_shift1 - 1);

Ltmp2 = L_divide(Ltmp3, Ltmp);
Ltmp2 = L_shr(Ltmp2, 27 - 1 + norm_shift1 - norm_shift); // * scaled as 27,4 *

if (Ltmp2 == 0)
Ltmp2 = 1;

Ltmp1 = fnLog10(Ltmp2);
Ltmp3 = L_add(Ltmp1, LOG_OFFSET - 80807124); // * -round(log10(2^4)*2^26 *
Ltmp2 = L_mult(TEN_S5_10, extract_h(Ltmp3));
if (Ltmp2 < 0)
Ltmp2 = 0;
// * 0.1875 scaled as 10,21 *
Ltmp1 = L_add(Ltmp2, CONST_0_1875_S10_21);
// * tmp / 0.375 2.667 scaled as 5,10, Ltmp is scaled 15,16 *
Ltmp = L_mult(extract_h(Ltmp1), CONST_2_667_S5_10);
ch_snr = extract_h(Ltmp);
}
*/



2、优化后程序:
//因循环体太大,拆成两个循环并把相应的函数内嵌以使程序能pipeline,
//用L_div_tmp[]保存因拆分而产生的中间变量。
for (i = LO_CHAN; i <= HI_CHAN; i++)
{
//norm_shift = norm_l(st->ch_noise);
norm_shift = _norm(st->ch_noise);
Ltmp = _sshl(st->ch_noise, norm_shift);

//norm_shift1 = norm_l(st->ch_enrg);
norm_shift1 = _norm(st->ch_enrg);
//Ltmp3 = L_shl1(st->ch_enrg, norm_shift1 - 1);
LLtmp1 = st->ch_enrg;
LLtmp1 = LLtmp1 << (norm_shift1 + 7);
Ltmp3 = (Word32)(LLtmp1 >> 8);

Ltmp2 = IL_divide(Ltmp3, Ltmp);
//Ltmp2 = L_shr(Ltmp2, 27 - 1 + norm_shift1 - norm_shift);
Ltmp2 = (Ltmp2 >> (27 - 1 + norm_shift1 - norm_shift));

if (Ltmp2 == 0)
Ltmp2 = 1;
L_div_tmp = Ltmp2;
}
for (i = LO_CHAN; i <= HI_CHAN; i++)
{
Ltmp2 = L_div_tmp;
Ltmp1 = IfnLog10(Ltmp2);
//Ltmp3 = L_add(Ltmp1, LOG_OFFSET - 80807124);
Ltmp3 = _sadd(Ltmp1, LOG_OFFSET - 80807124);
//Ltmp2 = L_mult(TEN_S5_10, extract_h(Ltmp3));
Ltmp2 = _smpy(TEN_S5_10, (Ltmp3 >> 16));
if (Ltmp2 < 0)
Ltmp2 = 0;

Ltmp1 = _sadd(Ltmp2, CONST_0_1875_S10_21);

//Ltmp = L_mult(extract_h(Ltmp1), CONST_2_667_S5_10);
Ltmp = _smpy((Ltmp1 >> 16), CONST_2_667_S5_10);
//ch_snr = extract_h(Ltmp);
ch_snr = (Ltmp >> 16);
}

3、优化说明
观察上面这个循环,循环体本身比较大,且含有两个函数L_divide()和
fnLog10(),而C62内部只有32个寄存器,且有些寄存器是系统用的,如B14、B15这样循环体太大将会导致寄存器不够分配,从而导致系统编译器无法实现循环的pipeline。

为了实现循环的pipeline。我们需要把循环体进行拆分,拆分时要考虑以下几点:
(1)、拆分成几个循环比较合适?在各个循环能pipeline的前提下,拆开的循环个数越少越好。这就要求尽可能让各个循环的运算量接近。
(2)考虑在什么地方把程序拆开比较合适?循环体里的数据流往往并不是单一的,在拆开的断点处势必要用中间变量保存上次的循环运算结果,供以后的循环用。适当的拆开循环体,使所需的中间变量越少越好。
(3)循环体中的函数调用必须定义成内嵌形式,含有函数调用的循环系统是无法使之pipeline的;各个循环体中的判断分支机构不可太多,否则系统也无法使之pipeline,为此应近可能把可以确定下来的分支确定下来,并尽可能用内嵌指令。

针对上面这个例子,考虑:
(1)为让各个循环的运算量大致相当,应把L_divide()和fnLog10()分到两个循环中去,从循环体大小上考虑,估计拆成两个循环比较合适。
(2)考虑在什么地方把程序拆开比较合适?在
if (Ltmp2 == 0)
Ltmp2 = 1;
后拆开,因为后面用到的数据只有Ltmp2,故只需用一个数组保存每次循环的Ltmp2值即可。
(3)循环体中的两处函数调用L_divide()和fnLog10()都定义了其内嵌形式,IL_divide()和IfnLog10()。当把可以确定下来的分支作确定处理,并尽可能用内嵌指令后,该循环体中所剩的分支结构已很少,循环体可以pipeline。优化前程序用2676 cycle,优化后用400 cycle。优化后两个子循环的MII分别为14和6cycle。
返回列表