Управление когерентностью DMA-кэша - PullRequest
21 голосов
/ 20 августа 2011

У меня такой вопрос: как я могу определить, когда безопасно отключить отслеживание кэша, когда я правильно использую [pci_]dma_sync_single_for_{cpu,device} в моем драйвере устройства?

Я работаю над драйвером устройства для устройства, которое записывает напрямую в ОЗУ через PCI Express (DMA), и беспокоюсь об управлении когерентностью кэша. При запуске DMA можно установить управляющий бит, чтобы включить или отключить отслеживание кэша во время прямого доступа к памяти, очевидно, для производительности я бы хотел, чтобы отслеживание кэша было отключено, если это вообще возможно.

В подпрограмме прерывания я при необходимости вызываю pci_dma_sync_single_for_cpu() и ..._for_device() при переключении буферов DMA, но в 32-битном Linux 2.6.18 (RHEL 5) оказывается, что эти команды являются макросами, которые расширяются до нуля. ... что объясняет, почему мое устройство возвращает мусор, когда отслеживание кэша отключено в этом ядре!

Я просмотрел историю исходников ядра, и кажется, что до 2.6.25 только 64-битный x86 имел хуки для синхронизации DMA. В версии 2.6.26, похоже, существует общий унифицированный механизм косвенного обращения для синхронизации DMA (в настоящее время include/asm-generic/dma-mapping-common.h) через поля sync_single_for_{cpu,device} из dma_map_ops, но до сих пор мне не удалось найти какие-либо определения этих операций.

Ответы [ 2 ]

16 голосов
/ 27 февраля 2012

Я действительно удивлен, что никто не ответил на этот вопрос, поэтому здесь мы переходим к ответу, не относящемуся к Linux (у меня недостаточно знаний о самом ядре Linux, чтобы быть более конкретным) ...

Отслеживание кэша просто говорит контроллеру DMA отправлять запросы на аннулирование кэша всем процессорам для памяти, в которую осуществляется DMA. Это, очевидно, увеличивает нагрузку на шину когерентности кэша и особенно плохо масштабируется с дополнительными процессорами, поскольку не все процессоры будут иметь соединение с одним скачком с контроллером DMA, выдающим анализатор. Следовательно, простой ответ на вопрос «когда безопасно отключить отслеживание кэша» заключается в том, что когда DMA-память либо не существует ни в одном из кэшей ЦП, ИЛИ ее строки кэша помечены как недействительные. Другими словами, любая попытка чтения из области DMAed всегда приводит к чтению из основной памяти.

Итак, как вы гарантируете, что чтение из области DMAed всегда будет идти в основную память?

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

Этап 1: добавить «грязную» область памяти DMA в список «грязных и нуждающихся в очистке» памяти DMA.

Этап 2: В следующий раз, когда устройство прерывает работу со свежими данными DMA, выдайте асинхронный локальный кэш ЦП, аннулирующий для сегментов DMA в списке «грязный и подлежащий очистке» для всех ЦП, которые могут обращаться к этим блокам (часто каждый CPU запускает свои собственные списки, состоящие из блоков локальной памяти). Переместить указанные сегменты в «чистый» список.

Этап 3: следующее прерывание DMA (которое, конечно, вы уверены, что не произойдет до завершения предыдущего аннулирования кэша), возьмите новую область из «чистого» списка и сообщите устройству, что его следующий DMA должен войти в тот. Утилизируйте любые грязные блоки.

Стадия 4: повтор.

Насколько это больше работы, у него есть несколько основных преимуществ. Во-первых, вы можете привязать обработку DMA к одному ЦП (обычно к первичному ЦП0) или к одному узлу SMP, что означает, что только один ЦП / узел должен беспокоиться о недействительности кэша. Во-вторых, вы предоставляете подсистеме памяти гораздо больше возможностей для скрытия задержек памяти, распределяя операции с течением времени и распределяя нагрузку на шину когерентности кэша. Ключом к производительности, как правило, является попытка заставить любой DMA происходить на CPU как можно ближе к соответствующему контроллеру DMA и в памяти как можно ближе к этому CPU.

Если вы всегда передаете недавно DMAed в память пользовательскому пространству и / или другим процессорам, просто вставьте свежую полученную память в начало конвейера аннулирования асинхронного кэша. Некоторые ОС (не уверенны в Linux) имеют оптимизированную подпрограмму для предварительного упорядочения обнуленной памяти, поэтому ОС в основном обнуляет память в фоновом режиме и поддерживает быстрый кэш-память вокруг - это позволит вам поддерживать новые запросы памяти ниже этого кешируемого объема, поскольку обнуление памяти очень медленно Я не знаю ни одной платформы, созданной за последние десять лет, которая использует обнуление аппаратной разгрузки памяти, поэтому вы должны предположить, что вся свежая память может содержать действительные строки кэша, которые необходимо аннулировать.

Я ценю, что это отвечает только на половину вашего вопроса, но это лучше, чем ничего. Удачи!

Найл

6 голосов
/ 06 февраля 2013

Возможно, немного запоздало, но:

Если вы отключите отслеживание кэша, оборудование больше не будет заботиться о когерентности кэша. Следовательно, ядро ​​должно сделать это самостоятельно. За последние несколько дней я потратил некоторое время на обзор вариантов [pci_] dma_sync_single_for_ {cpu, device} для X86. Я не нашел никаких признаков того, что они прилагают какие-либо усилия для поддержания согласованности. Это согласуется с тем фактом, что отслеживание кэша по умолчанию включено в спецификации PCI (e).

Следовательно, если вы отключаете отслеживание кэша, вам придется самостоятельно поддерживать согласованность в своем драйвере. Возможно, вызвав clflush_cache_range () (X86) или подобное?

Refs:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...