有時候為了加快大量數據的存取操作,我優化了重要路徑上的算法,用盡了精簡代碼的技巧,還采用處理指令矢量化的技能,為程序定制了一個內存管理器以增加程序的緩沖友好性(cache friendly),一般情況下是可以達到最終目的了,可在圖像處理相關的代碼中,竟然發現最大優化機會在地址訪問上,比如本人曾經見過這樣的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);???// 這個函數的內部實現對于32bit pixel -> 24bit pixel比較麻煩哦

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

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


所以我的策略是:動態分配時,多分配一個機器字的空間,然后想個辦法讓Pointer定在這個分配的線性空間內的首個“機器字的n倍處”,之后的對象訪問對齊問題靠padding完成(不過,這一步只有在真的需要時才作,因為會有大量空間浪費!)。


這里給出了me的對齊code:

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

就這么點。

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

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