博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux 如何降低入向收包软中断占比
阅读量:6863 次
发布时间:2019-06-26

本文共 5979 字,大约阅读时间需要 19 分钟。

最近遇到一个问题,当tcp收包的时候,我们的服务器的入向软中断比例很高。

我们知道,napi模式,可以降低收包入向软中断占比,那么,针对napi模式,能不能优化?本文针对2.6.32-358内核进行分析:

static void net_rx_action(struct softirq_action *h){    struct list_head *list = &__get_cpu_var(softnet_data).poll_list;    unsigned long time_limit = jiffies + 2;    int budget = netdev_budget;----------------这个值可以通过/proc/sys/net/core/netdev_budget修改,默认是300    void *have;    int select;    struct rps_remote_softirq_cpus *rcpus;    local_irq_disable();    while (!list_empty(list)) {-------------------不为空,则一直循环        struct napi_struct *n;        int work, weight;        /* If softirq window is exhuasted then punt.         * Allow this to run for 2 jiffies since which will allow         * an average latency of 1.5/HZ.         */        if (unlikely(budget <= 0 || time_after(jiffies, time_limit)))----------时间到,或者配额到了,则退出循环。            goto softnet_break;        local_irq_enable();        /* Even though interrupts have been re-enabled, this         * access is safe because interrupts can only add new         * entries to the tail of this list, and only ->poll()         * calls can remove this head entry from the list.         */        n = list_first_entry(list, struct napi_struct, poll_list);        have = netpoll_poll_lock(n);        weight = n->weight;--------------napi配置的weight,这个是一次poll的配额,和上面总的配合一起控制收包,这个在netif_napi_add 函数中设置。
/* This NAPI_STATE_SCHED test is for avoiding a race * with netpoll's poll_napi(). Only the entity which * obtains the lock and sees NAPI_STATE_SCHED set will * actually make the ->poll() call. Therefore we avoid * accidently calling ->poll() when NAPI is not scheduled. */ work = 0; if (test_bit(NAPI_STATE_SCHED, &n->state)) { work = n->poll(n, weight);------------回调poll,不同的厂家有不同的实现,比如intel的ixgbe_poll实现 trace_napi_poll(n); } WARN_ON_ONCE(work > weight); budget -= work; local_irq_disable(); /* Drivers must not modify the NAPI state if they * consume the entire weight. In such cases this code * still "owns" the NAPI instance and therefore can * move the instance around on the list at-will. */ if (unlikely(work == weight)) { if (unlikely(napi_disable_pending(n))) { local_irq_enable(); napi_complete(n); local_irq_disable(); } else list_move_tail(&n->poll_list, list); } netpoll_poll_unlock(have); } out: rcpus = &__get_cpu_var(rps_remote_softirq_cpus); select = rcpus->select; rcpus->select ^= 1; local_irq_enable(); net_rps_action(&rcpus->mask[select]); #ifdef CONFIG_NET_DMA /* * There may not be any more sk_buffs coming right now, so push * any pending DMA copies to hardware */ dma_issue_pending_all(); #endif return; softnet_break: __get_cpu_var(netdev_rx_stat).time_squeeze++; __raise_softirq_irqoff(NET_RX_SOFTIRQ); goto out; }

 从代码可以看出,限制一次调用net_rx_action的地方,无非是时间,还有netdev_budget,如果把netdev_budget 调大,是不是就可以一次性多收一点包呢,意味着触发软中断的次数就会减少,答案是肯定的。

那么默认值来看,netdev_budget 比napi配置的weight要大。

 

/* initialize NAPI */

netif_napi_add(adapter->netdev, &q_vector->napi,ixgbe_poll, 64);-------传入64

void netif_napi_add(struct net_device *dev, struct napi_struct *napi,            int (*poll)(struct napi_struct *, int), int weight){    INIT_LIST_HEAD(&napi->poll_list);    napi->gro_count = 0;    napi->gro_list = NULL;    napi->skb = NULL;    napi->poll = poll;    if (weight > NAPI_POLL_WEIGHT)        pr_err_once("netif_napi_add() called with weight %d on device %s\n",--------会打印,但是也不会限制                weight, dev->name);    napi->weight = weight;    list_add(&napi->dev_list, &dev->napi_list);    napi->dev = dev;#ifdef CONFIG_NETPOLL    spin_lock_init(&napi->poll_lock);    napi->poll_owner = -1;#endif    set_bit(NAPI_STATE_SCHED, &napi->state);

我们通过将传入的64改大到256,因为在ixgbe_poll 函数中,这个值控制了一次循环收包的个数。

int ixgbe_poll(struct napi_struct *napi, int budget){    struct ixgbe_q_vector *q_vector =                container_of(napi, struct ixgbe_q_vector, napi);    struct ixgbe_adapter *adapter = q_vector->adapter;    struct ixgbe_ring *ring;    int per_ring_budget;    bool clean_complete = true;#ifdef CONFIG_IXGBE_DCA    if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)        ixgbe_update_dca(q_vector);#endif    ixgbe_for_each_ring(ring, q_vector->tx)----------------------遍历tx队列,跟本文讨论的内容不相关,本文讨论收包        clean_complete &= !!ixgbe_clean_tx_irq(q_vector, ring);    if (!ixgbe_qv_lock_napi(q_vector))        return budget;    /* attempt to distribute budget to each queue fairly, but don't allow     * the budget to go below 1 because we'll exit polling */    if (q_vector->rx.count > 1)        per_ring_budget = max(budget/q_vector->rx.count, 1);---通过增大 budget,从64改大到256,增加了一次循环收包的个数    else        per_ring_budget = budget;    ixgbe_for_each_ring(ring, q_vector->rx)-----------遍历收包队列,        clean_complete &= (ixgbe_clean_rx_irq(q_vector, ring,                   per_ring_budget) < per_ring_budget);    ixgbe_qv_unlock_napi(q_vector);    /* If all work not completed, return budget and keep polling */    if (!clean_complete)        return budget;    /* all work done, exit the polling mode */    napi_complete(napi);    if (adapter->rx_itr_setting & 1)        ixgbe_set_itr(q_vector);    if (!test_bit(__IXGBE_DOWN, &adapter->state))        ixgbe_irq_enable_queues(adapter, ((u64)1 << q_vector->v_idx));    return 0;}

通过将 budget 从64改大到256,同样的入向流量,软中断从25%降低到23%,效果很明显。

那么,能否无限制改大呢,显然不行,一则是改大后,各个队列收包就很难均衡,因为每个队列收完对应的报文之后(除非收空了),才能返回,这样,就关中断时间太长了。

可能有人会问,这个改大收包个数,但是处理软中断的总时间应该没变化,为什么会降低呢,取个极限的例子,napi出来就是应对以前单个包就需要一个中断的问题的,所以单次收包

多一些应该是有用的。

除此之外,通过设置网卡的rx-usecs属性,将这个值改大些,也可以降低软中断的占比。

ethtool -c eth0Coalesce parameters for eth0:Adaptive RX: off  TX: offstats-block-usecs: 0sample-interval: 0pkt-rate-low: 0pkt-rate-high: 0rx-usecs: 1-------------默认是1,改成512 ethtool –C eth0 rx-usecs 512

 这个减少了硬中断的触发次数,但是呢,显而易见的是,增加了延迟,如果你的系统是要求实时性极高的,可能要减少该值。

第三个方法就是开启gro了,gro开启之后,收包的时候,如果是同一个流的包,且网卡支持gro属性的话,根据协议的回调会尝试进行合并报文,当前由于目前这个流的宏值

只有最多8个流,超过的会直接送上协议栈,不会合并。当然如果是服务器,发包为主的话,其实gro是有害无益的,因为目前的flow个数限制太多,而且对于tcp来说,ack的报文也不会合并。

所以如果是服务器端,要定制化自己的gro,比如使用hash链来管理flow,使用ack合并来减少软中断消耗。

转载于:https://www.cnblogs.com/10087622blog/p/8385910.html

你可能感兴趣的文章
Winsock—I/O模型之选择模型(一)
查看>>
socket select模型
查看>>
WPF中的容器控件——GridSplit
查看>>
日志收集系统
查看>>
linux 防火墙 命令
查看>>
Java 条件语句
查看>>
python 基本数据类型之字符串功能
查看>>
js工厂模式
查看>>
STM32 内存管理实验
查看>>
7.html超链接的使用
查看>>
数组的使用及问题
查看>>
jquery eval解析JSON中的注意点介绍
查看>>
Linux常用命令及Shell的简单介绍
查看>>
速腾雷达客户端软件使用说明
查看>>
tf.variable和tf.get_Variable以及tf.name_scope和tf.variable_scope的区别
查看>>
Git Manual / Git使用手册 / Git, GitLab, Git Bash, TortoiseGit (建议全文复制到Word文档中通过导航窗格查看)...
查看>>
将mnist数据集存储到本地文件
查看>>
买房签定金合同或转让合同之前需要了解到的一些问题
查看>>
C#数据导出Excel详细介绍
查看>>
f5基本介绍
查看>>