有時(shí)候?yàn)榱思涌齑罅繑?shù)據(jù)的存取操作,我優(yōu)化了重要路徑上的算法,用盡了精簡(jiǎn)代碼的技巧,還采用處理指令矢量化的技能,為程序定制了一個(gè)內(nèi)存管理器以增加程序的緩沖友好性(cache friendly),一般情況下是可以達(dá)到最終目的了,可在圖像處理相關(guān)的代碼中,竟然發(fā)現(xiàn)最大優(yōu)化機(jī)會(huì)在地址訪問上,比如本人曾經(jīng)見過這樣的source code:
? typedef unsigned Pixel32;
? struct Pixel24 { u8 r, g, b; };

? Pixel24* pRaw = new Pixel24[width*height];
??Pixel32* pSrcImg = loadFromFile("tangent.bmp");
? fillPort(pRaw, dstRt, pSrcImg, srcRt);???// 這個(gè)函數(shù)的內(nèi)部實(shí)現(xiàn)對(duì)于32bit pixel -> 24bit pixel比較麻煩哦

我知道,典型的IA32系的處理器的尋址操作在機(jī)器字的n倍處最快的。
C++中:
? int a;
??Obj x;
的代碼產(chǎn)生的訪問對(duì)象的地址由編譯器完成了!而且絕對(duì)保證以最快地方式訪問;
?而 Obj* x;
??????Pixel24* pRaw = new Pixel24[sizeof(Pixel24)*width*height];
????? Pixel32* pSrcImg = ....
的pRaw, pSrcImg就隨運(yùn)行時(shí)而定,不一定在“機(jī)器字的n倍處”,而且其一部分?jǐn)?shù)據(jù)在“機(jī)器字的n倍處”。

可想而知,32bit的像素在memory上很容得以地址對(duì)齊,但是也可能其首地址沒有在機(jī)器字的n倍處,可24bit就更麻煩了。


所以我的策略是:動(dòng)態(tài)分配時(shí),多分配一個(gè)機(jī)器字的空間,然后想個(gè)辦法讓Pointer定在這個(gè)分配的線性空間內(nèi)的首個(gè)“機(jī)器字的n倍處”,之后的對(duì)象訪問對(duì)齊問題靠padding完成(不過,這一步只有在真的需要時(shí)才作,因?yàn)闀?huì)有大量空間浪費(fèi)!)。


這里給出了me的對(duì)齊code:

?
template <typename Pointer, int Align =4>
? Pointer alignAddress(void* raw)
? { // 把raw對(duì)齊為機(jī)器字的整數(shù)倍,Align為機(jī)器字的字節(jié)數(shù).(需要在raw處多分配align個(gè)字節(jié))
??? // Align默認(rèn)為4,即32bit機(jī)的地址對(duì)齊
??? Pointer p = reinterpret_cast<Pointer>(
????? (reinterpret_cast<uintptr_t>(raw) + Align-1) & ~(Align-1) );???// 這里有點(diǎn)技巧
??? return p;
? }

就這么點(diǎn)。

可以這樣使用:
??????#define ALIGN_SET 4
??????Pixel24* pT = new unsigned char[sizeof(Pixel24)*width*height + ALIGN_SET];
????? Pixel24* pRaw = alignAddress<Pixel24*, ALIGN_SET>(pT);
????? // pRaw就是所要的地址,需要時(shí)對(duì)Pixel24開啟編譯器padding選項(xiàng)

????? 有了這樣的保證,前面的fillPort的優(yōu)化工作就更容易了!