Memcpy из памяти PCIe занимает больше времени, чем memcpy в память PCIe

Я пытаюсь выполнять чтение/запись данных на/с ПК с Linux с/на устройство PCIe 2.0 (2-полосное). Память для чтения и записи находится в разных местах ОЗУ устройства PCIe. Эти воспоминания отображаются на ПК с Linux с помощью ioremap. Мой вариант использования — достичь пропускной способности чтения/записи 18 МБ/с, которая, очевидно, поддерживается каналом PCIe. Память на устройстве PCIe не кэшируется.

Я могу достичь пропускной способности записи, т.е. когда я пишу из локальной памяти ПК с Linux в память устройства PCIe с помощью memcpy. В этом случае memcpy занимает менее 1 мс для 9216 байт данных. Но когда я читаю ioremapped память PCIe в локальную память Linux, происходит потеря данных. Я профилировал memcpy, и это занимает более 1 мс, иногда 2 мс для 9216 байт данных. Я не хочу делать DMA для этой операции.

Есть мысли, в чем может быть проблема в этом случае? Как я могу справиться с этим?


person Mohnish Jain    schedule 31.01.2017    source источник
comment
Начните с публикации некоторого кода.   -  person sphinks    schedule 31.01.2017
comment
Это то, что вы получаете за некешированные переводы. Запись выполняется быстрее, потому что ее можно буферизовать.   -  person CL.    schedule 31.01.2017
comment
Чтения, с другой стороны, гарантируют, что все предыдущие записи выполняются на шине. Это также может повлиять на пропускную способность.   -  person 0andriy    schedule 31.01.2017
comment
@КЛ. Спасибо за ответ. Память не кэшируется на стороне устройства PCIe, а не на стороне ПК с Linux. Буфер памяти устройства PCIe заполняется с правильной скоростью. Memcpy из памяти PCIe в кэшированную локальную память ПК с Linux занимает больше времени. Я не понял, что вы имели в виду под записью быстрее.   -  person Mohnish Jain    schedule 01.02.2017
comment
Когда хост записывает в устройство PCIe, ему не нужно ждать завершения самой записи.   -  person CL.    schedule 01.02.2017
comment
Если ваш источник, место назначения и количество байтов выровнены по 32-битам, вы можете использовать __iowrite32_copy и __ioread32_copy (не забывая делить количество байтов на 4) вместо memcpy. Если ваш источник, место назначения и количество байтов выровнены по 64-битной системе, вы можете использовать __iowrite64_copy и __ioread64_copy (не забывая разделить количество байтов на 8).   -  person Ian Abbott    schedule 01.02.2017


Ответы (1)


Это вполне ожидаемо, и вы ничего не можете с этим поделать. ЦП может выполнять только сериализованные чтения и записи размером в слово, которые имеют очень низкую пропускную способность по каналу PCIe из-за накладных расходов протокола. Каждая операция имеет 24 или 28 байт-времени связанных с ней служебных данных - это 12- или 16-байтовый заголовок TLP плюс 12-байтовые служебные данные канального уровня, а ЦП может работать только с 4 или 8 байтами за раз. ... в лучшем случае эффективность 25% (8/(8+24) = 25%), а в худшем случае эффективность 12,5% (4/(4+28) = 12,5%).

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

Решение? Используйте ДМА. PCIe специально разработан для поддержки эффективных операций прямого доступа к памяти по шине, поскольку устройства могут выполнять гораздо большие операции чтения и записи, минимум до 128 байт на операцию.

person alex.forencich    schedule 16.07.2019