kworker进程

kworker进程是内核工作线程的占位符进程,它执行大部分内核的实际处理,特别是在有中断,定时器,I/O等的情况下,这些进程通常对应于绝大多数分配的"system"时间运行过程。

分类

worker_pool 分成两类:

  • normal worker_pool,给通用的 workqueue 使用;

    我们可以通过 ps | grep kworker 命令来查看所有 worker 对应的内核线程,normal worker_pool 对应内核线程 (worker_thread()) 的命名规则是这样的:

    1
    2
    3
    4
    5
    
    snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id,
         pool->attrs->nice < 0  ? "H" : "");
      
    worker->task = kthread_create_on_node(worker_thread, worker, pool->node,
                          "kworker/%s", id_buf);
    

    so 类似名字是 normal worker_pool:

    1
    2
    3
    4
    5
    
    shell@PRO5:/ $ ps | grep "kworker"
    root      14    2     0      0     worker_thr 0000000000 S kworker/1:0H     // cpu1 高优先级 worker_pool 的第 0 个 worker 进程
    root      17    2     0      0     worker_thr 0000000000 S kworker/2:0      // cpu2 低优先级 worker_pool 的第 0 个 worker 进程
    root      18    2     0      0     worker_thr 0000000000 S kworker/2:0H     // cpu2 高优先级 worker_pool 的第 0 个 worker 进程
    root      23699 2     0      0     worker_thr 0000000000 S kworker/0:1      //
    
  • unbound worker_pool,给 WQ_UNBOUND 类型的的 workqueue 使用;

    大部分的 work 都是通过 normal worker_pool 来执行的 ( 例如通过 schedule_work()、schedule_work_on() 压入到系统 workqueue(system_wq) 中的 work),最后都是通过 normal worker_pool 中的 worker 来执行的。这些 worker 是和某个 CPU 绑定的,work 一旦被 worker 开始执行,都是一直运行到某个 CPU 上的不会切换 CPU。

    unbound worker_pool 相对应的意思,就是 worker 可以在多个 CPU 上调度的。但是他其实也是绑定的,只不过它绑定的单位不是 CPU 而是 node。所谓的 node 是对 NUMA(Non Uniform Memory Access Architecture) 系统来说的,NUMA 可能存在多个 node,每个 node 可能包含一个或者多个 CPU。

    unbound worker_pool 对应内核线程 (worker_thread()) 的命名规则是这样的:

    1
    2
    3
    4
    
    snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id);
      
    worker->task = kthread_create_on_node(worker_thread, worker, pool->node,
                          "kworker/%s", id_buf);
    

    so 类似名字是 unbound worker_pool:

    shell@PRO5:/ $ ps | grep “kworker” root 23906 2 0 0 worker_thr 0000000000 S kworker/u20:2 // unbound pool 20 的第 2 个 worker 进程 root 24564 2 0 0 worker_thr 0000000000 S kworker/u20:0 // unbound pool 20 的第 0 个 worker 进程 root 24622 2 0 0 worker_thr 0000000000 S kworker/u21:1 // unbound pool 21 的第 1 个 worker 进程

调试

  • 通过kworker监视处理器负载(使用top或某些东西),并在高负载的时刻执行echo l > /proc/sysrq-trigger创建回溯。 (在Ubuntu上,这需要您使用sudo -s登录)。做几次,然后在dmesg输出结束时观看回溯。看看在CPU返回中经常发生的事情,希望它指向您的问题的根源。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    示例:e1000e。在我的情况下,我几乎每次发现一个这样的回溯:
      
    Call Trace:
     delay_tsc+0x4a/0x80
     __const_udelay+0x2c/0x30
     e1000_acquire_swflag_ich8lan+0xa2/0x240 [e1000e]
     e1000e_read_phy_reg_igp+0x29/0x80 [e1000e]
     e1000e_phy_has_link_generic+0x85/0x120 [e1000e]
     e1000_check_for_copper_link_ich8lan+0x48/0x930 [e1000e]
     e1000e_has_link+0x55/0xd0 [e1000e]
     e1000_watchdog_task+0x5e/0x960 [e1000e]
      
    它暗示了我在e1000e以太网卡模块中的一个问题,实际上sudo rmmod e1000e使得高CPU负载立即消失[e1000e bug #26]。
    
  • Perf是一种更专业的方法来分析哪些内核任务占用CPU:

    安装perf:

    1
    
    sudo apt-get install linux-tools-common linux-tools-3.11.0-15-generic
    

    在所有CPU上记录大约10秒的回溯:

    1
    
    sudo perf record -g -a sleep 10
    

    分析录音:

    1
    
    sudo perf report
    

引用地址

http://kernel.meizu.com/linux-workqueue.html