⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c6000优化经验.txt

📁 dsp开发过程中必备的参考资料,内有常见开发经常遇到问题的说明及应注意的问题
💻 TXT
📖 第 1 页 / 共 3 页
字号:
 C6XX优化经验总结
一、c6x的编译的常用选项 

(一)c6x的编译程序为“cl6x.exe”使用的方法 

Cl6x [options] [filenames] 

Cl6x:  编译程序 

Options:   编译选项 

Filenames: C或汇编源文件 

说明: 

编译选项是一个字母或者两个字母,对大小写不敏感。 

编译选项的前面需要有一个“-”符号。 

一个字母的选项可以合并在一起。比如“-sgq”与“-s -g -q”相同。 

两个字母的选项如果第一个字母相同也可以合并在一起。比如“-mgt”与“-mg 

-mt”相同。 

  

(二)有关优化的选项 

-mt:表示在程序中没有使用alaising技术,这使得编译器可以进行比较好的优化。 

-o3:对文件级别进行最强的优化,一般在编译时应该使用这个选项。但是在个别情 

况下使用这个选项优化程序可能会出现错误(-o2有相同现象,-o0和-o1不会出现错 

误)。可能是在优化循环,组织流水线的时候发生错误。如果有这种现象出现可以 

同时使用-g选项,程序优化就不会出现错误,但是优化效果会下降。另外可以调整 

程序的表达方式,可能会避免编译器发生错误。 

-pm:在程序级别进行优化。可以将所以文件联合在一起进行优化,主要有去掉没有 

被调用的函数、总是常数的变量以及没有使用的函数返回值。建议由程序员自己进 

行这种优化工作。使用这个选项在win98下编译可能会出现找不到编译程序的情况。 

-ms0:不使用冗余循环进行优化,减小程序的大小。一般情况下这个选项对程序大 

小的优化作用不明显。 

-mh[n]:去掉流水线的epilog,减小程序的大小。这个选项的作用比较明显。但是 

有可能出现读取地址超出有效范围的问题,所以要在数据段的开始和结尾处增加一 

些pading,或者在分配内存时保证数组的前面和后面一段范围内都是有效的地址。 

可选的参数n给出这种pading的长度字节数。 

  

(三)保留编译和优化信息的选项 

-k:保留优化后生成汇编语言文件。 

-s:汇编语言文件中加入优化信息,如果没有则加入C语言源程序作为注释。 

-mw:在汇编语言文件加入软件流水线信息。 

  

(四)有关调试和剖析的选项 

-g:允许符号调试,在“out”文件中包含符号信息和行号信息,可以在c语言级别 

进行调试和剖析。使用联合使用-g、-mt和-o3可以保证能够进行符号调试的情况 

下最大限度的优化。 

-mg:允许profile优化后的程序。 在“out”文件中包含符号信息和很少的行号信 

息。允许在c语言的函数基本进行剖析。 

如果联合使用这两个选项,-g选项可能被忽略,结果与只用-mg相同。 

  

(五)其它类型 

-mln:生成大内存模式的程序。 

    -ml0:缺省情况下将集合变量(数组和结构)作为far型。 

    -ml1:缺省情况下将全部函数作为far型 

    -ml2: 等于-ml0加-ml1 

    -ml3: 缺省情况下将全部数据和函数作为far型 

  

(六)建议使用的编译方式 

Cl6x -gk -mt  -o3 -mw -ss  “filename” 

方式1用于程序的调试,这种方式具有比较强的优化能力,并且支持符号调试。在编 

译的过程中不会发生错误。由于生成的“out”文件中包含了符号信息和行号信息, 

所以比较大。 

Cl6x -k -mgt  -o3 -mw -ss  “filename” 

方式2用于程序的剖析(profile),这种方式的优化能力几乎最强(绝大多数情况 

下与方式3相同),并且支持对程序进行profile。文件中只包含了符号信息和很少 

的行号信息,所以“out”文件比较小。 

Cl6x -k -mt  -o3  -mw -ss  “filename” 

方式3用于最终的发行版本程序,可以对程序进行最强的优化,并且去掉了全部的符 

号和行号信息,所以“out”文件比较小。 

由多个文件组成的程序应该编写makefile,将编译参数放在该文件中,并在其中说 

明使用的编译器的版本号。 

  

(七)连接参数 

-heap:指定堆的大小 

-stack: 指定栈的大小 

连接的各种选项应该统一放在“cmd”文件中 

  

二、双重循环和多重循环的优化总结 

  

        双重循环多重循环看起来比较复杂,但实际上多重循环优化方法比较简单 

,就在于一个字:“拆”,一旦完成这一步之后,多重循环就成为单层循环,优化 

就可以按照普通的单层循环来做了。 

        多重循环的特点是在优化器优化时只在最内层循环中形成一个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); 

    } 

内层循环循环次数较少,运算量也不大,资源方面只占用了一个乘法器,一个cycl 

e只使用一次乘法器,而事实上我们可以在一个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); 

    } 

        这样虽然代码长度增加了,可变成了单循环,所有的运算都参加到pipeli 

ne中来,在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]); 

            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 

  

CCS的优化: 

  

三、16位变为32位操作,使用intrinsic函数,用const等。 

1、源代码: 

Word32 L_mpy_ll(Word32 L_var1, Word32 L_var2) 

{ 

   double  aReg; 

    Word32 lvar; 

    /* (unsigned)low1 * (unsigned)low1 */ 

    aReg = (double)(0xffff & L_var1) * (double)(0xffff & L_var2) * 2.0; 

   /* >> 16 */ 

    aReg = (aReg / 65536); 

    aReg = floor(aReg); 

    /* (unsigned)low1 * (signed)high2 */ 

    aReg += (double)(0xffff & L_var1) * ((double)L_shr(L_var2,16)) * 2.0 

; 

    /* (unsigned)low2 * (signed)high1 */ 

    aReg += (double)(0xffff & L_var2) * ((double)L_shr(L_var1,16)) * 2.0 

; 

   /* >> 16 */ 

    aReg = (aReg / 65536); 

    aReg = floor(aReg); 

   /* (signed)high1 * (signed)high2 */ 

    aReg += (double)(L_shr(L_var1,16)) * (double)(L_shr(L_var2,16)) * 2. 

0; 

    /* saturate result.. */ 

    lvar = L_saturate(aReg); 

    return(lvar); 

} 

  

2、改编后的代码: 

static inline Word32 L_mpy_ll(Word32 L_var1, Word32 L_var2) 

{ 

    Word32 aReg_hh; 

    Word40 aReg,aReg_ll,aReg_lh,aReg_hl; 

    aReg_ll = (Word40)_mpyu(L_var1, L_var2)>>16; 

    aReg_lh = (Word40)_mpyluhs(L_var1, L_var2); 

    aReg_hl = (Word40)_mpyhslu(L_var1, L_var2); 

    aReg_hh = _smpyh(L_var1, L_var2); 

    aReg    = _lsadd(aReg_ll, _lsadd(aReg_lh, aReg_hl)); 

    aReg    = _lsadd(aReg>>15, aReg_hh); 

    return(_sat(aReg)); 

} 

  

3、优化方法说明: 

C6000编译器提供的intrinsic 可快速优化C代码,intrinsic用前下划线表示同调用 

函数一样可以调用它,即直接内联为C6000的函数。例如,在上例的源代码中没有使 

用intrinsics,每一行C代码需多个指令周期,在改编后的代码中,每一行代码仅需 

一个指令周期。例如, 

“aReg_ll = (Word40)_mpyu(L_var1, L_var2)>>16”中“_mpyu”就是一个intrin 

sics函数,它表示两个无符号数的高16位相乘,结果返回。C6000支持的所有intri 

nsics指令及其功能参见《TMS320C6000系列DSP的原理与应用》一书的第265、266页 

,该书还提供了另外的例子。这些内联函数定义在CCS所在的C6000\CGTOOLS\Inclu 

de目录下的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 * b; 

    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, b); 

        sum2 += _mpyh(a, b); 

    } 

     return sum1 + sum2; 

} 

技巧: 

在C语言的调试全部通过以后,可以尝试将尽可能多的语句使用intrinsics函数加以 

改编,尤其在循环体内,这种改编可以大幅度减少执行时间。 

  

四、 

1、源代码: 

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]; 

   } 

} 

  

2、改编后的代码: 

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]; 

   } 

  

3、优化方法说明: 

C6000编译器如果确定两条指令是不相关的,则安排它们并行执行。 关键字const可 

以指定一个变量或者一个变量的存储单元保持不变。这有助于帮助编译器确定指令 

的不相关性。例如上例中,源代码不能并行执行,而结果改编后的代码可以并行执 

行。 

  

4、技巧: 

使用const可以限定目标,确定存在于循环迭代中的存储器的不相关性。 

  

五、 

1、源代码: 

void vecsum(short *sum, short *in1, short *in2, unsigned int N) 

{ 

    int i; 

  

    for (i = 0; i < N; i++) 

        sum = in1 + in2; 

} 

  

2、改编后的代码: 

void vecsum6(int *sum, const int *in1, const int *in2, unsigned int N) 

{ 

    int i; 

    int sz = N >> 2; 

  

    _nassert(N >= 20); 

  

    for (i = 0; i < sz; i += 2) 

    { 

        sum   = _add2(in1  , in2); 

        sum[i+1] = _add2(in1[i+1], in2[i+1]); 

    } 

} 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -