免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 思一克

关于LINUX上中断在各个CPU之间的负载平衡问题 [复制链接]

论坛徽章:
0
发表于 2007-07-12 20:20 |显示全部楼层
seeker 兄真强~!

论坛徽章:
0
发表于 2007-07-12 21:14 |显示全部楼层
都很强。偶只有看的份。

论坛徽章:
0
发表于 2007-07-13 14:28 |显示全部楼层
以下是arch/i386/kernel/io_apic.c的补丁。在1个NIC,2个CPU和 2个NIC, 2个CPU上都平衡的很好。多个CPU也应该可以很好地平衡。但是我没有测试。



  1. --- io_apic.c        2007-07-13 13:24:57.000000000 +0800
  2. +++ io_apic.c      2007-07-13 14:24:15.000000000 +0800
  3. @@ -46,6 +46,23 @@

  4. #include "io_ports.h"

  5. +
  6. +#define SEEKER_BALANCE_NETWORK_IRQ
  7. +/* network irq balancer testing version, by seeker. 2007.07.13
  8. + * tested on 1 NIC with 2 cpus, 2 NICs with 2 cpus. it should be working on more NICs and more CPUs
  9. + *
  10. + * tested on
  11. + * Linux yelinux 2.6.13-15-johnye #16 SMP Thu Jul 12 13:05:37 CST 2007 i686 athlon i386 GNU/Linux
  12. + *
  13. + * you are welcome to do more testing on a linux box with 3 or more cpus,
  14. + *
  15. + * you should apply this patch to testing server instead of to production server.
  16. + *
  17. + * user mode irqbalance is not needed. please don't run it on kernel with this patch.
  18. + *
  19. + */
  20. +
  21. +
  22. int (*ioapic_renumber_irq)(int ioapic, int irq);
  23. atomic_t irq_mis_count;

  24. @@ -294,6 +311,16 @@

  25. static long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL;

  26. +#ifdef SEEKER_BALANCE_NETWORK_IRQ
  27. +struct {
  28. +       char irq;
  29. +       unsigned char count;
  30. +} cpuinfo[NR_CPUS];
  31. +
  32. +unsigned char wait[NR_IRQS];
  33. +unsigned char isnet[NR_IRQS];
  34. +#endif
  35. +
  36. static unsigned long move(int curr_cpu, cpumask_t allowed_mask,
  37.                         unsigned long now, int direction)
  38. {
  39. @@ -336,6 +363,20 @@
  40.                 irq_desc_t *desc = irq_desc + irq;
  41.                 unsigned long flags;

  42. +#ifdef SEEKER_BALANCE_NETWORK_IRQ
  43. +               if(isnet[irq]) {
  44. +                   if(cpuinfo[new_cpu].count > 0) {
  45. +                       //printk("-------- .\n");
  46. +                       return;
  47. +                   }
  48. +                   //printk("ye1: old %d new %d:  LAST_CPU_IRQ(new_cpu, irq) %d\n", cpu, new_cpu, LAST_CPU_IRQ(new_cpu, irq));
  49. +                   cpuinfo[cpu].irq = 0;  //old cpu
  50. +                   cpuinfo[cpu].count = 0;
  51. +                   cpuinfo[new_cpu].irq = irq;
  52. +                   cpuinfo[new_cpu].count++;
  53. +               }
  54. +               //printk("PEND: irq %d mask %p\n", irq, cpumask_of_cpu(new_cpu));
  55. +#endif
  56.                 spin_lock_irqsave(&desc->lock, flags);
  57.                 pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu);
  58.                 spin_unlock_irqrestore(&desc->lock, flags);
  59. @@ -354,6 +395,14 @@
  60.                         if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) <
  61.                                                 useful_load_threshold)
  62.                                 continue;
  63. +
  64. +#ifdef SEEKER_BALANCE_NETWORK_IRQ
  65. +                       if(isnet[j]) {
  66. +                               printk("not for net irq %d...\n", j);
  67. +                               continue;
  68. +                       }
  69. +#endif
  70. +
  71.                         balance_irq(i, j);
  72.                 }
  73.         }
  74. @@ -362,6 +411,42 @@
  75.         return;
  76. }

  77. +
  78. +#ifdef SEEKER_BALANCE_NETWORK_IRQ
  79. +void net_balance(int irq)
  80. +{
  81. +int cpu, ncpus;
  82. +unsigned long max;
  83. +int max_cpu;
  84. +
  85. +       //if(++wait[irq] < 32) return;
  86. +       wait[irq] = 0;
  87. +
  88. +       if(!isnet[irq]) return;
  89. +
  90. +       max = ncpus = 0;
  91. +       max_cpu = -1;
  92. +       for(cpu = 0; cpu < NR_CPUS; cpu++) {
  93. +               if(!cpu_online(cpu)) continue;
  94. +               ncpus++;
  95. +               //printk("YE cpu %d irq %d  ", cpu, LAST_CPU_IRQ(cpu, irq));
  96. +               //printk("IRQ_DELTA(irq %d cpu %d) %d\n", irq, cpu, IRQ_DELTA(cpu, irq));
  97. +               //
  98. +               if(max < LAST_CPU_IRQ(cpu, irq)) {
  99. +                       max = LAST_CPU_IRQ(cpu, irq);
  100. +                       max_cpu = cpu;
  101. +               }
  102. +       }
  103. +       if(ncpus < 2) return;
  104. +
  105. +        //printk("YE irq %d max_cpu %d. irq %d count %d\n", irq, max_cpu, cpuinfo[max_cpu].irq, cpuinfo[max_cpu].count);
  106. +       if(max_cpu >= 0) {
  107. +               balance_irq(max_cpu, irq);
  108. +       }
  109. +}
  110. +#endif
  111. +
  112. +
  113. static void do_irq_balance(void)
  114. {
  115.         int i, j;
  116. @@ -376,6 +461,13 @@
  117.         unsigned long imbalance = 0;
  118.         cpumask_t allowed_mask, target_cpu_mask, tmp;

  119. +
  120. +#ifdef SEEKER_BALANCE_NETWORK_IRQ
  121. +       if(irqbalance_disabled)
  122. +              printk("SEEKER: irqblance_disabled %d  physical_balance %d, %d\n", irqbalance_disabled, physical_balance, NO_BALANCE_IRQ);
  123. +       //irqbalance_disabled = 0;  //JOHNYE
  124. +#endif
  125. +
  126.         for (i = 0; i < NR_CPUS; i++) {
  127.                 int package_index;
  128.                 CPU_IRQ(i) = 0;
  129. @@ -387,6 +479,14 @@
  130.                         /* Is this an active IRQ? */
  131.                         if (!irq_desc[j].action)
  132.                                 continue;
  133. +
  134. +#ifdef SEEKER_BALANCE_NETWORK_IRQ
  135. +                       if(!strncmp(irq_desc[j].action->name, "eth", 3)) {  //network
  136. +                               isnet[j] = 1;
  137. +                               net_balance(j);
  138. +                       }
  139. +#endif
  140. +
  141.                         if ( package_index == i )
  142.                                 IRQ_DELTA(package_index,j) = 0;
  143.                         /* Determine the total count per processor per IRQ */
复制代码

论坛徽章:
0
发表于 2007-07-13 14:43 |显示全部楼层
还是有问题和要改进的地方。

2 NIC 2 CPU,因为我是想让任何时刻都不在同一个CPU上有2个NIC中断,而2个NIC的中断频率是不同的,所以一段时间后,会失去完全平衡。

这个不是程序的系统问题,而是算法问题。

如果允许在一些时候多个NIC中断可以在同一个CPU,那么就是完全平衡的。

你们看如何是好。


yelinux:/home/linux/debug/_SOFTIRQ # cat /proc/interrupts
           CPU0       CPU1
  0:    4383309     691086          XT-PIC  timer
  8:          1          1    IO-APIC-edge  rtc
  9:          0          0   IO-APIC-level  acpi
16:     264724      96705   IO-APIC-level  libata
17:          0          0   IO-APIC-level  libata
18:          0          0   IO-APIC-level  ohci_hcd:usb1
19:          0          0   IO-APIC-level  ehci_hcd:usb2
20:      19142      20688   IO-APIC-level  eth2
21:     521682     561369   IO-APIC-level  eth0
NMI:          0          0
LOC:    5073684    5073391
ERR:          0
MIS:          0

论坛徽章:
0
发表于 2007-07-15 14:37 |显示全部楼层

回复 #30 思一克 的帖子

我觉得不能盲目地平衡各个CPU的中断,因为这还涉及到很多hot cache的问题,比如conntrack entry的cache,盲目地把中断分布到不同的CPU上,不见得有很好的效率。
对于tcp报文来说,还有一个报文顺序的问题,容易造成乱序。

论坛徽章:
0
发表于 2007-07-15 16:56 |显示全部楼层
TO wheelz,

我觉得:
1)首先,完全可以平均分配到各CPU. 可以保证各CPU上的NIC中断总数平衡.
2)平衡动作不应该太频繁. 比如很长时间做一次, 或有很大的不平衡后再去平衡一次.
3)如果活动NIC数目<= CPU数目,确保任何时刻没有2个中断在同一个CPU上.

通过以上的,
1)可以使CPU负载平衡. 比如做NAT的机器, 主要负载都在中断中.中断平衡了,负载就平衡了
2)hot cache的问题可以忽略不记,因为平衡动作不是很频繁.

负载平衡到多CPU上不一定能直接提高速度(和一个CPU负责一个NIC比),因为我上面的贴分析过了, 同一个时刻还是一个CPU在处理一个中断. 也就是说,网络的代码(比如IPTABLES的一个匹配流程)本质上是有顺序的, 无法直接并行执行.

但考虑到和用户程序的竞争,有可能间接获得效率.

但平衡了之后效率也不应该有损失.

具体的还需要实验给出结论.

我还在改进代码. 但实验条件不是很具备.





原帖由 wheelz 于 2007-7-15 14:37 发表
我觉得不能盲目地平衡各个CPU的中断,因为这还涉及到很多hot cache的问题,比如conntrack entry的cache,盲目地把中断分布到不同的CPU上,不见得有很好的效率。
对于tcp报文来说,还有一个报文顺序的问题,容易 ...

论坛徽章:
0
发表于 2007-07-16 09:30 |显示全部楼层
周末看代码, 发现linux内核并没有在每次任务切换时更新local APIC的TPR寄存器, 而ia32手册上恰恰是这样期望的,并且说否则就可能导致中断都送往同一个CPU

会不会是这个问题?  我觉得这个问题是「中断相关的」而不是「网络相关的」

http://www.cs.helsinki.fi/linux/linux-kernel/2002-10/1392.html

[ 本帖最后由 albcamus 于 2007-7-16 11:44 编辑 ]

论坛徽章:
0
发表于 2007-07-16 16:14 |显示全部楼层
你说的APIC的问题我不清楚。

CUP负载不平衡是中断的问题,不是网络或相关程序(比如IPTABLES)的问题。
中断平衡了,CPU负载就平衡了。

原帖由 albcamus 于 2007-7-16 09:30 发表
周末看代码, 发现linux内核并没有在每次任务切换时更新local APIC的TPR寄存器, 而ia32手册上恰恰是这样期望的,并且说否则就可能导致中断都送往同一个CPU

会不会是这个问题?  我觉得这个问题是「中断相关 ...

论坛徽章:
0
发表于 2007-07-16 16:46 |显示全部楼层
原帖由 思一克 于 2007-7-16 16:14 发表
你说的APIC的问题我不清楚。

CUP负载不平衡是中断的问题,不是网络或相关程序(比如IPTABLES)的问题。
中断平衡了,CPU负载就平衡了。



好晕啊, 刚刚看了2.6.20的代码, local APIC的任务优先级寄存器TPR、仲裁优先级寄存器APR,和处理器优先级寄存器PPR, 这3个寄存器Linux一个都没使用!  都搞不懂Linux现在是怎么进行IRQ routing的?  莫非跟generic IRQ补丁有关?

我再看看2.6.18的代码是怎样的吧──跟generic IRQ补丁没关系,即使是在2.6.12上,Linux还是没使用这几个寄存器。

[ 本帖最后由 albcamus 于 2007-7-16 17:17 编辑 ]

论坛徽章:
0
发表于 2007-07-17 12:02 |显示全部楼层
我的是2。6。13

仅仅eth0, eth2 做了自己的平衡,其他的中断没有动。你看,原来也是分配的,而不是一律到CPU0


cat /proc/interrupts
           CPU0       CPU1
  0:   33584050     149794          XT-PIC  timer
  8:          1          1    IO-APIC-edge  rtc
  9:          0          0   IO-APIC-level  acpi
16:     279433     873456   IO-APIC-level  libata
17:          0          0   IO-APIC-level  libata
18:          0          0   IO-APIC-level  ehci_hcd:usb1
19:          0          0   IO-APIC-level  ohci_hcd:usb2
20:    1097617    1156171   IO-APIC-level  eth0
21:      42546      12937   IO-APIC-level  eth2
NMI:          0          0
LOC:   33731906   33732698
ERR:          0
MIS:          0
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP