• C6000代码层面优化(一)


          201487日,看了一片很长见识的博文,关于DSP如何优化的,有一个问题没有搞通,“百度”一下关键字,居然搜查了一模一样的博文N片,现在也搞不懂这篇博文的原创作者是谁了。反正我感觉直接转摘过去,要是消化不掉,也没啥意思,所以我把我可以理解消化的就先记录下来吧。

     一、双重循环或多重循环在保证功能的前提下,减少嵌套循环的层数,原因有二个,如下:

    1)优化器优化时只在最内层循环中形成一个 pipeline,这样循环语句就不能充分利用C6 的软件流水线,而且对于内部循环的次数较少的情况,消耗在 prolog(填充)和eplog(排空)上的 cycle 数也是不可忽视的。

    2) 一个 cycle 内使用两个乘法器,如果内层循环循环次数较少,运算量也不大,一个cycle 只使用一次乘法器,而事实上我们可以在,所以还可以充分利用另外的一个乘法器。
        备注:一个内层循环会形成一个pipeline,流水优化是在pipeline中,一个pipeline中代码运行的时间,会消耗一个或者多个cycle

    例子:FIR滤波器原始程序
      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[i] = (sum >> 15);
      }

    可以优化为:
     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[i] = (sum >> 15);
       }

    }

    二、使用intrinsic函数,16位扩展为32
    c6000编译器提供的intrinsic 可快速优化C代码,intrinsic用前下划线表示同调用函数一样可以调用它,即直接内联为C6000的函数。
    例如,“aReg_ll = (Word40)_mpyu(L_var1, L_var2)>>16”中“_mpyu”就是一个intrinsics函数,它表示两个无符号数的高16位相乘,结果返回。

    这些内联函数定义在CCS所在的C6000/CGTOOLS/Include目录下的C6X.h文件中。
    下面这个例子是C6000的“Programmer's Guide”上提取的使用intrinsics优化C代码的例子。
    源代码:
    int dotprod(const short *a, const short *b, unsigned int N)
    {
    int i, sum = 0;
    for (i = 0; i < N; i++)
    sum += *(a+i) * *(b+i);
    return sum;
    }

    改编后代码:
    int dotprod(const int *a, const int *b, unsigned int N)
    {
    int i, sum1 = 0, sum2 = 0;
    for (i = 0; i < (N >> 1); i++)
    {
    sum1 += _mpy (*(a+i), *(a+i));
    sum2 += _mpyh(*(a+i), *(a+i));
    }
    return sum1 + sum2;
    }

    三、使用 const 可以限定目标

    C6000编译器如果确定两条指令是不相关的,则安排它们并行执行。 关键字const可以指定一个变量或者一个变量的存储单元保持不变。
    这有助于帮助编译器确定指令的不相关性。例如下例中,源代码不能并行执行,而结果改编后的代码可以并行执行。
    void fir_fxd1(short input[], short coefs[], short out[])
    {
    int i, j;
    for (i = 0; i < 40; i++)
    {
    for (j = 0; j < 16; j++)
    out[i*16+j]= coefs[j] * input[i + 15 - j];
    }
    }
    改编后的代码:
    void fir_fxd2(const short input[], const short coefs[], short out[])
    {
    int i, j;
    for (i = 0; i < 40; i++)
    {
    for (j = 0; j < 16; j++)
    out[i*16+j]= coefs[j] * input[i + 15 - j];
    }

    }

    四、if...else...语句的优化

    如果在循环中出现if...else...语句,由于if...else...语句中有跳转指令,而每个跳转指令有5个延迟间隙,因此程序执行时间延长;另外,循环内跳转也使软件流水受到阻塞。直接使用逻辑判断语句可以去除不必要的跳转。
    源代码:
    if (sub (ltpg, LTP_GAIN_THR1) <= 0)
    {
    adapt = 0; 
    }
    else

    if (sub (ltpg, LTP_GAIN_THR2) <= 0)
    {
    adapt = 1; 
    }
    else
    {
    adapt = 2; 
    }
    }

    改编后的代码:
      adapt = (ltpg>LTP_GAIN_THR1) + (ltpg>LTP_GAIN_THR2); 

    本篇先写到这里,以上内容均属于个人理解,事例和文字来源网络,若有新的理解,将持续更新。

  • 相关阅读:
    Java项目中读取properties文件,以及六种获取路径的方法
    在eclipse中使用JUnit4,以及使用JUnit4进行单元测试的技巧
    [Evernote]印象笔记使用经验技巧
    使用Word2010发布博客文章
    Win7/8 绿色软件开机启动
    常见笔试题
    排序
    数据库知识归纳(索引)
    数据库知识归纳(事务)
    Redis
  • 原文地址:https://www.cnblogs.com/mfc1207/p/3928848.html
Copyright © 2020-2023  润新知