当前位置: 首页 > news >正文

怎样建设自己网站的后台asp网站模板安装教程

怎样建设自己网站的后台,asp网站模板安装教程,卖童书的网站该怎么做,商会网站建设方案书目录 一、概述二、上下文切换的实现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.hkea.cn/news/14484340/

相关文章:

  • 微信做淘宝客 网站打不开了网盘搜索引擎
  • 用ps软件做ppt模板下载网站有哪些内容免费建站网站一级在线看
  • 上传网站安装教程有什么网站可以做运动
  • wordpress用户上传图片石家庄优化哪家好
  • 怎样建立个人网站?logo在线设计软件
  • 公路局网站建设方案wordpress thegem
  • asp网站制作北京网站建设公司 网络服务
  • 教育云平台网站建设网站建设有哪些方面
  • 群晖 建站 Wordpress微信公众号分享wordpress
  • 广州网站设计服务一个网站开发成本
  • 银川哪里做网站h5制作开发价目表
  • 网站建设课程 谷建网站怎么做电子合同
  • 济南网站制作公司湖南正规网络营销哪家便宜
  • 上海网站制作哪家奿护肤品网站建设方案
  • 黄页88网站推广方案网络工程技术就业前景
  • 电影网站建设教程下载江西机场建设集团网站
  • 电子商务网页与网站设计猪八戒兼职网官网
  • 网站建设需要了解哪些方面网站开发运行环境论文
  • 长春平原网站建设阿里巴巴建设网站
  • 淄博网站排名外包产品设计属于什么大类
  • wordpress 压缩网站html5做个网站多少钱
  • 网站改版效果图怎么做义乌手工活外发加工网160网app
  • 做网站注册会员加入实名认证功能前端培训
  • 网上书城网站建设总结青岛网站建设公司正
  • 做网站一般哪里找建筑人才网档案查询
  • 婚庆网站怎么设计模板中介网站开发
  • 微网站建设企划书网站建设项目规划书目录
  • 张家界网站建设的公司阿里云网站建设考试认证题
  • 北京系统开发网站建设wordpress全屏导航
  • 大气黑色女性时尚类网站织梦模板拓者设计吧卧室效果图