讓你的軟體飛起來 演算法優化

2022-06-12 08:06:08 字數 4905 閱讀 1195

摘自網路:

封面:

內容:          

**的運算速度取決於以下幾個方面

1、  演算法本身的複雜度,比如mpeg比jpeg複雜,jpeg比bmp的編碼複雜。

2、 cpu自身的速度和設計架構

3、  cpu的匯流排頻寬

4、  您自己**的寫法

本文主要介紹如何優化您自己的code,實現軟體的加速。

先看看我的需求

我們乙個圖象模式識別的專案,需要將rgb格式的彩色影象先轉換成黑白影象。

影象轉換的公式如下:y = 0.299 * r + 0.587 * g + 0.114 * b;

影象尺寸640*480*24bit,rgb影象已經按照rgbrgb順序排列的格式,放在記憶體裡面了。

我已經悄悄的完成了第乙個優化

以下是輸入和輸出的定義:

#define xsize 640

#define ysize 480

#define imgsize xsize * ysize

typedef struct rgb

unsigned char r;

unsigned char g;

unsigned char b;

}rgb;

struct rgb in[imgsize]; //需要計算的原始資料

unsigned char out[imgsize]; //計算後的結果

第乙個優化:

優化原則:影象是乙個2d陣列,我用乙個一維陣列來儲存。編譯器處理一維陣列的效率要高過二維陣列。

先寫乙個**:

y = 0.299 * r + 0.587 * g + 0.114 * b;

void calc_lum()

int i;

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

double r,g,b,y;

unsigned char yy;

r = in[i].r;

g = in[i].g;

b = in[i].b;

y = 0.299 * r + 0.587 * g + 0.114 * b;

yy = y;

out[i] = yy;

這大概是能想得出來的最簡單的寫法了,實在看不出有什麼毛病,好了,編譯一下跑一跑吧。

第一次試跑

這個**分別用vc6.0和gcc編譯,生成2個版本,分別在pc上和我的embedded system上面跑。

速度多少?

在pc上,由於存在硬體浮點處理器,cpu頻率也夠高,計算速度為20秒。

我的embedded system,沒有以上2個優勢,浮點操作被編譯器分解成了整數運算,運算速度為120秒左右。

優化二:去掉浮點運算

上面這個**還沒有跑,我已經知道會很慢了,因為這其中有大量的浮點運算。只要能不用浮點運算,一定能快很多。

y = 0.299 * r + 0.587 * g + 0.114 * b;

這個公式怎麼能用定點的整數運算替代呢?

0.299 * r可以如何化簡?

y = 0.299 * r + 0.587 * g + 0.114 * b;

y = d + e + f;

d = 0.299 * r;

e = 0.587 * g;

f = 0.114 * b;

我們就先簡化算式d吧!

rgb的取值範圍都是0~255,都是整數,只是這個係數比較麻煩,不過這個係數可以表示為:0.299 = 299 / 1000;

所以 d = ( r * 299) / 1000;

y = (r * 299 + g * 587 + b * 114) / 1000;

這一下,能快多少呢?

embedded system上的速度為45秒;

pc上的速度為2秒;

優化三:將除法轉化為移位操作

y = (r * 299 + g * 587 + b * 114) / 1000;

這個式子好像還有點複雜,可以再砍掉乙個除法運算。

前面的算式d可以這樣寫:

0.299=299/1000=1224/4096

所以 d = (r * 1224) / 4096

y=(r*1224)/4096+(g*2404)/4096+(b*467)/4096

再簡化為:

y=(r*1224+g*2404+b*467)/4096

這裡的/4096除法,因為它是2的n次方,所以可以用移位操作替代,往右移位12bit就是把某個數除以4096了。

void calc_lum()

int i;

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

int r,g,b,y;

r = 1224 * in[i].r;

g = 2404 * in[i].g;

b = 467 * in[i].b;

y = r + g + b;

y = y >> 12; //這裡去掉了除法運算

out[i] = y;

這個**編譯後,又快了20%。

雖然快了不少,還是太慢了一些,20秒處理一幅影象,地球人都不能接受

優化四:將有限的計算結果變為查詢表的方法:

rgb的取值有文章可做,rgb的取值永遠都大於等於0,小於等於255,我們能不能將d,e,f都預先計算好呢?然後用查表演算法計算呢?

我們使用3個陣列分別存放def的256種可能的取值,然後。。。

查表陣列初始化

int d[256],f[256],e[256];

void table_init()

int i;

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

d[i]=i*1224; 

d[i]=d[i]>>12;

e[i]=i*2404; 

e[i]=e[i]>>12; 

f[i]=i*467; 

f[i]=f[i]>>12;

void calc_lum()

int i;

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

int r,g,b,y;

r = d[in[i].r];//查表

g = e[in[i].g];

b = f[in[i].b];

y = r + g + b;

out[i] = y;

這一次的成績把我嚇出一身冷汗,執行時間居然從30秒一下提高到了2秒!在pc上測試這段**,眼皮還沒眨一下,**就執行完了。一下提高15倍,爽不爽?

優化五、復用將單個或者序列轉化為多路並行

很多embedded system的32bit cpu,都至少有2個alu,能不能讓2個alu都跑起來?

void calc_lum()

int i;

for(i = 0; i < imgsize; i += 2) //一次並行處理2個資料

int r,g,b,y,r1,g1,b1,y1;

r = d[in[i].r];//查表 //這裡給第乙個alu執行

g = e[in[i].g];

b = f[in[i].b];

y = r + g + b;

out[i] = y;

r1 = d[in[i + 1].r];//查表 //這裡給第二個alu執行

g1 = e[in[i + 1].g];

b1 = f[in[i + 1].b];

y = r1 + g1 + b1;

out[i + 1] = y;

2個alu處理的資料不能有資料依賴,也就是說:某個alu的輸入條件不能是別的alu的輸出,這樣才可以並行。

這次成績是1秒。

優化六,改變資料型別或者資料位數

檢視這個**

int d[256],f[256],e[256]; //查表陣列

void table_init()

int i;

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

d[i]=i*1224; 

d[i]=d[i]>>12;

e[i]=i*2404; 

e[i]=e[i]>>12; 

f[i]=i*467; 

f[i]=f[i]>>12;

到這裡,似乎已經足夠快了,但是我們反覆實驗,發現,還有辦法再快!

可以將int d[256],f[256],e[256]; //查表陣列

更改為unsigned shortd[256],f[256],e[256]; //查表陣列

這是因為編譯器處理int型別和處理unsigned short型別的效率不一樣。

再改動inlinevoid calc_lum()

int i;

for(i = 0; i < imgsize; i += 2) //一次並行處理2個資料

int r,g,b,y,r1,g1,b1,y1;

r = d[in[i].r];//查表 //這裡給第乙個alu執行

g = e[in[i].g];

b = f[in[i].b];

y = r + g + b;

out[i] = y;

r1 = d[in[i + 1].r];//查表 //這裡給第二個alu執行

g1 = e[in[i + 1].g];

b1 = f[in[i + 1].b];

y = r1 + g1 + b1;

out[i + 1] = y;

將函式宣告為inline,這樣編譯器就會將其嵌入到母函式中,可以減少cpu呼叫子函式所產生的開銷。

這次速度:0.5秒

主要思想:空間、時間的相互轉化

讓你的程式飛起來

本方法可以讓c語言指令進一步接近彙編指令的執行效率,提高微控制器 嵌入式系統的速度和穩定性,但程式設計時應採取函式化的程式設計法 例如使用swap 函式時,必要時加注釋。0.位運算心法 1.如果乘上乙個2的倍數數值,可以改用左移運算 left shift 加速 300 x x 2 x x 64 改為...

讓SQL飛起來

讓sql飛起來 人們在使用sql時往往會陷入乙個誤區,即太關注於所得的結果是否正確,而忽略了不同的實現方法之間可能存在的效能差異,這種效能差異在大型的或是複雜的資料庫環境中 如聯機事務處理oltp或決策支援系統dss 中表現得尤為明顯。筆者在工作實踐中發現,不良的sql往往來自於不恰當的索引設計 不...

讓你的軟體飛起來 RGB轉為YUV

朋友曾經給我推薦了乙個有關 優化的pdf文件 讓你的軟體飛起來 看完之後,感受頗深。為了推廣其,同時也為了自己加深印象,故將其總結為word文件。下面就是其的詳細內容總結,希望能於己於人都有所幫助。速度取決於演算法 同樣的事情,方法不一樣,效果也不一樣。比如,汽車引擎,可以讓你的速度超越馬車,卻無法...