
第十讲存储管理.doc
8页第十讲 存储管理1. 在如下一段 C语言程序的 for 循环中,void cycle(double* a) {int i;double b[65536];for(i=0; i<3; i++) {memcpy(a, b, sizeof(b));}}程序 memcpy函数执行过程中可能发生哪些例外,各多少次答:忽略外部中断(包括键盘,鼠标等输入) ,内部程序执行例外可能有:① TLB例外( TLB Miss Exception )② 缺页异常( Page Fault Exception )TLB例外和页大小有关,还和 TLB 表项以及替换算法有关(分表假设为 4K、128 项和最近未使用 LUR,不考虑 ITLB miss 例外),则: 65536*8*2 =512*2=256*4k, 也就是 256 次例外缺页异常具体次数和页大小有关,假设页大小为 4K( 假设页分配后不会被替换出去,且忽略临时变量 i ,以及指令代码段发生的缺页例外,假设内存足够大,页加载入主存后不会被替换) :正常情况下 a 不会缺页, b 缺页可以有 128 次2. 对于指令 Cache 是否有必要考虑 Cache 别名问题?答:有必要,可能会由于 cache 别名导致取错指令,甚至导致 Last level cache 不能维护和一级指令 cache 之间的 inclusion 关系,从而导致死机。
3. 假定在某一个 CPU的 Cache 中需要 64 位虚拟地址, 8 位的进程标识,而其支持的物理内存最多有 64GB请问,使用虚拟地址索引比使用物理地址作为索引的 Tag 大多少?这个值是否随着 Cache 块大小的变化而发生改变?答:由于虚拟地址有 64 位,进程标识为 8 位;而物理地址是 64GB,即需要 36 位物理地址这样,使用虚拟地址比使用物理地址总共增加的位数为 8+( 64-36)= 8+ 28= 36 位;而保持页大小不变化,改变块的大小,增加的位数保持不变4. 考虑一个包含 TLB 的当代处理器1)请阐述 TLB、 TLB 失效例外、页表和 Page fault之间的关系2)如果有这样一个机器设计:对于同样的虚拟地址,TLB命中和Pagefault同时发生,这样的设计合理么?为什么?(3)现代计算机页表普遍采用层次化的方式,请解释原因答:1) TLB : Translation lookaside buffer, 即旁路转换缓冲,或称为页表缓冲;里面存放的是一些页表文件(虚拟地址到物理地址的转换表) TLB 是页表的一个子集TLB失效例外: 假如某个虚地址 VA,在 TLB 中没有找到对应的页表项,则发生 TLB 失效例外 (TLB miss exception) 。
页表:简单的说,页表是内存块的目录文件,作用是实现从页号到物理块号的地址映射用固定大小的 页 (Page) 来描述逻辑地址空间,用相同大小的页框 (Frame) 来描述物理内存空间,从逻辑页到物理页框的页面映射 ,这些页面映射就是一张张页表(PageTable ) .PageFault:缺页,就是TLB 中没有虚地址VA对应的页表,主存中也没有VA对应的物理地址这时候发生 Page Fault Exception (缺页例外),需要交给操作系统处理,通常需要消耗很多的时间来处理该例外2) 不合理,因为 Page Fault 发生时意味着主存中没有虚地址 VA 对应的页表,这是 TLB 中也应该没有,因为 TLB 里的页表都是主存中换进去的,是主存中页表的子集,应该发生 TLB miss 倘若没有发生,说明 TLB 不是主存页表的子集,这会导致存储不一致,也违背了层次化设计的基本要求3) 多级页表可以减少页表所占用的存储空间比如:一个 32 位逻辑地址空间的计算机系统,页大小为 4KB,那么页表有一百万条目假设每个条目占 4B,则需要 4MB物理地址空间来存储页表本身一个虚地址 (32 位系统,页大小 4K) 可以被分为 : 一个 20 位的页号 +一个 12 位的偏移。
如果对页表进行再分页,那么页号分解为 : 一个 10 位的页号 +一个 10 位的偏移因此,一个逻辑地址表示如下 :p1 是用来访问外部页表的索引 , p2 是外部页表的页偏移5. 已知一台计算机的虚地址为 48 位,物理地址为 40 位,页大小为 16KB,TLB 为 64 项全相联, TLB的每项包括一个虚页号vpn,一个物理页号 pfn ,以及一个有效位valid ,请根据如下模块接口写出一个TLB的地址查找部分的 Verilog 代码module tlb_cam(vpn_in,pfn_out, hit,);其中 vpn_in 为输入的虚页号, pfn_out为输出的物理页号, hit为表示是否找到的输出信号,“ ”表示与该 TLB输入输出有关的其他信号重复的代码可以用“ ”来简化答:module tlb_cam(input_valid,vpn_in,pfn_out, hit, clock);inputclock;inputinput_valid;input [33:0] vpn_in;output[25:0] pfn_out;outputhit;reg [33:0] vpn_reg;always@(posedge clock) beginif(input_reg)vpn_reg <= vpn_in;endreg[60:0]cam_content[63:0];//[60:60]valid[59:34]pfn [33:0]vpnwire [63:0]entry_hit;assignentry_hit[0]=cam_content[0][60]&& (vpn_in==cam_content[0][33:0]);assignentry_hit[1]=cam_content[1][60]&& (vpn_in==cam_content[1][33:0]);assignentry_hit[63]= cam_content[63][60]&& (vpn_in==cam_content[63][33:0]);assign hit = |entry_hit;assign pfn_out= {26{entry_hit[0]}} {26{entry_hit[1]}}& cam_content[0][59:34] & cam_content[1][59:34]||{26{entry_hit[63]}}& cam_content[63][59:34];endmodule6. (博士)很多处理器都提供了可变页的支持,也就是 TLB的每项可以代表不同大小的页( 1K/2K/4K 甚至 1G)。
请简述 Linux 为了支持可变页需要进行哪些支持答:① 首先,需要内核有判断页大小是多少的机制可以分为两种,一种是内核基于启发式的方法内自行来决定(比如对一些数据段用大页表,而指令段小页表) ;另一种是应用程序将相关的信息传给内核(需要编译器支持) 前者复杂度高,难以得到好的效果,后者相对容易实现(因为应用程序本身对其各个数据结构更了解)一般选用后者② 决定不同页表的大小的判断粒度是每个地址进行判断(细粒度,这时对于不同地址的代码段,可能其页表大小不一样) ,还是直接根据地址段数属性(粗粒度,如数据段,代码段等)来判断(这时候,可能所有代码段的页表大小都一样) ③ 对应的 memory allocation 等函数也该需要进行修改一便用于变长页表7. ( 博士 ) 针对 linux/mips 页表组织,修改 TLB相关控制寄存器的格式(如果你认为必要可以增减控制寄存器或者其它处理逻辑)以减少 refill 例外处理时间描述你的方案,给出使用新寄存器组实现的 refill 例外处理代码Linux 的 tlb 重填代码(共 18 条指令 )mfc0k0,CP0_BADVADDR# 取发生 tlbmiss 的地址srlk0,k0,22# 最高 10 位是第一级页表的索引lwk1,pgd_current# 取页表入口指针sllk0,k0,2# 每项 4 个字节 , 所以索引 *4= 偏移adduk1,k1, k0#*k1 指向下一级页表入口mfc0k0,CP0_CONTEXT#context包含失效的虚页号lwk1,(k1)# 取出第二级页表srlk0,k0,1andk0,k0,0xff8# 算出第二级页表的偏移adduk1,k1, k0lwk0,0(k1)# 成对存放 , 一个偶数页lwk1,4(k1)# 加一个奇数页srlk0,k0,6# 移出 6 位无用的位mtc0k0,CP0_ENTRYLO0# 写入偶数页表项srlk1,k1,6mtc0k1,CP0_ENTRYLO1# 写入奇数页表项tlbwr# 写入 TLB 的一个随机项eret#异常返回tlbwr# 写入 TLB 的一个随机项eret#异常返回所做的。