Что такое согласованная память на GPU?

Я не наткнулся ни разу на термин "некогерентная" и "когерентная" память в

технические статьи, связанные с графическим программированием. Я искал простое и ясное объяснение, но нашел в основном "хардкорные" статьи this. Я был бы рад получить ответ стиля непрофессионала на то, какая когерентная память на самом деле находится на архитектурах графических процессоров и как она сравнивается с другими (возможно, некогерентными) типами памяти.

Ответы

Ответ 1

Память - это память. Но разные вещи могут получить доступ к этой памяти. Графический процессор может получить доступ к памяти, процессор может получить доступ к памяти, а может быть, к другим аппаратным битам, что угодно.

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

Проще говоря, кеши.

Оказывается, изменение памяти дорого. Поэтому мы делаем все возможное, чтобы избежать изменения памяти, если мы не будем абсолютно обязаны. Когда вы пишете один байт от CPU до указателя в памяти, CPU еще не записывает этот байт. Или, по крайней мере, не в память. Он записывает его в локальную копию этой памяти, называемую "кешем".

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

Но если у вас есть два отдельных устройства, которые используют одну и ту же память, вам нужно каким-то образом убедиться, что записи одного устройства видны другим устройствам. Большинство графических процессоров не могут читать кеш процессора. И на большинстве языков ЦП нет поддержки на уровне языка, чтобы сказать "эй, что я написал в память? Я действительно хочу, чтобы ты теперь записывал ее в память". Поэтому вам обычно нужно что-то, чтобы обеспечить видимость изменений.

В Vulkan память, помеченная как "HOST_COHERENT", означает, что если вы пишете в эту память (через отображаемый указатель, поскольку это единственный способ, с помощью которого Vulkan позволяет вам напрямую записывать в память), вам не нужно использовать специальные чтобы убедиться, что графический процессор может видеть эти изменения. Графический обзор любых изменений гарантирован. Если этот флаг недоступен в памяти, вы должны использовать API Vulkan для обеспечения согласованности определенных областей данных, к которым вы хотите получить доступ.

С когерентной памятью происходит одна из двух вещей с точки зрения аппаратного обеспечения. Либо доступ к ЦП в память не кэшируется ни в одном из кэшей ЦП, либо у графического процессора есть прямой доступ к кэшам ЦП (возможно, из-за того, что они находятся на той же матрице, что и CPU (ы)). Обычно вы можете сказать, что последнее происходит, потому что встроенные GPU-реализации Vulkan не потрудились предлагать некогерентные варианты памяти.

Ответ 2

Если память когерентна, все потоки, обращающиеся к этой памяти, всегда должны согласовывать состояние памяти, например: если поток 0 считывает ячейку памяти A, а поток 1 считывает одно и то же местоположение одновременно, оба потока должны всегда прочитайте одно и то же значение.

Но если память не является когерентной, тогда потоки A и B могут считывать разные значения. Thread 0 может подумать, что местоположение A содержит 1, а поток считает, что это место содержит 2. Различные потоки будут иметь некогерентный вид памяти.

Когерентность трудно достичь с большим количеством ядер. Часто каждое ядро ​​должно знать о доступе к памяти из всех других ядер. Так что, если у вас 4 ядра в четырехъядерном процессоре, когерентность не так уж и сложна, поскольку каждое ядро ​​должно быть проинформировано о том, что память обращается к адресам из 3 других ядер, но в GPU с 16 ядрами каждое ядро ​​должно быть осведомлено о память обращается на 15 других ядер. Сердечники обмениваются данными о содержимом своего кеша, используя так называемые "протоколы согласованности кеша".

Вот почему графические процессоры часто поддерживают только ограниченные формы согласованности. Если некоторые ячейки памяти доступны только для чтения или доступны только одному потоку, то не требуется согласования. Если кеши небольшие, а согласованность не всегда требуется, но только при определенных инструкциях программы, тогда можно добиться правильного поведения программы с использованием кеш-флешей до или после определенных обращений к памяти.

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