Как найти максимально достижимую производительность базовых векторных / матричных операций с системой кэш-памяти? - PullRequest
0 голосов
/ 21 января 2019

Это основной вопрос, требующий вычисления «пиковой достижимой производительности» (в MFLOPS) векторно-векторного, векторно-матричного и матрично-матричного умножения с учетом определенной информации о системе памяти.Ниже приводится описание вопроса:

  • система памяти с кэш-памятью 1 уровня 32 КБ и DRAM 512 МБ с процессором, работающим на частоте 1 ГГц
  • Задержкак кэшу L1 - один цикл, а задержка к DRAM - 100 циклов
  • В каждом цикле памяти процессор выбирает четыре слова (т. е. размер строки кэша равен четырем словам)
  • Матрицы имеют размерность4K х 4K.(Каждая строка матрицы занимает 16 КБ памяти) и размещена в порядке строк

Часть (a): Для произвольных векторов a и b, что это такоепиковая производительность, учитывая следующий код:

1 /* dot product loop */
2 for (i = 0; i < dim; i++)
3 dot_prod += a[i] * b[i];

часть (b): Какова пиковая производительность умножения матрицы на вектор, заданного следующим кодом:

1 /* matrix-vector product loop */
2 for (i = 0; i < dim; i++)
3 for (j = 0; i < dim; j++)
4 c[i] += a[i][j] * b[j];

Часть (с): Какова производительность умножения матрицы на матрицу, заданную следующим кодом:

1 /* matrix-matrix product loop */
2 for (i = 0; i < dim; i++)
3 for (j = 0; i < dim; j++)
4 for (k = 0; k < dim; k++)
5 c[i][j] += a[i][k] * b[k][j];

На самом деле я знаю правильные решения для каждой части (40, 80 и 16 MFLOPS соответственно) , но я не могу полностью понять причины этих решений.В некоторых случаях у меня нет опыта работы с CS / EE, поэтому мое понимание систем кеша и памяти очень ограничено.Я впервые пытаюсь понять некоторые из этих понятий в более академической манере.

Для части (а) я понимаю, что вы можете извлечь 8 слов с двумя выборками строк кэша.Другими словами, 8 операций с плавающей запятой будут выполняться для каждых 2 выборок строк кэша.Вот откуда должны приходить 40 MFLOPS, так как 4 операции в каждом цикле эквивалентны 40 MFLOPS.

Часть (b) - это то, где я начинаю путаться. Согласно решению , по-видимому, если вектор b кэшируется, 8 операций могут быть выполнены на одной строке кэша .Это приведет к 8 операциям за цикл, т.е. 80 MFLOPS.На данный момент я запутался, почему выборка вектора b в кеш, похоже, не принимается во внимание.Постановка задачи никогда не описывает вектор b как уже существующий в кэше.Не означает ли это, что будет задержка, связанная с извлечением этого вектора и его первоначальным размещением в кеше?

Часть (c) на самом деле имеет для меня больше смысла, поскольку 8 операций с плавающей запятой выполняются над 5 строками кэша (1 для матрицы A и 4 для матрицы B, так как вам нужно обращаться к элементам по столбцам).

Основная путаница, с которой я столкнулся, связана с частью (b).Мне также трудно найти похожие примеры.Все, что я обнаружил, было либо над головой, либо недостаточно подробным.Если кто-то может дать простое и прямое объяснение (особенно для части (b)), это действительно помогло бы мне понять эти фундаментальные понятия.

Большое спасибо заранее!Просто пытаюсь учиться здесь!

1 Ответ

0 голосов
/ 21 января 2019

Мы можем считать, что эта проблема связана с памятью, и рассмотреть только кеш и доступ к памяти, чтобы решить эту проблему.

a / Первая итерация создает пропуск кеша.Следующие 3 итерации доступа к a [i] и b [i] относятся только к данным кеша.Следовательно, через каждые 4 итерации происходит 2 пропуска кэша для a [i] и b [i].Таким образом, 4 итерации длятся 2 * 100 циклов (задержка памяти).В 4 итерации мы выполняем 4 * 2 операций (* и + =).

Таким образом, 8 мс каждые 200 нс - это 8/2 * 10⁻6 операций / с = 40MFlops

b / Послефаза прогрева, вектор b остается в кеше и больше не будет создавать пропуски в кеше.Точно так же промахи для c - один раз каждые 4N операций и ими можно пренебречь.Таким образом, каждые 4 итерации приходится 1 промах кэша.4 итерации длятся 100 циклов и выполняют 4 * 2 операции.

8 операций каждые 10Ons - это 80Glops

c / Умножение матриц выполняется неправильно.Каждый доступ к b [k] [j] относится к другой строке кэша.Действительно, то, что вы говорите в описании проблемы, неверно.Если матрицы имеют размер 4 КБ * 4 КБ, они содержат 16 КБ элементов и требуют не менее 4 * 16 КБ = 64 КБ (если число с плавающей запятой, 128 КБ, если оно удваивается) (а не 16 КБ).Соответственно, матрицы НЕ помещаются в кэш 32 КБ, и каждый доступ к b [k] [j] приводит к отсутствию кэша.Каждые 4 итерации a [i] [k] является промахом кэша, и промахами за c [i] [j] можно пренебречь.Таким образом, для 4 итераций требуется 5 месс доступа и последние 5 * 100 циклов.В 4 итерации есть 4 * 2 операции (* и + =).

Таким образом, 8 операций в 500 нс - это 16GFlops.

...