免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5993 | 回复: 11
打印 上一主题 下一主题

method to improve network throughput with multi-core processor [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-07-31 20:35 |只看该作者 |倒序浏览
请大家贴测试结果

  1. diff -upr linux-2.6.20.7/drivers/net/e1000/e1000_main.c linux-2.6.20.7-devQ/drivers/net/e1000/e1000_main.c
  2. --- linux-2.6.20.7/drivers/net/e1000/e1000_main.c        2007-05-28 10:50:46.000000000 +0800
  3. +++ linux-2.6.20.7-devQ/drivers/net/e1000/e1000_main.c        2007-05-28 11:29:11.000000000 +0800
  4. @@ -944,7 +944,7 @@ e1000_probe(struct pci_dev *pdev,
  5.         netdev->watchdog_timeo = 5 * HZ;
  6. #ifdef CONFIG_E1000_NAPI
  7.         netdev->poll = &e1000_clean;
  8. -        netdev->weight = 64;
  9. +        netdev->weight = 16;
  10. #endif
  11.         netdev->vlan_rx_register = e1000_vlan_rx_register;
  12.         netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
  13. @@ -1333,7 +1333,7 @@ e1000_sw_init(struct e1000_adapter *adap
  14.         for (i = 0; i < adapter->num_rx_queues; i++) {
  15.                 adapter->polling_netdev[i].priv = adapter;
  16.                 adapter->polling_netdev[i].poll = &e1000_clean;
  17. -                adapter->polling_netdev[i].weight = 64;
  18. +                adapter->polling_netdev[i].weight = 16;
  19.                 dev_hold(&adapter->polling_netdev[i]);
  20.                 set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state);
  21.         }
  22. @@ -3435,11 +3435,21 @@ e1000_xmit_frame(struct sk_buff *skb, st
  23.                                     max_per_txd, nr_frags, mss));

  24.         netdev->trans_start = jiffies;
  25. -
  26. -        /* Make sure there is space in the ring for the next send. */
  27. -        e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
  28. -
  29.         spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
  30. +        /* Make sure there is space in the ring for the next send. */
  31. +        //e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
  32. +        if (8 +2 > E1000_DESC_UNUSED(tx_ring)) {
  33. +                int tx_cleaned = 0;
  34. +                if (spin_trylock(&adapter->tx_queue_lock)) {
  35. +                        if (8 +2 > E1000_DESC_UNUSED(tx_ring))
  36. +                        tx_cleaned = e1000_clean_tx_irq(adapter, tx_ring);
  37. +                        else
  38. +                        tx_cleaned = 1;
  39. +                        spin_unlock(&adapter->tx_queue_lock);
  40. +                }
  41. +                if (!tx_cleaned)
  42. +                e1000_maybe_stop_tx(netdev, tx_ring, 8 +2);
  43. +        }
  44.         return NETDEV_TX_OK;
  45. }

  46. @@ -3977,8 +3987,11 @@ e1000_clean(struct net_device *poll_dev,
  47.          * simultaneously.  A failure obtaining the lock means
  48.          * tx_ring[0] is currently being cleaned anyway. */
  49.         if (spin_trylock(&adapter->tx_queue_lock)) {
  50. +                if (8 +2 > E1000_DESC_UNUSED(&adapter->tx_ring[0]))
  51.                 tx_cleaned = e1000_clean_tx_irq(adapter,
  52.                                                 &adapter->tx_ring[0]);
  53. +                else
  54. +                tx_cleaned = 1;
  55.                 spin_unlock(&adapter->tx_queue_lock);
  56.         }

  57. @@ -4056,7 +4069,7 @@ e1000_clean_tx_irq(struct e1000_adapter

  58.         tx_ring->next_to_clean = i;

  59. -#define TX_WAKE_THRESHOLD 32
  60. +#define TX_WAKE_THRESHOLD 4 //32
  61.         if (unlikely(cleaned && netif_carrier_ok(netdev) &&
  62.                      E1000_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) {
  63.                 /* Make sure that anybody stopping the queue after this
  64. diff -upr linux-2.6.20.7/include/linux/netdevice.h linux-2.6.20.7-devQ/include/linux/netdevice.h
  65. --- linux-2.6.20.7/include/linux/netdevice.h        2007-05-28 10:43:47.000000000 +0800
  66. +++ linux-2.6.20.7-devQ/include/linux/netdevice.h        2007-06-27 11:55:19.000000000 +0800
  67. @@ -619,7 +619,7 @@ struct softnet_data
  68.         struct sk_buff_head        input_pkt_queue;
  69.         struct list_head        poll_list;
  70.         struct sk_buff                *completion_queue;
  71. -
  72. +        atomic_t                poll_nr;
  73.         struct net_device        backlog_dev;        /* Sorry. 8) */
  74. #ifdef CONFIG_NET_DMA
  75.         struct dma_chan                *net_dma;
  76. @@ -872,7 +872,11 @@ static inline int netif_rx_reschedule(st
  77.                 dev->quota += undo;

  78.                 local_irq_save(flags);
  79. -                list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
  80. +                list_add_tail(&dev->poll_list,
  81. +                        &__get_cpu_var(softnet_data).poll_list);
  82. +                atomic_inc(&__get_cpu_var(softnet_data).poll_nr);
  83. +                /* accord to smp */
  84. +                smp_mb__after_atomic_inc();
  85.                 __raise_softirq_irqoff(NET_RX_SOFTIRQ);
  86.                 local_irq_restore(flags);
  87.                 return 1;
  88. @@ -894,6 +898,8 @@ static inline void netif_rx_complete(str
  89.         list_del(&dev->poll_list);
  90.         smp_mb__before_clear_bit();
  91.         clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
  92. +        /* smp_mb__before_atomic_dec(); */
  93. +        atomic_dec(&per_cpu(softnet_data, smp_processor_id()).poll_nr);
  94.         local_irq_restore(flags);
  95. }

  96. @@ -919,6 +925,8 @@ static inline void __netif_rx_complete(s
  97.         list_del(&dev->poll_list);
  98.         smp_mb__before_clear_bit();
  99.         clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
  100. +        /* smp_mb__before_atomic_dec(); */
  101. +        atomic_dec(&per_cpu(softnet_data, smp_processor_id()).poll_nr);
  102. }

  103. static inline void netif_tx_lock(struct net_device *dev)
  104. diff -upr linux-2.6.20.7/include/linux/skbuff.h linux-2.6.20.7-devQ/include/linux/skbuff.h
  105. --- linux-2.6.20.7/include/linux/skbuff.h        2007-05-28 10:42:57.000000000 +0800
  106. +++ linux-2.6.20.7-devQ/include/linux/skbuff.h        2007-06-27 11:21:59.000000000 +0800
  107. @@ -114,6 +114,14 @@ struct sk_buff_head {
  108.         spinlock_t        lock;
  109. };

  110. +struct sk_buff_queue {
  111. +        struct sk_buff *next;
  112. +        struct sk_buff *prev;
  113. +        __u32                qlen;
  114. +        unsigned long        last;
  115. +};
  116. +extern __u32        __sk_buff_thresh;
  117. +extern int        __sk_buff_nics[8];
  118. struct sk_buff;

  119. /* To allow 64K frame to be packed as single skb without frag_list */
  120. diff -upr linux-2.6.20.7/net/core/dev.c linux-2.6.20.7-devQ/net/core/dev.c
  121. --- linux-2.6.20.7/net/core/dev.c        2007-05-28 10:45:11.000000000 +0800
  122. +++ linux-2.6.20.7-devQ/net/core/dev.c        2007-06-27 11:59:03.000000000 +0800
  123. @@ -1123,6 +1123,8 @@ void __netif_rx_schedule(struct net_devi
  124.         local_irq_save(flags);
  125.         dev_hold(dev);
  126.         list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
  127. +        atomic_inc(&__get_cpu_var(softnet_data).poll_nr);
  128. +        smp_mb__after_atomic_inc();
  129.         if (dev->quota < 0)
  130.                 dev->quota += dev->weight;
  131.         else
  132. @@ -3506,6 +3508,7 @@ static int __init net_dev_init(void)
  133.                 skb_queue_head_init(&queue->input_pkt_queue);
  134.                 queue->completion_queue = NULL;
  135.                 INIT_LIST_HEAD(&queue->poll_list);
  136. +                atomic_set(&queue->poll_nr, 0);
  137.                 set_bit(__LINK_STATE_START, &queue->backlog_dev.state);
  138.                 queue->backlog_dev.weight = weight_p;
  139.                 queue->backlog_dev.poll = process_backlog;
  140. diff -upr linux-2.6.20.7/net/core/skbuff.c linux-2.6.20.7-devQ/net/core/skbuff.c
  141. --- linux-2.6.20.7/net/core/skbuff.c        2007-05-28 10:44:47.000000000 +0800
  142. +++ linux-2.6.20.7-devQ/net/core/skbuff.c        2007-06-27 11:24:19.000000000 +0800
  143. @@ -70,7 +70,8 @@

  144. static struct kmem_cache *skbuff_head_cache __read_mostly;
  145. static struct kmem_cache *skbuff_fclone_cache __read_mostly;
  146. -
  147. +__u32 __sk_buff_thresh = 31;
  148. +int __sk_buff_nics[8] = { 0, 0, 0, 0, /**/ 0, 0, 0, 0 };
  149. /*
  150.   *        Keep out-of-line to prevent kernel bloat.
  151.   *        __builtin_return_address is not used because it is not always
  152. diff -upr linux-2.6.20.7/net/ipv4/ip_input.c linux-2.6.20.7-devQ/net/ipv4/ip_input.c
  153. --- linux-2.6.20.7/net/ipv4/ip_input.c        2007-05-28 10:45:48.000000000 +0800
  154. +++ linux-2.6.20.7-devQ/net/ipv4/ip_input.c        2007-06-27 14:09:24.000000000 +0800
  155. @@ -328,7 +328,7 @@ drop:
  156.         return -1;
  157. }

  158. -static inline int ip_rcv_finish(struct sk_buff *skb)
  159. +static inline int ip_rcv_finish2(struct sk_buff *skb)
  160. {
  161.         struct iphdr *iph = skb->nh.iph;

  162. @@ -367,6 +367,100 @@ drop:
  163.          return NET_RX_DROP;
  164. }

  165. +static void __tfn(unsigned long data)
  166. +{
  167. +        unsigned long now = jiffies, cnt = 0;
  168. +        struct sk_buff * head = (void *) data;
  169. +        while (head) {
  170. +                struct sk_buff * skb = head;
  171. +                ++cnt;
  172. +                head = head->next;
  173. +                skb->prev =
  174. +                skb->next = NULL;
  175. +                ip_rcv_finish2(skb);
  176. +        }
  177. +        if (net_ratelimit())
  178. +                printk(KERN_INFO "skbQ tfn by %d jiff<%lu %lu> cnt %lu\n",
  179. +                        smp_processor_id(), now, jiffies, cnt);
  180. +}
  181. +#define HERE_ARE 32
  182. +static struct timer_list buff_ts[HERE_ARE] cacheline_aligned_in_smp;
  183. +static struct sk_buff_queue buff_qs[HERE_ARE] cacheline_aligned_in_smp;
  184. +
  185. +static inline int __skb__nic_hit(const struct sk_buff *skb)
  186. +{
  187. +        int j, k;
  188. +        if (!skb || !skb->iif)
  189. +                return 0;
  190. +        k = sizeof(__sk_buff_nics) >> 2;
  191. +        for (j = 0; j < k; j++) {
  192. +                if (__sk_buff_nics[j] > 0 &&
  193. +                    __sk_buff_nics[j] == skb->iif)
  194. +                        return skb->iif;
  195. +        }
  196. +        return 0;
  197. +}
  198. +
  199. +static inline int ip_rcv_finish(struct sk_buff * skb)
  200. +{
  201. +#ifdef CONFIG_SMP
  202. +        unsigned long flags, now = jiffies;
  203. +        int cpu = smp_processor_id();
  204. +        int j = cpu;
  205. +        struct timer_list *t = &buff_ts[cpu];
  206. +        struct sk_buff_queue *q = &buff_qs[cpu];
  207. +        if (!__skb__nic_hit(skb))
  208. +                return ip_rcv_finish2(skb);
  209. +        if (!q->next) {
  210. +                q->next =
  211. +                q->prev = (struct sk_buff *)q;
  212. +                q->qlen = 0;
  213. +                q->last = now;
  214. +                init_timer(t);
  215. +        }
  216. +        local_irq_save(flags);
  217. +        __skb_queue_tail((struct sk_buff_head *)q, skb);
  218. +        local_irq_restore(flags);
  219. +        if (q->qlen > __sk_buff_thresh
  220. +            || now > 4 + q->last) {
  221. +                int best =256, ok = HERE_ARE -1;
  222. +               
  223. +                if (timer_pending(t))
  224. +                        return 0;
  225. +                for_each_online_cpu(cpu) {
  226. +                        int pnr =
  227. +                        atomic_read(&per_cpu(softnet_data, cpu).poll_nr);
  228. +                        if (!pnr) {
  229. +                                ok = cpu;
  230. +                                break;
  231. +                        } else if (best > pnr) {
  232. +                                ok = cpu;
  233. +                                best = pnr;
  234. +                        }
  235. +                }
  236. +                local_irq_save(flags);
  237. +                t->data = (unsigned long) q->next;
  238. +                q->prev->next = NULL;
  239. +                q->next =
  240. +                q->prev = (struct sk_buff *)q;
  241. +                q->qlen = 0;
  242. +                q->last = now;
  243. +                local_irq_restore(flags);
  244. +               
  245. +                t->function = __tfn;
  246. +                t->expires = now = jiffies;
  247. +                add_timer_on(t, ok);
  248. +                if (net_ratelimit())
  249. +                        printk(KERN_INFO "skbQ sched<%d %d> jiff %lu\n",
  250. +                                j, ok, now);
  251. +        }
  252. +        return 0;
  253. +#else        /* CONGIF_SMP */
  254. +        return ip_rcv_finish2(skb);
  255. +#endif
  256. +}
  257. +#undef HERE_ARE
  258. +
  259. /*
  260.   *         Main IP Receive routine.
  261.   */
  262. diff -upr linux-2.6.20.7/net/ipv4/sysctl_net_ipv4.c linux-2.6.20.7-devQ/net/ipv4/sysctl_net_ipv4.c
  263. --- linux-2.6.20.7/net/ipv4/sysctl_net_ipv4.c        2007-05-28 10:46:27.000000000 +0800
  264. +++ linux-2.6.20.7-devQ/net/ipv4/sysctl_net_ipv4.c        2007-06-27 11:31:15.000000000 +0800
  265. @@ -186,6 +186,9 @@ static int strategy_allowed_congestion_c

  266. }

  267. +extern __u32        __sk_buff_thresh;
  268. +extern int        __sk_buff_nics[8];
  269. +
  270. ctl_table ipv4_table[] = {
  271.          {
  272.                 .ctl_name        = NET_IPV4_TCP_TIMESTAMPS,
  273. @@ -211,7 +214,23 @@ ctl_table ipv4_table[] = {
  274.                 .mode                = 0644,
  275.                 .proc_handler        = &proc_dointvec
  276.         },
  277. -        {
  278. +        {
  279. +                .ctl_name        = 11,
  280. +                .procname        = "skbuff_thresh",
  281. +                .data                = &__sk_buff_thresh,
  282. +                .maxlen                = 4,
  283. +                .mode                = 0644,
  284. +                .proc_handler        = &proc_dointvec
  285. +        },
  286. +         {
  287. +                .ctl_name        = 12,
  288. +                .procname        = "skbuff_nics",
  289. +                .data                = &__sk_buff_nics,
  290. +                .maxlen                = sizeof(__sk_buff_nics),
  291. +                .mode                = 0644,
  292. +                .proc_handler        = &proc_dointvec
  293. +        },
  294. +        {
  295.                 .ctl_name        = NET_IPV4_TCP_RETRANS_COLLAPSE,
  296.                 .procname        = "tcp_retrans_collapse",
  297.                 .data                = &sysctl_tcp_retrans_collapse,

复制代码

[ 本帖最后由 sisi8408 于 2007-8-22 11:07 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-08-02 16:36 |只看该作者
能不能讲一下思路啊,或者放patch过的代码吧。这样贴上来的代码好难看啊。。。。-

论坛徽章:
0
3 [报告]
发表于 2007-08-02 19:39 |只看该作者
it is not complex to issue, hehe,
#patch -p1 < ../whatever

源自ippen报告的数据
关于多处理器在大网络负载中的调度
=====================


1 引言
  ====

处理器如何适应大网络负载,一直是防火墙应用中密切关注的话题,
这里引用chinaunix.net上的一片报告来摆事实,
正是这篇报告强烈的吸引我想在多处理器调度上认真地作点实际有用的文章。


linux nat 不支持双cpu?

我用linux做nat,服务器是intel的双至强64位的3Gcpu,内存1G,软件系统 centos3.6,

将流量加上后,用top检测CPU的状态,发现四个内核cpu只用了一个(64位至强CPU有两个内核),

即有一个内核是满负载,其他三个完全空闲,但只要将NAT取消,4个cpu就平均分配任务,
非常不解,各位老大有何办法?在网上搜索了一下,可以确认netfilter是支持多CPU的。


贴个top状态,可以看见第四个cpu是满负载,其他空闲,
cpu会轮换----过一段时间后会变为第一个cpu满负载


09:55:02  up 20:06,  1 user,  load average: 0.99, 0.95, 0.83
33 processes: 31 sleeping, 2 running, 0 zombie, 0 stopped

CPU states:  cpu    user    nice  system    irq  softirq  iowait    idle
=================================================

           total    0.0%    0.0%    0.0%   0.0%    25.3%    0.0%   74.6%

           cpu00    0.1%    0.0%    0.0%   0.0%     0.0%    0.0%   99.8%
           cpu01    0.0%    0.0%    0.0%   0.0%     0.3%    0.0%   99.6%
           cpu02    0.0%    0.0%    0.0%   0.0%     1.0%    0.0%   99.0%
           cpu03    0.0%    0.0%    0.0%   0.0%   100.0%    0.0%    0.0%

Mem:  1009404k av,  451252k used,  558152k free,       0k shrd,    1312k buff

        20976k active,               6428k inactive
Swap:       0k av,       0k used,       0k free                   23980k cached

/*
* 这是我看到的最满意的报告,关于多处理器跑吞吐。
*
* 1,由于处理器富裕,可以看到相对实际的top,在cpu00上。

*
* 2,数据是真实的,可能由NAPI导致cpu03的高负荷。
*
* 3,数据表明,NAPI在cpu03上发挥了威力,也证明,NAPI被合理调度的必要。
*/

# Generated by iptables-save v1.2.8 on Fri May 12 10:54:35 2006
*nat
PREROUTING ACCEPT [3073422:457854968]

POSTROUTING ACCEPT [2305671:391634389]
:OUTPUT ACCEPT [78:12168]
-A POSTROUTING -o eth1 -p tcp -m tcp --dport 25 -j RETURN
-A POSTROUTING -o eth1 -p udp -m udp --dport 25 -j RETURN

-A POSTROUTING -o eth1 -p tcp -m tcp --dport 110 -j RETURN

-A POSTROUTING -o eth1 -p udp -m udp --dport 110 -j RETURN

-A POSTROUTING -o eth1 -p tcp -m tcp --sport 25 -j RETURN
-A POSTROUTING -o eth1 -p udp -m udp --sport 25 -j RETURN

-A POSTROUTING -o eth1 -p tcp -m tcp --sport 110 -j RETURN

-A POSTROUTING -o eth1 -p udp -m udp --sport 110 -j RETURN

-A POSTROUTING -o eth1 -p tcp -m tcp --sport 80 -j RETURN
-A POSTROUTING -s 211.156.xxx.xxx -o eth1 -j RETURN

-A POSTROUTING -d
210.17.209.0/255.255.255.0 -o eth1 -j RETURN
-A POSTROUTING -d 202.106.168.0/255.255.255.0 -o eth1 -j RETURN
-A POSTROUTING -d
202.108.44.0/255.255.255.0 -o eth1 -j RETURN
-A POSTROUTING -d 61.135.159.0/255.255.255.0 -o eth1 -j RETURN
-A POSTROUTING -d
219.142.91.0/255.255.255.0 -o eth1 -j RETURN
-A POSTROUTING -d 203.166.128.137 -o eth1 -j RETURN

-A POSTROUTING -s 211.156.xxx.xxx/255.255.240.0 -o eth1 -j SNAT --to-source
221.xxx.xxx.xxx-221.xxx.xxx.xxx
-A POSTROUTING -s 210.xxx.xxx.xxx/255.255.192.0 -o eth1 -j SNAT --to-source 221.xxx.xxx.xxx-221.xxx.xxx.xxx
-A POSTROUTING -s  61.xxx.xxx.xxx/255.255.192.0 -o eth1 -j SNAT --to-source
221.xxx.xxx.xxx-221.xxx.xxx.xxx
-A POSTROUTING -s 125.xxx.xxx.xxx/255.255.0.0   -o eth1 -j SNAT --to-source 221.xxx.xxx.xxx-221.xxx.xxx.xxx
COMMIT
# Completed on Fri May 12 10:54:35 2006

wc -l /proc/net/ip_conntrack

121382
这个数在高峰时到190000

/*
* 1,121382远大于65535,snat占了多少?
*
* 2,由于NAPI的bh性质,snat不会在处理器之间漂移。
*
* 3,150M流量的压力不算大,处理器负荷却100%,
*    snat在65535空间内发生碰撞?
*/

网路带宽峰值大约在150M,用户数不太好统计,因为nat是为了解决到网通速度的问题,

无法确认有多少用户访问网通


方才发现更怪的问题,运行了/etc/init.d/iptables restart后,cpu的状态好了

11:12:44  up 21:23,  1 user,  load average: 0.00, 0.02, 0.14
33 processes: 32 sleeping, 1 running, 0 zombie, 0 stopped

CPU states:  cpu    user    nice  system    irq  softirq  iowait    idle
==================================================
           total    0.0%    0.0%    0.0%   0.1%    27.6%    0.0%   72.2%

           cpu00    0.0%    0.0%    0.0%   0.2%    29.2%    0.0%
   70.5%
           cpu01    0.0%    0.0%    0.0%   0.2%    26.6%    0.0%   73.1%
           cpu02    0.0%    0.0%    0.0%   0.0%    26.6%    0.0%   73.3%
           cpu03    0.0%    0.0%    0.0%   0.2%    28.0%   
0.0%   71.7%

Mem:  1009404k av,  152464k used,  856940k free,       0k shrd,    1316k buff
        21144k active,               6604k inactive
Swap:       0k av,       0k used,       0k free                   24416k cached


系统又变成只用一个cpu工作了,看样子是内核有些问题!!!

/*
* 内核没问题,内网卡又NAPI了!!!
*/

参考白金提供的资料,做 irq affinity 静态捆绑
将eth0 和cpu3、cpu2做静态捆绑,eth1 和 cpu0、cpu1做静态捆绑,
cpu负载均衡好些,但eth1绑定的CPU还是不均衡,
eth1上做了nat,可见的确是netfilter对smp的支持不好


/*
* 将NAPI绑在哪个处理器上都不解决问题!!!
*/

13:36:22  up 23:47,  1 user,  load average: 0.99, 0.97, 0.91
33 processes: 31 sleeping, 2 running, 0 zombie, 0 stopped

CPU states:  cpu    user    nice  system    irq  softirq  iowait    idle

           total    0.0%    0.0%    0.0%   0.1%    45.0%    0.0%   54.7%

           cpu00    0.2%    0.0%    0.2%   0.0%     1.2%    0.0%   98.3%
           cpu01    0.0%    0.0%    0.0%   0.0%   100.0%    0.0%
    0.0%
           cpu02    0.0%    0.0%    0.0%   0.0%    22.2%    0.0%   77.7%
           cpu03    0.0%    0.0%    0.0%   0.4%    56.4%    0.0%   43.2%

Mem:  1009404k av,  198512k used,  810892k free,       0k shrd,    1316k buff

        21136k active,               6604k inactive
Swap:       0k av,       0k used,       0k free                   24420k cached

/*
* snat消耗高达20%,没想到,~5%的说法不靠谱。
*/

先告诉大家2.4.31内核nat测试结果,测试的结果有些意外,

虽然platinum 和johnbull 提供的信息表明smp不如up,但测试结果看来,smp的负载能力较up的内核高,
这个和具体环境有关系,系统有个程序叫irqbalance,其作用是将irq中断平均分配各多个CPU,
作用和smp_affinity类似,

/*
* 多数情况下,irqbalance被NAPI误导。
*/

启动后,明显看到IRQ中断分配给两个不同的CPU,因而我的两张网卡的数据处理分别由两个CPU分配,

因而负载能力比UP高。

测试中,如果用up内核,早上10:00左右cpu就到了100%,一直到晚上1:00左右才降下来;

用smp内核,负责nat的网卡的cpu最高到 82%,负责内网网卡的cpu最高在56%,
余下的两颗CPU一直100%空闲(我的机器是双CPU双核,所以总共4个CPU)

结论:虽然smp对netfilter支持不好,但如果你有两张网卡的话,
双cpu和smp系统对系统负载能有提高,但如果是单网卡的话,smp就没有意义了,


三张以上网卡和更多的CPU是否能有更高的性能?尚未测试,个人认为有系统性能会更高。
2.6的内核仍然测试中,2.6up内核编译有错,nat无法加载,要下周才有结果了


2.6kernel的测试结果
kernel 2.6 的测试结果比2.4要好,正如白金说的,2.6的内核比2.4内核效率高,
而且在测试结果看来,2.6内核在nerfilter上的效率比2.4要高约20%,在承载相同流量的情况下,

up核心cpu利用率最高82%,明显比2.4要好多了。

可是2.6的内核出现一个错误,其间cpu会全速处理一些任务,会导致瞬间的流量中断,错误信息是
warning: many lost ticks.
Your time source seems to be instable or some driver is hogging interupts
rip run_timer_softirq+0x164/0x1bb


/*
* 这是rtable和netfilter的本质区别,
* 有真实数据的佐证,PRR也无话可说。
*/

我在多个2.6内核版本中都发现过这个问题,2.4的版本就没有发现这个问题,在网上搜索了一下,
似乎和acpi有关,但将acpi进程关闭也无效,大家能否提供些有用的信息?


2  问题说明和解决
   ==========

在4/8-core处理器规模上市的前夕,cpu和nic的调度已经引起广泛的重视,

如Ingo Molnar的o(1)scheduler,这是高档货,还需要时间去消化。

具体到跑吞吐,典型的情况是route+netfilter,主要因素包括:
1,NAPI,2,rtable,3,conntrack+nat

NAPI是通用的优秀的解决方案,这里的报告反映了一个特例,
即cpu相对nic富裕,这样的条件显然要求NAPI能够在cpu之间漂移,
但与NAPI的设计格格不入。


2.6.14之后的内核已经将中断线程化,schedule可以发生在更大的范围,
softirq就是典型代表。

我还将保持NAPI的主导地位,根据实际需求在pre_routing之后或
post_routing之前作调度:
被NAPI绑架的cpu-A查找负荷最轻的cpu-B,通过bh调度将数据包交给cpu-B,
cpu-A回头去做irq应答。

这里将对NAPI的核心数据结构作微小的修改,但严格保持调度对多处理器的流畅,

期望显著提高cpu相对nic富裕的吞吐。

[ 本帖最后由 sisi8408 于 2007-8-20 23:27 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2007-08-02 20:20 |只看该作者
对于NAT SERVER和GATEWAY的机器

让一个CPU专门负责一个网卡就可以了. 如果2个NIC, 4个CPU, 有2个CPU对提高速度没有什么帮助.

让CPU负载均衡是不难做到了. 我自己PATCH了一下也可以平衡的很好. 但平衡对增加速度没有太大帮助.

论坛徽章:
0
5 [报告]
发表于 2007-08-03 17:22 |只看该作者
LZ能讲一下PATCH加速的原理?

论坛徽章:
0
6 [报告]
发表于 2007-08-03 20:13 |只看该作者
我还将保持NAPI的主导地位,

这是Alexey Kuznetsov的杰作,Paul R. Russell也必须保持,
当然,netfilter有自己的魅力。

根据实际需求在pre_routing之后或post_routing之前作调度:
被NAPI绑架的 cpu-A 查找负荷最轻的 cpu-B,
通过bh调度将数据包交给 cpu-B,
cpu-A 回头去做irq应答。

也就是各司其职,事成于专,尽可能保持CPU cache发烫,
实际结果是两个CPU在bh中同时参与包的处理。
如果网卡个数增加,效果更明显。

提升速度,在硬件既定时,已经是纯粹在考验软件,
Alexey Kuznetsov 的代码目前是最好的,
rtable+tc+netfilter可与任何unices单挑,
而且,速度的提升,又证明slab cache majorly by Alen Cox 是可靠的。

[ 本帖最后由 sisi8408 于 2007-8-3 20:30 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2007-08-03 20:39 |只看该作者
原文中的

  1. /* Sorry. 8) */
复制代码

一行,是Jamal Hadi Salim留的?

这里提供了方法论,就去分析哪些代码为什么是可靠的,
再把方法应用在实际需求中,再制造出变种,以适应不同的需求,VFS 就是典范。

[ 本帖最后由 sisi8408 于 2007-8-25 20:07 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2007-08-06 12:04 |只看该作者
thanks.

这个不是INTERRUPT负载均衡,而是直接均衡CPU处理SOFTIRQ的负荷。比均衡中断应该更好。

基本看懂了。实验结果如何?

论坛徽章:
0
9 [报告]
发表于 2007-08-09 20:17 |只看该作者

  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. #include<sys/types.h>
  4. #include<sys/sysinfo.h>
  5. #include<unistd.h>

  6. #define __USE_GNU
  7. #include<sched.h>
  8. #include<ctype.h>
  9. #include<string.h>

  10. int main(int argc, char* argv[])
  11. {
  12.         int num = sysconf(_SC_NPROCESSORS_CONF);
  13.         int created_thread = 0;
  14.         int myid;
  15.         int i;
  16.         int j = 0;

  17.         cpu_set_t mask;
  18.         cpu_set_t get;

  19.         if (argc != 2)
  20.         {
  21.                 printf("usage : ./cpu num\n");
  22.                 exit(1);
  23.         }

  24.         myid = atoi(argv[1]);

  25.         printf("system has %i processor(s). \n", num);

  26.         CPU_ZERO(&mask);
  27.         CPU_SET(myid, &mask);

  28.         if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
  29.         {
  30.                 printf("warning: could not set CPU affinity, continuing...\n");
  31.         }
  32.         while (1)
  33.         {

  34.                 CPU_ZERO(&get);
  35.                 if (sched_getaffinity(0, sizeof(get), &get) == -1)
  36.                 {
  37.                         printf("warning: cound not get cpu affinity, continuing...\n");
  38.                 }
  39.                 for (i = 0; i < num; i++)
  40.                 {
  41.                         if (CPU_ISSET(i, &get))
  42.                         {
  43.                                 printf("this process %d is running processor : %d\n",getpid(), i);
  44.                         }
  45.                 }
  46.         }
  47.         return 0;
  48. }
复制代码

相互补充,from scutan

论坛徽章:
0
10 [报告]
发表于 2007-08-17 20:05 |只看该作者
感谢帮助测试的兄弟


  1. +        while (head) {
  2. +                struct sk_buff * skb = head;
  3. +                ++cnt;
  4. +                head = head->next;
  5. +                skb->prev =
  6. +                skb->next = NULL;
  7. +                ip_rcv_finish2(skb);
  8. +        }
复制代码


1,正面结果,while循环的速度大于800Kpps,
     处理器Xeon-5130-2.0GHz。


  1. +                for_each_online_cpu(cpu) {
  2. +                        int pnr =
  3. +                        atomic_read(&per_cpu(softnet_data, cpu).poll_nr);
  4. +                        if (!pnr) {
  5. +                                ok = cpu;
  6. +                                break;
  7. +                        } else if (best > pnr) {
  8. +                                ok = cpu;
  9. +                                best = pnr;
  10. +                        }
  11. +                }
  12. +
复制代码


2,正面结果,ok cpu被调度,且可以在低load cpus之间轮换。


  1. +                if (timer_pending(t))
  2. +                        return 0;
复制代码


3,负面结果,导致slab cache崩溃。

[ 本帖最后由 sisi8408 于 2007-8-25 20:08 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP