[资料分享] TMS320C66x双重循环和多重循环的优化总结

Aguilera   2019-3-21 18:29 楼主
双重循环多重循环看起来比较复杂,但实际上多重循环优化方法比较简单,就在于一个字:“拆”,一旦完成这一步之后,多重循环就成为单层循环,优化就可以按照普通的单层循环来做了。
        多重循环的特点是在优化器优化时只在最内层循环中形成一个pipeline,这样循环语句就不能充分利用C6的软件流水线,而且对于内部循环的次数较少的情况,消耗在prolog(循环填充)和eplog(循环排空)上的cycle数也是不可忽视的。
针对这种状况可以考虑将多重循环拆开形成一个单层循环,可以拆外层循环也可以拆内层循环,一般视具体情况而定。这样就可以充分利用优化器构成的Pipeline。如下例:


void fir2(const short input[], const short coefs[], short out[])
{
        int i, j;
        int sum = 0;
        for (i = 0; i < 40; i++)
        {
                for (j = 0; j < 16; j++)
                        sum += coefs[j] * input[i + 15 - j];
                out = (sum >> 15);
        }
}
        内层循环循环次数较少,运算量也不大,资源方面只占用了一个乘法器,一个cycle只使用一次乘法器,而事实上我们可以在一个cycle内使用两个乘法器,所以还可以充分利用另外的一个乘法器。因此考虑将内层循环拆开来执行,如下:


void fir2_u(const short input[], const short coefs[], short out[])
{
        int i, j;
        int sum;
        for (i = 0; i < 40; i++)
        {
                sum = coefs[0] * input[i + 15];
                sum += coefs[1] * input[i + 14];
                sum += coefs[2] * input[i + 13];
                sum += coefs[3] * input[i + 12];
                sum += coefs[4] * input[i + 11];
                sum += coefs[5] * input[i + 10];
                sum += coefs[6] * input[i + 9];
                sum += coefs[7] * input[i + 8];
                sum += coefs[8] * input[i + 7];
                sum += coefs[9] * input[i + 6];
                sum += coefs[10] * input[i + 5];
                sum += coefs[11] * input[i + 4];
                sum += coefs[12] * input[i + 3];
                sum += coefs[13] * input[i + 2];
                sum += coefs[14] * input[i + 1];
                sum += coefs[15] * input[i + 0];
                out = (sum >> 15);
        }
}
        这样虽然代码长度增加了,可变成了单循环,所有的运算都参加到pipeline中来,在Piped loop kernal中产生每一个cycle内都使用了两个乘法器,充分利用了DSP内部的资源,提高了运行效率。又如下例:
tot = 4;
for (k = 0; k < 4; k++)
{
        max = 0;
        for (i = k; i < 44; i += STEP)
        {
                s = 0;
                for (j = i; j < 44; j++)
                        s = L_mac(s, x[j], h[j - i]);//乘加运算相当于_add(s,_mpy(x[j],h[j-i]))
                y32 = s;
                s = L_abs(s);
                if (L_sub(s, max) >(Word32) 0)
                        max = s;
        }
        tot = L_add(tot, L_shr(max, 1));
}
        在这个多层循环中一共有三层循环,而最内层的循环的运算量很小,只有一次乘累加操作,而我们知道C6中一个packet中可以做两个乘累加运算,所以为了增加内部循环的运算,减少外部循环的层数,我们可以将第一层循环的操作拆开,其负责的运算加入到内部循环中,也就是在内层循环中一次做四次的乘累加运算,这样将多次操作形成pipeline,提高了运行效率,优化后的C代码如下:
tot = 4;
max0 = 0;
max1 = 0;
max2 = 0;
max3 = 0;
for (i = 0; i < 44; i += STEP) //STEP=4, 11 times cirs
{
        //code
        for (j = 0; j <= 40 - i; j++)
        {
                s0 = (Word32)(_sadd(s0, _smpy(hh[j], xx[j + i])));
                s1 = (Word32)(_sadd(s1, _smpy(hh[j], xx[j + i + 1])));
                s2 = (Word32)(_sadd(s2, _smpy(hh[j], xx[j + i + 2])));
                s3 = (Word32)(_sadd(s3, _smpy(hh[j], xx[j + i + 3])));
        }
}
//code

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复