Приветствую вас, дорогие земляне!Много промахов кеша, умножение матричной матрицы
Это обзор:
Я делаю разреженную матрицу умножения, где у меня есть два плотных матриц, но я заинтересован только в некоторых элементах производства. У меня есть две матрицы и один 2d индексный массив:
float * A:[M*K]
float * B:[N*K]
int [][] idx: [M][nSelection] (that is there are nselection rows in B, per row in matrix A that I want to multiply)
и я хочу, чтобы вычислить:
out=A*B' // but of course only for the indices i,j where idx[i][k]=j for some k.
Это зернистость материи: Я хочу, чтобы держать вещи в процессоре кэш, пока я размножая умножаем 16 поплавки в то время:
for (int kk = 0; kk < K; kk+=KK){
int begin = 0;
int end = M;
for (int i = begin; i < end; i++){
for (int j = 0; j < numberToAccept; j++){
int theid = idx[i * numberToAccept + j];
tempOut[i*numberToAccept+j] += blas_function_for_dotProduct(KK, A+i*K + kk, 1, B+theid*K + kk, 1);
}
}
}
числа Я работаю с являются:
M = 2048; N=10240; K=4096; nSelection=100;
Таким образом, идея заключается в том, что если я разобрать матрицы в маленьких частях маленьких частями (в направлении KK в кусках 16 поплавков = 1 cacheline) Я иметь возможность загружать обе матрицы только один раз. То есть, матрица A загружается последовательно, поэтому, кроме первой загрузки каждой строки, все остальные нагрузки должны быть хитами. матрица B загружается в случайном порядке, но поскольку я обрабатываю все это в кусках 64 байта (16 поплавков), тогда для этого потребуется 640 КБ. У меня 6 МБ L1, поэтому он должен оставаться там, если процессор использует LRU.
Я использую Valgrind, чтобы посмотреть на кэш-промахов и это то, что я получаю:
==3264== D refs: 2,383,524,642 (2,272,927,073 rd + 110,597,569 wr)
==3264== D1 misses: 114,096,428 ( 113,982,278 rd + 114,150 wr)
==3264== LLd misses: 95,822,173 ( 95,736,938 rd + 85,235 wr)
==3264== D1 miss rate: 4.7% ( 5.0% + 0.1% )
==3264== LLd miss rate: 4.0% ( 4.2% + 0.0% )
Также я получаю тот же результат, если доступ предсказуем (подсчитывая).
Я получаю тот же результат с N = 512. но при N = 256, я вдруг получить хиты кэш (произвольного доступа):
==16546== D refs: 2,383,525,914 (2,272,928,002 rd + 110,597,912 wr)
==16546== D1 misses: 114,096,557 ( 113,982,392 rd + 114,165 wr)
==16546== LLd misses: 1,372,862 ( 1,287,624 rd + 85,238 wr)
==16546== D1 miss rate: 4.7% ( 5.0% + 0.1% )
==16546== LLd miss rate: 0.0% ( 0.0% + 0.0% )
Дело в том, что у меня есть кэш 6MB на мой мобильный Core i7. И 512 * 16 * размер поплавка - 23 КБ. Так почему я получаю так много промахов? (Я написал большую часть этой вчерашней ночи, сегодня я нашел ответ.