2017-03-02 30 views
12

Aşağıdaki örnek kod, N boyutunda bir matris oluşturur ve bunu SAMPLES kez döndürür. N = 512 Transpozisyon işleminin ortalama yürütme süresi 2144 μs (coliru link) 'dir. İlk bakmak değil mi? ... BuradaBu matris aktarımları neden bu kadar sezgiseldir?

  • N = 5131451 μs
  • N = 519600 μs
  • N = 530486 μs
  • N = 540 için sonuçlar

    Eh, hiçbir özel yoktur → 492 μs (en sonunda teori çalışmaya başlar :).

Peki neden pratikte bu basit hesaplamalar teoriden bu kadar farklı? Bu davranış, CPU önbellek tutarlılığı veya önbellek özleri ile ilgilidir? Eğer öyleyse lütfen açıklayınız.

#include <algorithm> 
#include <iostream> 
#include <chrono> 

constexpr int N  = 512; // Why is 512 specifically slower (as of 2016) 
constexpr int SAMPLES = 1000; 
using us = std::chrono::microseconds; 

int A[N][N]; 

void transpose() 
{ 
    for (int i = 0 ; i < N ; i++) 
    for (int j = 0 ; j < i ; j++) 
     std::swap(A[i][j], A[j][i]); 
} 

int main() 
{ 
    // initialize matrix 
    for (int i = 0 ; i < N ; i++) 
    for (int j = 0 ; j < N ; j++) 
     A[i][j] = i+j; 

    auto t1 = std::chrono::system_clock::now(); 
    for (int i = 0 ; i < SAMPLES ; i++) 
     transpose(); 
    auto t2 = std::chrono::system_clock::now(); 

    std::cout << "Average for size " << N << ": " << std::chrono::duration_cast<us>(t2 - t1).count()/SAMPLES << " (us)"; 
} 
+0

Snippet'i kaç kez çalıştırdınız? Çalışma süreleri, sisteminizin kaç tane başka şey yapabildiğine bağlı olarak, çalışmaya göre değişebilir. Bunlar yaklaşık 10 veya 20 koşunun ortalama zamanları mı, yoksa sadece tek bir koşunun zamanlamaları mı? – JGroven

+1

Muhtemelen 512, önbelleklere çok uyan sihirli bir boyuttur, böylece çok fazla önbellek kaçırırsınız. Diğer boyutlar daha iyi uyum sağlar, böylece daha az özlüyorsunuz. – NathanOliver

+0

Yanlış yol @NathanOliver - 512, 513'den çok * daha yavaş * –

cevap

6

Bu, önbellek hatalarından kaynaklanmaktadır. Kaçının miktarını görmek için valgrind --tool=cachegrind'u kullanabilirsiniz.

Average for size 512: 13052 (us)==21803== 
==21803== I refs:  1,054,721,935 
==21803== I1 misses:   1,640 
==21803== LLi misses:   1,550 
==21803== I1 miss rate:   0.00% 
==21803== LLi miss rate:   0.00% 
==21803== 
==21803== D refs:  524,278,606 (262,185,156 rd + 262,093,450 wr) 
==21803== D1 misses:  139,388,226 (139,369,492 rd +  18,734 wr) 
==21803== LLd misses:   25,828 (  7,959 rd +  17,869 wr) 
==21803== D1 miss rate:   26.6% (  53.2%  +   0.0% ) 
==21803== LLd miss rate:   0.0% (  0.0%  +   0.0% ) 
==21803== 
==21803== LL refs:   139,389,866 (139,371,132 rd +  18,734 wr) 
==21803== LL misses:   27,378 (  9,509 rd +  17,869 wr) 
==21803== LL miss rate:   0.0% (  0.0%  +   0.0% ) 

While, N=530 kullanarak aşağıdaki çıktıyı var: Gördüğünüz gibi, D1 512 numarada özlüyor

Average for size 530: 13264 (us)==22783== 
==22783== I refs:  1,129,929,859 
==22783== I1 misses:   1,640 
==22783== LLi misses:   1,550 
==22783== I1 miss rate:   0.00% 
==22783== LLi miss rate:   0.00% 
==22783== 
==22783== D refs:  561,773,362 (280,923,156 rd + 280,850,206 wr) 
==22783== D1 misses:  32,899,398 (32,879,492 rd +  19,906 wr) 
==22783== LLd misses:   26,999 (  7,958 rd +  19,041 wr) 
==22783== D1 miss rate:   5.9% (  11.7%  +   0.0% ) 
==22783== LLd miss rate:   0.0% (  0.0%  +   0.0% ) 
==22783== 
==22783== LL refs:   32,901,038 (32,881,132 rd +  19,906 wr) 
==22783== LL misses:   28,549 (  9,508 rd +  19,041 wr) 
==22783== LL miss rate:   0.0% (  0.0%  +   0.0% ) 

530 oranla yaklaşık 3,5 kat daha büyük olduğu N = 512 kullanma aşağıdaki çıktıyı var

+0

Yani bir çözüm, bir "önbellek dostu" matrisi için bir sonraki büyük boyutlu matrisi kullanmak ve bazı kullanılmayan sütunları (ve muhtemelen satırları) bırakmak olacaktır, ancak daha hızlı olmalıdır. – rcgldr

+0

Yup ve yüksek özlü isabet oranı, ilişkilendirmenin belirli bellek erişim kalıpları altında toplam önbelleğin yalnızca bir kısmının kullanılmasına izin vermesidir. –

+1

@rcgldr: Bellek erişim düzenini değiştirmek daha iyi bir çözüm olurdu. Tek öğeleri değiştirmek yerine, 4x4 bloğunu değiştirin, böylece takasın her iki ucu için aynı önbellek satırındaki tüm öğelere erişebilirsiniz. –

İlgili konular