Эффективные сокеты Linux (DMA/zero-copy)
Я создаю очень высокопроизводительный Linux-сервер (на основе epoll, неблокирующих сокетов и асинхронного ввода-вывода IO [на основе io_submit/io_getevents/eventfd]). Некоторые из моих тестов показывают, что способ, которым я управляю сокетами, недостаточно эффективен для моих требований. В частности, я заинтересован в получении данных из буфера пользовательского пространства на сетевую карту и с сетевой карты обратно в буфер пользовательского пространства (пусть теперь игнорирует вызов sendfile).
Из того, что я понимаю, вызов чтения/записи в неблокирующемся сокете Linux не является полностью асинхронным - системные вызовы блокируются, когда он копирует буфер из пользовательского пространства в ядро (или наоборот) и только затем возвращается. Есть ли способ избежать этого подслушивания в Linux? В частности, существует полностью асинхронный вызов записи, который я могу сделать в сокете, который будет немедленно возвращен, DMA - буфер пользовательского пространства на сетевую карту, если необходимо, и сигнал/установить событие/и т.д. по окончании? Я знаю, что у Windows есть интерфейс для этого, но я не мог найти ничего об этом в Linux.
Спасибо!
Ответы
Ответ 1
Недавно появилось несколько разговоров о linux-kernel о предоставлении API для чего-то в этих строках, но суть в том, что вы не можете DMA из общих буферов пользовательского пространства на сетевую карту, потому что:
- Что-то похожее на непрерывные данные в линейном адресном пространстве пользовательского пространства, вероятно, не связано друг с другом в физической памяти, что является проблемой, если сетевая карта не выполняет DMA с распределением рассеяния;
- На многих компьютерах не все адреса физической памяти "DMA-able". В настоящий момент нет возможности для приложения userpace специально запросить DMA-способный буфер.
В последних ядрах вы можете попытаться использовать vmsplice
и splice
вместе для достижения желаемого - vmsplice
страницы (с SPLICE_F_GIFT
), которые вы хотите отправить в трубу, затем splice
их ( с SPLICE_F_MOVE
) от трубы в гнездо.
Ответ 2
AFAIK вы используете наиболее эффективные звонки, если вы не можете использовать sendfile (2). Различные аспекты эффективного высокопроизводительного сетевого кода покрываются Проблема C10K