Количество копий памяти в * nix системах между пакетами на сетевой карте и пользовательским приложением? - PullRequest
5 голосов
/ 21 апреля 2010

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

Поэтому мой вопрос к тем, кто использует сетевые стеки в Unix или Unix-подобных системах. Какую разницу они, вероятно, смогут реализовать, используя этот метод? Не стесняйтесь отвечать с точки зрения копий памяти, числа спасенных китов или областей размером с Уэльс;)

Их обмен сообщениями основан на UDP, насколько я понимаю, поэтому нет проблем с установлением TCP-соединений и т. Д. Любые другие вопросы по этой теме будут с благодарностью рассмотрены!

С наилучшими пожеланиями,

Майк

Ответы [ 2 ]

1 голос
/ 22 апреля 2010

Есть несколько картинок http://vger.kernel.org/~davem/tcp_output.html Googled с tcp_transmit_skb(), который является ключевой частью tcp datapath. На его сайте есть еще кое-что интересное http://vger.kernel.org/~davem/

В user - tcp для передачи части канала данных имеется 1 копия от пользователя в skb с skb_copy_to_page (при отправке tcp_sendmsg()) и 0 копия с do_tcp_sendpages (вызывается tcp_sendpage()). Копия необходима для хранения резервной копии данных на случай недоставленного сегмента. Буферы skb в ядре могут быть клонированы, но их данные останутся в первом (оригинальном) skb. Sendpage может взять страницу из другой части ядра и сохранить ее для резервного копирования (я думаю, что есть что-то вроде COW)

Пути вызова (вручную из lxr). Отправка tcp_push_one / __tcp_push_pending_frames

tcp_sendmsg() <-  sock_sendmsg <- sock_readv_writev <- sock_writev <- do_readv_writev

tcp_sendpage() <- file_send_actor <- do_sendfile 

Получите tcp_recv_skb()

tcp_recvmsg() <-  sock_recvmsg <- sock_readv_writev <- sock_readv <- do_readv_writev

tcp_read_sock() <- ... spliceread for new kernels.. smth sendfile for older

В получить может быть 1 копия от ядра к пользователю skb_copy_datagram_iovec (вызывается из tcp_recvmsg). А для tcp_read_sock () может быть копия. Это вызовет sk_read_actor функцию обратного вызова. Если он соответствует файлу или памяти, он может (или не может) копировать данные из зоны DMA. Если это другая сеть, она имеет skb принятого пакета и может повторно использовать свои данные на месте.

Для udp - получить = 1 копия - skb_copy_datagram_iovec вызывается из udp_recvmsg. передать = 1 копия - udp_sendmsg -> ip_append_data -> getfrag (похоже, ip_generic_getfrag с 1 копией от пользователя, но может быть чем-то вроде sendpage / splice, без копирования страницы.)

Вообще говоря, при отправке из / получения в пространство пользователя должна быть как минимум 1 копия и 0 при использовании нулевой копии (сюрприз!) С исходными / целевыми буферами пространства ядра для данных. Все заголовки добавляются без перемещения пакета, сетевая карта с поддержкой DMA (все современные) будет принимать данные из любого места в адресном пространстве с поддержкой DMA. Для старых карт необходим PIO, поэтому будет еще одна копия, от пространства ядра до регистров / памяти PCI / ISA / smthelse.

UPD: В пути от NIC (но это зависит от ник, я проверил 8139too) к стеку tcp есть еще одна копия : от rx_ring до skb и то же самое для получения: от skb до tx буфер + 1 копия . Вы должны заполнить заголовки ip и tcp, но есть ли в skb их или место для них?

1 голос
/ 22 апреля 2010

Чтобы уменьшить задержку в High-performance, вы должны отказаться от использования драйвера ядра.Наименьшая задержка будет достигнута с помощью драйверов пользовательского пространства (MX делает это, Infinband тоже может быть).

Существует довольно хороший (но немного устаревший) обзор внутренних компонентов сети Linux "Карта сетевого кода вЯдро Linux 2.4.20 ".Существует несколько схем передачи данных по TCP / UDP.

Использование необработанных сокетов сделает путь к пакетам tcp немного короче (спасибо за идею).Код TCP в ядре не увеличит задержку.Но пользователь должен обрабатывать все протоколы TCP.Есть некоторый шанс оптимизировать его для некоторых конкретных ситуаций.Код для кластеров не требует обработки длинных или медленных ссылок, как для стека TCP / UDP по умолчанию.

Мне тоже очень интересна эта тема.

...