CSAPP: cache lab (Part B未完成)

源文件及解决方法: https://github.com/xuzhezhaozhao/CSAPP-Labs

实验分为两部分


Part A:

这一部分是写一个小的C语言程序, 通过命令行输入参数s, b, E和traces文件, traces文件为内存读取过程

文件, 分析内存读取过程中hit, miss和eviction的次数.

看完文档之后发现文档中没有提及eviction的策略, 就是如果set中lines是满的的话应该选择替换哪一行.

于是修改了一个traces文件进行测试, 修改文件如下:

 L 10,1
 M 20,1
 L 22,1
 S 18,1
 L 110,1
 L 210,1
 M 12,1
 L 13,1
 L 211,1
 L 123,1
 L 223,1
 L 21,1
 L 22,1
 L 223,1
 L 123,1
 L 22,1

测试输入参数:

# ./csim-ref -v -s 4 -E 2 -b 4 -t traces/yi.trace

输出为:

L 10,1 miss 
M 20,1 miss hit 
L 22,1 hit 
S 18,1 hit 
L 110,1 miss 
L 210,1 miss eviction 
M 12,1 miss eviction hit 
L 13,1 hit 
L 211,1 hit 
L 123,1 miss 
L 223,1 miss eviction 
L 21,1 miss eviction 
L 22,1 hit 
L 223,1 hit 
L 123,1 miss eviction 
L 22,1 miss eviction 
hits:8 misses:10 evictions:6

分析之后得出所用的策略为替换最久没有读取过的行.

因为是模拟cache存储器的工作过程, 我们也可以把程序分为几个步骤:

1. 从地址参数中提取出set bits并转换为十进制以选择set;

2. 从地址参数中提取出tag bits并转换为十进制以选择line;

3. 判断该地址块中的内存是否在cache中, 当miss的时候如果line已经满了还要选择要被替换的行.

先定义数据结构:

[cpp]  view plain copy
  1. typedef struct {  
  2.     int valid;  /* valid bit per line */  
  3.     int tag;    /* tag of a line */  
  4.     int access_time;    /* 取值大小为1~line_num, 为1时说明是要被替换的 */  
  5. }line;  
  6. typedef struct {  
  7.     line *lines;  
  8. }set;  
  9. typedef struct {  
  10.     int set_num;    /* cache sets num */  
  11.     int line_num;   /* lines per set */  
  12.     set *sets;  
  13. }simu_cache;  

前两步可以用下面两个函数实现:

[cpp]  view plain copy
  1. /** 
  2.  * 返回地址addr中的set bits的十进制形式 
  3.  */                                                                               
  4. int getSetBits(int addr, int s, int b)  
  5. {  
  6.         int mask;  
  7.         mask = 0x7fffffff >> (31 - s);   
  8.         addr = addr >> b;  
  9.         return (mask & addr);  
  10. }  
  11.   
  12. /** 
  13.  * 返回addr的tag位十进制形式 
  14.  */  
  15. int getTagBits(int addr, int s, int b)  
  16. {  
  17.         int mask;  
  18.         mask = 0x7fffffff >> (31 - s - b);   
  19.         addr = addr >> (s + b);   
  20.         return (mask & addr);  
  21. }  
第三步麻烦一点, 我的想法是在line的结构体中加上一个access_time参数, 每次访问这一行时就把这个参数置为set中line的行数, 然后更新其他line中的access_time值, 更新方法为如果其他line中的access_time值当前访问line的原先的access_time值大, 当这个line的access_time值减1, 否则不变. 这样当line是满的时候, access_time值为1的line就是那个最久没有访问过的line. 当发生替换时就选择这个line.

具体实现如下:

[cpp]  view plain copy
  1. /** 
  2.  * 更新lines的访问时间 
  3.  */  
  4. int updateAccessTime(simu_cache *cache, int selset, int cl)  
  5. {  
  6.     int i;  
  7.     for (i = 0; i < cache->line_num; i++) {  
  8.         if (1 == cache->sets[selset].lines[i].valid &&   
  9.             cache->sets[selset].lines[i].access_time >   
  10.                 cache->sets[selset].lines[cl].access_time) {  
  11.             --cache->sets[selset].lines[i].access_time;    
  12.         }  
  13.     }  
  14.     cache->sets[selset].lines[cl].access_time = cache->line_num;  
  15.     return 0;  
  16. }  

最后的解析函数如下:

[cpp]  view plain copy
  1. int parse_traces(simu_cache *cache, char *line_buf, int s, int E, int b, int flag)  
  2. {  
  3.     int i;  
  4.     char opt;  
  5.     int addr;  
  6.     int selset, tag;  
  7.     sscanf(line_buf, " %c %x", &opt, &addr);  
  8.     selset = getSetBits(addr, s, b);  
  9.     tag = getTagBits(addr, s, b);  
  10.     for (i = 0; i < cache->line_num; i++) {  
  11.         if (1 == cache->sets[selset].lines[i].valid &&   
  12.                 tag == cache->sets[selset].lines[i].tag) {  
  13.             /* Hit immediately */  
  14.             if ('M' == opt) {  
  15.                 ++hits;  
  16.                 ++hits;  
  17.             } else {  
  18.                 ++hits;  
  19.             }  
  20.             updateAccessTime(cache, selset, i);  
  21.             return HIT;  
  22.         }  
  23.     }  
  24.   
  25.     /* Not Hit */  
  26.     ++misses;  
  27.     for (i = 0; i < cache->line_num; i++) {  
  28.         if (0 == cache->sets[selset].lines[i].valid) {                 
  29.             /* there is a empty line, No eviction */  
  30.             cache->sets[selset].lines[i].valid = 1;  
  31.             cache->sets[selset].lines[i].tag = tag;  
  32.             updateAccessTime(cache, selset, i);  
  33.             if ('M' == opt) {  
  34.                 ++hits;  
  35.                 return MISS_AND_HIT;  
  36.             } else {  
  37.                 return MISS;      
  38.             }  
  39.         }  
  40.     }  
  41.   
  42.     /* Need eviction */  
  43.     ++evictions;  
  44.     for (i = 0; i < cache->line_num; i++) {  
  45.         if (1 == cache->sets[selset].lines[i].access_time) {  
  46.             cache->sets[selset].lines[i].valid = 1;  
  47.             cache->sets[selset].lines[i].tag = tag;  
  48.             updateAccessTime(cache, selset, i);  
  49.             if ('M' == opt) {  
  50.                 ++hits;  
  51.                 return MISS_EVICTION_AND_HIT;  
  52.             } else {  
  53.                 return MISS_AND_EVICTION;  
  54.             }  
  55.         }  
  56.   
  57.     }  
  58.   
  59.     return 0;  
  60. }  

Part B: 

这部分的任务是根据给定的cache对给定大小的矩阵相乘运算进行优化, 以减少misses的次数. 由于在性能分析的时候要用到valgrind软件生成traces文件, 所以要先下载安装valgrind包, ubuntu下的安装命令为: 

sudo apt-get valgrind.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值