Нулевое копирование с операциями Scatter/Gather и без них

Я только что прочитал статью, в которой объясняется механизм нулевого копирования.

В нем рассказывается о разнице между нулевым копированием с поддержкой Scatter/Gather и без нее.

NIC без поддержки SG, копии данных следующие

введите здесь описание изображения

NIC с поддержкой SG, копии данных следующие

введите здесь описание изображения

Одним словом, нулевая копия с поддержкой SG может исключить одну копию ЦП.

Мой вопрос в том, что почему данные в буфере ядра могут быть разбросаны?


person sliter    schedule 19.03.2012    source источник


Ответы (3)


Поскольку средства сопоставления/распределения памяти ядра Linux по умолчанию создают виртуально непрерывные, но, возможно, физически непересекающиеся области памяти.
Это означает, что чтение из файловой системы, которое sendfile() выполняет внутренне, направляется в буфер в виртуальной памяти ядра< /em>, который код DMA должен «преобразовать» (из-за отсутствия лучшего слова) во что-то, что может понять механизм DMA сетевой карты.

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

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

person FrankH.    schedule 19.03.2012

Re: Мой вопрос: почему данные в буфере ядра могут быть разбросаны?

Потому что он уже разбросан. Очередь данных перед сокетом TCP не делится на дейтаграммы, которые будут выходить на сетевой интерфейс. Scatter позволяет вам хранить данные там, где они есть, и вам не нужно копировать их, чтобы создать плоский буфер, приемлемый для оборудования.

С помощью функции gather вы можете передать сетевой карте дейтаграмму, разбитую на части по разным адресам в памяти, которые могут быть ссылками на исходные буферы сокетов. Карта будет считывать его из этих мест и отправлять как единое целое.

Без сбора (аппаратные средства требуют простых линейных буферов) дейтаграмма должна быть подготовлена ​​как непрерывно расположенная строка байтов, и все данные, которые ей принадлежат, должны быть memcpy-d на свои места из буферов, которые ставятся в очередь для передачи на сокете.

person Kaz    schedule 19.03.2012

Поскольку, когда вы пишете в сокет, заголовки пакета собираются в другом месте, отличном от ваших пользовательских данных, поэтому для объединения в сетевой пакет устройству требуется возможность «сбора», по крайней мере, для получения заголовков и данных. .

Кроме того, чтобы ЦП не приходилось читать данные (и, таким образом, заполнять свой кэш бесполезными вещами, которые ему больше никогда не понадобятся), сетевая карта также должна генерировать свои собственные контрольные суммы IP и TCP (здесь я предполагаю TCP, потому что 99% ваших массовых передач данных будет TCP). Это нормально, потому что в настоящее время они все могут.

В чем я не уверен, так это в том, как все это взаимодействует с TCP_CORK.

Большинство протоколов, как правило, имеют собственные заголовки, поэтому гипотетический протокол выглядит так:

Клиент: Отправить запрос Сервер: Отправить некоторые метаданные; отправить данные файла

Таким образом, мы, как правило, имеем серверное приложение, собирающее некоторые заголовки в памяти, выдающее write(), за которым следует операция, подобная sendfile(). Я полагаю, что в этом случае заголовки все равно копируются в буфер ядра.

person MarkR    schedule 19.03.2012