2011-08-20 3 views
19

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

Я работаю над драйвером устройства для устройства, которое напрямую записывается в ОЗУ через PCI Express (DMA), и я обеспокоен управлением связью кеша. Существует бит управления, который я могу установить при запуске 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, но до сих пор мне не удалось найти никаких определений этих операций.

+0

Там было несколько LWN статей о DMA и когерентности кэша вы можете захотеть взглянуть вокруг на lwn.net – Spudd86

+1

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

ответ

15

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

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

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

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

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

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

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

Этап 4: Повторите.

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

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

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

Найл

4

Может быть, немного с опозданием, но:

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

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

Refs:

Смежные вопросы