为什么我联通卡1元联通500m流量多少钱,今天我一整天不开过,但不知为什么它自己

《自己动手写操作系统第六章》引来minix中断处理方式 - 操作系统当前位置:& &&&《自己动手写操作系统第六章》引来minix中断处理方式《自己动手写操作系统第六章》引来minix中断处理方式&&网友分享于:&&浏览:14次《自己动手写操作系统第六章》引入minix中断处理方式摘要:回过头来看,我们发现我们的中断处理程序写的并不够优雅。中断被响应需要三个条件:Eflags中的中断标记是打开状态;中断屏蔽寄存器没有屏蔽对应中断,设置了EOI标志。
1.修改一下时钟中断处理程序:g/kernel/kernel.asm
inc dword [k_reenter]
cmp dword [k_reenter], 0
jne .1 ;重入进入.1
mov esp, StackT 切到内核栈
push .restart_v2
push .restart_reenter_v2
clock_handler
add esp, 4
对应前面的push语句
.restart_v2:
mov esp, [p_proc_ready] ; 离开内核栈;
[esp + P_LDT_SEL]
lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax
193 .restart_reenter_v2: 如果(k_reenter != 0),会跳转到这里
dec dword [k_reenter] k_reenter--;
197 ┣ 恢复原寄存器值
add esp, 4
注意:上面的代码从逻辑上也发生了改变:在发生了中断重入的时候,仍然会执行中断服务程序,不过仅仅会打印&!&就返回;没有发生中断切换的时候就会执行进程切换。
& & 我们来看看对应的中断处理程序:
21 PUBLIC void clock_handler(int irq)
disp_str(&#&);
if (k_reenter != 0) {
disp_str(&!&);
p_proc_ready++;
if (p_proc_ready &= proc_table + NR_TASKS) {
p_proc_ready = proc_
我们更改代码以后,再来运行一下程序:
思考:上面的代码是否会产生中断重入导致的堆栈溢出问题?
2.修改restart程序
restart是将睡眠的程序重新运行的一段程序,是用汇编在kernel.asm中定义的,由main.c中的tnix_main()调用,然后进入死循环:
k_reenter = -1;
p_proc_ready
restart();
while(1){}
我们来修改restart的代码:
353 restart:
mov esp, [p_proc_ready]
[esp + P_LDT_SEL]
lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax
358 restart_reenter:
dec dword [k_reenter];由于这一句,我们需要将k_reenter的初始值从-1改成0
add esp, 4
由于时钟中断的后部分和restart是相同的,我们可以将这时钟中断中重合的部分省略。
3修改中断处理程序——save
对比原来的中断处理程序:我们总结一下时钟中断程序的内容:
1)保护上下文
2)判断中断重入与堆栈切换
3)开中断与中断处理核心程序
4)恢复上下文(已经并在了restart过程当中)
现在,我们将1)和2)也独立出来:
sub esp, 4
197 ┣ 保存原寄存器值
mov dx, ss
mov ds, dx
mov es, dx
mov eax,esp
inc dword [k_reenter]
cmp dword [k_reenter], 0
mov esp, StackT 切到内核栈
restart_reenter
[eax+RETADR-P_STACKBASE]& &&中断处理程序的部分内容:
158 hwint00: Interrupt routine for irq 0 (the clock).
byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符
mov al, EOI ┓reenable master 8259
out INT_M_CTL, ┛& & &这里,我们注意到一个很奇怪的call指令——没有以ret结尾。为什么呢?想一想,ret从堆栈中弹出返回地址赋值给eip;但是由于这里,esp在call指令中发生了变化,所以没法用ret进行返回,需要使用jmp,就是call指令的下一条指令的地址作为call过程的返回地址。
4.修改中断处理程序——时钟中断的可重入问题
& & & &我们在本文第一部分已经分析过,这种情况下的代码仍然可能导致时钟中断的重入问题:所以,我们有必要在重新打开中断之前关闭时钟中断;在关闭中断之后再打开时钟中断。
al,INT_M_CTLMASK
out INT_M_CTLMASK,al
mov al, EOI ┓reenable master 8259
out INT_M_CTL, ┛
clock_handler
add esp, 4
al,INT_M_CTLMASK
and al,0xFE
out INT_M_CTLMASK
5.修改中断处理程序——代码模块化:统一的中断处理例程
& &&在上面的这段代码中,我们注意到,真正与时钟相关的部分是有限的,这很容易扩展到其他中断类型。我们来定义一个宏hwint_master 1来处理硬件中断。
150 ; 中断和异常 -- 硬件中断
151 ; ---------------------------------
152 %macro
hwint_master
al, INT_M_CTLMASK ┓
al, (1 && %1) ┣ 屏蔽当前中断
out INT_M_CTLMASK, ┛
mov al, EOI ┓置EOI位
out INT_M_CTL, ┛
159 CPU在响应中断的过程中会自动关中断,这句之后就允许响应新的中断
[irq_table + 4 * %1] ┣ 中断处理程序;很显然,irq_table是一个函数指针组成的数组,我们在global.c中对他加以定义
al, INT_M_CTLMASK ┓
and al, ~(1 && %1) ┣ 恢复接受当前中断
out INT_M_CTLMASK, ┛
168 %endmacro
& &&相关:
irq_table在global.c中进行定义:
irq_hander irq_tabel[NR_IRQ];
申明:extern irq_hander irq_table[];在global.h
在type.h中增加对irq_handler的定义:typedef void (*irq_handler) (int irq)
const.h :#define
& & 接下来,我们来初始化irq_table,先都初始化成spurious_irp:
在init_8259A函数中:
for(i=0;i&NR_IRQ;i++LL)
irq_table[i]=surious_
& & 现在,我们需要一个函数对irq_table[0]进行赋值:
&44 PUBLIC void put_irq_handler(int irq, t_pf_irq_handler handler)
disable_irq(irq);这一句是必须的——进行中断处理之前,先关对应中断
irq_table[irq] =
& & 这里,你看到,我们使用了一个中断使能函数disable_irq,我们接下来看它和另外一个函数enable_irq的结构体。
123 ; ========================================================================
void disable_irq(int irq);
125 ; ========================================================================
126 ; Disable an interrupt request line by setting an 8259 bit.
127 ; Equivalent code for irq & 8:
out_byte(INT_CTLMASK, in_byte(INT_CTLMASK) | (1 && irq));
129 ; Returns true iff the interrupt was not already disabled.
131 disable_irq:
mov ecx, [esp + 4] irq
rol ah, ah = (1 && (irq % 8))
jae disable_8 disable irq &= 8 at the slave 8259
139 disable_0:
al, INT_M_CTLMASK
jnz dis_ already disabled?
out INT_M_CTLMASK, set bit at master 8259
mov eax, 1 disabled by this function
148 disable_8:
al, INT_S_CTLMASK
jnz dis_ already disabled?
out INT_S_CTLMASK, set bit at slave 8259
mov eax, 1 disabled by this function
157 dis_already:
xor eax, already disabled
161 & &相应的enable的代码我们省略,请读者自行看书讲解。
6.应用统一的中断处理范式
& & 在main.c中,绑定中断处理程序到固定的引脚。
p_proc_ready
put_irq_handler(CLOCK_IRQ, clock_handler);
/* 设定时钟中断处理程序 */
enable_irq(CLOCK_IRQ);
/* 让8259A可以接收时钟中断 */
restart();在init_8259A中屏蔽所有的中断:out_byte(INT_M_CTLMASK,0xFF).
& & & & 回过头来总结一下,我们是如何将中断处理流程范式化的:我们将寄存器恢复、堆栈切换ldt等操作提取出来,归到restart部分;将中断处理核心部分:打印相关信息和进程切换放到时钟中断处理句柄中;将上下文的保存、判断中断重入等放到save函数之中;为了防止时钟中断重入,我们在中断处理流程中加入中断使能控制语句;接下来,将时钟中断处理,推广到一般化的中断处理,将上述中断处理过程 封装成宏定义hwint_master。过程大致如此,可以看出,这是一个从特殊化到一般化的过程,也是我们避免代码臃肿和出错的良好方式。
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有文章 - 295
评论 - 439CPU上下文切换的次数和时间(context switch) - iamzhongyong - ITeye技术网站
博客分类:
什么是CPU上下文切换?
现在linux是大多基于抢占式,CPU给每个任务一定的服务时间,当时间片轮转的时候,需要把当前状态保存下来,同时加载下一个任务,这个过程叫做上下文切换。时间片轮转的方式,使得多个任务利用一个CPU执行成为可能,但是保存现场和加载现场,也带来了性能消耗。
那线程上下文切换的次数和时间以及性能消耗如何看呢?
如何获得上下文切换的次数?
vmstat直接运行即可,在最后几列,有CPU的context switch次数。 这个是系统层面的,加入想看特定进程的情况,可以使用pidstat。
$ vmstat 1 100
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
cs us sy id wa st
88 233484 288756 1784744
88 233236 288756 1784752
0 6202 7880
88 233360 288756 1784800
112 6277 7612
88 232864 288756 1784804
644 5747 6593
执行pidstat,将输出系统启动后所有活动进程的cpu统计信息:
linux:~ # pidstat
Linux 2.6.32.12-0.7-default (linux)
%usr %system
11:37:19: pidstat获取信息时间点
PID: 进程pid
%usr: 进程在用户态运行所占cpu时间比率
%system: 进程在内核态运行所占cpu时间比率
%CPU: 进程运行所占cpu时间比率
CPU: 指示进程在哪个核运行
Command: 拉起进程对应的命令
备注:执行pidstat默认输出信息为系统启动后到执行时间点的统计信息,因而即使当前某进程的cpu占用率很高,输出中的值有可能仍为0。
上下文切换的性能消耗在哪里呢?
context switch过高,会导致CPU像个搬运工,频繁在寄存器和运行队列直接奔波
,更多的时间花在了线程切换,而不是真正工作的线程上。直接的消耗包括CPU寄存器需要保存和加载,系统调度器的代码需要执行。间接消耗在于多核cache之间的共享数据。
引起上下文切换的原因有哪些?
对于抢占式操作系统而言, 大体有几种:
1、当前任务的时间片用完之后,系统CPU正常调度下一个任务;
2、当前任务碰到IO阻塞,调度线程将挂起此任务,继续下一个任务;
3、多个任务抢占锁资源,当前任务没有抢到,被调度器挂起,继续下一个任务;
4、用户代码挂起当前任务,让出CPU时间;
5、硬件中断;
如何测试上下文切换的时间消耗?
LMbench,知道这个工具,是在霸爷的博客上面(),然后就开始在测试环境下搞了一把,一会就出结果了。然后就搞了台线上机器安装这个工具,然后测试,后面在测试Memory的时候,直接导致Load飙升,还好没人发现,机器java进程重启就好了。这方面纯粹是业务选手。霸爷说分析的结果对于高性能C的开发同学来说,是需要熟记的,没办法,咱是搞java的,只能每个指标逐个看一下了。
LMbench的简单介绍?
首先看英文介绍:LMbench -Tools for Performance Analysis,微观性能分析工具。
官方地址:
下载地址:
LMbench主要能干啥?
主要是带宽(读取缓存文件、内存拷贝、读写内存、管道等)和反应时间(上下文切换、网路、进程创建等)的评测工具。
LMbench 安装?
#wget http:
#tar -zxvf lmbench3.tar.gz
#cd lmbench3
中间遇到一个问题,就是报错,在CSDN上面找到了答案,这这里贴一下。
此时会报错:
make[2]: *** 没有规则可以创建“bk.ver”需要的目标“../SCCS/s.ChangeSet”。 停止。
make[2]:正在离开目录 `/home/hero/lmbench3/src'
make[1]: *** [lmbench] 错误 2
make[1]:正在离开目录 `/home/hero/lmbench3/src'
make: *** [build] 错误 2
解决办法:
lmbench3目录下
#mkdir SCCS
./SCCS/s.ChangeSet
LMbench关于结果解释(这次主要关注线程切换信息)
在网上找了半天,信息很少,只能看doc下面的英文解释了。
测试上下文切换的时间,一个上下文切换,包括保存一个进程状态的保存和恢复另外一个进程的时间。
典型的上下文切换性能,仅仅是测量最小的线程切换时间。仅仅是做进程切换,任何实质的任务都不做。
Context switching - times in microseconds - smaller is better
-------------------------------------------------------------------------
2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K
ctxsw ctxsw
--------- ------------- ------ ------ ------ ------ ------ ------- -------
commonway Linux 2.6.18- 9.2400 4.0200 9.0300 7.5600 8.3800
11.6 6.28000
时间的单位是微秒。
LMbench是如何来测量进程切换的时间的?
The benchmark is a ring of two to twenty processes that are connected
with Unix pipes.
A token is passed from process to process, forcing
context switches.
The benchmark measures the time it takes to pass
the token two thousand times from process to process.
Each hand off
of the token has two costs: (a) the context switch, and (b) the cost
of passing the token.
In order to get just the context switching time,the benchmark first measures the cost of passing the token through a
ring of pipes in a single process.
This time is defined as the cost
of passing the token and is not included in the reported context switch
When the processes are larger than the default baseline of ``zero''
(where zero means just big enough to do the benchmark), the cost
of the context switch includes the cost of restoring user level
state (cache lines).
This is accomplished by having the process
allocate an array of data and sum it as a series of integers
after receiving the token but before passing the token to the
next process.
Note that the overhead mentioned above includes
the cost of accessing the data but because it is measured in
just one address space, the cost is typically the cost with hot
So the context switch time does not include anything
other than the context switch provided that all the processes
fit in the cache.
If there are cache misses (as is common), the
cost of the context switch includes the cost of those cache misses.
首先是看任务处理的时间(通过一次任务处理,这个任务处理的时间被定义为token时间,不包括线程切换的)。
然后多次执行,排除任务执行的时间,然后计算出CS的时间(如果有cache miss,则CS的时间也包括cache misses的时间)。
文章参考:
霸爷和周忱的博客
浏览 11473
iamzhongyong
浏览: 343694 次
来自: 杭州
有2个问题请教:1. 这里的base32算法为什么需要以负数的 ...
不错非常好!推荐一个以电商购物支付流程中,在各大参与者系统中可 ...
&分布式锁&这节里,如果本身“构建唯一索引 ...
非常感谢分享,让我对最终一致性的解决方案有了实际的应用君,已阅读到文档的结尾了呢~~
广告剩余8秒
文档加载中
MINIX3操作系统架构及启动过程分析
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
MINIX3操作系统架构及启动过程分析
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer--144.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口

我要回帖

更多关于 联通流量卡1元500m 的文章

 

随机推荐