Готовый перевод Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 17.8. Receive Interrupt Mitigation
17.8 Подавление приема прерываний
Вы видели, что для каждого пакета, который принимается
интерфейсом, возникает прерывание. Как правило, так и должно быть.
Однако, высокопроизводительные интерфейсы могут принимать тысячи
пакетов в секунду. При такой загрузке прерываниями, общая
производительность система ухудшается.
Для улучшения производительности Linux-систем, разработчики
сетевой подсистемы могут создать альтернативный интерфейс
(называемый NAPI)1, в основе которого лежит механизм опроса. Слово
«опрос» может не понравиться тем разработчикам драйверов, которые
видели много неэффективных и не элегантных технологий опроса. Но,
опрос не эффективен, только тогда, когда интерфейс не получает работы,
ведя опрос. Когда в системе имеется высокопроизводительный
интерфейс, обрабатывающий большой трафик, то всегда есть пакеты для
обработки. В такой ситуации можно обойтись без прерываний. Нужно
только, чтобы новые пакеты забирались из интерфейса достаточно часто.
[NAPI] означает "новый API", у иследователей лучше получатеся создавать интерфейсы чем называть их.
Прекращение приема прерываний может существенно разгрузить
процессор. Также , NAPI драйвер может не передавать пакеты в ядро,
если этих пакетов мало, а накапливать их в сетевом коде, для еще
большего повышения производительности. По различным причинам, в
NAPI драйверах уменьшается вероятность изменения порядка следования
пакетов.
Не все устройства могут работать в NAPI режиме. NAPI –
совместимый интерфейс должен иметь возможность сохранения
нескольких пакетов, внутри карты или во встроенной памяти для ПДП.
Интерфейс должен обеспечивать возможность запрещения прерываний
при получении пакета, в тоже время продолжать выдавать прерывания
при завершении отправки пакета и других событиях. Есть и другие
тонкости, при написании NAPI-совместимого драйвера. О них можно
прочитать в файле Documentation/networking/NAPI_HOWTO.txt, в исходных
кодах ядра.
Относительно мало драйверов реализуют интерфейс NAPI. Имеет
смысл потратить время на реализацию NAPI, если вы пишите драйвер
интерфейса, который генерирует огромное количество прерываний.
Когда драйвер snull загружается с параметром use_napi не равным
нулю, он работает в режиме NAPI. При инициализации мы настраиваем 2
поля внешней структуры net_device.
if (use_napi) {
dev->poll = snull_poll;
dev->weight = 2;
}
Поле poll должно указывать на функцию опроса, в нашем случае -
snull_poll. Поле weight описывает, на сколько большой трафик может
быть обработан устройством. Не существует строгих правил для выбора
значения этого параметра. По соглашению, Ethernet-интерфейс
производительностью 10MBps использует weight = 16, а более быстрый
weight = 64. Не заносите в weight значение, превышающее количество
пакетов, которое может хранить ваш интерфейс. В snull мы
устанавливаем weight= 2, для демонстрации отсроченного приема
пакетов.
Следующим шагом в создании NAPI-совместимого драйвера, внесем
изменения в обработку прерывания. Когда ваш интерфейс (в начале
прием прерываний - разрешен) сигнализирует о прибытии пакета,
обработчик прерывания не обрабатывает этот пакет. Вместо этого, запрещается дальнейший прием прерываний, а ядру сообщается, что пора
начинать опрос устройства. В snull, обработка прерывания по событию
приема пакета, изменяется:
if (statusword & SNULL_RX_INTR) {
snull_rx_ints(dev, 0); /* Запрещаем прерывания */
netif_rx_schedule(dev);
}
Когда интерфейс информирует о том, что прибыл пакет, обработка
прерываний – прекращается. Далее необходимо вызвать
netif_rx_schedule, благодаря чему в будущем произойдет вызов метода
poll.
Когда интерфейс информирует о том, что прибыл пакет, обработка
прерываний – прекращается. Далее необходимо вызвать
netif_rx_schedule, благодаря чему в будущем произойдет вызов метода
poll.
int (*poll)(struct net_device *dev, int *budget);
Реализация в snull метода poll:
static int snull_poll(struct net_device *dev, int *budget)
{
int npackets = 0, quota = min(dev->quota, *budget);
struct sk_buff *skb;
struct snull_priv *priv = netdev_priv(dev);
struct snull_packet *pkt;
while (npackets < quota && priv->rx_queue) {
pkt = snull_dequeue_buf(dev);
skb = dev_alloc_skb(pkt->datalen + 2);
if (! skb) {
if (printk_ratelimit())
printk(KERN_NOTICE "snull: packet dropped\n");
priv->stats.rx_dropped++;
snull_release_buffer(pkt);
continue;
}
memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen);
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY; /* не проверяем */
netif_receive_skb(skb);
/* статистика */
npackets++;
priv->stats.rx_packets++;
priv->stats.rx_bytes += pkt->datalen;
snull_release_buffer(pkt);
}
/* если обработали все пакеты, сообщаем об этом ядру и разрешаем
прерывания */
*budget -= npackets;
dev->quota -= npackets;
if (! priv->rx_queue) {
netif_rx_complete(dev);
snull_rx_ints(dev, 1);
return 0;
}
/* Мы не смогли все обработать */
return 1;
}
В центральной части функции создается skb, хранящий пакет. Этот
код аналогичен рассмотренному ранее snull_rx, но есть отличия:
Параметр budget содержит максимальное количество пакетов,
которое может быть передано ядру. В структуре dev поле quota
предоставляет другое максимальное значение. Метод poll
должен использовать наименьшее из них. Это приводит к
снижению количества реально принимаемых пакетов. budget –
максимальное количество пакетов, которое может принять
текущий процессор. quota – ограничение интерфейса, обычно
оно устанавливается при инициализации, как и weight.
Пакет передается ядром с помощью функции
netif_receive_skb, что лучше чем netif_rx.
Если метод poll обработал все пакеты, то снова разрешается
прием прерываний, прекращается опрос (netif_rx_complete),
и возвращается 0. Если обработаны не все пакеты –
возвращается 1.
Сетевая подсистема гарантирует, что метод устройства poll не
будет выполняться одновременно на нескольких процессорах. Конечно,
методы poll для различных устройств, могут выполняться одновременно.
Внимание! Этот перевод, возможно, ещё не готов.
Его статус: перевод редактируется
Переведено на Нотабеноиде
http://notabenoid.org/book/11832/38389
Переводчики: hardorsoft
Настройки
Готово:
