Следующий пример кода генерирует матрицу размера N
и переносит ее SAMPLES
количество раз.
Когда N = 512
среднее время выполнения операции транспонирования 2144 μs
(ссылка coliru).
На первый взгляд нет ничего особенного, правильно?...
Ну, вот результаты для
-
N = 513
→1451 μs
-
N = 519
→600 μs
-
N = 530
→486 μs
-
N = 540
→492 μs
(наконец, теория начинает работать:).
Итак, почему на практике эти простые вычисления так отличаются от теории? Связано ли это с когерентностью кэш-памяти процессора или пропуском кэша? Если да, пожалуйста, объясните.
#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)";
}