离开以后
众里寻她千百度,那人却在灯火栏栅处。
yayj 发表于 2005-12-02 17:17:10
关于混合轮询
yayj 发表于 2005-11-29 19:33:46
以下内容主要来自Luigi Rizzo(assisstant professor), Dipartimento di Ingegneria dell'Informazione of the Università di Pisa, Italy. 的文章。Luigi实现了FreeBSD中的polling。
---------------------------------------------------------------------------------
正如《操作系统》教科书上所说的,纯粹轮询方式不好(polling is bad)。
FreeBSD中采用的DEVICE_POLLING不是纯粹轮询。当启用DEVICE_POLLING的时候,系统将网络设备的基于中断的处理替换为一 种混合的中断-轮询模式(简称“polling, 轮询”),在启用了轮询的网卡上,在每次时钟tick的等待循环中,以及(可选地,每次)系统调用时,将进行轮询。
此外,FreeBSD中的polling实现还允许精确地分配目态和管态的CPU周期比例。
由于减少了中断发生的次数,这可以节省一些时钟周期(我们知道,在发生中断时需要进行目态/管态,以及上下文的切换)。当网络繁忙时,网卡可以轻易地产生每秒钟数十甚至上百次的中断,并耗尽所有的CPU时间。
当然,更有用的特性(通过采用适当的控制算法)是,混合轮询允许管理员决定使用多大比例的CPU来处理设备操作。这样,即使在网络流量过大的情况下,用户 进程也不会饿死并最终导致“活锁(livelock)”,换言之,由于花费过多时间处理数据包而无法完成那些有用的(处理数据)工作,并最终只能把那些数 据包丢弃。
当然,混合轮询也有一些缺点。因为需要轮询网卡上的数据,因此在响应数据包时,将可能有微小的延迟(不超过1/HZ)。不过这通常并不是问题,在空闲的系 统上,轮询网卡数据将持续地进行,因此几乎没有任何延迟;而当系统忙时,额外的1ms延迟与由于其他处理造成的延迟相比,基本上可以忽略不计。
在繁忙的网络上运行的路由器或服务器上,如果可能发生由于网络流量造成的过载,则应该启用混合轮询。普通的*BSD和Linux都会由于没有启用混合轮询而发生活锁,更糟糕的是,吞吐量迅速下降到一个很低的水平。
此外,对于伪实时[pseudo-real-time]的工作站,也应采用混合轮询,因为这样调度器的行为将更容易预测。
在没有过载的服务器上,混合轮询不会带来明显的性能提升;当负载适中时,将有0-50%的性能提升,而在重负载的环境下,性能提升将比较明显。
---------------------------------------------------------------------------------
由于systm.h中对于DEVICE_POLLING与SMP的互斥限制,DEVICE_POLLING不能与SMP同时启用。但如果把那一行去掉,DEVICE_POLLING也可以在SMP上用(采用1个线程,尽管原则上SMP应该并行地处理中断)。
疑邻盗斧
yayj 发表于 2005-11-08 00:32:37
SystemV ABI笔记(Intel386处理器,第4版)
yayj 发表于 2005-10-29 20:37:36
在结构或联合中,每个成员变量的首地址要与它对应类型的对齐方式相匹配。在
struct {
char c;
short s;
};
这个结构中c和s成员之间就有1个字节的填充区,sizeof的运算结果是4。
结构或联合的对齐字节数是等于成员变量中对齐字节数最大的一个。
union {
char c[3];
short s;
};
这个联合的对齐字节数应该是与short类型一样,sizeof的运算结果是4。
未显式声明为signed的bit域都认为是无符号的,如有char c:3,则cÎ[0,3]。
bit域必须放在它对应类型的字段内,并且这个字段必须是对齐的。在
struct {
short t:9;
short u:9;
};
这个结构中,t和u之间有7bit的填充区。而在
struct {
short s:9;
int i:9;
};
这个结构中,s和i之间就没有填充区。
未命名的bit域不会影响整个结构或联合的对齐字节数,但会影响成员的对齐。
2. 函数调用
栈是按字长(对Intel386来说是4字节)对齐的。参数入栈的时候也要保持栈的对齐,若参数的长度不足4字节或4字节的倍数,则需要在参数的后面添加填充区。
若函数使用了%ebp、%ebx、%edi、%esi和%esp这几个寄存器,则需要把它们保存在自己的栈帧(Stack Frame)后。
几个主要寄存器的意义:
%esp:栈顶指针,它始终指向当前栈顶,并且始终按字长对齐。
%ebp:栈帧指针(stack frame pointer),栈帧是可选的,gcc中可以用-fomit-frame-pointer取消栈帧。
%eax:若函数的返回值是整数(包括char、short等)或者指针时,函数一般用它来保存返回值。若返回值是一个结构或联合,函数会用它来保存结构或联合的地址(可能有编译器优化的问题)。其它时候%eax是可以任意读写的。
%ebx:当把程序编译为与位置无关的代码时,%ebx用来保存全局偏移表的地址;其它时候它只是用来作为函数的局部寄存器。
被调用的函数必须从堆栈中移出返回地址,让%esp恢复到call指令调用前的状态。意即入栈的参数是由调用者来清理的。
关于返回结构或联合的函数。
这个函数的调用者要在自己的栈中为这个返回值预留出空间,并在把所有参数压入堆栈后,再把这个空间的地址压入堆栈,相当于第0个参数。
函数要把返回值复制到地址所指向的对象中。
函数必须在它返回时把这个地址从栈中移出。意即虽然这个地址是由调用者压入堆栈的,但它却是由被调用者清除的。
重载操作符需要注意的地方
yayj 发表于 2005-10-28 10:40:18
- 不能重载以下四个操作符
:: . ?
- 重载以下操作符时需要把重载函数声明为类成员操作符
赋值=、下标[]、调用()、成员访问->
