пятница, 4 февраля 2022 г.

Как работает host visible память

 Некоторые особенности работы с разными типами памяти в Vulkan.

Host Coherent

  • Для этого типа памяти доступен маппинг в CPU-visible память.
  • При вызове memcpy() идет синхронное копирование в GPU память, поэтому профайлер покажет потерю производительности на вызове memcpy(). С одной стороны это упрощает профилирование, так как в GL/DX11 это бы происходило неявно в другом потоке и профайлер показал бы замедление на любом другом вызове API при котором произойдет синхронизация потоков. С другой стороны копирование в GPU память лучше делать в отдельном потоке.
  • Нет гарании, что сразу по завершенью memcpy() данные будут доступны на GPU. Это гарантирует только то, что чтение памяти на стороне CPU завершено. Передача данных по PCI-E может продолжаться еще некоторое время.
  • В vulkan для передачи данных существует 3 этапа синхронизации, но для coherent памяти используется только один - барьер с source = (host stage и write access).
  • Спецификация vulkan гарантирует, что доступен как минимум один тип host coherent памяти .

Host Сached

  • Для этого типа памяти в RAM резервируется память.
  • При вызове memcpy() идет копирование внутри RAM, что намного быстрее передачи по PCI-E.
  • Для некогерентной памяти дейсвуют все 3 этапа синхронизации:
    • Вызов vkFlushMappedMemoryRanges() делает изменения памяти видимой для драйвера (host domain availability operation).
    • Вызов vkQueueSubmit() и аналогичных команд делает изменения памяти видимой для GPU (domain operation from host to device).
    • Барьер с source = (host stage и write access) перед использованием памяти на стороне GPU (device domain visibility operation).
  • Чаще cached памяти используется для чтения с GPU, для этого используются другие синхронизации:
    • Барьер с destination = (host stage и read access) после записи в память на стороне GPU (device domain availability operation).
    • Вызов vkWaitForFences() для ожидания завершения операции на GPU дополнительно гарантирует, что изменения в памяти будут доступны на стороне CPU (domain operation from device to host).
    • Вызов vkInvalidateMappedMemoryRanges() делает изменение памяти видимой на стороне CPU (host domain visibility operation).

Host Cached Coherent

  • То же самое что и host cached, но не требует вызывать vkFlushMappedMemoryRanges() и vkInvalidateMappedMemoryRanges().
  • Синхронизация данных между CPU и GPU может происходить ассинхронно, то есть передача данных может начаться раньше, чем при использовании Flush / Invalidate

Device Local Host Coherent

  • Поддержка такого типа памяти на дискретных картах добавилась в 2019 году.
  • Обычно доступно не более 256Мб памяти, но на некоторых картах есть возможность всю память сделать host visible.
  • По моим тестам запись в такую память на 10% медленее чем host coherent. Но для небольших объемов данных это незначительно.
  • Из преимуществ - запись данных на GPU завершается при выходе из memcpy(), поэтому не возникает микрофризов, когда данные все еще передаются по PCI-E, а выполнение команд на GPU не может начаться без этих данных.

Оптимизация

  • AMD в последних докладах рекомендует при передаче данных по PCI-E выравнивать указатели по 64 байта, а также последовательное чтение или запись.
  • В движке idTech полностью избавились от юниформ в host coherent памяти в пользу device local, так получается более стабильный FPS, то есть не возникает микрофризов на GPU.
  • Для передачи больших объемов данных, например стримингу текстур, стоит использовать отдельный поток и отдельную очередь на GPU (transfer queue), что доступно начиная с GTX 9xx серии и AMD GCN.
  • Если отельные очереди недоступны, то запись в память должна быть в самом начале кадра, а на стороне GPU барьер с host stage должен быть как можно позже. Барьер для отдельных буферов с host visible памятью может быть эфеективнее чем общий memory barrier, например один буфер используется для юниформ и нужен сразу, а другой с текстурами нужен намного позже - после shadow pass и depth pre-pass.
  • Стоит ограничить объем памяти, который копируется за один кадр из расчета (пропускная_способность_PCI-E / время_кадра), при этом оставить резерв на неэффективную передачу данных по PCI-E, например при копировании из невыровненой памяти.
  • Копирование юниформ и стриминг текстур идут по одному и тому же PCI-E, поэтому передача больших объемов данных так же замедлит или отложит заливку юниформ, что приведет к ожиданию на стороне GPU.

Комментариев нет:

Отправить комментарий