Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
17.8 Подавление приема прерываний
hardorsoft
26.10.10 в 02:57
|
|
Вы видели, что для каждого пакета, который принимается интерфейсом, возникает прерывание. Как правило, так и должно быть. Однако, высокопроизводительные интерфейсы могут принимать тысячи пакетов в секунду. При такой загрузке прерываниями, общая производительность система ухудшается.
hardorsoft
26.10.10 в 02:57
|
|
Для улучшения производительности Linux-систем, разработчики сетевой подсистемы могут создать альтернативный интерфейс (называемый NAPI)1, в основе которого лежит механизм опроса. Слово «опрос» может не понравиться тем разработчикам драйверов, которые видели много неэффективных и не элегантных технологий опроса. Но, опрос не эффективен, только тогда, когда интерфейс не получает работы, ведя опрос. Когда в системе имеется высокопроизводительный интерфейс, обрабатывающий большой трафик, то всегда есть пакеты для обработки. В такой ситуации можно обойтись без прерываний. Нужно только, чтобы новые пакеты забирались из интерфейса достаточно часто.
hardorsoft
26.10.10 в 02:58
|
|
[NAPI] означает "новый API", у иследователей лучше получатеся создавать интерфейсы чем называть их.
hardorsoft
26.10.10 в 03:04
|
|
Прекращение приема прерываний может существенно разгрузить процессор. Также , NAPI драйвер может не передавать пакеты в ядро, если этих пакетов мало, а накапливать их в сетевом коде, для еще большего повышения производительности. По различным причинам, в NAPI драйверах уменьшается вероятность изменения порядка следования пакетов.
hardorsoft
26.10.10 в 02:58
|
|
Не все устройства могут работать в NAPI режиме. NAPI – совместимый интерфейс должен иметь возможность сохранения нескольких пакетов, внутри карты или во встроенной памяти для ПДП. Интерфейс должен обеспечивать возможность запрещения прерываний при получении пакета, в тоже время продолжать выдавать прерывания при завершении отправки пакета и других событиях. Есть и другие тонкости, при написании NAPI-совместимого драйвера. О них можно прочитать в файле Documentation/networking/NAPI_HOWTO.txt, в исходных кодах ядра.
hardorsoft
26.10.10 в 02:58
|
|
Относительно мало драйверов реализуют интерфейс NAPI. Имеет смысл потратить время на реализацию NAPI, если вы пишите драйвер интерфейса, который генерирует огромное количество прерываний.
hardorsoft
26.10.10 в 02:58
|
|
Когда драйвер snull загружается с параметром use_napi не равным нулю, он работает в режиме NAPI. При инициализации мы настраиваем 2 поля внешней структуры net_device.
hardorsoft
26.10.10 в 02:59
|
|
if (use_napi) { dev->poll = snull_poll; dev->weight = 2; }
hardorsoft
26.10.10 в 03:05
|
|
Поле poll должно указывать на функцию опроса, в нашем случае - snull_poll. Поле weight описывает, на сколько большой трафик может быть обработан устройством. Не существует строгих правил для выбора значения этого параметра. По соглашению, Ethernet-интерфейс производительностью 10MBps использует weight = 16, а более быстрый weight = 64. Не заносите в weight значение, превышающее количество пакетов, которое может хранить ваш интерфейс. В snull мы устанавливаем weight= 2, для демонстрации отсроченного приема пакетов.
hardorsoft
26.10.10 в 03:05
|
|
Следующим шагом в создании NAPI-совместимого драйвера, внесем изменения в обработку прерывания. Когда ваш интерфейс (в начале прием прерываний - разрешен) сигнализирует о прибытии пакета, обработчик прерывания не обрабатывает этот пакет. Вместо этого, запрещается дальнейший прием прерываний, а ядру сообщается, что пора начинать опрос устройства. В snull, обработка прерывания по событию приема пакета, изменяется:
hardorsoft
26.10.10 в 03:06
|
|
if (statusword & SNULL_RX_INTR) { snull_rx_ints(dev, 0); /* Запрещаем прерывания */ netif_rx_schedule(dev); }
hardorsoft
26.10.10 в 03:07
|
|
Когда интерфейс информирует о том, что прибыл пакет, обработка прерываний – прекращается. Далее необходимо вызвать netif_rx_schedule, благодаря чему в будущем произойдет вызов метода poll.
hardorsoft
26.10.10 в 03:07
|
|
Когда интерфейс информирует о том, что прибыл пакет, обработка прерываний – прекращается. Далее необходимо вызвать netif_rx_schedule, благодаря чему в будущем произойдет вызов метода poll.
hardorsoft
26.10.10 в 03:08
|
|
int (*poll)(struct net_device *dev, int *budget);
hardorsoft
26.10.10 в 03:08
|
|
Реализация в snull метода poll:
hardorsoft
26.10.10 в 03:08
|
|
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; }
hardorsoft
26.10.10 в 03:08
|
|
В центральной части функции создается skb, хранящий пакет. Этот код аналогичен рассмотренному ранее snull_rx, но есть отличия:
hardorsoft
26.10.10 в 03:09
|
|
Параметр budget содержит максимальное количество пакетов, которое может быть передано ядру. В структуре dev поле quota предоставляет другое максимальное значение. Метод poll должен использовать наименьшее из них. Это приводит к снижению количества реально принимаемых пакетов. budget – максимальное количество пакетов, которое может принять текущий процессор. quota – ограничение интерфейса, обычно оно устанавливается при инициализации, как и weight.
hardorsoft
26.10.10 в 03:09
|
|
Пакет передается ядром с помощью функции netif_receive_skb, что лучше чем netif_rx.
hardorsoft
26.10.10 в 03:09
|
|
Если метод poll обработал все пакеты, то снова разрешается прием прерываний, прекращается опрос (netif_rx_complete), и возвращается 0. Если обработаны не все пакеты – возвращается 1.
hardorsoft
26.10.10 в 03:09
|
|
Сетевая подсистема гарантирует, что метод устройства poll не будет выполняться одновременно на нескольких процессорах. Конечно, методы poll для различных устройств, могут выполняться одновременно.
hardorsoft
26.10.10 в 03:10
|
|