С оптимизация кэша для прямого отображения кэш

возникли некоторые проблемы с определением скорости попадания и промаха следующих двух фрагментов кода.

данная информация: у нас есть 1024-байтовый кэш с прямым отображением с размерами блоков 16 байт. Таким образом, это составляет 64 строки (наборы в этом случае). Предположим, кэш пустой. Рассмотрим следующий код:

struct pos {
    int x;
    int y;
};

struct pos grid[16][16];
int total_x = 0; int total_y = 0;

void function1() {
    int i, j;
    for (i = 0; i < 16; i++) {
         for (j = 0; j < 16; j++) {
             total_x += grid[j][i].x;
             total_y += grid[j][i].y;
         }
    }
}

void function2() {
    int i, j;
    for (i = 0; i < 16; i++) {
         for (j = 0; j < 16; j++) {
             total_x += grid[i][j].x;
             total_y += grid[i][j].y;
         }
    }
}

Я могу сказать из некоторых основных правил (т. е. массивы C являются порядком строк), что function2 должен быть лучше. Но я не понимаю, как рассчитать попадание / промах проценты. По-видимому, function1() пропускает 50% времени, в то время как function2 () пропускает только 25% времени.

может кто-нибудь рассказать мне, как работают эти вычисления? Все, что я действительно вижу, это то, что не более половины сетки когда-либо поместится внутри кэша сразу. Кроме того, легко ли распространить эту концепцию на ассоциативные кэши k-way?

спасибо.

2 ответов


как данные хранятся в
Каждая структура pos имеет размер 8 байт, таким образом, общий размер pos[16][16] 2048 байт. И порядок массива таков:
pos[0][0] pos[0][1] pos[0][2] ...... pos[0][15] pos[1]0[] ...... pos[1][15].......pos[15][0] ......pos[15][15]

организация кэша по сравнению с данными
Для кэша каждый блок составляет 16 байт, что соответствует размеру двух элементов матрица. Весь кэш составляет 1024 байта,что составляет половину размера всего массива. Поскольку кэш напрямую сопоставлен, это означает, что если мы обозначим блок кэша от 0 до 63, мы можем с уверенностью предположить, что сопоставление должно выглядеть следующим образом
------------ память----------------------------кэш
pos[0][0] pos[0][1] -----------> block 0
pos[0][2] pos[0][3] -----------> block 1
pos[0][4] pos[0][5] -----------> block 2
pos[0][14] pos[0][15] --------> block 7
.......
pos[1][0] pos[1][1] -----------> block 8
pos[1][2] pos[1][3] -----------> block 9
.......
pos[7][14] pos[7][15] --------> block 63
pos[8][0] pos[8][1] -----------> block 0
.......
pos[15][14] pos[15][15] -----> block 63

как function1 управляет
Цикл следует за внутренним циклом по столбцу, что означает, что первая итерация загружает pos[0][0] и pos[0][1] кэш block 0 вторая итерация нагрузки pos[1][0] и pos[1][1] кэш block 8. Тайникихолод, Итак, первая колонка x всегда пропустить, а y - это всегда хит. Данные второго столбца предположительно загружаются в кэш во время доступа к первому столбцу, но это не случае. С pos[8][0] доступ уже выселить бывшего pos[0][0] страница(они оба сопоставляются с block 0!).Итак, Мисс ставка 50%.

как function2 управляет
Вторая функция имеет хороший Шаг-1 модели доступа. Это означает, что при обращении pos[0][0].x pos[0][0].y pos[0][1].x pos[0][1].y только первый из них является пропуском из-за холодного кэша. Все следующие паттерны одинаковы. Поэтому Мисс ставка составляет только 25%.

ассоциативный кэш K-way следует тому же анализу, хотя это может быть более утомительным. Для получения максимальной отдачи от кэш-системы, попробуйте инициировать хороший шаблон доступа, скажем stride-1, и использовать эти данные как можно больше во время каждой загрузки из памяти. Микроархитектура реального мира cpu использует другой интеллектуальный дизайн и алгоритм для повышения эффективности. Лучший метод - всегда измерять время в реальном мире, сбрасывать основной код и делать тщательный анализ.


хорошо, мои лекции по информатике немного далеки, но я думаю, что я понял это (это на самом деле очень простой пример, когда вы думаете об этом).

ваша структура имеет длину 8 байт (2 x 4). Поскольку кэш блоков 16 байт, доступ к памяти grid[i][j] будет получать ровно две записи структуры (grid[i][j] и grid[i][j+1]). Поэтому, если вы пройдете через второй индекс, только каждый 4-й доступ приведет к чтению памяти. Если вы пройдете через первый Индекс, вы, вероятно, выбросите вторая запись, которая была извлечена, зависит от количества извлечений во внутреннем цикле против общего размера кэша.

теперь мы должны подумать и о размере кэша: вы говорите, что у вас есть 64 строки, которые непосредственно сопоставлены. В функции 1 внутренний цикл равен 16 выборкам. Это означает, что 17-я выборка вы попадаете в сетку[j] [i+1]. На самом деле это должен быть хит, так как он должен был храниться в кэше с момента последнего внутреннего цикла. Поэтому каждый второй внутренний цикл должен состоять только из хитов.