Что в действительности измеряет тест пропускной способности памяти STREAM? - PullRequest
3 голосов
/ 11 мая 2019

У меня есть несколько вопросов по STREAM (http://www.cs.virginia.edu/stream/ref.html#runrules) тест.

  1. Ниже приведен комментарий от stream.c. Каково обоснование требования о том, что массивы должны быть 4 разаразмер кеша?
 *       (a) Each array must be at least 4 times the size of the
 *           available cache memory. I don't worry about the difference
 *           between 10^6 and 2^20, so in practice the minimum array size
 *           is about 3.8 times the cache size.
Я изначально предполагаю, что STREAM измеряет пиковую пропускную способность памяти.Но позже я обнаружил, что когда я добавляю дополнительные массивы и обращаюсь к массиву, я могу получить большие значения пропускной способности.Поэтому мне кажется, что STREAM не гарантирует насыщение пропускной способности памяти.Тогда мой вопрос заключается в том, что на самом деле измеряет STREAM и как вы используете числа, сообщаемые STREAM?

Например, я добавил два дополнительных массива и не забудьте получить к ним доступ вместе с оригиналом a / b./ c массивов.Я изменяю учет байтов соответственно.С этими двумя дополнительными массивами мой номер полосы пропускания увеличился на ~ 11,5%.

> diff stream.c modified_stream.c
181c181,183
<                       c[STREAM_ARRAY_SIZE+OFFSET];
---
>                       c[STREAM_ARRAY_SIZE+OFFSET],
>                       e[STREAM_ARRAY_SIZE+OFFSET],
>                       d[STREAM_ARRAY_SIZE+OFFSET];
192,193c194,195
<     3 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE,
<     3 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE
---
>     5 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE,
>     5 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE
270a273,274
>             d[j] = 3.0;
>             e[j] = 3.0;
335c339
<           c[j] = a[j]+b[j];
---
>           c[j] = a[j]+b[j]+d[j]+e[j];
345c349
<           a[j] = b[j]+scalar*c[j];
---
>           a[j] = b[j]+scalar*c[j] + d[j]+e[j];

CFLAGS = -O2 -fopenmp -D_OPENMP -DSTREAM_ARRAY_SIZE = 50000000

Мой кэш последнего уровня около35 МБ.

Любой комнет?

Спасибо!

Это для сервера Skylake Linux.

Ответы [ 3 ]

7 голосов
/ 13 мая 2019

Доступ к памяти в современных компьютерах намного сложнее, чем можно было ожидать, и очень трудно сказать, когда модель «высокого уровня» разваливается из-за некоторых «низкоуровневых» деталей, о которых вы не зналиbefore ....

Код теста STREAM измеряет только время выполнения - все остальное выводится.Полученные числа основаны как на решениях о том, что я считаю «разумным», так и на предположениях о том, как работает большинство компьютеров.Правила запуска являются продуктом проб и ошибок, пытаясь сбалансировать переносимость с универсальностью.

Тест STREAM сообщает значения «пропускной способности» для каждого ядра.Это простые вычисления, основанные на предположении, что каждый элемент массива с правой стороны каждого цикла должен быть считан из памяти, а каждый элемент массива с левой стороны каждого цикла должен быть записан в память.Тогда «полоса пропускания» - это просто общий объем перемещенных данных, деленный на время выполнения.

В этом простом вычислении заложено удивительное количество допущений.

  • Модель предполагает, что компилятор генерирует код для выполнения всех загрузок, сохранений и арифметических инструкций, которые подразумеваются подсчетами трафика памяти.Подход, используемый в STREAM для поощрения этого, довольно устойчив, но продвинутый компилятор может заметить, что все элементы массива в каждом массиве содержат одно и то же значение, поэтому фактически необходимо обработать только один элемент из каждого массива.(Вот как работает код проверки.)
  • Иногда компиляторы перемещают вызовы таймера из своего местоположения исходного кода.Это (едва заметное) нарушение языковых стандартов, но его легко уловить, поскольку обычно оно приводит к бессмысленным результатам.
  • Модель предполагает незначительное количество обращений в кэш.(При попадании в кэш вычисленное значение по-прежнему является «пропускной способностью», а не «пропускной способностью памяти».) Ядра STREAM Copy и Scale загружают только один массив (и хранят один массив), поэтому, если хранилища обходят кешобщий объем трафика, проходящего через кеш в каждой итерации, равен размеру одного массива.Адресация и индексация кэша иногда очень сложны, и политики замены кэша могут быть динамическими (псевдослучайными или основанными на показателях использования во время выполнения).В качестве компромисса между размером и точностью я выбрал 4x в качестве минимального размера массива относительно размера кэша, чтобы гарантировать, что большинство систем имеют очень низкую долю обращений в кэш (т. Е. Достаточно мало, чтобы оказывать незначительное влияние насообщаемая производительность).
  • Подсчет трафика данных в STREAM не "отдает должное" дополнительным передачам, которые выполняет аппаратное обеспечение, но которые не были явно запрошены.Это в первую очередь относится к трафику «запись на выделение» - большинство систем считывают каждый целевой адрес хранилища из памяти, прежде чем хранилище сможет обновить соответствующую строку кэша.Многие системы имеют возможность пропустить это «распределение записи», либо выделяя строку в кеше без ее чтения (POWER), либо выполняя хранилища, которые обходят кеш и переходят прямо в память (x86).Дополнительные замечания по этому вопросу приведены в http://sites.utexas.edu/jdm4372/2018/01/01/notes-on-non-temporal-aka-streaming-stores/
  • Многоядерные процессоры с более чем двумя каналами DRAM, как правило, не могут достичь асимптотической полосы пропускания, используя только одно ядро.Директивы OpenMP, которые изначально были предоставлены для больших систем с общей памятью, теперь должны быть включены почти на каждом процессоре с более чем двумя каналами DRAM, если вы хотите достичь асимптотических уровней пропускной способности.
  • Пропускная способность одноядерного ядра все еще важна, но, как правило, ограничена количеством пропусков кэша, которые может генерировать одно ядро, а не пиковой пропускной способностью DRAM системы.Вопросы представлены в http://sites.utexas.edu/jdm4372/2016/11/22/sc16-invited-talk-memory-bandwidth-and-system-balance-in-hpc-systems/
  • В случае с одноядерным процессором количество незавершенных кэш-данных L1 слишком мало для получения полной пропускной способности - для вашего масштабируемого процессора Xeon требуется около 140 одновременных пропусков кеш-памяти для каждого сокета, но одно ядро ​​может поддерживать только одно ядро.10-12 L1 Data Cache отсутствует.Аппаратные средства предварительной выборки L2 могут генерировать дополнительный параллелизм памяти (если я правильно помню, до ~ 24 кеш-пропусков на ядро), но для достижения средних значений вблизи верхнего предела этого диапазона требуется одновременный доступ к большему количеству страниц объемом 4 КБ.Ваши дополнительные чтения массива дают аппаратным средствам предварительной выборки L2 больше возможностей для генерирования (близкого к) максимального числа одновременных обращений к памяти.Увеличение на 11% -12% вполне разумно.
  • Ожидается, что увеличение доли операций чтения также повысит производительность при использовании всех ядер.В этом случае преимущество главным образом заключается в уменьшении количества «остановок чтения-записи» на интерфейсе DDR4 DRAM.При отсутствии хранилищ поддерживаемая полоса пропускания должна достигать пика 90% на этом процессоре (при использовании 16 или более ядер на сокет).

Дополнительные примечания по предотвращению трафика «запись-выделение»:

  1. В архитектурах x86 хранилища, обходящие кеш, обычно делают недействительным соответствующий адрес из локальных кешей и хранят данные в «буфере объединения записей», пока процессор не решит отправить данные в память.Другие процессоры могут хранить и использовать «устаревшие» копии строки кэша в течение этого периода.Когда буфер объединения записи очищается, строка кэша отправляется контроллеру памяти в транзакции, которая очень похожа на запись IO DMA.Контроллер памяти отвечает за выдачу «глобальных» недействительных адресов по адресу перед обновлением памяти.Необходимо соблюдать осторожность, когда эти потоковые хранилища используются для обновления памяти, которая распределяется между ядрами.Общая модель состоит в том, чтобы выполнить потоковые хранилища, выполнить ограничение хранилища, затем выполнить «обычное» хранилище для переменной «flag».Ограничение хранилища гарантирует, что никакой другой процессор не увидит обновленную переменную «flag», пока результаты всех потоковых хранилищ не будут видны глобально.(При использовании последовательности «обычных» хранилищ результаты всегда становятся видимыми в программном порядке, поэтому не требуется никаких ограничений хранилища.)
  2. В архитектуре PowerPC / POWER команду DCBZ (или DCLZ) можно использовать дляизбегайте записи, выделяйте трафик.Если строка находится в кеше, ее содержимое устанавливается на ноль.Если строка не находится в кэше, строка выделяется в кэше с ее содержимым, установленным на ноль.Недостатком этого подхода является то, что здесь представлен размер строки кэша.DCBZ на PowerPC с 32-байтовыми строками кэша очистит 32 байта.Эта же инструкция для процессора с 128-байтовыми строками кэша очистит 128 байт.Это раздражало продавца, который использовал оба.Я не помню достаточно деталей модели порядка памяти POWER, чтобы прокомментировать, как / когда транзакции когерентности становятся видимыми с этой инструкцией.
2 голосов
/ 13 мая 2019

Ключевым моментом здесь, как указано в ответе доктора Бандбайла, является то, что STREAMS учитывает только полезную полосу пропускания, видимую из исходного кода. (Он является автором теста.)

На практике поток записи будет также стоить пропускной способности чтения для запросов RFO (Read For Ownership). Когда процессор хочет записать 16 байтов (например) в строку кэша, сначала он должен загрузить исходную строку кэша, а затем изменить ее в кэше L1d.

( Если ваш компилятор не будет автоматически векторизован с хранилищами NT, которые обходят кеш и избегают этого RFO. Некоторые компиляторы будут делать это для циклов, которые они ожидают записать массив, слишком большой для кеша, до того, как какой-либо из них будет перезапущен -Распознать.)

См. Enhanced REP MOVSB ​​для memcpy для получения дополнительной информации об обходе кеш-памяти хранилищ, которые избегают RFO.


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

1 голос
/ 11 мая 2019

Целью теста STREAM является не измерение максимальной пропускной способности памяти (т. Е. Максимальной пропускной способности памяти, которая может быть достигнута в системе), а измерение «пропускной способности памяти» ряда ядер (COPY, SCALE, SUM и TRIAD), которые важны для сообщества HPC.Поэтому, когда пропускная способность, о которой сообщает STREAM, выше, это означает, что приложения HPC, вероятно, будут работать быстрее в системе.

Также важно понимать значение термина «пропускная способность памяти» в контексте эталонного теста STREAM, который объясняется в последнем разделе документации.Как уже упоминалось в этом разделе, существует как минимум три способа подсчета количества байтов для эталонного теста.В тесте STREAM используется метод STREAM, который считает количество прочитанных и записанных байтов на уровне исходного кода.Например, в ядре SUM (a (i) = b (i) + c (i)) два элемента читаются, а один элемент записывается.Следовательно, при условии, что все обращения осуществляются в память, число байтов, к которым обращаются из памяти за одну итерацию, равно количеству массивов, умноженному на размер элемента (который составляет 8 байтов).STREAM вычисляет пропускную способность путем умножения общего количества элементов, к которым был получен доступ (подсчитано с использованием метода STREAM), на размер элемента и деления его на время выполнения ядра.Чтобы учесть различия между прогонами, каждое ядро ​​запускается несколько раз, и сообщается среднее арифметическое, минимальное и максимальное значения пропускной способности.

Как видите, пропускная способность, сообщаемая STREAM, не является реальнойпропускная способность памяти (на аппаратном уровне), поэтому даже не имеет смысла говорить, что это пиковая пропускная способность.Кроме того, он почти всегда намного ниже максимальной пропускной способности.Например, эта статья показывает, как страницы ECC и 2 МБ влияют на полосу пропускания, сообщаемую STREAM.Написание эталона, который фактически обеспечивает максимально возможную пропускную способность памяти (на аппаратном уровне) на современных процессорах Intel, является серьезной проблемой и может быть хорошей проблемой для всего кандидата наук.Тезис.Однако на практике пиковая пропускная способность менее важна, чем пропускная способность STREAM в домене HPC.(Связано: см. мой ответ для получения информации о проблемах, связанных с измерением пропускной способности памяти на аппаратном уровне.)

Относительно вашего первого вопроса, обратите внимание, что STREAM просто предполагает, что все чтение и записьудовлетворены основной памятью, а не кешем.Выделение массива, который намного больше, чем размер LLC, помогает повысить вероятность того, что это так.По сути, сложные и недокументированные аспекты LLC, включая политику замены и политику размещения, должны быть побеждены.Это не должно быть точно в 4 раза больше, чем LLC.Насколько я понимаю, это то, что доктор Bandwidth нашел, чтобы работать на практике.

...