英文网站建设的问题,支持wordpress的空间,腾讯企业邮箱官网登录入口网页版,免费制作短视频的软件目录 一、概述二、上下文切换的实现1、context_switch2、switch_mm3、switch_to 三、观测进程上下文切换 一、概述
进程的上下文切换是指在多任务操作系统中#xff0c;当操作系统决定要切换当前运行的进程时#xff0c;将当前进程的状态保存起来#xff0c;并恢复下一个要… 目录 一、概述二、上下文切换的实现1、context_switch2、switch_mm3、switch_to 三、观测进程上下文切换 一、概述
进程的上下文切换是指在多任务操作系统中当操作系统决定要切换当前运行的进程时将当前进程的状态保存起来并恢复下一个要运行的进程的状态。上下文切换是操作系统实现进程调度和实现多任务的关键机制之一。
操作系统一个非常重要的功能就是进程的管理通过调度策略选择合适的进程来执行对于单个 CPU 而言进程是串行分时执行这就需要内核支持进程切换挂起一个正在 CPU 中执行的进程恢复执行之前挂起的进程。
CPU 和寄存器是所有进程共用的CPU 在运行任何 task 之前必须地依赖一些环境包括 CPU 寄存器和程序计数器除此之外进程运行过程中还需要用到虚拟内存。进程在切换过程中主要的工作就是切换进程空间虚拟内存切换 CPU 寄存器和程序计数器。
二、上下文切换的实现
进程切换由两部分组成
切换页全局目录安装一个新的地址空间切换内核态堆栈及硬件上下文。
Linux 内核中由 context_switch 实现了上述两部分内容。
调用 switch_mm 完成用户空间切换调用 switch_to 完成内核栈及寄存器切换。
1、context_switch
下面是上下文切换的内核源码完整的源码见目录 kernel/sched/core.c 的 context_switch 函数
static inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,struct task_struct *next)
{struct mm_struct *mm, *oldmm;prepare_task_switch(rq, prev, next);mm next-mm; // 下一个要执行的进程的虚拟内存oldmm prev-active_mm; // 将要被切换出去的进程的虚拟内存arch_start_context_switch(prev);if (!mm) { // 内核线程的 mm 为 NULLnext-active_mm oldmm;atomic_inc(oldmm-mm_count);enter_lazy_tlb(oldmm, next);} else // 用户进程的 mm 不为 NULLswitch_mm(oldmm, mm, next);if (!prev-mm) {prev-active_mm NULL;rq-prev_mm oldmm;}spin_release(rq-lock.dep_map, 1, _THIS_IP_);context_tracking_task_switch(prev, next);switch_to(prev, next, prev); // 切换寄存器和内核栈barrier();return finish_task_switch(prev);
}执行流程如下
通过进程描述符 next-mm 是否为空判断当前进程是否是内核线程因为内核线程的内存描述符 mm_struct *mm 总是为空。如果是内核线程则借用 prev 进程的 active_mm对于用户进程active_mm mm对于内核线程mm NULLactive_mm prev-active_mm。如果 prev-mm 不为空则说明 prev 是用户进程调用 mmgrab 增加 mm-mm_count 引用计数。对于内核线程会启动懒惰 TLB 模式。懒惰 TLB 模式是为了减少无用的TLB刷新。enter_lazy_tlb 与体系结构相关。如果是用户进程则调用 switch_mm (或 switch_mm_irqs_off) 完成用户地址空间切换switch_mm (或 switch_mm_irqs_off) 与体系结构相关。调用 switch_to 完成内核态堆栈及硬件上下文切换switch_to 与体系结构相关。switch_to 执行完成后next 进程获得 CPU 使用权prev 进程进入睡眠状态。调用 finish_task_switch如果 prev 是内核线程则调用 mmdrop 减少内存描述符引用计数。如果引用计数为 0则释放与页表相关的所有描述符和虚拟内存。
2、switch_mm
对于用户进程需要完成用户空间的切换switch_mm 函数完成了这个任务。switch_mm 是与体系架构相关的函数。更确切地说是切换地址转换表(pgd)由于 pgd 包括进程 系统空间0xc000 0000 ~ 0xffff ffff和 用户空间0x0000 0000 ~ 0xbfff ffff的地址映射但是由于所有进程的系统空间的地址映射都是相同的。所以实质上就是进行用户空间的切换。
Linux 5.6.4 内核调用 switch_mm_irqs_off 切换用户进程空间对于没有定义该函数的架构则调用的是switch_mm。x86 体系架构定义了 switch_mm_irqs_off 函数ARM 体系架构没有定义。
#ifndef switch_mm_irqs_off#define switch_mm_irqs_off switch_mm
#endif函数定义为
static inline void switch_mm( struct mm_struct * prev,struct mm_struct * next,struct task_struct * tsk){int cpu smp_processor_id();if (likely(prev ! next)) {cpu_clear(cpu, prev-cpu_vm_mask);
#ifdef CONFIG_SMPper_cpu(cpu_tlbstate, cpu).state TLBSTATE_OK;per_cpu(cpu_tlbstate, cpu).active_mm next;
#endifcpu_set(cpu, next-cpu_vm_mask);load_cr3(next-pgd); // 将下一个进程页表的 pgd 装载进 CR3 寄存器if (unlikely(prev-context.ldt ! next-context.ldt))load_LDT_nolock(next-context, cpu);}
#ifdef CONFIG_SMPelse {per_cpu(cpu_tlbstate, cpu).state TLBSTATE_OK;BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm ! next);if (!cpu_test_and_set(cpu, next-cpu_vm_mask)) {load_cr3(next-pgd); // 将下一个进程页表的 pgd 装载进 CR3 寄存器load_LDT_nolock(next-context, cpu);}}
#endif
}这部分核心的代码是 load_cr3这个函数加载下一个进程页表 pgd 地址加载进 CR3 寄存器。CR3 是 CPU 的一个寄存器它存储了当前进程的顶级页表 pgd。
如果 CPU 要使用进程的虚拟内存内核可以从 CR3 寄存器里面得到 pgd 在物理内存的地址通过页表就可以得到虚拟内存对应的物理地址这样就可以得到物理内存的数据。
3、switch_to
对于内核空间及寄存器的切换switch_to 函数完成了这个任务。
switch_to 调用到 __switch_to该宏函数定义在目录 arch/x86/include/asm/switch_to.h
#define switch_to(prev, next, last) \
do { \/* \* Context-switching clobbers all registers, so we clobber \* them explicitly, via unused output variables. \* (EAX and EBP is not listed because EBP is saved/restored \* explicitly for wchan access and EAX is the return value of \* __switch_to()) \*/ \unsigned long ebx, ecx, edx, esi, edi; \\asm volatile(pushfl\n\t /* save flags */ \pushl %%ebp\n\t /* save EBP */ \movl %%esp,%[prev_sp]\n\t /* save ESP */ \movl %[next_sp],%%esp\n\t /* restore ESP */ \movl $1f,%[prev_ip]\n\t /* save EIP */ \pushl %[next_ip]\n\t /* restore EIP */ \__switch_canary \jmp __switch_to\n /* regparm call */ \1:\t \popl %%ebp\n\t /* restore EBP */ \popfl\n /* restore flags */ \\/* output parameters */ \: [prev_sp] m (prev-thread.sp), \[prev_ip] m (prev-thread.ip), \a (last), \\/* clobbered output registers: */ \b (ebx), c (ecx), d (edx), \S (esi), D (edi) \\__switch_canary_oparam \\/* input parameters: */ \: [next_sp] m (next-thread.sp), \[next_ip] m (next-thread.ip), \\/* regparm parameters for __switch_to(): */ \[prev] a (prev), \[next] d (next) \\__switch_canary_iparam \\: /* reloaded segment registers */ \memory);
} while (0)switch_to 宏用于进程切换,给定了前一个进程结构体指针 prev以及需要切换到的进程结构体指针 next从 prev 切换到 next。
prev 和 next 是输入参数分别表示被替换进程和新进程描述符的地址在内存中的位置。而 last 是输出参数假设内核决定暂停进程 A 而激活进程 B而后又激活进程 A则必须暂停另一个进程 C通常不同于进程 B则它表示宏把进程 C 的描述符地址写在内存的什么位置在 A 恢复执行后。
在进程切换之前宏把第一个输入参数 prev即在 A 的内核堆栈中分配的 prev 局部变量表示的变量的内容存入 CPU 的 eax 寄存器。在完成进程切换A 已经恢复执行时宏把 CPU 的 eax 寄存器的内容写入由第三个输出参数 last 所指示的 A 在内存中的位置。因为 CPU 寄存器不会在切换点发生变化所以 C 的描述符地址也存在内存的这个位置。在 schedule() 执行过程中参数 last 指向 A 的局部变量 prev所以 prev 被 C 的地址覆盖。 三、观测进程上下文切换
systemtap 提供了跟踪进程释放执行权被切换出 CPU 的 probe 方法 scheduler.cpu_off 这个 probe 的定义 如下
/*** probe scheduler.cpu_off - Process is about to stop running on a cpu* * name: name of the probe point* task_prev: the process leaving the cpu(same as current)* task_next: the process replacing current* idle: boolean indicating whether current is the idle process** Context: The process leaving the cpu.**/
probe scheduler.cpu_off kernel.trace(sched_switch) !,kernel.function(context_switch)
{name cpu offtask_prev $prevtask next $nextidle __is_idle()
}可以看到 cpu_off 时间其实是 sched_switch 内核 trace 事件和 context_switch 内核函数的封装同时提供了 task_prev 和 task_next 两个有用的参数。
task_prev 表示当前进程的 task struct 结构体也就是马上要释放执行权的 task structtask_next 表示马上要执行的进程的 task struct 结构体。 注意这里的进程是广义的进程也可以是线程本质是一个 task struct。 我们就可以通过 cpu_off 事件来统计一段时间内的进程切换情况完整的 systemtap 脚本如下所示
global csw_countprobe scheduler.cpu_off {csw_count[task_prev,task_next]
}function fmt_task(task_prev, task_next){return sprintf(tid(%d)-tid(%d),task_tid(task_prev), task_tid(task_next))
}function print_context_switch_top5() {fprintf(%45s %10s\n, Context switch, COUNT)foreach([task_prev,task_next] in csw_count- limit 5) {printf(%45s %10d\n, fmt_task(task_prev, task_next), csw_count[task_prev, task_next])}delete csw_count
}probe timer.s(1) {print_context_switch_top5()printf(-----------------------------------------------\n)
}其中 csw_count 是 systemtap 的关联数组虽然这名字叫数组其实是一个字典跟其它语言的 map/dict/hash 类似。csw_count[task_prevtask_next] 语法的含义是将 task_prev 和 task_next 两个值联合起来为字典的 key。
如果我们由进程 A 切换到 BB 切换到 CC 切换到 A那么这个关联数组的形式如下
csw_count[AB]1
csw_count[BC]1
csw_count[CA]1接下来我们来执行 4 个跑满 CPU 的单线程程序在我双核机器上每个程序会占据 50% 的 CPU 左右开启四个终端执行四次下面的程序
$ sha256sum /dev/zerotop 命令的输出如下这四个进程分别为 27458、27460、27590、27636。 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND
27460 root 20 0 116664 1140 856 R 50.8 0.1 0:35.12 sha256sum
27636 root 20 0 116664 1140 856 R 50.3 0.1 0:24.84 sha256sum
27458 root 20 0 116664 1140 856 R 49.7 0.1 0:36.18 sha256sum
27590 root 20 0 116664 1140 856 R 49.7 0.1 0:28.66 sha256sum然后使用 stap 执行上面的 systemtap 脚本
Context switch COUNT
tid(27460)-tid(27636) 62
tid(27636)-tid(27460) 62
tid(27590)-tid(27458) 44
tid(27458)-tid(27590) 43
tid(27458)-tid(25116) 10可以看到1s 内这四个进程切换得非常频繁。 文章转载自: http://www.morning.thmlt.cn.gov.cn.thmlt.cn http://www.morning.yfwygl.cn.gov.cn.yfwygl.cn http://www.morning.yswxq.cn.gov.cn.yswxq.cn http://www.morning.xtqr.cn.gov.cn.xtqr.cn http://www.morning.dmhs.cn.gov.cn.dmhs.cn http://www.morning.dpnhs.cn.gov.cn.dpnhs.cn http://www.morning.sbkb.cn.gov.cn.sbkb.cn http://www.morning.nlcw.cn.gov.cn.nlcw.cn http://www.morning.flncd.cn.gov.cn.flncd.cn http://www.morning.drfcj.cn.gov.cn.drfcj.cn http://www.morning.kkdbz.cn.gov.cn.kkdbz.cn http://www.morning.csznh.cn.gov.cn.csznh.cn http://www.morning.ydxx123.cn.gov.cn.ydxx123.cn http://www.morning.fpqsd.cn.gov.cn.fpqsd.cn http://www.morning.zxfr.cn.gov.cn.zxfr.cn http://www.morning.qnzpg.cn.gov.cn.qnzpg.cn http://www.morning.xtdtt.cn.gov.cn.xtdtt.cn http://www.morning.rgtp.cn.gov.cn.rgtp.cn http://www.morning.ztnmc.cn.gov.cn.ztnmc.cn http://www.morning.duqianw.com.gov.cn.duqianw.com http://www.morning.hqykb.cn.gov.cn.hqykb.cn http://www.morning.mxdiy.com.gov.cn.mxdiy.com http://www.morning.gxfzrb.com.gov.cn.gxfzrb.com http://www.morning.pqbkk.cn.gov.cn.pqbkk.cn http://www.morning.wcczg.cn.gov.cn.wcczg.cn http://www.morning.knpbr.cn.gov.cn.knpbr.cn http://www.morning.wmsgt.cn.gov.cn.wmsgt.cn http://www.morning.nsrtvu.com.gov.cn.nsrtvu.com http://www.morning.xdttq.cn.gov.cn.xdttq.cn http://www.morning.qbwbs.cn.gov.cn.qbwbs.cn http://www.morning.xrnh.cn.gov.cn.xrnh.cn http://www.morning.zxqxx.cn.gov.cn.zxqxx.cn http://www.morning.hhmfp.cn.gov.cn.hhmfp.cn http://www.morning.zrmxp.cn.gov.cn.zrmxp.cn http://www.morning.sgtq.cn.gov.cn.sgtq.cn http://www.morning.zbtfz.cn.gov.cn.zbtfz.cn http://www.morning.bprsd.cn.gov.cn.bprsd.cn http://www.morning.nxnrt.cn.gov.cn.nxnrt.cn http://www.morning.rfpxq.cn.gov.cn.rfpxq.cn http://www.morning.wkrkb.cn.gov.cn.wkrkb.cn http://www.morning.lywpd.cn.gov.cn.lywpd.cn http://www.morning.dkqbc.cn.gov.cn.dkqbc.cn http://www.morning.pqjlp.cn.gov.cn.pqjlp.cn http://www.morning.mhrzd.cn.gov.cn.mhrzd.cn http://www.morning.jnzfs.cn.gov.cn.jnzfs.cn http://www.morning.wklrz.cn.gov.cn.wklrz.cn http://www.morning.xnrgb.cn.gov.cn.xnrgb.cn http://www.morning.qqrlz.cn.gov.cn.qqrlz.cn http://www.morning.kqglp.cn.gov.cn.kqglp.cn http://www.morning.pfggj.cn.gov.cn.pfggj.cn http://www.morning.xnpj.cn.gov.cn.xnpj.cn http://www.morning.cnbdn.cn.gov.cn.cnbdn.cn http://www.morning.bdfph.cn.gov.cn.bdfph.cn http://www.morning.rhmt.cn.gov.cn.rhmt.cn http://www.morning.qnwyf.cn.gov.cn.qnwyf.cn http://www.morning.skrww.cn.gov.cn.skrww.cn http://www.morning.mmhyx.cn.gov.cn.mmhyx.cn http://www.morning.wjfzp.cn.gov.cn.wjfzp.cn http://www.morning.kghss.cn.gov.cn.kghss.cn http://www.morning.thlzt.cn.gov.cn.thlzt.cn http://www.morning.bpmdh.cn.gov.cn.bpmdh.cn http://www.morning.xsjfk.cn.gov.cn.xsjfk.cn http://www.morning.fchkc.cn.gov.cn.fchkc.cn http://www.morning.xysxj.com.gov.cn.xysxj.com http://www.morning.smkxm.cn.gov.cn.smkxm.cn http://www.morning.twgzq.cn.gov.cn.twgzq.cn http://www.morning.hnzrl.cn.gov.cn.hnzrl.cn http://www.morning.ldnrf.cn.gov.cn.ldnrf.cn http://www.morning.sgpnz.cn.gov.cn.sgpnz.cn http://www.morning.fgxnb.cn.gov.cn.fgxnb.cn http://www.morning.shxmr.cn.gov.cn.shxmr.cn http://www.morning.gwjnm.cn.gov.cn.gwjnm.cn http://www.morning.nqypf.cn.gov.cn.nqypf.cn http://www.morning.rfxyk.cn.gov.cn.rfxyk.cn http://www.morning.kfysh.com.gov.cn.kfysh.com http://www.morning.kdnrp.cn.gov.cn.kdnrp.cn http://www.morning.fylqz.cn.gov.cn.fylqz.cn http://www.morning.rnwt.cn.gov.cn.rnwt.cn http://www.morning.cjwkf.cn.gov.cn.cjwkf.cn http://www.morning.jphxt.cn.gov.cn.jphxt.cn