网卡软中断绑定优化

这篇博客总结了处理网卡软中断不均衡问题的经验,包括问题的现象(软中断集中在单个CPU核心,硬件中断队列不足)以及解决办法(中断一对一绑定,启用RFS和RPS)。提供了一个自动化绑定脚本来优化CPU使用平衡。
部署运行你感兴趣的模型镜像


今天测试刚好发现一个关于网卡软中断不均衡的问题,之前处理过类似情况,一直未有总结,今天稍作总结下,并写了个自动化绑定脚本。关于什么是软中断,网卡硬件中断队列,RFS,RPS 这些概,这里不做具体解释。感兴趣可自行google

问题现象:

         1.  网卡软中断不平衡,集中在一个CPU核心上(mpstat 查看%soft集中,通常是cpu0)

         2.  网卡的硬件中断队列不够, < CPU 核心数,无法一对一绑定,导致部分CPU核心%soft 较少,CPU使用不均衡


解决办法:

         情况1: 绑定网卡中断,通常是和CPU 一对一绑定

         情况2: 开启RFS,RPS


最终效果:

mpstat -P ALL 2



cpu 线程利用率



附上tuneNetSoft.py 脚本内容,主要是用于绑定软中断和开启RPS,RFS




#!/usr/bin/env python
#python version < 3
#net irq_smp_affinity && rps,rfs setting
#version 1.0
#author: pylt


import re
from os import system,popen
from os import walk as walkdir
from optparse import OptionParser

RPS_CPUS_VALUE = 'ffffffff'
RPS_FLOW_VALUE = '4096'
RPS_RFS_DEFAULT = '0'
interrupts_file = '/proc/interrupts'
rps_cpus_list = []
rps_flow_list = []
#ENTRY_VALUE=32768

def get_device():
    return re.findall(r'([a-z]+\d+)\s+Link.*',popen('ifconfig').read())

def get_rfs_rps_file(net_device):   
    rps_path = '/sys/class/net/' + net_device + '/queues/'
    for s in walkdir(rps_path):
        if len(s[2]) == 2:
            rps_cpus_list.append('/'.join([s[0],s[2][0]]))
            rps_flow_list.append('/'.join([s[0],s[2][1]]))

def file_hander(TARGET,VALUE='0'):
    try:
          f_hander = open(TARGET,'w')
          f_hander.write(VALUE)
    finally:
          f_hander.close()

def set_rfs_rps(net_device):  
    get_rfs_rps_file(net_device)
    def set_rps_cpus_value(PATH):
        file_hander(PATH,RPS_CPUS_VALUE)

    def set_rps_flow_value(PATH):
        file_hander(PATH,RPS_FLOW_VALUE)

    map(set_rps_cpus_value,rps_cpus_list)
    map(set_rps_flow_value,rps_flow_list)
   
def unset_rfs_rps(net_device):
    get_rfs_rps_file(net_device)   
    def unset_rps_cpus_value(PATH):
        file_hander(PATH,RPS_RFS_DEFAULT)

    def unset_rps_flow_value(PATH):
        file_hander(PATH,RPS_RFS_DEFAULT)
    
    map(unset_rps_cpus_value,rps_cpus_list)
    map(unset_rps_flow_value,rps_flow_list)
   
def set_irq_balance():
    	stop_irq_balance = 'service irqbalance stop'  
    	system(stop_irq_balance)
    	interrupts_ct = open(interrupts_file)
    	cores_nr = len(interrupts_ct.readline().split()) # 获取CPU核心数
    	irq_bit = 0
    	while True:
              inter_line = interrupts_ct.readline()
              if inter_line == "":
              	 break
              js = inter_line.split()
              if len(js[-1]) > 5:
                  if re.match(r'eth.-',js[-1][:5]):
					 irq_nr = js[0][:-1]            
					 TARGET = '/proc/irq/%s/smp_affinity' %(irq_nr)
					 VALUE = str(re.sub('0x','',hex(1 << irq_bit)))  #1 << irq_bit 相对于2的N次方 ,hex() 二进制转十六进制
					 file_hander(TARGET,VALUE)
					 irq_bit += 1
					 if irq_bit == cores_nr:
						irq_bit = 0

def unset_irq_balance():
      start_irq_balance = 'service irqbalance start'
      system(start_irq_balance)
    
def usage():
    usage = '''=================================================
Description: irq_balance_set && rfs_rps_set tools
Usage:
      <script> -i  : set irq smp_affinity
               -I  : unset irq smp_affinity
               -r  : set rfs && rps
               -R  : unset rfs && rps
    '''
    print usage

if __name__ == '__main__':

   parser = OptionParser() 
   parser.add_option("-i", action="store_true", 
                  dest="irq_true", 
                  default=False) 
   parser.add_option("-I", action="store_true", 
                  dest="irq_false", 
                  default=False)
   parser.add_option("-r", action="store_true", 
                  dest="rps_true", 
                  default=False)
   parser.add_option("-R", action="store_true", 
                  dest="rps_false", 
                  default=False)
   (options, args) = parser.parse_args() 

   if options.irq_true == True: 
         set_irq_balance()
         print "irq_balance_set successfully"  
   elif options.irq_false == True:
         unset_irq_balance()
         print "unset irq balance successfully"
   elif options.rps_true == True:
         device_list = get_device()
         map(set_rfs_rps,device_list)
         print "rfs&&rps configured successfully"
   elif options.rps_false == True:
         device_list = get_device() 
         map(unset_rfs_rps,device_list)
         print "unconfigured rfs&&rps successfully"
   else:
         usage()








您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>好的,我现在需要回答用户关于Linux内中IRQ软中断的实现和处理的问题。首先,用户提到了几个引用,我需要结合这些引用来构建回答。 首先,用户引用了关于_bh()后缀的软中断,说明它仍然会禁用软中断处理程序[^1]。这可能涉及到软中断的上下文和禁用机制。接下来,用户引用了关于SMP和IO APIC的内容[^2],这可能与中断在多环境中的处理有关。第三个引用提到中断处理程序将RX缓冲区条目加入轮询列表,并触发软中断处理数据包[^3],这可能涉及网络数据包的处理流程。 我需要先解释IRQ软中断的基本概念。软中断(softirq)是Linux内中处理延迟敏感任务的一种机制,通常在硬件中断处理程序(上半部)之后执行,属于中断的下半部(bottom half)。这样可以减少硬件中断的延迟,提高系统的响应能力。 然后,实现方式部分需要涵盖软中断的初始化、注册、触发和处理流程。例如,softirq_vec数组存储处理函数,open_softirq()用于注册,raise_softirq()触发软中断,而处理可能在中断退出时或ksoftirqd线程中进行。引用中的触发软中断可能对应raise_softirq()的调用。 处理流程方面,需要提到在中断上下文中(如网络驱动处理数据包后)触发软中断,然后在适当的时机(如中断返回前或ksoftirqd线程)执行。这里需要结合引用中的例子,说明数据包处理如何通过软中断完成。 相关问题部分,用户可能对性能优化、多处理、与tasklet的区别、调试方法感兴趣。例如,如何避免软中断过载(引用[^1]提到禁用软中断的情况),多环境中的负载均衡(引用涉及SMP),以及调试工具如ftrace的使用。 需要注意引用标记的正确使用,确保每个引用在回答中自然出现,例如在处理流程部分引用,在禁用机制部分引用[^1],在多处理部分引用。同时,保持回答结构清晰,分点解释概念、实现、处理流程和相关问题。</think>### Linux内中的IRQ软中断实现与处理 #### 一、IRQ软中断的基本概念 软中断(softirq)是Linux内中用于处理延迟敏感任务的心机制,属于中断下半部(bottom half)的一种实现。硬件中断(上半部)负责快速响应设备事件,而软中断则处理耗时操作(如网络数据包处理、定时任务等),以减少中断屏蔽时间。 #### 二、软中断的实现方式 1. **数据结构** 内通过`softirq_vec`数组管理软中断处理函数,每个条目对应一种类型的软中断: ```c struct softirq_action { void (*action)(struct softirq_action *); }; static struct softirq_action softirq_vec[NR_SOFTIRQS]; ``` 2. **注册与触发** - 使用`open_softirq()`注册处理函数,例如网络子系统注册`NET_RX_SOFTIRQ`: ```c open_softirq(NET_RX_SOFTIRQ, net_rx_action); ``` - 通过`raise_softirq(int nr)`触发软中断,例如网络驱动接收数据后触发。 3. **执行上下文** 软中断在以下两种场景执行: - **中断退出路径**:硬件中断处理完成后,调用`irq_exit()`时检查并执行。 - **ksoftirqd线程**:若软中断负载过高,内线程`ksoftirqd/CPU编号`会接管处理。 #### 三、软中断处理流程 1. **触发阶段** 硬件中断处理程序(如网卡中断)将数据加入队列,调用`raise_softirq(NET_RX_SOFTIRQ)`标记软中断待处理。 2. **执行阶段** - 内调用`__do_softirq()`遍历`softirq_vec`,执行所有已触发的软中断。 - 若执行时间超过`MAX_SOFTIRQ_TIME`(2ms)或触发次数超过`MAX_SOFTIRQ_RESTART`(10次),剩余任务交由`ksoftirqd`线程处理。 #### 四、关键特性与优化 1. **并发控制** - 使用`local_bh_disable()`/_bh()后缀函数禁用软中断,防止重入。 - 通过每CPU变量(如`irq_stat[CPU].__softirq_pending`)实现无锁化处理。 2. **多负载均衡** 在SMP系统中,软中断绑定到特定CPU或由调度器动态分配。禁用IO APIC(如`nosmp`参数)会影响中断路由[^2]。 #### 五、典型应用场景 1. **网络协议栈** `NET_RX_SOFTIRQ`处理接收数据包,`NET_TX_SOFTIRQ`处理发送完成通知。 2. **块设备层** `BLOCK_SOFTIRQ`用于IO请求完成回调。 3. **定时器** `TASKLET_SOFTIRQ`调度延迟任务(如高精度定时器)。 ```c // 示例:触发网络接收软中断 void netif_rx(struct sk_buff *skb) { // 将数据包加入队列 __skb_queue_tail(&queue, skb); raise_softirq_irqoff(NET_RX_SOFTIRQ); // 触发软中断 } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值