今天os課上老師提到影響缺頁次數的因素中有乙個是程式的區域性性越好,越不容易缺頁,並舉了個關於雙重for迴圈順序的選擇問題作為例子。
我回去也查詢資料研究了一下這個問題。
程式的區域性性原理是指程式在執行時呈現出區域性性規律,即在一段時間內,整個程式的執行僅限於程式中的某一部分。相應地,執行所訪問的儲存空間也侷限於某個記憶體區域。也就是說,程式傾向於引用鄰近於其他最近引用過得資料項,或者最近引用過的資料項本身。我的理解就是:通過利用「快取」來提高程式執行效率
程式的區域性性又通常有兩種不同的形式:時間區域性性(temporal locality)和空間區域性性(spatial locality).
時間區域性性:被引用過一次的儲存器位置在未來會被多次引用
空間區域性性:如果乙個儲存器的位置被引用,那麼將來他附近的位置也會被引用。也就是說靠近當前正在被訪問記憶體的記憶體內容很快也會被訪問。
先以一維陣列為例,考慮對程式資料引用的區域性性。
借用《深入理解計算機系統》書中的例子進行分析
sumvec函式中陣列v的元素是被順序讀取的,乙個接乙個,按照它們儲存在儲存器中的順序。(假設位址從0開始).因此對於變數v,函式有很好的空間的區域性性。因此這個函式有良好的區域性性。
向上面例子中按順序、連續的對v的引用,稱為步長為1的引用模式(相對於元素大小)。同理,在乙個連續的向量中,每隔k個元素對向量進行訪問,稱為步長為k的引用。一般來說,隨著步長的增加,空間區域性性會下降。
再考慮二維陣列
圖中函式是對乙個二維陣列求和(m=2,n=3)。雙重巢狀迴圈按照行優先的順序讀取陣列的元素。因此函式具有良好的空間區域性性,因為它按照陣列被儲存的行優先順序來訪問這個陣列,因此得到的是乙個步長為1的引用模式和良好的空間區域性性。從而使得程式執行效率得到提高。
但我們更換讀取順序的時候,交換i和j的迴圈。如下圖所示
這時候發生了巨大的變化!函式的空間區域性性變得很差,因為他按照列順序來掃瞄陣列,而不是按照行順序。因為c陣列在儲存器中是按照行順序的,結果這裡就得到的是步長為n的引用模式。從而使得程式效率降低。
#include #include #include int main()}}
finish = clock();
duration = (double)(finish - start) / clocks_per_sec;
printf( "%f seconds\n", duration );
start = clock();
for (int k = 0; k < 1000; k++)//迴圈放大時間}}
可以發現當行列數相同的時候,按照行順序掃面的效率要高一些。也符合之前的理論分析.
當我把陣列定義改為a[10][10000]的時候,測試結果如下,依舊為行順序掃瞄效率較高。
陣列改為a[10000][10]後,測試結果如下,依舊為行順序掃瞄效率較高。
通過對雙重迴圈不同迴圈順序的效率分析,初步理解了區域性性原理。也就是說現代的計算機體系的儲存技術至少都用了區域性儲存思想,即cpu提取記憶體的乙個位置的資料放到cache中的同時,也會把其附近的資料也提取到cache中,如果記憶體以行優先儲存方式(注意這個前提!),則提取array[0][0]位置的資料的同時,則也會順便把"array[0][1], array[0][2],tarray[0][3], array[0][4]..."等資料提取出來存放在快取中。這樣在後邊連續的幾次迴圈中均可以命中快取,從而減少快取失效,提高程式的執行效率。
維基百科
計算機體系結構與程式效能
《深入理解計算機系統》
程式區域性性原理感悟
區域性性原理 程式的區域性性原理是指程式在執行時呈現出區域性性規律,即在一段時間內,整個程式的執行僅限於程式中的某一部分。相應地,執行所訪問的儲存空間也侷限於某個記憶體區域。區域性性原理又表現為 時間區域性性和空間區域性性。時間區域性性是指如果程式中的某條指令一旦執行,則不久之後該指令可能再次被執行...
程式訪問的區域性性原理
程式訪問的區域性性原理包括時間區域性性和空間區域性性。時間區域性性是指在最近的未來要用到的資訊,很可能是現在正在使用的資訊,因為程式中存在迴圈。空間區域性性是指在最近的未來要用到的資訊,很可能與現在正在使用的資訊在儲存空間上是連續的,因為指令通常是順序存放 順序執行的,資料一般也是以向量 陣列等形式...
常用概念之程式區域性性原理
程式的區域性性原理是指程式在執行時呈現出區域性性規律,即在一段時間內,整個程式的執行僅限於程式中的某一部分。它們傾向於引用的資料項鄰近於其他最近引用過的資料項,或者鄰近於最近自我引用過的資料項。在現代計算機系統的各個層次,從硬體到作業系統 應用程式等,設計上都利用了區域性性原理。比如快取機制,cpu...