国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
C6000軟件優(yōu)化經(jīng)驗(yàn)總結(jié)zz
DSP 優(yōu)化心得 
1
推薦C6XX優(yōu)化經(jīng)驗(yàn)總結(jié)
一、c6x的編譯的常用選項(xiàng)
(一)c6x的編譯程序?yàn)?#8220;cl6x.exe”使用的方法
Cl6x [options] [filenames]
Cl6x:   編譯程序
Options:  編譯選項(xiàng)
Filenames:  C或匯編源文件
說(shuō)明:
編譯選項(xiàng)是一個(gè)字母或者兩個(gè)字母,對(duì)大小寫不敏感。
編譯選項(xiàng)的前面需要有一個(gè)“-”符號(hào)。
一個(gè)字母的選項(xiàng)可以合并在一起。比如“-sgq”與“-s -g -q”相同。
兩個(gè)字母的選項(xiàng)如果第一個(gè)字母相同也可以合并在一起。比如“-mgt”與“-mg -mt”相同。
(二)有關(guān)優(yōu)化的選項(xiàng)
-mt:表示在程序中沒(méi)有使用alaising技術(shù),這使得編譯器可以進(jìn)行比較好的優(yōu)化。
-o3:對(duì)文件級(jí)別進(jìn)行最強(qiáng)的優(yōu)化,一般在編譯時(shí)應(yīng)該使用這個(gè)選項(xiàng)。但是在個(gè)別情況下使用這個(gè)選項(xiàng)優(yōu)化程序可能會(huì)出現(xiàn)
錯(cuò)誤(-o2有相同現(xiàn)象,-o0和-o1不會(huì)出現(xiàn)錯(cuò)誤)。可能是在優(yōu)化循環(huán),組織流水線的時(shí)候發(fā)生錯(cuò)誤。如果有這種現(xiàn)象出現(xiàn)可以同時(shí)
使用-g選項(xiàng),程序優(yōu)化就不會(huì)出現(xiàn)錯(cuò)誤,但是優(yōu)化效果會(huì)下降。另外可以調(diào)整程序的表達(dá)方式,可能會(huì)避免編譯器發(fā)生錯(cuò)誤。
-pm:在程序級(jí)別進(jìn)行優(yōu)化??梢詫⑺晕募?lián)合在一起進(jìn)行優(yōu)化,主要有去掉沒(méi)有被調(diào)用的函數(shù)、總是常數(shù)的變量以及沒(méi)有使用的
函數(shù)返回值。建議由程序員自己進(jìn)行這種優(yōu)化工作。使用這個(gè)選項(xiàng)在win98下編譯可能會(huì)出現(xiàn)找不到編譯程序的情況。
-ms0:不使用冗余循環(huán)進(jìn)行優(yōu)化,減小程序的大小。一般情況下這個(gè)選項(xiàng)對(duì)程序大小的優(yōu)化作用不明顯。
-mh[n]:去掉流水線的epilog,減小程序的大小。這個(gè)選項(xiàng)的作用比較明顯。但是有可能出現(xiàn)讀取地址超出有效范圍的問(wèn)題,
所以要在數(shù)據(jù)段的開(kāi)始和結(jié)尾處增加一些pading,或者在分配內(nèi)存時(shí)保證數(shù)組的前面和后面一段范圍內(nèi)都是有效的地址。
可選的參數(shù)n給出這種pading的長(zhǎng)度字節(jié)數(shù)。
(三)保留編譯和優(yōu)化信息的選項(xiàng)
-k:保留優(yōu)化后生成匯編語(yǔ)言文件。
-s:匯編語(yǔ)言文件中加入優(yōu)化信息,如果沒(méi)有則加入C語(yǔ)言源程序作為注釋。
-mw:在匯編語(yǔ)言文件加入軟件流水線信息。
(四)有關(guān)調(diào)試和剖析的選項(xiàng)
-g:允許符號(hào)調(diào)試,在“out”文件中包含符號(hào)信息和行號(hào)信息,可以在c語(yǔ)言級(jí)別進(jìn)行調(diào)試和剖析。使用聯(lián)合使用-g、-mt和-o3可以保
證能夠進(jìn)行符號(hào)調(diào)試的情況下最大限度的優(yōu)化。
-mg:允許profile優(yōu)化后的程序。 在“out”文件中包含符號(hào)信息和很少的行號(hào)信息。允許在c語(yǔ)言的函數(shù)基本進(jìn)行剖析。
如果聯(lián)合使用這兩個(gè)選項(xiàng),-g選項(xiàng)可能被忽略,結(jié)果與只用-mg相同。
(五)其它類型
-mln:生成大內(nèi)存模式的程序。
  -ml0:缺省情況下將集合變量(數(shù)組和結(jié)構(gòu))作為far型。
  -ml1:缺省情況下將全部函數(shù)作為far型
  -ml2: 等于-ml0加-ml1
  -ml3: 缺省情況下將全部數(shù)據(jù)和函數(shù)作為far型
(六)建議使用的編譯方式
Cl6x -gk -mt -o3 -mw -ss  “filename”
方式1用于程序的調(diào)試,這種方式具有比較強(qiáng)的優(yōu)化能力,并且支持符號(hào)調(diào)試。在編譯的過(guò)程中不會(huì)發(fā)生錯(cuò)誤。
由于生成的“out”文件中包含了符號(hào)信息和行號(hào)信息,所以比較大。
Cl6x -k -mgt -o3 -mw -ss  “filename”
方式2用于程序的剖析(profile),這種方式的優(yōu)化能力幾乎最強(qiáng)(絕大多數(shù)情況下與方式3相同),
并且支持對(duì)程序進(jìn)行profile。文件中只包含了符號(hào)信息和很少的行號(hào)信息,所以“out”文件比較小。
Cl6x -k -mt -o3 -mw -ss  “filename”
方式3用于最終的發(fā)行版本程序,可以對(duì)程序進(jìn)行最強(qiáng)的優(yōu)化,并且去掉了全部的符號(hào)和行號(hào)信息,所以“out”文件比較小。
由多個(gè)文件組成的程序應(yīng)該編寫makefile,將編譯參數(shù)放在該文件中,并在其中說(shuō)明使用的編譯器的版本號(hào)。
(七)連接參數(shù)
-h(huán)eap:指定堆的大小
-stack: 指定棧的大小
連接的各種選項(xiàng)應(yīng)該統(tǒng)一放在“cmd”文件中
二、雙重循環(huán)和多重循環(huán)的優(yōu)化總結(jié)
雙重循環(huán)多重循環(huán)看起來(lái)比較復(fù)雜,但實(shí)際上多重循環(huán)優(yōu)化方法比較簡(jiǎn)單,就在于一個(gè)字:“拆”,一旦完成這一步之后,
多重循環(huán)就成為單層循環(huán),優(yōu)化就可以按照普通的單層循環(huán)來(lái)做了。
多重循環(huán)的特點(diǎn)是在優(yōu)化器優(yōu)化時(shí)只在最內(nèi)層循環(huán)中形成一個(gè)pipeline,這樣循環(huán)語(yǔ)句就不能充分利用C6的軟件流水線,
而且對(duì)于內(nèi)部循環(huán)的次數(shù)較少的情況,消耗在prolog和eplog上的cycle數(shù)也是不可忽視的。
針對(duì)這種狀況可以考慮將多重循環(huán)拆開(kāi)形成一個(gè)單層循環(huán),可以拆外層循環(huán)也可以拆內(nèi)層循環(huán),
一般視具體情況而定。這樣就可以充分利用優(yōu)化器構(gòu)成的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[i] = (sum >> 15);
  }
內(nèi)層循環(huán)循環(huán)次數(shù)較少,運(yùn)算量也不大,資源方面只占用了一個(gè)乘法器,一個(gè)cycle只使用一次乘法器,
而事實(shí)上我們可以在一個(gè)cycle內(nèi)使用兩個(gè)乘法器,所以還可以充分利用另外的一個(gè)乘法器。因此考慮將內(nèi)層循環(huán)拆開(kāi)來(lái)執(zhí)行,如下:
  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);
  }
這樣雖然代碼長(zhǎng)度增加了,可變成了單循環(huán),所有的運(yùn)算都參加到pipeline中來(lái),在Piped loop kernal
中產(chǎn)生每一個(gè)cycle內(nèi)都使用了兩個(gè)乘法器,充分利用了DSP內(nèi)部的資源,提高了運(yùn)行效率。又如下例:

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[i] = s;
      s = L_abs(s);
      if (L_sub(s, max) > (Word32) 0)
      max = s;
    }
    tot = L_add(tot, L_shr(max, 1)); 
  }
在這個(gè)多層循環(huán)中一共有三層循環(huán),而最內(nèi)層的循環(huán)的運(yùn)算量很小,只有一次乘累加操作,
而我們知道C6中一個(gè)packet中可以做兩個(gè)乘累加運(yùn)算,所以為了增加內(nèi)部循環(huán)的運(yùn)算,減少外部循環(huán)的層數(shù),
我們可以將第一層循環(huán)的操作拆開(kāi),其負(fù)責(zé)的運(yùn)算加入到內(nèi)部循環(huán)中,也就是在內(nèi)層循環(huán)中一次做四次的乘累加運(yùn)算,
這樣將多次操作形成pipeline,提高了運(yùn)行效率,優(yōu)化后的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的優(yōu)化:
三、16位變?yōu)?2位操作,使用intrinsic函數(shù),用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、優(yōu)化方法說(shuō)明:
C6000編譯器提供的intrinsic 可快速優(yōu)化C代碼,intrinsic用前下劃線表示同調(diào)用函數(shù)一樣可以調(diào)用它,即直接內(nèi)聯(lián)為C6000的函數(shù)。
例如,在上例的源代碼中沒(méi)有使用intrinsics,每一行C代碼需多個(gè)指令周期,在改編后的代碼中,每一行代碼僅需一個(gè)指令周期。
例如,
“aReg_ll = (Word40)_mpyu(L_var1, L_var2)>>16”中“_mpyu”就是一個(gè)intrinsics函數(shù),它表示兩個(gè)無(wú)符號(hào)數(shù)的高16位相乘,
結(jié)果返回。C6000支持的所有intrinsics指令及其功能參見(jiàn)《TMS320C6000系列DSP的原理與應(yīng)用》一書的第265、266頁(yè),
該書還提供了另外的例子。這些內(nèi)聯(lián)函數(shù)定義在CCS所在的C6000\CGTOOLS\Include目錄下的C6X.h文件中。
下面這個(gè)例子是C6000的“Programmer's Guide”上提取的使用intrinsics優(yōu)化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], b[i]);
sum2 += _mpyh(a[i], b[i]);
}
return sum1 + sum2;
}
技巧:
在C語(yǔ)言的調(diào)試全部通過(guò)以后,可以嘗試將盡可能多的語(yǔ)句使用intrinsics函數(shù)加以改編,
尤其在循環(huán)體內(nèi),這種改編可以大幅度減少執(zhí)行時(shí)間。
四、
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、優(yōu)化方法說(shuō)明:
C6000編譯器如果確定兩條指令是不相關(guān)的,則安排它們并行執(zhí)行。 關(guān)鍵字const可以指定一個(gè)變量或者一個(gè)變量的存儲(chǔ)單元保持不變。
這有助于幫助編譯器確定指令的不相關(guān)性。例如上例中,源代碼不能并行執(zhí)行,而結(jié)果改編后的代碼可以并行執(zhí)行。
4、技巧:
使用const可以限定目標(biāo),確定存在于循環(huán)迭代中的存儲(chǔ)器的不相關(guān)性。
五、
1、源代碼:
void vecsum(short *sum, short *in1, short *in2, unsigned int N)
{
int i;
for (i = 0; i < N; i++)
sum[i] = in1[i] + in2[i];
}
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[i] = _add2(in1[i] , in2[i]);
sum[i+1] = _add2(in1[i+1], in2[i+1]);
}
}
3、優(yōu)化方法說(shuō)明:
源代碼中,函數(shù)變量的定義是 short *sum, short *in1, short *in2, 改編后的代碼函數(shù)變量是
int *sum, const int *in1, const int *in2, 整數(shù)類型由16位改編成32位,這時(shí)使用內(nèi)聯(lián)指令“_add2”一次可以完成兩組16位整數(shù)的
加法, 效率提高一倍。注意這里還使用了關(guān)鍵字const和內(nèi)聯(lián)指令_nassert優(yōu)化源代碼。
4、技巧:
用內(nèi)聯(lián)指令_add2、_mpyhl、_mpylh完成兩組16位數(shù)的加法和乘法,效率比單純16位數(shù)的加法和乘法提高一倍。
六、if...else...語(yǔ)句的優(yōu)化
(一)
1、源代碼:
if (sub (ltpg, LTP_GAIN_THR1) <= 0)
{
adapt = 0;
}
else
{
if (sub (ltpg, LTP_GAIN_THR2) <= 0)
{
adapt = 1;
}
else
{
adapt = 2;
}
}
2、改編后的代碼:
  adapt = (ltpg>LTP_GAIN_THR1) + (ltpg>LTP_GAIN_THR2);
(二)
1、源代碼:
if (adapt == 0)
{
if (filt>5443)
{
result = 0;
}
else
{
if (filt < 0)
{
result = 16384;
}
else
{
filt = _sshl (filt, 18)>>16; // Q15
result = _ssub (16384, _smpy(24660, filt)>>16);
}
}
}
else
{
result = 0;
}
2、改編后的代碼:
filt1 = _sshl (filt, 18)>>16;
tmp = _smpy(24660, filt1)>>16;
result = _ssub(16384, tmp * (filt>=0));
result = result * (!((adapt!=0)||(filt>5443)));
(三)
1、源代碼:
static Word16 saturate(Word32 L_var1)
{
  Word16 swOut;
  if (L_var1 > SW_MAX)
  {
    swOut = SW_MAX;
    giOverflow = 1;
  }
  else if (L_var1 < SW_MIN)
  {
    swOut = SW_MIN;
    giOverflow = 1;
  }
  else
    swOut = (Word16) L_var1;    /* automatic type conversion */
  return (swOut);
}
2、改編后的代碼:
static inline Word32 L_shl(Word32 a,Word16 b)
{
return ((Word32)((b) < 0 ? (Word32)(a) >> (-(b)) : _sshl((a),(b)))) ;
}
3、優(yōu)化方法說(shuō)明:
如果在循環(huán)中出現(xiàn)if...else...語(yǔ)句,由于if...else...語(yǔ)句中有跳轉(zhuǎn)指令,而每個(gè)跳轉(zhuǎn)指令有5個(gè)延遲間隙,
因此程序執(zhí)行時(shí)間延長(zhǎng);另外,循環(huán)內(nèi)跳轉(zhuǎn)也使軟件流水受到阻塞。直接使用邏輯判斷語(yǔ)句可以去除不必要的跳轉(zhuǎn)。
例如在例1的源代碼最多有兩次跳轉(zhuǎn),而改編后不存在跳轉(zhuǎn)。例2和例3同樣也去掉了跳轉(zhuǎn)。
4、技巧:
盡可能地用邏輯判斷語(yǔ)句替代if...else...語(yǔ)句,減少跳轉(zhuǎn)語(yǔ)句。
七、
1、源程序
  dm = 0x7FFF;
  for (j = 0; j < nsiz[m]; j = add(j, 1))
  {
    if (d[j] <= dm)
    {
      dm = d[j];
      jj = j;
    }
  }
  index[m] = jj;
2、優(yōu)化后的程序
  dm0 = dm1 = 0x7fff;
  d0 = (Word16 *)&d[0];
  d1 = (Word16 *)&d[1];
  # pragma MUST_ITERATE(32,256,64);
  for (j = 0; j < Nsiz; j+=2)
  {
    n0 = *d0;
    d0 += 2;
    n1 = *d1;
    d1 += 2;
    if (n0 <= dm0)
    {
      dm0 = n0;
      jj0 = j;
    }
    if (n1 <= dm1)
    {
      dm1 = n1;
      jj1 = j+1;
    }
  }
  if (dm1 != dm0)
  {
    index[m] = (dm1 < dm0)? jj1:jj0;
  }
  else
  {
    index[m] = (jj1 > jj0)? jj1:jj0;
  }
3、優(yōu)化說(shuō)明
  求數(shù)組的最小值程序,優(yōu)化時(shí)為了提高程序效率在一個(gè)循環(huán)之內(nèi)計(jì)算N=1,3,5..和n=2,4,6...的最小值,
  然后在比較二者的大小以求得整個(gè)數(shù)組的最小值。
八、
1、源程序
  for (k = 0; k < NB_PULSE; k++)
  {
    i = codvec[k];
    j = sign[i]; 
    index = mult(i, Q15_1_5);
    track = sub(i, extract_l(L_shr(L_mult(index, 5), 1)));
    if (j > 0)
    {
      if (i < l_subfr) code[i] = add(code[i], 4096); 
      codvec[k] += (2 * L_SUBFR);
    }
    else
    {
      if (i < l_subfr) code[i] = sub(code[i], 4096); 
      index = add(index, 16);
    }
    if (indx[track] < 0)
    {
      indx[track] = index;
    }
    else
    {
      if (((index ^ indx[track]) & 16) == 0)
      {
        if (sub(indx[track], index) <= 0)
        {
          indx[track] = shl((indx[track] & 16), 3)
             + shr(extract_l(L_mult((indx[track] &                15), NB_POS)), 1) + (index & 15);
        }
        else
        {
          indx[track] = shl((index & 16), 3)
             + shr(extract_l(L_mult((index & 15),                  NB_POS)), 1) + (indx[track] & 15);
        }
      }
      else
      {
        if (sub((indx[track] & 15), (index & 15)) <= 0)
        {
          indx[track] = shl((index & 16), 3)
             + shr(extract_l(L_mult((index & 15),                  NB_POS)), 1) + (indx[track] & 15);
        }
        else
        {
          indx[track] = shl((indx[track] & 16), 3)
             + shr(extract_l(L_mult((indx[track] & 15),              NB_POS)), 1) + (index & 15);
        }
      }
    }
  }
2、優(yōu)化后的程序
  for (k = 0; k < 8; k++)
  {
    i    = codvec[k];
    j    = sign[i];
    index = _smpy(i, 6554)>>16;
    track    = i - index*5;
    con = (j > 0);
    codvec[k] = codvec[k] + 110*con;
index = index + (!con)*16;
    conn = (i < l_subfr);
    cono  = (j > 0)? 1:-1;
    code[i] = code[i] + 4096*conn*cono; 
n0   = index;
t0  = indx[track];
n1   = n0&16;
t1   = t0&16;
n2   = n0&15;
t2   = t0&15;
    tmp0   = (_sshl(n1,19)>>16) + n2*NB_POS + t2;
    tmp1   = (_sshl(t1,19)>>16) + t2*NB_POS + n2;
    conp   = (((n1 == t1)&&(t0 > n0))||((n1 != t1)&&(t2 <= n2)));
tmp   = conp*tmp0 + (!conp)*tmp1;
    if (t0 < 0)
      indx[track] = n0;
    else
      indx[track] = tmp;
  }
3、優(yōu)化說(shuō)明
  源程序中在循環(huán)中含有許多的if結(jié)構(gòu),在優(yōu)化時(shí)對(duì)if結(jié)構(gòu)首先進(jìn)行化簡(jiǎn),
  再將化簡(jiǎn)后的if結(jié)構(gòu)用條件運(yùn)算表達(dá)式進(jìn)行改寫,最后使循環(huán)可以Pipeline。
九、
1、源程序
  for (i = 0; i < n; i++)
  {
   max = -32767;
   for (j = 0; j < n; j++)
   {
    if (sub (tmp2[j], max) >= 0)
    {
      max = tmp2[j];
      ix = j;
    }
   }
   tmp2[ix] = -32768;
   tmp[i] = ix;
  }
2、優(yōu)化后的程序
if (n0>n1) {temp=n0;n0=n1;n1=temp;}
if (n1>n2) {temp=n1;n1=n2;n2=temp;}
   if (n2>n3) {temp=n2;n2=n3;n3=temp;}
   if (n3>n4) {temp=n3;n3=n4;n4=temp;}
   if (n0>n1) {temp=n0;n0=n1;n1=temp;}
   if (n1>n2) {temp=n1;n1=n2;n2=temp;}
   if (n2>n3) {temp=n2;n2=n3;n3=temp;}
   if (n0>n1) {temp=n0;n0=n1;n1=temp;}
   if (n1>n2) {return n1;}
3、優(yōu)化說(shuō)明
  源程序也為一個(gè)求中值的問(wèn)題,由于已知循環(huán)次數(shù)固定為5,因此將循環(huán)展開(kāi)使用if語(yǔ)句直接求取中值。
十、
1、源程序
static Word16 Bin2int (Word16 no_of_bits, Word16 *bitstream)
{
Word16 value, i, bit;
value = 0;
for (i = 0; i < no_of_bits; i++)
{
value = shl (value, 1);
bit = *bitstream++;
if (sub (bit, BIT_1) == 0)
value = add (value, 1);
}
return (value);
}
for (i = 0; i < prmno[mode]; i++)
{
prm[i] = Bin2int (bitno[mode][i], bits);
bits += bitno[mode][i];
}
2、優(yōu)化后的程序
value = 0;
  bitsp = bits;
  bitnop= &bitno[mode][0];
j = *bitnop++;
j1 = *bitnop++;
j2 = *bitnop++;
j3 = *bitnop++;
j4 = *bitnop++;
_nassert(loop[mode]>=35);
for (i = 0; i < loop[mode]; i++)
{
value = value*2 + *bitsp++;
j--;
if (j == 0)
{
*prm++ = value;
value = 0;
j = j1;
j1 = j2;
j2 = j3;
j3 = j4;
j4 = *bitnop++;
}
}
3、優(yōu)化說(shuō)明
  源程序按照數(shù)據(jù)位流定義取出參數(shù),為雙重循環(huán)結(jié)構(gòu),優(yōu)化中采用重新根據(jù)位流的bit長(zhǎng)度定義循環(huán)次數(shù),
  化簡(jiǎn)為單重循環(huán),然后優(yōu)化循環(huán),去除boundary,使pipeline的數(shù)目最小。
十一、copy程序的優(yōu)化
  1、源代碼:
Word16 i;
for (i = 0; i < L; i++)
{
y[i] = x[i];
}
  2、改編代碼:
(1)要求數(shù)組長(zhǎng)度能被2整除
Word32  i;
Word32   temp;
int *p1 = (int *)&x[0];
int *q1 = (int *)&y[0];
for (i = 0; i < L/2; i++)
{
temp = *p1++;
*q1++ = temp;
}
(2)要求數(shù)組長(zhǎng)度能被4整除
Word32  i;
Word32   temp1, temp2;
Word32   *pin1, *pin2, *pout1, *pout2;
pin1 = (Word32 *)&x[0];
pin2 = (Word32 *)&x[2];
pout1= (Word32 *)&y[0];
pout2= (Word32 *)&y[2];
for (i = 0; i < L/4; i++)
{
temp1 = *pin1;
temp2 = *pin2;
pin1+=2;
pin2+=2;
*pout1= temp1;
*pout2= temp2;
pout1+=2;
pout2+=2;
}
3、優(yōu)化方法說(shuō)明:
把一次循環(huán)拷貝一個(gè)word16的數(shù)改為一次循環(huán)拷貝2個(gè)word16或4個(gè)word16的數(shù)。
4、技巧:
充分利用c6xx一次讀取32位數(shù)的特性,并利用一個(gè)指令周期能讀取兩個(gè)數(shù)據(jù)的特點(diǎn)。
十二、set_zero程序的優(yōu)化
  1、源代碼:
Word16 i;
for (i = 0; i < L; i++)
{
x[i] = 0;
}
  2、改編代碼:
(1)數(shù)組長(zhǎng)度能被2整除
Word32 i;
int *x1 = (int *)&x[0];
for (i = 0; i < L/2; i++)
{
*x1++ = 0;
}
(2)數(shù)組長(zhǎng)度能被4整除
Word32 i;
int *x1 = (int *)&x[0];
int *x2 = (int *)&x[2];
for (i = 0; i < L/4; i++)
{
*x1 = 0;
*x2 = 0;
x1++;
x2++;
x1++;
x2++;
}
3、優(yōu)化方法說(shuō)明:
把一次循環(huán)為一個(gè)word16的數(shù)賦值改為一次為2個(gè)或4個(gè)word16的數(shù)賦值。
4、技巧:
充分利用C6XX一次讀取32位數(shù)的特點(diǎn),并利用一個(gè)指令周期能讀取兩個(gè)數(shù)據(jù)的特點(diǎn)。
十三、32bit數(shù)與16bit數(shù)相乘
1、源代碼:
L_tmp0 = Mac_32_16(L_32, hi1, lo1, lo2);
2、改編代碼:
L_tmp0=_sadd(_sadd(_smpyhl(hl32, lo2),
  (_mpyus(hl32, lo2)>>16)<<1), L_32);
3、優(yōu)化方法說(shuō)明:
  hl32是32bit的數(shù),hi1和lo1是16bit的數(shù),且 hl32 = hi 1<<16 + lo1 << 1 ,即hi1和lo1分別是hl32的高16位數(shù)和低16位數(shù)。
  函數(shù)Mac_32_16(L_32, hi1, lo1, lo2)實(shí)現(xiàn)
    L_32 = L_32 + (hi1*lo2)<<1 + ((lo1*lo2)>>15)<<1
  源代碼是把一個(gè)32位的數(shù)拆成兩個(gè)16位的數(shù)與一個(gè)16位的數(shù)相乘,優(yōu)化后的代碼不拆開(kāi)32位的數(shù),
  直接用32位的數(shù)與16位的數(shù)相乘。運(yùn)用這種方法必須保證hl32的最低一位數(shù)必須為0,否則應(yīng)用指令_clr(hl32, 0, 0)把
  最低位清零。
4、技巧:
  源代碼中的低16位數(shù)lo1是hl32的低16位右移一位得到的(留出一位符號(hào)位)。在與lo2相乘時(shí)又右移了15位,
  所以在改編代碼中右移16位,并且是以無(wú)符號(hào)數(shù)與lo2相乘。
十四、32bit數(shù)與32bit數(shù)相乘
1、源代碼:
L_tmp = Mac_32 (L_32, hi1, lo1, hi2, lo2);
2、改編代碼:
  L_tmp = _sadd(_sadd(_smpyh(hl1_32, hl2_32),
      ((_mpyhslu(hl1_32, hl2_32)>>16)<<1)+
      ((_mpyhslu(hl2_32, hl1_32)>>16)<<1)), L_32);
3、優(yōu)化方法說(shuō)明:
  兩個(gè)32位的數(shù)相乘,不必分成四個(gè)16位的數(shù)相乘,直接用32位相乘。其中:
    hl1_32 = hi1<<16 + lo1<<1, hl2_32 = hi2 <<16 + lo2 <<1 。
源代碼實(shí)現(xiàn): L_32 = L_32 + (hi1*hi2)<<1 + ( (hi1*lo2)>>15 + (lo1*hi2)>>15 )<<1
4、技巧:
低16位與高16位相乘時(shí),低16位使用的是無(wú)符號(hào)數(shù)。
十五、16位除法的優(yōu)化
1、源代碼:
Word16 div_s (Word16 var1, Word16 var2)  //實(shí)現(xiàn) var1/var2
{
Word16 var_out = 0;
Word16 iteration;
Word32 L_num = (Word32)var1;
Word32 L_denom = (Word32)var2;
for (iteration = 0; iteration < 15; iteration++)
{
var_out <<= 1;
L_num <<= 1;
if (L_num >= L_denom)
{
L_num = L_sub (L_num, L_denom);
var_out = add (var_out, 1);
}
}
return (var_out);
}
2、改編代碼:
Word16 div_s1 (Word16 var1, Word16 var2)
{
Word32 var1int;
Word32 var2int;
var1int = var1 << 16;
var2int = var2 << 15;
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
var1int = _subc(var1int,var2int);
return (var1int & 0xffff);
}
3、優(yōu)化方法說(shuō)明:
實(shí)現(xiàn)16位的除法,要求被除數(shù)var1和除數(shù)var2都是整數(shù),且var1<=var2。利用C6XX特有的指令subc,實(shí)現(xiàn)除法的循環(huán)移位相減操作。
4、技巧:
把被除數(shù)和除數(shù)都轉(zhuǎn)換成32位數(shù)來(lái)操作,返回時(shí)取低16位數(shù)。
十六、C6X優(yōu)化inline舉例:
1、原程序:
  for (i = LO_CHAN; i <= HI_CHAN; i++)
  {
    norm_shift = norm_l(st->ch_noise[i]);
    Ltmp = L_shl(st->ch_noise[i], norm_shift);
    norm_shift1 = norm_l(st->ch_enrg[i]);
    Ltmp3 = L_shl1(st->ch_enrg[i], 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[i] = extract_h(Ltmp);
  }
  */
 
 
 
2、優(yōu)化后程序:
  //因循環(huán)體太大,拆成兩個(gè)循環(huán)并把相應(yīng)的函數(shù)內(nèi)嵌以使程序能pipeline,
  //用L_div_tmp[]保存因拆分而產(chǎn)生的中間變量。
  for (i = LO_CHAN; i <= HI_CHAN; i++)
  {
    //norm_shift = norm_l(st->ch_noise[i]);
    norm_shift = _norm(st->ch_noise[i]);
    Ltmp = _sshl(st->ch_noise[i], norm_shift);
    //norm_shift1 = norm_l(st->ch_enrg[i]); 
    norm_shift1 = _norm(st->ch_enrg[i]);   
    //Ltmp3 = L_shl1(st->ch_enrg[i], norm_shift1 - 1);
    LLtmp1 = st->ch_enrg[i];   
    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[i] = Ltmp2;
  }
  for (i = LO_CHAN; i <= HI_CHAN; i++)
  {
    Ltmp2 = L_div_tmp[i];
    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[i] = extract_h(Ltmp);
    ch_snr[i] = (Ltmp >> 16);
  }
 
3、優(yōu)化說(shuō)明
  觀察上面這個(gè)循環(huán),循環(huán)體本身比較大,且含有兩個(gè)函數(shù)L_divide()和
  fnLog10(),而C62內(nèi)部只有32個(gè)寄存器,且有些寄存器是系統(tǒng)用的,如B14、B15這樣循環(huán)體太大將會(huì)導(dǎo)致寄存器不夠分配,
  從而導(dǎo)致系統(tǒng)編譯器無(wú)法實(shí)現(xiàn)循環(huán)的pipeline。
 
  為了實(shí)現(xiàn)循環(huán)的pipeline。我們需要把循環(huán)體進(jìn)行拆分,拆分時(shí)要考慮以下幾點(diǎn):
  (1)、拆分成幾個(gè)循環(huán)比較合適?在各個(gè)循環(huán)能pipeline的前提下,拆開(kāi)的循環(huán)個(gè)數(shù)越少越好。這就要求盡可能讓各個(gè)
  循環(huán)的運(yùn)算量接近。
  (2)考慮在什么地方把程序拆開(kāi)比較合適?循環(huán)體里的數(shù)據(jù)流往往并不是單一的,在拆開(kāi)的斷點(diǎn)處勢(shì)必要用中間變量保
  存上次的循環(huán)運(yùn)算結(jié)果,供以后的循環(huán)用。適當(dāng)?shù)牟痖_(kāi)循環(huán)體,使所需的中間變量越少越好。
  (3)循環(huán)體中的函數(shù)調(diào)用必須定義成內(nèi)嵌形式,含有函數(shù)調(diào)用的循環(huán)系統(tǒng)是無(wú)法使之pipeline的;各個(gè)循環(huán)體中的判斷分支
  機(jī)構(gòu)不可太多,否則系統(tǒng)也無(wú)法使之pipeline,為此應(yīng)近可能把可以確定下來(lái)的分支確定下來(lái),并盡可能用內(nèi)嵌指令。 
 
  針對(duì)上面這個(gè)例子,考慮:
  (1)為讓各個(gè)循環(huán)的運(yùn)算量大致相當(dāng),應(yīng)把L_divide()和fnLog10()分到兩個(gè)循環(huán)中去,從循環(huán)體大小上考慮,
  估計(jì)拆成兩個(gè)循環(huán)比較合適。
  (2)考慮在什么地方把程序拆開(kāi)比較合適?在
    if (Ltmp2 == 0)
      Ltmp2 = 1;
后拆開(kāi),因?yàn)楹竺嬗玫降臄?shù)據(jù)只有Ltmp2,故只需用一個(gè)數(shù)組保存每次循環(huán)的Ltmp2值即可。
  (3)循環(huán)體中的兩處函數(shù)調(diào)用L_divide()和fnLog10()都定義了其內(nèi)嵌形式,IL_divide()和IfnLog10()。
  當(dāng)把可以確定下來(lái)的分支作確定處理,并盡可能用內(nèi)嵌指令后,該循環(huán)體中所剩的分支結(jié)構(gòu)已很少,循環(huán)體可以pipeline。
  優(yōu)化前程序用2676 cycle,優(yōu)化后用400 cycle。優(yōu)化后兩個(gè)子循環(huán)的MII分別為14和6cycle。
內(nèi)存地址形式: 奔騰,C6000都是32位計(jì)算機(jī),字長(zhǎng)32,但內(nèi)存地址都是按字節(jié)組織的 一個(gè)字4字節(jié)(查看內(nèi)存時(shí)候各個(gè)字
時(shí)候:例如兩個(gè)連續(xù)字ox1000 ox1004) 寫匯編程序時(shí)候,下一個(gè)字也需要+4,但寫 C語(yǔ)言時(shí)候,int 型,+1就是加4
但是,在Tiger SHARC中,雖然也是32位機(jī),但內(nèi)存是地址是按字組織的,查看內(nèi)存時(shí),連續(xù)的字地址相差1
//////////////////////////////////////////////////////////////////////////////////自己寫的一段性能很高的代碼///////////////////////////
 #i nclude <stdio.h>
#define INTRINSIC
short add(short var1,short var2)
  {
   short var_out;
   int L_somme;
   L_somme = (int) var1 + var2;
   return(var_out);
  }
 
int main()
{
int i,result;
#ifdef INTRINSIC
for(i=0; i<1000;i++)
{
result=_sadd(100000,20);
result>0X00007fff?result=0x7fff:(result<0x8000?result=0x8000:0);
}
#else
for(i=0;i<1000;i++)
add(10,20);
#endif
return 0;
}
 

本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/henhen2002/archive/2009/09/13/4549689.aspx
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
C6000軟件優(yōu)化經(jīng)驗(yàn)總結(jié)(1)
avr單片機(jī) 串口實(shí)現(xiàn)printf(使用變參函數(shù))
STM32實(shí)現(xiàn)IIR低通濾波器
好指標(biāo)只要一個(gè)就夠了(高低點(diǎn)無(wú)一漏過(guò)),剩下的只是執(zhí)行紀(jì)律
通達(dá)信分時(shí)指標(biāo)公式 (主、副圖)
C++基本數(shù)據(jù)類型的封裝
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服