第一篇:北邮操作系统第二次实验[模版]
北京邮电大学操作系统实验实验报告
班号:2011211314姓名:oneseven学号:
实验日期: 2013.12.16 实验名称: 操作系统实验
一、实验目的
通过模拟实现内存分配的伙伴算法和请求页式存储管理的几种基本页面置换算法,了解存储技术的特点。掌握虚拟存储请求页式存储管理中几种基本页面置换算法的基本思想和实现过程,并比较它们的效率。
二、实验内容
1.实现一个内存管理的伙伴算法,实现内存块申请时的分配和释放后的回收。
实验准备
用随机函数仿真进程进行内存申请,并且以较为随机的次序进行释放。对其碎片进行统计,当申请分配内存失败时区分实际空间不足和由于碎片而不能满足。
2.设计一个虚拟存储区和内存工作区,并使用下述算法计算访问命中率。
1)最佳置换算法(Optimal)
2)先进先出法(Fisrt In First Out)
3)最近最久未使用(Least Recently Used)4)最不经常使用法(Least Frequently Used)
其中,命中率=1-页面失效次数/页地址流长度。试对上述算法的性能加以较各:页面个数和命中率间的关系;同样情况下的命中率比较。
实验准备
本实验中主要的流程:首先用srand()和rand()函数定义和产生指令序列,然后将指令序列变换成相应的页地址流,并针对不同的算法计算出相应的命中率。
实验可先从一个具体的例子出发。
(1)通过随机数产生一个指令序列,共2048条指令。指令的地址按下述原则生成: A:50%的指令是顺序执行的
B:25%的指令是均匀分布在前地址部分 C:25%的指令是均匀分布在后地址部分 具体的实施方法是:
A:在[0,1023]的指令地址之间随机选取一起点m B:顺序执行一条指令,即执行地址为m+1的指令
C:在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m’ D:顺序执行一条指令,其地址为m’+1 E:在后地址[m’+2,2047]中随机选取一条指令并执行 F:重复步骤A-E,直到2048次指令(2)将指令序列变换为页地址流 设:页面大小为4K;
用户内存容量4页到32页; 用户虚存容量为32K。
在用户虚存中,按每K存放64条指令排列虚存地址,即2048条指令在虚存中的存放方式为:
第 0 条-第 63 条指令为第0页(对应虚存地址为[0,63])第64条-第127条指令为第1页(对应虚存地址为[64,127])
………………………………
-1- 第1984条-第2047条指令为第31页(对应虚存地址为[1984,2047])按以上方式,用户指令可组成32页。
以此为基础,给出较为一般的情形:仿真内存容量和虚存容量参数变化时的情形。
3.实现内存的slab分配器:
其基本思想是:一次向内核获取整数页,slab根据数据结构的大小进行划分为一个个小的数据结构,当需要时直接从该链表上摘取一个返回应用程序,当应用程序释放时,而非真正释放,只需要该空间放回到链表中,当分散的一页多块又聚集一页时,又会拼成一页,同时判断slab空闲的页数,如果空闲页超过一定的页数,就会向系统释放一定的页数。一个slab分配器只能管理一个指定大小的数据结构分配。
三、项目要求及分析
3.1实现一个内存管理的伙伴算法,实现内存块申请时的分配和释放后的回收。假设系统的可利用内存空间容量为2m个字(地址从0到2m-1),则在开始运行时,整个内存区是一个大小为2m的空闲块,在运行了一段时间之后,被分隔成若干占用块和空闲块。为了在分配时查找方便起见,我们将所有大小相同的空闲块建于一张子表中。每个子表是一个双重链表,这样的链表可能有m+1个,将这m+1个表头指针用向量结构组织成一个表,这就是伙伴系统中的可利用空间表,如图所示:
分配算法:
当用户提出大小为n的内存请求时,首先在可利用表上寻找结点大小与n相匹配的子表,若此子表非空,则将子表中任意一个结点分配之即可;若此子表为空,则需从结点更大的非空子表中去查找,直至找到一个空闲块,则将其中一部分分配给用户,而将剩余部分插入相应的子表中。
若2k-1 < n ≤ 2k-1,又第k+1个子表不空,则只要删除此链表中第一个结点并分配给用户即可;若 2k-2 < n ≤ 2k-1-1,此时由于结点大小为2k-1 的子表为空,则需从结点大小为2k 的子表中取出一块,将其中一半分配给用户,剩余的一半作为一个新结点插入在结点大小为2k-1的子表中,若2k-i-1 < n ≤ 2k-i-1(i为小于是的整数),并且所有结点小于2k的子表均为空,则同样需从结点大小为2k的子表中取出一块,将其中2k-i的一小部分分配给用户,剩余部分分割成若干个结点分别插入在结点大小为2k-1、2k-
2、…、2k-i的子表中。回收算法:
在用户释放不再使用的占用块时,系统需将这新的空闲块插入到可利用空间表中去。这里,同样有一个地址相邻的空闲块归并成大块的问题。但是在伙伴系统中仅考虑互为“伙伴”的两个空闲块的归并。
何谓“伙伴”?如前所述,在分配时经常需要将一个大的空闲块分裂成两个大小相等的存
-2- 储区,这两个由同一大块分裂出来的小块就称之“互为伙伴”。例如:假设p为大小为pow(2,k)的空闲块的初始地址,且p MOD pow(2,k+1)=0,则初始地址为p和p+pow(2,k)的两个空闲块互为伙伴。在伙伴系统中回收空闲块时,只当其伙伴为空闲块时才归并成大块。也就是说,若有两个空闲块,即使大小相同且地址相邻,但不是由同一大块分裂出来的,也不归并在一起。
由此,在回收空闲块时,应首先判别其伙伴是否为空闲块,若否,则只要将释放的空闲块简单插入在相应子表中即可;若是,则需在相应子表中找到其伙伴并删除之,然后再判别合并后的空闲块的伙伴是否是空闲块。依此重复,直到归并所得空闲块的伙伴不是空闲块时,再插入到相应的子表中去。
3.2.设计一个虚拟存储区和内存工作区,并使用下述算法计算访问命中率。
页式虚拟存储器实现的一个难点是设计页面调度(置换)算法,即将新页面调入内存时,如果内存中所有的物理页都已经分配出去,就要按某种策略来废弃某个页面,将其所占据的物理页释放出来,供新页面使用。页面替换算法主要用于如下几个地方:
(1)虚拟存储器中,主存页面(或程序段)的替换。
(2)Cache中的块替换。
(3)虚拟存储器的快慢表中,快表的替换。
(4)虚拟存储器中,用户基地址寄存器的替换。
在虚拟存储器中常用的页面替换算法有如下几种:
(1)最优替换算法,即OPT算法(OPTimal replacement algorithm)。上面介绍的几种页面替换算法主要是以主存储器中页面调度情况的历史信息为依据的,它假设将来主存储器中的页面调度情况与过去一段时间内主存储器中的页面调度情况是相同的。显然,这种假设不总是正确的。最好的算法应该是选择将来最久不被访问的页面作为被替换的页面,这种替换算法的命中率一定是最高的,它就是最优替换算法。
要实现OPT算法,唯一的办法是让程序先执行一遍,记录下实际的页地址流情况。根据这个页地址流才能找出当前要被替换的页面。显然,这样做是不现实的。因此,OPT算法只是一种理想化的算法,然而,它也是一种很有用的算法。实际上,经常把这种算法用来作为评价其它页面替换算法好坏的标准。在其它条件相同的情况下,哪一种页面替换算法的命中率与OPT算法最接近,那么,它就是一种比较好的页面替换算法。(2)先进先出算法,即FIFO算法(First-In First-Out algorithm)。这种算法选择最先调入主存储器的页面作为被替换的页面。它的优点是比较容易实现,能够利用主存储器中页面调度情况的历史信息,但是,没有反映程序的局部性。因为最先调入主存的页面,很可能也是经常要使用的页面。
(3)最久没有使用算法,即LRU算法(Least Recently Used algorithm)。这种算法把近期最久没有被访问过的页面作为被替换的页面。它把LFU算法中要记录数量上的“多”与“少”简化成判断“有”与“无”,因此,实现起来比较容易。
(4)近期最少使用算法,即LFU算法(Least Frequently Used algorithm)。这种算法选择近期最少访问的页面作为被替换的页面。显然,这是一种非常合理的算法,因为到目前为止最少使用的页面,很可能也是将来最少访问的页面。该算法既充分利用了主存中页面调度情况的历史信息,又正确反映了程序的局部性。但是,这种算法实现起来非常困难,它要为每个页面设置一个很长的计数器,并且要选择一个固定的时钟为每个计数器定时计数。在选择被替换页面时,要从所有计数器中找出一个计数值最大的计数器。因此,通常采用如下一种相 -3- 对比较简单的方法。
3.3实现内存的slab分配器
slab描述符和空闲对象管理部分成为 slab的管理部分,也可以称为slab头
slab的头可以放在slab自身,也可以放在 slab 之外。如果slab头放在了slab 之外,那么用户申请obj时,需要首先访问 slab头,slab头提供未使用free obj的指针
然后再访问这个free obj的地址。完成这项工作需要访问2个页块。会带来效率上的损失。slab头始终位于slab 也存在问题,比如一个页面只有4K,objsize = 2K,那么slab 头在slab 上,就意味着,这个4K的页面只能够分配一个obj。造成了内存的浪费。
如果 页数太少,存放的 obj个数少,那么 增加管理开销,同时 内存使用率低,如果页数太多对伙伴内存系统不好,所以需要一定的策略妥协。
这个妥协过程是有calculate_slab_order 这个函数来实现的。从 0阶(即一页)到kmalloc的最高阶 KMALLOC_MAX_ORDER,挨个尝试,由cache_estimate这个函数计算 如果选用order 阶,那么能分配 多少个 obj(num),剩余空间是多少(remainder)。所谓剩余空间,就是除去slab头(如果有的话),除去 obj*num,剩下的边角料空间是多少。需要分成两种情况去计算,分成两种情况的原因,很快就能看到 A)slab头不在slab上,即 flag & CFLGS_OFF_SLAB == 1的时候 这种情况比较简单,由于管理数据完全不在slab 上,size_tslab_size = PAGE_SIZE < 换句话,slab头的大小取决于obj的个数,obj的个数取决于 slab头的大小,四、具体实现 4.1实现一个内存管理的伙伴算法,实现内存块申请时的分配和释放后的回收。 程序: #include #define MIN_MOMORY_SIZE 536870912 //随机产生的最小内存空间 #define WORKTIME 1500 //系统工作时间 #define MAX_REQ_SIZE 268435456 //申请空闲内存分配的最大容量:256M #define MIN_DUE 30 //使用内存块的最短时间 #define MAX_DUE 90 //使用内存块的最长时间 #define OCCUPY_INTERVAL 60 //每次分配的最大间隔 #define USED 1 //内存块被使用 #define UNUSED 0 //内存块未被使用 //内存块链表结点结构 typedefstructbuddy_node { int flag; //标记空间是否被使用 -4- int base; //本块儿内存的基地址 int occupy; //实际使用空间大小 int fragment; //碎片大小 intduetime; //使用时间 structbuddy_node *nextPtr; //指向下一个结点 } Buddy, *BuddyPtr; IndexTable table[INDEX_SIZE];//使用哈希表管理伙伴系统 int ready = 0; //需要分配内存的时刻 intavailSpace; //可分配空间大小 inttotalFragment = 0; //总碎片大小 //函数:添加结点(形参为内存块结点的信息) void insert_node(inti, intinbase, int f, intocc, int frag, int d){ BuddyPtrnewnodePtr = NULL, prePtr = NULL, curPtr = NULL; newnodePtr =(BuddyPtr)malloc(sizeof(Buddy));//分配结点 newnodePtr->base = inbase;newnodePtr->flag = f;newnodePtr->occupy = occ;newnodePtr->fragment = frag;newnodePtr->duetime = d;newnodePtr->nextPtr = NULL; if(table[i].headPtr == NULL) table[i].headPtr = newnodePtr; else { curPtr = table[i].headPtr;prePtr = NULL; //按地址顺序插入内存块 while(curPtr&&curPtr->base } if(prePtr == NULL){ //插在最前 newnodePtr->nextPtr = curPtr; table[i].headPtr = newnodePtr; } else if(curPtr == NULL){ //插在最后 prePtr->nextPtr = newnodePtr; } else { //插在中间 prePtr->nextPtr = newnodePtr;newnodePtr->nextPtr = curPtr; -5- } } } //函数:删除结点 intdelete_node(inti, BuddyPtrdelPtr){ BuddyPtrprePtr = NULL, curPtr = NULL;intbasehold = delPtr->base; curPtr = table[i].headPtr; while(curPtr!= delPtr){ //寻找要删除的结点的位置 prePtr = curPtr;curPtr = curPtr->nextPtr; } if(prePtr == NULL) //要删除的结点在最前 table[i].headPtr = curPtr->nextPtr; else //要删除的结点不在链表的最前 prePtr->nextPtr = curPtr->nextPtr; free(curPtr); //释放结点 return basehold; //返回删除的内存块结点的基地址 } //函数:伙伴系统的分配算法 void buddy_allocate(inttime_slice){ inti, j, size, due;int state = 0; //分配状态:0为未分配,1为已分配 intinbase, basehold;BuddyPtrcurPtr = NULL; if(ready == time_slice){ //到达分配内存的时刻 printf(“Time %d:”, time_slice); size = 1 + rand()% MAX_REQ_SIZE; //申请使用内存的大小 due = MIN_DUE + rand()%(MAX_DUEsize;curPtr->duetime = due + ready; //修改可系统分配空间和碎片大小 availSpace-= table[i].nodesize;totalFragment += curPtr->fragment; state = 1;//标记已分配 break; } //空闲块的大小刚大于申请大小的2倍 else { basehold = delete_node(i, curPtr);//删除较大的空闲块并保留其基地址 inbase = basehold + table[i].nodesize; j = i; //分割空闲块 do { j--;inbase-= table[j].nodesize; //设置要添加内存块结点的基地址 insert_node(j, inbase, UNUSED, 0, 0, 0);//添加较小的空闲块 printf(“A block cut takes placen”); } while(table[j].nodesize / size > 1); //分配 insert_node(j, basehold, USED, size, table[j].nodesizesize; state = 1;//标记已分配 } } //块被占用,查看下一结点 else curPtr = curPtr->nextPtr; } } } printf(“Allocated %d,Fragment %d,Due %dn”, size, totalFragment, ready+due); -7- } else if((availSpace< size)&&((availSpace + totalFragment)>= size))printf(“Allocation failed because of fragment!n”); else printf(“Allocation failed because of no enough unused space!n”); ready +=(1 + rand()% OCCUPY_INTERVAL);//下次需要分配内存的时刻 } } //函数:伙伴系统的回收算法 void buddy_retrieve(inttime_slice){ inti, basehold, dif;int f = 0;intModnext=0;BuddyPtrcurPtr = NULL, todelPtr = NULL; //依次查找,并回收需要回收的块 for(i = 0;i< INDEX_SIZE;i ++){ if(table[i].headPtr){ curPtr = table[i].headPtr; while(curPtr){ if((curPtr->flag == USED)&&(curPtr->duetime == time_slice)){//需要回收 //修改可系统分配空间和碎片大小 availSpace += table[i].nodesize;totalFragment-= curPtr->fragment; //回收为空闲块 curPtr->flag = UNUSED;curPtr->occupy = 0;curPtr->fragment = 0;curPtr->duetime = 0;printf(“Time %d:Retrieve %d,Fragment %dn”, time_slice, table[i].nodesize, totalFragment); } curPtr = curPtr->nextPtr; } } } //合并空闲块 for(i = 0;i< INDEX_SIZE;i ++){ if(table[i].headPtr){ -8- curPtr = table[i].headPtr; while(curPtr&&curPtr->nextPtr){ //将地址连续且都为空闲的块合并后加入下一级的链表中 if(curPtr->flag == UNUSED &&(curPtr->nextPtr)->flag == UNUSED){ dif =(curPtr->nextPtr)->base-curPtr->base; Modnext =((int)(curPtr->nextPtr->base))%(2*table[i].nodesize); if((dif == table[i].nodesize)&&(Modnext==0)){ //删除两个结点 todelPtr = curPtr;curPtr = curPtr->nextPtr;basehold = delete_node(i, todelPtr);todelPtr = curPtr;curPtr = curPtr->nextPtr;delete_node(i, todelPtr);insert_node(i+1, basehold, UNUSED, 0, 0, 0);//添加合并后的结点 printf(“Two blocks mergen”); } else curPtr = curPtr->nextPtr; } else curPtr = curPtr->nextPtr; } } } } //函数:伙伴系统的处理过程 void buddy_system(void){ inttime_slice = 0; //在每个时间片内使用分配算法和回收算法 for(;time_slice< WORKTIME;time_slice ++){ buddy_allocate(time_slice); //分配算法 buddy_retrieve(time_slice); //回收算法 } } int main(intargc, char *argv[]){ intmemory_size; -9- ini_index(); //初始化哈希索引表 srand(time(NULL)); //设置随机数种子 //随机产生需要管理的内存大小:512M ~ 1G memory_size = MIN_MOMORY_SIZE + rand()% MIN_MOMORY_SIZE;printf(“The size of memory is:%dn”, memory_size); int_system(memory_size); //初始化伙伴系统 buddy_system(); //伙伴系统的处理过程 printf(“Time %d:System execution stops and the spaces are all freed.n”, WORKTIME); free_system(); //释放所有结点 system(“pause”); return 0;} 4.2.设计一个虚拟存储区和内存工作区,并使用下述算法计算访问命中率。程序: #include //虚页长 #define clear_period 50 //清零周期 typedefstruct { intpn; //页号 intpfn; // 面号 int counter; // 一个周期内访问该页面的次数 int time; // time为访问时间 }pl_type;pl_typepl[total_vp];//页面结构数组 structpfc_struct{ //页面控制结构 intpn,pfn;structpfc_struct *next;};typedefstructpfc_structpfc_type; -10- pfc_typepfc[total_vp],*freepf_head,*busypf_head,*busypf_tail;intdiseffect,a[total_instruction];int page[total_instruction], offset[total_instruction];/* Name: void Lprintf(void) Achieve: 格式控制 */ void Lprintf(void){ inti,j;printf(“|”); for(i = 1;i<=6;i++) { for(j = 1;j<=9;j++)printf(“-”); if(i!=6)printf(“+”); } printf(“|n”); } /* Name: void initialize(inttotal_pf) Achieve:初始化相关数据结构 */ void initialize(inttotal_pf){ inti;diseffect=0; for(i=0;i { pl[i].pn=i;pl[i].pfn=INVALID; //置页面控制结构中的页号,页面为空 pl[i].counter=0;pl[i].time=-1;//页面控制结构中的访问次数为0,时间为-1 } for(i=1;i { pfc[i-1 ].next=&pfc[i];pfc[i-1].pfn=i-1;//建立pfc[i-1]和pfc[i]之间的连接 } pfc[total_pf-1].next=NUL;pfc[total_pf-1].pfn=total_pf-1; freepf_head=&pfc[0]; //页面队列的头指针为pfc[0] } /* -11- Name:void FIFO(inttotal_pf) Achieve:先进先出法(Fisrt In First Out)*/ void FIFO(inttotal_pf){ inti,j;pfc_type *p;//中间变量 initialize(total_pf);//初始化相关页面控制用数据结构 busypf_head=busypf_tail=NULL;//忙页面队列头,队列尾链接 for(i=0;i if(pl[page[i]].pfn==INVALID) //页面失效 { diseffect+=1;//失效次数 if(freepf_head==NULL)//无空闲页面 { p=busypf_head->next; pl[busypf_head->pn].pfn=INVALID; freepf_head=busypf_head;//释放忙页面队列的第一个页面 freepf_head->next=NULL;//表明还是缺页*/ busypf_head=p; } p=freepf_head->next; freepf_head->pn=page[i]; pl[page[i]].pfn=freepf_head->pfn; freepf_head->next=NULL;//使busy的尾为null if(busypf_tail==NULL) { busypf_tail=busypf_head=freepf_head; } else { busypf_tail->next=freepf_head; busypf_tail=freepf_head; } freepf_head=p; } } printf(“%6.3f”,1-(float)diseffect/320);} /* Name: void LRU(inttotal_pf) Achieve: 最近最久未使用(Least Recently Used)*/ -12- void LRU(inttotal_pf){ intmin,minj,i,j,present_time;//minj为最小值下标 initialize(total_pf);present_time=0;for(i=0;i if(pl[page[i]].pfn==INVALID)//页面失效 { diseffect++; if(freepf_head==NULL)//无空闲页面 { min=32767;//设置最大值 for(j=0;j { if(min>pl[j].time&&pl[j].pfn!=INVALID) { min=pl[j].time; minj=j; } } freepf_head=&pfc[pl[minj].pfn]; //空出一个单元 pl[minj].pfn=INVALID; pl[minj].time=0; freepf_head->next=NULL; } pl[page[i]].pfn=freepf_head->pfn;//有空闲页面,改为有效 pl[page[i]].time=present_time; freepf_head=freepf_head->next;//减少一个free 页面 } else { pl[page[i]].time=present_time;//命中则增加该单元的访问次数 present_time++; } } printf(“%6.3f”,1-(float)diseffect/320);} /* Name:void OPT(inttotal_pf) Achieve:最佳置换算法(Optimal)*/ void OPT(inttotal_pf){ -13- inti,j, max,maxpage,d,dist[total_vp];pfc_type *t;initialize(total_pf);for(i=0;i if(pl[page[i]].pfn==INVALID) /*页面失效*/ { diseffect++; if(freepf_head==NULL) /*无空闲页面*/ { for(j=0;j { if(pl[j].pfn!=INVALID) dist[j]=32767; else dist[j]=0; } for(j=0;j { if((pl[j].pfn!=INVALID)&&(dist[j]==32767)) { dist[j]=j; } } max=0; for(j=0;j if(max { max=dist[j]; maxpage=j; } freepf_head=&pfc[pl[maxpage].pfn]; freepf_head->next=NULL; pl[maxpage].pfn=INVALID; } pl[page[i]].pfn=freepf_head->pfn; freepf_head=freepf_head->next; } } printf(“%6.3f”,1-(float)diseffect/320);} /* Name: vodi LFU(inttotal_pf) Achieve:最不经常使用法(Least Frequently Used) -14- */ void LFU(inttotal_pf) { inti,j,min,minpage;pfc_type *t;initialize(total_pf);for(i=0;i if(pl[page[i]].pfn==INVALID)//页面失效 { diseffect++; if(freepf_head==NULL)//无空闲页面 { min=32767; //获取counter的使用用频率最小的内存 for(j=0;j { if(min>pl[j].counter&&pl[j].pfn!=INVALID) { min=pl[j].counter; minpage=j; } } freepf_head=&pfc[pl[minpage].pfn]; pl[minpage].pfn=INVALID; pl[minpage].counter=0; freepf_head->next=NULL; } pl[page[i]].pfn=freepf_head->pfn;//有空闲页面,改为有效 pl[page[i]].counter++; freepf_head=freepf_head->next;//减少一个free 页面 } else { pl[page[i]].counter; pl[page[i]].counter=pl[page[i]].counter+1; } } printf(“%6.3f”,1-(float)diseffect/320);} int main(int){ intS,i; -15- srand((int)getpid()); for(i=0;i { S=(int)rand()%320; a[i]=S; //任选一指令访问点 a[i+1]=a[i]+1;//顺序执行一条指令 a[i+2]=(int)rand()%a[i+1];//执行前地址指令m' a[i+3]=a[i+2]+1;//顺序执行一条指令 a[i+4]=(int)rand()%(319-a[i+2]-1)+a[i+2]+2;//执行后地址指令 } for(i=0;i { page[i]=a[i]/10; offset[i]=a[i]%10;} printf(“FrametOPTtFIFOtLRUtLFU n”);for(i=4;i<=32;i++)//用户内存工作区从4个页面到32个页面 { printf(“%dt”,i);OPT(i);printf(“t”); FIFO(i);printf(“t”); LRU(i); printf(“t”); LFU(i); printf(“n”);} system(“pause”);return 0;} 4.3 实现内存的slab分配器 程序: #include -17- } 五、调试运行结果 -18- 5.1 实现一个内存管理的伙伴算法 5.2设计一个虚拟存储区和内存工作区,并使用下述算法计算访问命中率。 -19- 5.3 实现内存的slab分配器 六、所遇问题及解决方法 1.在写第一个程序的时候,对树的合并在之前的学习中,有比较多的学习,数据结构中此程序有详细的介绍,因此在编写这个程序的时候,比较顺利的完成了要求。但要求中需要产生一些随机的数据,重新对随机仿真函数进行回顾,最后较为顺利的完成了程序。2.第二个程序,要求随机产生一些数据,对srand()和rand()函数定义和产生指令序列,在进一步的学习中,完成了这些函数,仿真内存容量和虚存容量参数变化时的情形,对此不太熟悉,四个算法对要求较高,在完成算法的学习后,完成了程序。 3.第三个程序因不太理解其要求,上网搜寻了一些代码,但对其最后的结果依然没有得出,为此询问了同学,但不知是否正确。 -20- 微波仿真实验报告 学 院:电子工程学院 班 级 学 号: 姓 名: 班内序号: 微波仿真课作业1 1.了解ADS Schematic的使用和设置 2.在Schematic里,分别仿真理想电容20pF和理想电感5nH,仿真频率为(1Hz-100GHz),观察仿真结果,并分析原因。20pF理想电容 仿真图 原因分析:史密斯原图下半部分是容性,随频率增加,电容由开路点变到短路点,通高频,阻低频。5nH理想电感 仿真图 原因分析:史密斯原图上半部分是感性,随频率增加,电容由短路点变到开路点,阻高频,通低频。 3. Linecalc的使用 a)计算中心频率1GHz时,FR4基片的50Ω微带线的宽度 宽度为:2.9112mm b)计算中心频率1GHz时,FR4基片的50Ω共面波导(CPW)的横截面尺寸(中心信号线宽度与接地板之间的距离) 横截面尺寸为:W=171.355mm,G=5mm,L=63.5mm 4.基于FR4基板,仿真一段特性阻抗为50Ω四分之一波长开路CPW线的性能参数,中心工作频率为1GHz。仿真频段(500MHz-3GHz),观察Smith圆图变化,分析原因。 仿真图 仿真图分析: 1、1GHz时,为四分之一波长,开路阻抗变换后变为短路,2GHz时为二分之一波长,所以仍为开路; 2、由于损耗,因此反射系数变小,所以等反射系数圆的半径也在变小。 5.基于FR4基板,仿真一段特性阻抗为50Ω四分之一波长短路CPW线的性能参数,中心工作频率为1GHz。仿真频段(500MHz-3GHz),观察Smith圆图变化,分别求出500MHz和2GHz的输入阻抗,分析变化原因。 仿真图 仿真图分析: 1、1GHz时,为四分之一波长,短路阻抗变换后变为开路,2GHz时为二分之一波长,所以仍为短路; 2、由于损耗,因此反射系数变小,所以等反射系数圆的半径也在变小。分别求出500MHz和2GHz的输入阻抗: 500MHz:Z0*(0.003+j0.001)2GHz:Z0*(0.012-j0.005) 6.分别用理想传输线和在FR4基片上的微带传输线,仿真一段特性阻抗为50Ω四分之一波长开路线的性能参数,工作频率为1GHz。仿真频段(500MHz-3GHz),观察Smith圆图变化,分别求出500MHz和2GHz的输入阻抗,分析变化原因。 仿真图 分别求出500MHz和2GHz的输入阻抗: 微带线 500MHz:Z0*(0.003-j0.992)2GHz:Z0*(32.830-j1.603)理想传输线 500MHz:Z0*(1.000E-10-j1.000)2GHz:Z0*(2.000E10-j2.000E5) 分析:因为相对于理想传输线,微带线有损耗产生误差,反射系数一直变小。 扩展仿真频率(500MHz-50GHz),分析曲线变化原因。 分析:对于理想传输线,反射系数不变,而对于微带线,由于存在损耗,反射系数会一直变小,因此其反射系数圆的半径在一直变小。 7.分别用理想传输线和在FR4基片上的微带传输线,仿真一段特性阻抗为50Ω四分之一波长短路线的性能参数,工作频率为1GHz。仿真频段(500MHz-3GHz),观察Smith圆图变化,分别求出500MHz和2GHz的输入阻抗,分析变化原因。 仿真图 分别求出500MHz和2GHz的输入阻抗: 微带线 500MHz:Z0*(0.009+j1.003)2GHz:Z0*(0.031+j0.002)理想传输线 500MHz:Z0*(5.551E-17+j1.000)2GHz:Z0*(8.284E-18-j1.000E-5) 分析:因为相对于理想传输线,微带线有损耗产生误差,反射系数一直变小。 扩展仿真频率(500MHz-50GHz),分析曲线变化原因。 分析:对于理想传输线,反射系数不变,而对于微带线,由于存在损耗,反射系数会一直变小,因此其反射系数圆的半径在一直变小。 8.分别用理想传输线和在FR4基片上的微带传输线,仿真一段特性阻抗为50Ω二分之一波长开路线的性能参数,工作频率为1GHz。仿真频段(500MHz-3GHz),观察Smith圆图变化,分别求出500MHz和2GHz的输入阻抗,分析变化原因。 仿真图 分别求出500MHz和2GHz的输入阻抗: 微带线 500MHz:Z0*(0.016+j0.006)2GHz:Z0*(16.430-j0.798)理想传输线 500MHz:Z0*(5.000E-11-j6.123E-17)2GHz:Z0*(2.000E10-j2.000E5) 分析:因为相对于理想传输线,微带线有损耗产生误差,反射系数一直变小。扩展仿真频率(500MHz-50GHz),分析曲线变化原因。 分析:对于理想传输线,反射系数不变,而对于微带线,由于存在损耗,反射系数会一直变小,因此其反射系数圆的半径在一直变小。 9.分别用理想传输线和在FR4基片上的微带传输线,仿真一段特性阻抗为50Ω二分之一波长短路线的性能参数,工作频率为1GHz。仿真频段(500MHz-3GHz),观察Smith圆图变化,分别求出500MHz和2GHz的输入阻抗,分析变化原因。 仿真图 分别求出500MHz和2GHz的输入阻抗: 微带线 500MHz:Z0*(55.044-j19.301)2GHz:Z0*(0.061+j0.004)理想传输线 500MHz:Z0*(-1.000+j1.633E16)2GHz:Z0*(8.284E-18-j1.000E-5) 分析:因为相对于理想传输线,微带线有损耗产生误差,反射系数一直变小。 扩展仿真频率(500MHz-50GHz),分析曲线变化原因。 分析:对于理想传输线,反射系数不变,而对于微带线,由于存在损耗,反射系数会一直变小,因此其反射系数圆的半径在一直变小。微波测量实验中测得的几个史密斯圆图 四分之一开路微带线 四分之一短路微带线 二分之一开路微带线 二分之一短路微带线 微波仿真课作业2 1. 用一段理想四分之一波长阻抗变换器匹配10欧姆到50欧姆,仿真S参数,给出-20dB带宽特性,工作频率为1GHz。计算得,22.36欧姆 仿真S参数 计算分析:由图计算-20dB带宽为 1071-929=142MHz;且如仿真图所示,在1GHz处回波损耗最低,实现阻抗匹配。2. 用一段FR4基片上四分之一波长阻抗变换器匹配10欧姆到50欧姆,仿真S参数,给出-20dB带宽特性,工作频率为1GHz,比较分析题1和题2的结果。 仿真S参数 由图计算-20dB带宽为1065-921=144MHz。 比较分析题1和题2的结果 分析,微带线与理想传输线之间有一定的误差: 1、如图所示可以看出微带线情况下,回波损耗最低点稍微偏离1GHz; 2、-20dB带宽为144MHz大于理想传输线时的142MHz; 3、1GHz阻抗匹配时,微带线时的回波损耗大于理想传输线。 3. 设计一个3节二项式匹配变换器,用于匹配10欧姆到50欧姆的传输线,中心频率是1GHz,该电路在FR4基片上用微带线实现,设计这个匹配变换器并计算 m0.1的带宽,给出回波损耗和插入损耗与频率的关系曲线,比较分析题2和题3的结果。 根据所学的理论知识,先依题意算出三节匹配微带线的阻抗值,然后通过LineCalc计算出相应微带线的长和宽,修改电路图中MLIN的相关参数。 Z1=40.89Ω W=4.198480mm L=40.404500mm Z2=22.36Ω W=9.620970mm L=38.833700mm Z3=12.23Ω W=19.83080mm L=37.648400mm 插入损耗 m0.1的带宽,即为-20dB带宽,由图计算得1325-680=645MHz; 比较分析题2和题3的结果,3节二项式匹配变换器匹配误差更大: 1、如图所示可以看出3节二项式匹配变换器匹配时回波损耗最低点明显偏离1GHz; 2、-20dB带宽为645MHz大于微带线情况; 3、但1GHz阻抗匹配时,3节二项式匹配变换器时的回波损耗小于微带线情况。 4. 题3中,若用3节切比雪夫匹配变换器实现,比较同样情况下的带宽,回波损耗和插入损耗与频率的关系曲线,比较分析题3和题4结果。 根据所学的知识可以计算出切比雪夫变换器匹配的三个微带线的阻抗,然后通过LineCalc计算出相应微带线的长和宽,修改电路图中MLIN的相关参数。Z1=35.94Ω W=4.948710mm L=40.0910mm Z2=22.11Ω W=9.6519mm L=38.8278mm Z3=13.55Ω W=17.57710mm L=37.8241mm 仿真图 插入损耗 m0.1的带宽,即为-20dB带宽,由图计算得1485-534=951MHz; 比较分析题3和题4的结果,即二项式匹配变换器与切比雪夫匹配变换器: 1、切比雪夫匹配变换器的带宽显著增加; 2、切比雪夫匹配变换器回波损耗具有等波纹特性; 3、两者的插入损耗差别不明显。 5. 对于一个负载阻抗ZL=60-j80欧姆,利用Smith Chart Utility功能,分别设计并联短路单枝节和并联开路单枝节匹配,并将Smith Chart Utility给出的匹配结果在Schematic中仿真,给出1-3GHz的回波损耗与频率的关系曲线,并给出m0.1的带宽。并联短路单枝节 计算并联短路单枝节-20dB带宽:1053-952=101MHz 并联开路单枝节 计算并联开路单枝节-20dB带宽:1023-975=48MHz 6. 并联双枝节匹配电路,并联双枝节为开路,枝节之间相距λ/8,中心工作频率为2GHz,利用理想传输线,给出1-3GHz的回波损耗与频率的关系曲线,并给出m0.1的带宽。并联双枝节, 枝节之间相距λ/8,中心工作频率为2GHz 仿真 如图在2GHz匹配 计算-20dB带宽:2012-1988=24MHz 操作系统实验 实验一 Linux常用命令实验 一.目的和要求 本实验的目的是熟悉Linux操作系统的命令接口、图形接口和程序接口;了解Linux操作系统的启动过程;了解Linux操作系统的目录结构;用vi编辑器编写简单的C语言程序,并用gcc编译器编译、运行。 二.实验内容 1、实现开机、登录、退出与关机: (1)如果以root用户登录,则命令窗口的提示符为#;如果以普通用户登录,则命令窗口的提示符为$;登陆用户名:user 密码:123456(2)修改口令(修改口令操作不做):成功进入系统后,在命令提示符后输入“passwd”并键入回车键 (3)退出帐号:命令方式下:logout(4)关机或重启: 命令方式下:halt或reboot 窗口方式下:“桌面”->“注销” 2、掌握的基本常用命令列表 (1)关于目录的操作命令:cd、ls、mkdir、rmdir、pwd等; (2)关于文件的操作命令:cat、find、man/help、vi/vim、cp、rm、mv、dd、du、df、chmod、ln等; (3)关于进程管理的操作命令:ps、kill、top、free 等; (4)关于系统管理的操作命令:whoami、passwd、adduser/useradd、addgroup、userdel、groupdel、su、who、Ctrl+Alt+Fn(n=1、2、3、4、5、6)(在X-Window界面下切换到字符界面,重新登录,Ctrl+Alt+F7返回图形界面)、Alt+Fn(n=1、2、3、4、5、6)(在6个虚拟终端之间切换)等; (5)安装和卸载文件系统:mount、umount等; (6)显示有关计算机系统信息的命令:uname(显示操作系统的名称)、uname –n(显示系统域名)、uname –p(显示系统的CPU名称) (7)其它命令:time、date、cal 等。 3、阅读/etc/inittab 文本文件,思考问题:如果要求启动Linux系统之后进入字符 1 操作系统实验 界面,应如何修改/etc/inittab文件?用户应具有什么权限? 4、切换到不同的虚拟终端,登录到Linux系统 5、vi 编辑器的使用(1)进入和退出vi(2)利用文本插入方式建立一个文件(3)在新建的文本文件上移动光标。 (4)对文本文件执行删除、复原、修改、替换操作。 6、熟悉gcc编译环境:编写一个C语言程序myfile1.c,求1~100中偶数的和,编译并运行。 (1)编译 gcc myfile1.c 运行./a.out(2)编译 gcc –o myfile1 myfile1.c 运行./myfile1 7、编写一个C语言程序myfile2.c,显示字符串“Hello, Linux!”,并将其反向输出。 8、熟悉Linux系统的目录结构,使用命令或者编写C语言程序报告Linux内核的行为。 报告以下内容: CPU类型和型号 内核版本 从系统最后一次启动以来经历了多长时间?形式为dd:hh:mm:ss 当前配置的内存数量 当前可用内存数量 自系统启动以来,发生的所有的中断的次数 从系统启动开始创建的进程数 内核执行的上下文转换的次数 三.实验提示 1、Linux安装 (1)安装前的准备工作 <1>.基本的硬件配置 由于安装涉及到各种硬件的设置,所以在安装前必须了解机器各种硬件的型号,硬盘的使用情况,内存的大小,鼠标的类型及接口,声卡,网卡,显卡,显示器的型号。 操作系统实验 <2>.有关网络的信息 IP地址,掩码,网关IP地址,域名服务器IP地址,域名,宿主机名。<3>.安装方式的选择 •从CD-ROM安装 •从FTP站点安装 •从NFS服务器安装 •从硬盘安装 硬盘分区 硬盘空间必须和计算机上安装的其他操作系统所使用的硬盘空间分开。特别要注意,如果硬盘空间很大,切忌不能将Linux装在8G以后。安装Red Hat Linux至少需要两个硬盘分区:一个或多个“Linux native”类型的分区,一个“Linux swap”类型的分区 分区命名设计Linux 通过字母和数字的组合来表示硬盘分区。 前两个字母-----分区名的前两个字母表明分区所在设备的类型。hd指IDE硬盘,sd指SCSI硬盘。 下一个字母-----分区在哪个设备。例如,/dev/hda(第一个IDE硬盘),/dev/sdb(第二个SCSI硬盘)。 数字-----代表分区。前四个分区(主分区或扩展分区)用数字1到4表示。逻辑分区从5开始。例如, 若IDE硬盘在安装Linux前安装了Windows系统并划分了C盘和逻辑分区D盘,那么D盘就是/dev/hda5, /dev/hda5表示第一个硬盘的第一个逻辑分区。 对于Linux初学者来说,为Linux分两个区(根分区和交换分区)是比较简单方便的。 一个交换分区:用来支持虚拟内存。一个根分区:根分区是/(根目录)的所在地,其中包含启动系统所需的文件和系统配置文件。这个分区要足够大。 一个/usr分区: /usr是Linux系统许多软件所在的地方。一个/home分区:这是用户的主目录所在地。(2)开始安装 注意点:我们一般选择的是图形化的安装方式。它的主要部分是相同的。 可能会在安装完成后第一次启动时才进行网卡的检测。 操作系统实验 在选择图形化界面时,有两种方式gnome和kde;它们各有优缺点。 系统会让你选择启动时是图形化方式,还是字符方式。请大家选择字符方式。 在选择防火墙的时候,在安装时请先不用防火墙。 图形化安装方式下,不能选择启动时的开启服务。可在系统安装完成后用setup命令进行修改。 2、进入Linux(1)登录 第一次登录系统,必须作为“root”登录。这个帐号对系统的一切都有完全的访问权限。 在login:提示符处输入root。按[Enter](或[Return]键).会出现Password提示。输入口令,应该看到类似以下的信息: [root@localhost /root] #(2)退出 输入[Ctrl]-[D](3)帐号和口令 <1>.帐号 创建新的帐号有几种方法,最基本的方法:useradd命令.[root @ localhost / root] # useradd Tom [root @ localhost / root] # <2>.口令 passwd 命令可以用来: 为新创建的用户分配口令。 修改已存在的用户的口令。 修改登录的用户的口令。此时必须以root登录。如: [root @ localhost / root]# passwd Tom New UNIX password: Retype new UNIX password: passwd:all authentication tokens updated successfully 4 操作系统实验 [root @ localhost / root]# 用新帐户登录: Red Hat Linux release 7.1(Manhattan) Kernel 2.0.34 on an i586 login: Tom Password: [Tom@ localhost Tom] $ <3>.su 命令 用su,当前的登录段能变成root(或其他用户)的登录段。如: [Tom@ localhost Tom] $ su Password: [root@ localhost Tom] # 也可以用su变成其他用户。这时,必须作为root运行su,给出用户名。<4>.关闭系统 关闭系统时,必须告诉所有的进程结束运行,使用shutdown命令。且只能由root 运行,格式是: shutdown -h-------在关闭完成后(Halt)停止系统。 -r--------在关闭完成后重启动(Reboot)系统。 3、vi 编辑器的使用(1)进入和退出vi <1>进入vi 在系统提示符($)下输入命令vi和想要编辑(建立)的文件名(如example),便可进入vi。 <2>退出vi 在命令方式下可有几种方法退出vi编辑器: :wq 把编辑缓冲区的内容写到正在编辑的文件中,退出编辑器,回到Linux shell下。 :ZZ 仅当作过修改时才将缓冲区内容写到文件上。 操作系统实验 :x 与 :ZZ 相同。 :q!强行退出vi。感叹号(!)告诉vi,无条件退出,丢弃缓冲区内容。这样,先前对该文件所做的修改或输入都被抛弃。(2)新建文件 <1>在Linux提示符$之后,输入命令 :vi myfile,然后按〈Enter〉键。<2>输入插入命令i(屏幕上看不到字符i)。<3>然后,输入以下文本行: To the only book tht I, For mang year you have been my favourite book <4>发现这两行有错,进行改正: 按〈Esc〉键,从插入方式回到命令方式。按光标上移键,使光标移到第一行。 按光标左移键,使光标移到“tht”的第二个“t”处。 输入i(这是插入命令),然后输入a。该行变成如下形式: To the only book that I, 按光标右移键,使光标移到“I”上。 我们想在“I”之后输入一个空格和单词“like”。为此,输入附加命令“a”。结果屏幕显示为: To the only book that a I,没有出现预期的效果......原来是:我们先前使用了插入命令i,至今并未用〈Esc〉键返回命令方式。所以,输入的所有字符都作为输入文本予以显示。<5>按〈Esc〉键,返回命令方式。 利用x命令删除错误字符。然后,进入插入方式,输入正确字符。<6>最后输入如下所示的文本: To the only book that I like, For many year you have been my favourite book I liveeyou all the time and could not have picked much better.<7>将编辑的文本文件存盘。(利用“:wq”命令,或者“:x”命令)<8>重新进入vi编辑程序,编辑上面的文件。(如:$ vi myfile) 操作系统实验 <9>在屏幕上见到myfile文件的内容。在屏幕底边一行显示出该文件的名称、行数和字符个数:“myfile”4 lines,130 characters 它仍然有错,需进一步修改。 <10>将光标移到第二行的year的r处。输入a命令,添加字符s。 <11>按〈Esc〉,回到命令方式。输入命令10〈Space〉,光标移至何处?---光标右移10个字符位置。 <12>利用取代命令r将liveeyou改为live you。 <13>将光标移至第三行。输入新行命令O(大写字母),屏幕上有什么变化?---光标移至上一行(新加空行)的开头。<14>输入新行的内容: We've been through much together 此时,vi处于哪种工作方式? <15>按〈Esc〉,回到命令方式。将光标移到第四行的live的v字母处。利用替换命令s将v改为k。 <16>在第四行的you之后添加单词very much。<17>修改后的文本是以下内容: To the only book that I like, For many years you have been my favourite book We've been through much together I like you very much all the the time and could not have picked much better.将该文件存盘,退出vi。 <18>重新编辑该文件。并将光标移到最后一行的have的v字母处,使用d$命令将v至行尾的字符都删除。 <19>现在想恢复17步的原状,怎么办?(使用复原命令u) <20>使用dd命令删除第一行;将光标移至through的u字母处,使用C(大写字母)命令进行修改,随便输入一串字符。将光标移到下一行的开头,执行5x命令;然后执行重复命令(.)。 <21>屏幕内容乱了!现在想恢复17步的原状,怎么办?(不写盘,强行退出vi) 4、Linux内核 操作系统实验 Linux 内核源程序目录结构(/usr/src/redhat/SOURCES)如下: /document :保存帮助文档 /arch :包含多个子目录,每个存放与特定体系结构相关的代码。如arch/i386(intel 386 体系结构),arch/sparc,arch/alpha等。每个子目录下至少又包含三个子目录: kernel(存放支持该体系结构特有的诸如信号处理和SMP之类特征的实现); lib(存放该体系结构特有的诸如Strlen和memcpy之类的高效率函数); mm(存放该体系结构特有的诸如内存管理程序的实现) /drivers :该目录占内核代码一半以上,包括显卡、网卡、SCSI适配器、软驱、PCI设备和其他外设的软件驱动程序。/fs:包含linux支持的文件系统。 /include :包含源程序中大部分包含(.h)文件。/init: 包含main.c,保存大部分协调内核初始化的代码。/ipc:实现了SYSTEM V的进程间通讯IPC。 /kernel:包含了linux最重要的部分:实现平台独立的基本功能,包括Sched.c、fork.c、exit.c。 /lib :存放字符串和内存操作函数。 /mm:包含与体系结构无关的内存管理代码。/net:包含了linux应用的网络协议代码。/script :包含用来配置内核的脚本。 5、报告Linux状态(/proc 中的信息) 在终端窗口提示符下,可以使用cat命令显示相关文件的内容,如: cat /proc/cpuinfo 通过编写程序,显示相关文件内容:应用文件操作,将相关 /proc中的文件读入到缓冲区中,可用fgets()函数按行取文件中数据,通过strstr()检验包含所需数据字符串。如存在,用printf()函数输出。(1)CPU类型和型号 /proc/cpuinfo文件提供了有关CPU的多种信息,这些信息是从内核里对CPU的测试代码中得到的。文件列出了CPU个数:processor;CPU制造商:vendor_id;CPU架构:model;CPU名称:model name;CPU时钟频率:cpu MHz;CPU缓存大小: 8 操作系统实验 cache size;CPU包含的指令集:flags。文件还包含了以bogomips表示的处理机速度,而且如果检测到CPU的多种特性或bug,文件还会包含相应的标志。该文件的格式为:文件由多行构成,每行包括一个域名称、一个冒号和一个值。 通过fopen()函数打开包含CPU类型和型号的文件cpuinfo,把内容读入字符数组char_all,然后通过strstr()函数查找CPU类型和型号所在的位置,用strncpy()函数拷贝到字符数组中,通过printf()标准输出函数输出。(2)存储器信息 /proc/meminfo 文件给出了内存状态的信息。它显示出系统中物理内存的总量:MenTotal;未使用的物理内存的总量:MemFree;用做文件缓冲的物理内存的总量:buffers;用做缓冲的物理内存的总量:Cached;活跃的内存大小:Active;不活跃的内存大小:Inactive;交换分区的总量:SwapTotal;交换分区未使用的总量:SwapFree等信息。(3)内核版本 文件/proc/version显示了正在运行的内核版本、编译此内核的gcc版本以及该内核的编译时间。 (4)从系统最后一次启动以来的时间,形式为dd:hh:mm:ss uptime读出的时间是以秒计的,所以根据要求要转换为天:小时:分钟:秒。1天为86400秒,1小时为3600秒,1分钟为60秒。通过两个运算符就可以很好的转换:“/”做除法取整运算,“%”做除法取余运算。举例:86800秒,(86800/86400)=1(天),(86800%86400)=400(余400秒);400秒,(400/3600)=0小时,(400%3600)=400(余400秒);400秒,(400/60)=6分钟,(400%60)=40(余40秒)。所以最后结果为:1:0:6:40。(5)其他信息的读取 从/proc/stat中读取信息 CPU花费在用户态、系统态和空闲态的时间——cpu 自系统启动以来,发生的所有的中断的次数——intr 内核执行的上下文转换的次数----ctxt 系统最后启动的时间----btime 从系统启动开始创建的进程数----processes 6、Linux的目录结构 操作系统实验 对于Linux来讲它的树型结构与Windows不同,Windows可以有多个分区,每个分区都有根,但Linux 只有一个根,其他的所有文件、目录或硬盘分区、软盘、光盘、U 盘都必须mount(挂载)到Linux 根下的一个目录中才能被访问和使用。下面列出根目录下的常见系统目录及其用途。 /bin bin是binary的缩写。这个目录沿袭了UNIX系统的结构,存放着使用者最经常使用的命令。例如cp、ls、cat,等等。 /boot 这里存放的是启动Linux时使用的一些核心文件。 /dev dev是device(设备)的缩写。这个目录下是所有Linux的外部设备,其功能类似DOS下的.sys和Win下的.vxd。在Linux中设备和文件是用同种方法访问的。例如:/dev/hda代表第一个物理IDE硬盘。 /etc 这个目录用来存放系统管理所需要的配置文件(例如配置文件inittab)和子目录。 /home 用户的主目录,比如说有个用户叫wang,那他的主目录就是/home/wang,也可以用~wang表示。 /lib 这个目录里存放着系统最基本的动态链接共享库,其作用类似于Windows里的.dll文件。几乎所有的应用程序都需要用到这些共享库。 /lost+found 这个目录平时是空的,当系统不正常关机后,这里就成了一些无家可归的文件的避难所,有点类似于DOS下的.chk文件。 /media 用来挂载光盘、U盘等文件系统的目录。/misc 用来挂载NFS 共享目录。 /mnt 用于挂载其他硬盘分区系统的目录(如挂载xp分区)。 /opt 某些第三方软件商软件的安装地点,如国产红旗office就存放于此。/proc 这个目录是一个虚拟的目录,它是系统内存的映射,可以通过直接访问这个目录来获取系统信息。也就是说,这个目录的内容不在硬盘上而是在内存里。 /root 系统管理员(也叫超级用户)的主目录。作为系统的拥有者,总要有些特权,比如单独拥有一个目录。 /sbin s就是Super User的意思,也就是说这里存放的是系统管理员使用的管理程序。 /tmp 这个目录是用来存放一些临时文件的地方。 /usr 这是最庞大的目录,要用到的应用程序和文件几乎都存放在这个目录 10 操作系统实验 下。其中包含以下子目录: /usr/X11R6 存放X-Window的目录; /usr/bin 存放着许多应用程序; /usr/sbin 给超级用户使用的一些管理程序就放在这里; /usr/include Linux下开发和编译应用程序需要的头文件,在这里查找; /usr/lib 存放一些常用的动态链接共享库和静态档案库; /usr/local 这是提供给一般用户的/usr目录,在这里安装软件最适合; /usr/src Linux开放的源代码就存在这个目录。 /var 这个目录中存放着那些不断在扩充着的东西,为了保持usr的相对稳定,那些经常被修改的目录可以放在这个目录下,实际上许多系统管理员都是这样做的。另外,系统的日志文件就在/var/log目录中。 我们一般日常能经常访问的目录有/home 目录、/mnt目录、/media 目录、/usr 目录。 操作系统实验总结 学号: 姓名: 班级: 在本学期的计算机操作系统这门课学习当中,为了更好的了解操作系统相关知识,我们通过OS Lab平台做了几个实验。在实验室的过程中,我对课堂上学到的操作系统的一些知识有了新的认识,同时还接触到了操作系统的相关源代码,而且通过实验的运行效果了解了平时我们看不到的操作系统的一些状况,收获还是很大的。下面先简要归纳在实验课上我做的几个实验的主要实验内容和实验步骤: 实验一:实验环境的使用 实验步骤: 1.1启动OS Lab OS Lab每次启动后都会首先弹出一个用于注册用户信息的对话框(可以选择对话框标题栏上的“帮助”按钮获得关于此对话框的帮助信息)。在此对话框中填入学号和姓名后,点击“确定”按钮完成本次注册。观察OS Lab主窗口的布局。OS Lab主要由下面的若干元素组成:菜单栏、工具栏以及停靠在左侧和底部的各种工具窗口,余下的区域用来放置编辑器窗口。 1.2 学习OS Lab的基本使用方法 练习使用OS Lab编写一个Windows控制台应用程序,熟悉OS Lab的基本使用方法(主要包括新建项目、生成项目、调试项目等)。 实验二:操作系统的启动 实验步骤: 2.1 准备实验 启动OS Lab,新建一个EOS Kernel项目,在“项目管理器”窗口中打开boot文件夹中的boot.asm和loader.asm两个汇编文件,按F7生成项目,生成完成后,使用Windows资源管理器打开项目文件夹中的Debug文件夹。找到由boot.asm生成的软盘引导扇区程序boot.bin文件,找到由loader.asm生成的loader程序loader.bin文件,记录下此文件的大小1566字节。 2.2 调试EOS操作系统的启动过程 2.2.1 使用Bochs做为远程目标机 将调试时使用的远程目标机修改为Bochs 2.2.2 调试BIOS程序 按F5启动调试,Bochs在CPU要执行的第一条指令(即BIOS的第一条指令)处中断,从Console窗口显示的内容中,我们可以获得关于BIOS第一条指令的相关信息,然后查看CPU在没有执行任何指令之前主要寄存器中的数据,以及内存中的数据。 2.2.3 调试软盘引导扇区程序 练习从0x7c00处调试软盘引导扇区程序;查看boot.lst文件;调试过程——软盘引导扇区程序的主要任务就是将软盘中的loader.bin文件加载到物理内存的0x1000处,然后跳转到loader程序的第一条指令(物理地址0x1000处的指令)继续执行loader程序; 2.2.4 调试加载程序 调试过程——Loader程序的主要任务是将操作系统内核(kernel.dll文件)加载到内存中,然后让CPU进入保护模式并且启用分页机制,最后进入操作系统内核开始执行(跳转到kernel.dll的入口点执行); 2.2.5 调试内核 2.2.6 EOS启动后的状态和行为 查看EOS的版本号;查看EOS启动后的进程和线程的信息;查看有应用程序运行时进程和线程的信息 实验三:进程的创建 实验步骤: 3.1 准备实验 启动OS Lab;新建一个EOS Kernel项目;分别使用Debug配置和Release配置生成此项目,从而在该项目文件夹中生成完全版本的EOS SDK文件夹;新建一个EOS应用程序项目;使用在第3步生成的SDK文件夹覆盖EOS应用程序项目文件夹中的SDK文件夹 3.2 练习使用控制台命令创建EOS应用程序的进程 3.3 练习通过编程的方式让应用程序创建另一个应用程序的进程 使用OS Lab打开本实验文件夹中的NewProc.c文件;查看应用程序创建另一个应用程序的进程的执行结果。 3.4 调试CreateProcess函数 调试CreateProcess函数创建进程的过程;分别验证应用程序和操作系统内核在进程的4G虚拟地址空间中所处的位置; 3.5 调试PsCreateProcess函数 调试PspCreateProcessEnvironment函数;调试进程控制块的创建过程;调试初始化进程控制块中各个成员变量的过程。 3.6 练习通过编程的方式创建应用程序的多个进程 使用OS Lab打开本实验文件夹中的参考源代码文件NewTwoProc.c,仔细阅读此文件中的源代码。使用NewTwoProc.c文件中的源代码替换EOS应用程序项目中EOSApp.c文件内的源代码,生成后启动调试,查看多个进程并发执行的结果。 实验四:线程的状态和转换 实验步骤: 4.1 准备实验 启动OS Lab,新建一个EOS Kernel项目 4.2 调试线程状态的转换过程 查看一下loop命令执行的效果;调试线程状态转换的过程;对断点进行一些调整。 4.2.1 线程由阻塞状态进入就绪状态: 将线程从等待队列中移除;将线程的状态由Waiting修改为Zero;将线程插入其优先级对应的就绪队列的队尾;将线程的状态由Zero修改为Ready。 4.2.2 线程由运行状态进入就绪状态: 线程中断运行,将线程中断运行时的上下文保存到线程控制块中;如果处于运行状态的线程被更高优先级的线程抢先,就需要将该线程插入其优先级对应的就绪队列的队首。(注意,如果处于运行状态的线程主动让出处理器,例如时间片用完,就需要将程插入其优先级对应的就绪队列的队尾);将线程的状态由Running修改为Ready 4.2.3 线程由就绪状态进入运行状态: 将线程从其优先级对应的就绪队列中移除;将线程的状态由Ready修改为Zero;将线程的状态由Zero修改为Running;将线程的上下文从线程控制块(TCB)复制到处理器的各个寄存器中,让线程从上次停止运行的位置继续运行。 4.2.4 线程由运行状态进入阻塞状态: 将线程插入等待队列的队尾;将线程的状态由Running修改为Waiting;将线程中断执行,并将处理器上下文保存到该线程的线程控制块中。 4.3 为线程增加挂起状态 观察loop线程被挂起的情况:删除之前添加的所有断点;按F5启动调试;待EOS启动完 毕,在EOS控制台中输入命令“loop”后按回车。此时可以看到loop线程的执行计数在不停增长,说明loop线程正在执行,记录下loop线程的ID;按Ctrl+F2切换到控制台2,输入命令“suspend 31”(如果loop线程的ID是31)后按回车;按Ctrl+1切换回控制台1,可以看到由于loop线程已经成功被挂起,其执行计数已经停止增长了。 在PsResumThread函数第119行需要添加的代码的流程可以是:首先调用List Remove Entry函数将线程从挂起线程队列中移除,然后调用PspReadyThread函数将线程恢复为就绪状态,最后调用PspThreadSchedule宏函数执行线程调度,让刚刚恢复的线程有机会执行。 实验过程: 做实验时,最开始并不是很了解OS Lab平台的使用,即使对着老师给的实验教程做还是不怎么会,于是请教会做的同学,通过同学的讲解我知道了怎样在OS Lab平台上建立项目,怎样更改路径并找到项目的源文件等等基本操作。 掌握对平台的简单应用后,做后面的实验我是按照实验教程上的步骤一步步的实施,并且每次都认真观察相应的运行结果,每个实验都会建议我们学习实验教程前面的理论部分,我想如果对他的理论不熟悉,就算试验成功了我也不知道为什么,所以我一般在做实验前会对前面的理论部分进行简要的学习和熟悉。做实验的过程中,有时候按照实验教程上的步骤做平台还是会出现一些错误,比如做实验三到调试CreateProcess函数时,出现的调试异常对话框中,本来是要点击“是”的,但做到这里电脑总是会出现像死机一样的状况,关掉平台重做到这里老是出现同样的问题,最后换电脑也是这样,然后我尝试不按照实验步骤点击“是”也不行,最后还是又还了电脑才做成功,问其他同学也有出现同样的问题,我想可能是平台和电脑上有什么地方有冲突吧。 之后做试验是遇到问题我还是选择多问同学,毕竟每个人擅长的是不同的,有些问题这个同学会解决,有些问题则是那个同学才懂解决,通过互相交流和学习,我们通过实验不仅巩固了课堂上学到的相关知识,也对操作系统有了更深的了解。 体会: 其实做完实验我还是不能保证我对OS Lab这个平台有很好的全面的了解,但是对一些基本操作及其快捷键我算是大致掌握了,通过这个平台我也是认识到了“没有做不到的,只有想不到的”,我觉得创建这个平台的人们真的是很了不起,这个平台让我们便动手便了解了平时我们看不到的操作系统的相关知识。要做好实验,得按照实验教程上面的内容一步步落实,要边做变领悟相关原理及运行结果的出现的原因,这样我们才能在试验中学到更多、掌握更多。其次,也遇到问题我们自然是要先自己思考,通过不同的尝试来解决,之后不能解决的我们要多向老师同学请教,通过互相交流得来的知识也是会让我们难忘的。 《操作系统》实验指导书 (适用于计科、网络工程、软件工程、信计专业) 计算机科学与技术学院 2010-5 目录 前言..................................................................................................................................................3 实验 一、进程管理与进程同步.......................................................................................................4 实验 二、存储器管理.......................................................................................................................6 实验 三、磁盘调度算法的设计.......................................................................................................7 实验 四、文件系统原理与模拟实现...............................................................................................8 前言 本课程将系统学习操作系统的基本概念和常用算法以及其发展情况和应用情况。通过本课程的学习,学生应达到如下要求: 1、加深理解操作系统原理。 2、熟悉操作系统的常用算法并完成算法的程序设计。 3、理解当前操作系统的应用前景和新的进展。 本课程主要讲解操作系统的实现原理,如进程管理、进程同步、存储器管理、设备管理和文件系统等。要求学生理解操作系统的基本原理并完成其中多种典型的操作系统的算法的模拟序设计。 学生可以采用任何一种自己熟悉的编程语言完成算法的程序设计,如C/C++、Delphi、VB、VC、C#等。 实验 一、进程管理 实验目的: 理解和掌握进程管理中死锁处理和进程同步的方法。 实验内容: 实现银行家算法、进程调度过程的模拟、读者-写者问题的写者优先算法。 实验步骤: 理解安全性算法和银行家算法的核心机制: 针对3类资源、5个进程的情况,设计相应的数据结构,分别表示每个进程占用各类资源的情况; 编程实现安全性算法函数,编制主函数,动态输入资源的占用情况,进程的资源申请,调用安全性函数,实现银行家算法; 测试:输入可分配和不可分配的请求,测试系统的正确性。 理解进程的三状态调度过程,及各状态间的转换关系; 模拟若干个进程的运行过程,将其存入进程文件中。如:进程1:运行5秒后有3秒的I/O操作,之后有10秒的运行,结束。可以写成:”p1:r5,io3,r3 e;” ; 编程实现调度算法函数,定义时间片大小和并发进程个数,不断从进程文件中读出进程信息,模拟进程的运行及调度过程; 测试:针对进程文件里面的数据为正常、缺项、格式不正确等各种情况,检测程序的执行结果。 设计读者--写者问题的写者优先算法; 学习Windows平台下信号量的API函数的使用;编制读写进程的模拟信息文件,里面包含多个读写进程的运行描述:编制读者--写者问题的写者优先算法,从进程模拟信息文件中取出进程信息,按要求启动对应的进程模拟程序,决定出读者/写者进程的运行次序。 实验结果: 银行家算法程序提供一个用户界面,可以在上边发出资源申请命令,系统应能给出是否可以接受申请,并且有结论输出; 进程调度模拟程序根据一个进程调度文件,模拟进程的各种调度过程,用适合的表达方式表示出来。 写者优先同步控制程序根据一个读写进程模拟信息文件,按照写者优先同步控制过程,用适合的表达方式表示出各读写进程的执行次序。 实验 二、存储器管理 实验目的: 理解各类置换算法的原理和虚拟存储器管理的方法。 实验内容: 编程实现LRU算法或CLOCK/改进算法等置换算法(二选一),模拟实现虚拟存储器的地址变换过程。 实验步骤: 理解LRU或CLOCK改进算法等置换算法; 设计与算法相关的数据结构,如:LRU的堆栈或CLOCK改进算法中的循环结构; 按照最多5块的内存分配情况,编程实现所选算法,动态输入访问内存的块号序列,输出置换结果; 测试:输入合法、非法的访问序列数据,检查程序的正确性和健壮性。 理解虚拟存储器的地址变换过程; 设计用于模拟快表、页表、地址变换所用的寄存器的数据结构; 编制页表的初始信息文件,举例说明文件中具有的信息:共有5块,每块的状态、在内存和外存的起始地址等。 编程实现虚拟存储器地址变换算法程序,动态输入所要访问的逻辑地址,变换过程文字描述以及变换后的物理地址; 测试:输入有效、无效地址,测试程序的正确性和错误处理能力。 实验结果: 置换算法程序提供内存访问序列的输入界面,输出正确的置换过程描述和置换结果; 虚拟地址变换程序提供逻辑地址输入界面,形象地表示出变换成物理地址的过程与最后变换成的物理地址。 实验 三、磁盘调度算法的设计 实验目的: 通过对磁盘调度算法的设计,深入理解提高磁盘访问速度的原理。 实验内容: 模拟实现磁盘调度算法:最短寻道时间优先(SSTF)和扫描(SCAN)算法。 要求: 可以对给出的任意的磁盘请求序列、计算平均寻道长度; 要求可定制磁盘请求序列长度、磁头起始位置、磁头移动方向。 测试:假设磁盘访问序列:98,183,37,122,14,124,65,67;读写头起始位置:53,方向:磁道增加的方向。 实验 四、文件系统原理与模拟实现 实验目的: 了解操作系统中文件系统的结构和管理过程,掌握经典的算法:混合索引与成组链接法等方法。 实验内容: 编程模拟实现混合索引和成组链接法算法; 实验步骤: 模拟混合索引的原理; 假设每个盘块16字节大小,每个盘块号占2字节: 设计支持混合索引算法的索引节点的数据结构;编程模拟实现混合索引算法。 测试:输入一个文件的长度,给出模拟分配占用的磁盘块的情况;输入一个需要访问的地址,计算该地址所在的盘块号。 模拟成组链接法的原理; 设系统具有7个可用磁盘块,每组3块。 编程模拟实现成组链接法。输入请求的磁盘块数,模拟成组链接分配;输入回收的磁盘块号,模拟成组链接回收。 测试:输入请求的磁盘块数,给出分配后的链接情况。输入回收的磁盘块号,给出回收后的链接情况。第二篇:北邮微波仿真实验1
第三篇:操作系统实验
第四篇:操作系统实验总结
第五篇:《操作系统》实验指导书