__builtin_prefetch() 是 gcc 的一個內置函數。它通過對數據手工預取的方法,減少了讀取延遲,從而提高了性能,但該函數也需要 CPU 的支持。
該函數的原型為:
void __builtin_prefetch (const void *addr, ...)
其中參數 addr 是個內存指針,它指向要預取的數據,我們人工需要判定這些數據是很快能訪問到的,或者說是它們就在最近的內存中 --- 一般來說,對於鏈表而言,各個節點在內存中基本上是緊挨着的,所以我們容易預取鏈表節點里的指針項。
該函數還有兩個可選參數,rw 和 locality 。
rw 是個編譯時的常數,或 1 或 0 。1 時表示寫(w),0 時表示讀(r) 。
locality 必須是編譯時的常數,也稱為“時間局部性”(temporal locality) 。時間局部性是指,如果程序中某一條指令一旦執行,則不久之后該指令可能再被執行;如果某數據被訪問,則不久之后該數據會被再次訪問。該值的范圍在 0 - 3 之間。為 0 時表示,它沒有時間局部性,也就是說,要訪問的數據或地址被訪問之后的不長的時間里不會再被訪問;為 3 時表示,被訪問的數據或地址具有高 時間局部性,也就是說,在被訪問不久之后非常有可能再次訪問;對於值 1 和 2,則分別表示具有低 時間局部性 和中等 時間局部性。該值默認為 3 。
用法:
for (i = 0; i < n; i++) { a[i] = a[i] + b[i]; __builtin_prefetch (&a[i+j], 1, 1); __builtin_prefetch (&b[i+j], 0, 1); /* ... */ }
另外,參數 addr 是需要用戶保證地址的正確,函數不會對不正確的地址做出錯誤的提示。
在 linux 內核中,經常會使用到這種預抓取技術。通常是通過宏和包裝器函數使用預抓取。下面是一個輔助函數示例,它使用內置函數的包裝器(見 ./linux/include/linux/prefetch.h)。這個函數為流操作實現預抓取機制。使用這個函數通常可以減少緩存缺失和停頓,從而 提高性能。
#ifndef ARCH_HAS_PREFETCH #define prefetch(x) __builtin_prefetch(x) #endif static inline void prefetch_range(void *addr, size_t len) { #ifdef ARCH_HAS_PREFETCH char *cp; char *end = addr + len; for (cp = addr; cp < end; cp += PREFETCH_STRIDE) prefetch(cp); #endif }