Архитектурные принципы памяти процессора
Поддержка общей памяти
Под общей памятью мы подразумеваем возможность процессорных ядер взаимодействовать друг с другом, храня данные в совместно используемых ячейках памяти, а затем читать их. Фактическая связь осуществляется через сеть межсоединений, как обсуждалось раннее.
Общее адресное пространство облегчает переход от модели последовательного программирования к модели параллельного программирования, в том, что структуры данных и структуры управления во многих случаях могут быть сохранены как те, что были в последовательной программе. Модели программирования, такие как OpenMP и Clik также поддерживают инкрементальную паралеллизацию программного обеспечения взамен разрушительного подхода, необходимого для подхода передачи сообщений. Тем не менее, общая память не является «бесплатной», особенно когда количество ядер увеличивается.
В выосокпроизводительной вычислительной области совместно используемая память, как правило, не применяется с тех пор, как его текущая реализация не масштабируется до тысяч или даже сотен тысяч узлов, используемых в самых эффективных вычислительных кластерах сегодня. Эти кластеры, однако, построены из общих узлов памяти и хотя программисты могут использовать или не использовать общие модели программирования в пределах узла, аппаратная часть этих узлов обычно реализует общее адресное пространство. Лучшие исполнительные программы в этих машинах обычно используют гибридную модель программирования с помощью передачи сообщений между узлами и совместно используемой памятью в пределах узла.
По этим причинам все мультиядерные процессоры общего назначения сегодня поддерживают общее адресное пространство между ядрами и системой памяти, требующей когерентности кэша.
По определению, система кэширования является когерентной, если и только если все процессоры на любой момент времени имеют согласованное представление о том, какова последняя остаточная стоимость каждого места.
В течение времени, различные виды архитектуры организации кэша предлагались, опираясь на частные, общие или смешанные, плоские или иерархические структуры кэша. Механизм когерентности кэша предоставляет процессорам быстрый доступ к наиболее часто используемым данным в своих собственных частных тайниках, поддерживая при этом единообразие при некоторых других обновлениях процесса с совместно используемыми переменными. Наиболее распространенная реализация использует механизмы аннулирования, где локальные копии аннулируются, если ядро обновляет общую переменную. Ядра обычно имеют частный кэш команд. Существует также общий кэш 2-го уровня, унифицированный для данных и инструкций. На данный момент мы предполагаем, что ядра и кэш L2 соединены между собой через общую шину. Рассмотрим случай, когда оба ядра 0 и 1 читают значение адреса А и таким образом, оба имеют копию в их кэше L1. Необходимость обеспечения согласованности кэш-памяти возникает, когда либо ядро 0, либо ядро 1 должно обновить значение А, а другое ядро впоследствии должно читать его.
Согласованные действия, происходящие в блоке кэш-памяти, определяются набором конечных автоматов. Различные используемые протоколы когерентности, часто называются в соответствии с их состояниями. Примером широко используемого протокола когерентности кэша является протокол MESI для многопроцессорного вычислительного комплекса, используемый в процессорах Intel. MESI поддерживает четыре состояния кэш-блоков, которые могут соответствовать нижеприведенным:
-Модифицированный – блок в этом состоянии является единственной действительной копией блока. Память не имеет достоверной информации, и ни один другой кэш не может иметь работоспособную копию. Ядро, которому принадлежит этот блок, имеет возможность записи без уведомления любого другого ядра.
-Исключающий – первое ядро для чтения в блоки из памяти будет загружать его в исключающее состояние. Это означает, что если одно ядро позже изменяет блок, оно может быть повышено до измененного состояние без уведомления. Это выгодно для подавляющего большинства данных, которые не распределяются между потоками или процессами. Если блок находится в исключающем состоянии, мы знаем, что
-Память имеет последнюю копию
-Нет никаких других кэшированных копий в системе
-Общий – как только второе ядро читает тот же самый блок, он будет загружен в кэш этого ядра и будет отмечен как общий во всех кэшах.
-Недопустимый – как только одна из копий будет модифицирована одним из ядер, все остальные копии будут помечены как недопустимые и должны будут обновиться при следующем доступе.
MESI является лишь одним из многих механизмов когерентности кэша, предложенных и реализованных за все время.
Понятие когерентности кэша позволяет с легкостью писать эффективные параллельные программы с помощью потоковых или ориентированных на задачи моделей программирования. Тем не менее, оно также повышает сложность иерархии памяти и потребление энергии. Очевидно, что для масштабирования параллельной программы использование общих ресурсов, будь то ячейки памяти, межсоединения или интерфейсы памяти приводит к затруднениям производительности.