03CPU上下文切换-Linux性能优化

基本概念

  • CPU上下文:即CPU在运行任何程序前所必须依赖的环境,即CPU寄存器和程序计数器。其中CPU寄存器是CPU内置的容量小、但速度极快的内存。而程序计数器则是用来存储CPU正在执行的指令位置、或者即将执行的下一条指令位置。
  • CPU上下文切换:即把前一个任务的CPU上下文(CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。而前一个任务的CPU上下文会存储在系统内核中,并在重新调度是重新加载。
  • CPU上下文切换根据场景可以划分为三类:进程上下文切换、线程上下文切换、中断上下文切换。

进程上下文切换

  • 进程的上下文切换需要保存当前进程的内核状态、CPU寄存器、虚拟内存、栈等,每次进程上下文切换都需要几十纳秒到数微妙的CPU时间,当进程上下文切换次数较多时,很容易造成CPU将大量时间消耗在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间,这就是导致平均负载升高的一个重要原因。
  • 触发进程调度的原因有如下几个:
    • 当某个进程的时间片耗尽,会被系统挂起,切换到其他正在等待CPU的进程运行。
    • 进程在系统资源不足(比如内存不足)时,要等资源满足后才可以运行,这个时候进程会被挂起,并由系统调度其他的进程运行。
    • 进程通过睡眠函数将自己主动挂起。
    • 出现优先级更高的进程运行时,当前进程被挂起,由高优先级进程先运行。
    • 发生硬件中断,CPU上的进程会被中断挂起,转而执行内核中的中断服务程序。

线程上下文切换

  • 线程和进程简要区别:
    • 当进程只有一个线程,则进程就等于线程。
    • 当进程拥有多个线程,这些线程会共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时是不需要修改的。
    • 线程也由自己的私有数据,比如栈和寄存器等,这些在上下文切换时也需要保存。
  • 线程上下文切换的两种情况:
    • 前后两个线程属于不同进程,此时由于资源不共享,所以切换过程和进程上下文切换一致。
    • 前后两个线程属于同个进程,此时因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。同进程内的线程切换要比多进程间的切换消耗更少的资源。

中断上下文切换

  • 跟进程上下文不同,中断上下文切换并不涉及到进程的用户态,所以不需要保存这个进程的虚拟内存、全局变量等用户态资源。只需要内核态中断服务程序执行所需的基本资源,比如CPU寄存器、内核堆栈、硬件中断参数等。
  • 中断上下文切换也需要消耗CPU,所以切换次数过多也会消耗大量的CPU,导致性能降低。

常用工具

  • 查看系统整体的上下文切换情况。

    1
    2
    3
    4
    5
    6
    7
    8
    # 每隔 5 秒输出 1 组数据
    $ vmstat 5
    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
    r b swpd free buff cache si so bi bo in cs us sy id wa st
    0 0 0 7005360 91564 818900 0 0 0 0 25 33 0 0 100 0 0

    #cs(context switch) 是每秒上下文切换的次数。
    #in(interrupt)则是每秒中断的次数。
  • 查看每个进程的详细情况。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 每隔 5 秒输出 1 组数据
    $ pidstat -w 5
    Linux 4.15.0 (ubuntu) 09/23/18 _x86_64_ (2 CPU)

    08:18:26 UID PID cswch/s nvcswch/s Command
    08:18:31 0 1 0.20 0.00 systemd
    08:18:31 0 8 5.40 0.00 rcu_sched

    #cswch: 每秒自愿上下文切换的次数。
    #nvcswch: 每秒非自愿上下文切换的次数。
  • 自愿上下文切换:指进程无法获取所需自愿,导致上下文切换。比如:I/O、内存等系统自愿不足时,会发生自愿上下文切换。

  • 非自愿上下文切换:指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如大量进程都在争抢CPU,就容易发生非自愿上下文切换。

总结

  • 无论那种场景的上下文切换,你需要明白:
    • CPU上下文切换是保证Linux系统正常工作的核心功能之一,一般不需要特别关注。
    • 过多的上下文切换会把CPU时间消耗在寄存器、内核栈、虚拟内存等数据的保存和恢复上,从而缩短进程真正的运行时间,导致系统的整体性能下降。
-------------本文结束感谢您的阅读-------------