zoukankan      html  css  js  c++  java
  • 《深入理解计算机系统》自学历程(一)模拟高速缓存逻辑(下)

    经过三次重写,和合计30多个小时的开发,终于把这个简单的逻辑做完了。(自己太笨)

    因为刚刚接触C,写的代码实现方式肯定有不对的地方,逻辑上可能也有疏漏,如果有看官发现问题还望及时给予指正,谢谢。

    一、整体概括:

    1.1目标:

    维护一个单独的缓存空间,该空间是低一级存储的缓存。缓存的大小比低级存储的大小要小很多,通过一个逻辑将底层存储的数据抽到缓存中的一个位置。

    1.2 实现思路:

      通过阅读《深入理解计算机系统》一书,了解低级存储与缓存之间关联规则是基于存储地址的,通过一个地址映射的规则,将低级存储的地址映射到缓存的制定位置。

      1.2.1 存储:

        存储是由一个个位构成的,每个位都有一个对应的地址,地址的大小取决于计算机的字长。

      1.2.2 低级存储:

        在这次的设计中低级存储只是一个抽象概念,实际上就是内存中的一块空间,只不过我通过映射值将低级存储的地址改为从F000开始的地址。

      1.2.3 缓存:

        缓存是比低级存储小得多的集合,因为存储越大寻址的时间越长,所以需要一个小的缓存来存储处理器近期使用到的数据。

        这次设计中的缓存也只是一个抽象概念,也是内存的一块空间,也是通过映射值将缓存的地址改为A000开始的地址。

      如何将低级存储的地址映射到缓存——缓存模型:

        缓存模型主要分——组、行、缓存单元

        1.2.3.1 组

          在逻辑上没有体现,知识对地址进行切割并划分了一个范围,是在映射逻辑上有关,在实际内存中不会存储。

        1.2.3.2 行

          也是一个逻辑体现,主要是为了更好的提升缓存的寻址效率而设置的思想。

        1.2.3.3 缓存单元:

          实际存储数据的对象,其中包含了标识、是否加载、以及字节块。

            标识:标识是地址的一部分根据规则截取出来的,通过地址另一部分找到对应的组以后就会对其中的行进行遍历,根据标识找到对应的行。

            是否加载:用来标识该缓存是否已经加载数据。

            字节块:用来存储缓存数据。(大小可设置)

          1.2.3.4 总结

          通过上述的几个对象,我们将缓存组织成了一个三层的结构,第一层是组、第二层是行、第三层是存储单元。一个缓存可以有S个组,可以有E个行,每行只能有一个缓存单元。

      1.2.4 全相连高速缓存、组相连高速缓存、直接映射高速缓存

        全相连高速缓存就是缓存中只有一个组,有E个行的方式实现。

        组相连高速缓存就是一个缓存中有S个组,E个行的实现方式。

        直接映射高速缓存就是一个缓存中有S个组,1个行和1个缓存单元的实现方式。

       1.2.5 缓存各项指标的设置:

        组数、行数、缓存数据块的大小的设置直接影响缓存的效率但也要根据实际情况,大小对不同的情况有不同的策略。

    二、具体实现:

      2.1 公共常量:

        计算机字长:MemAddrLength

      2.2 几个核心对象:

        2.2.1 硬件控制器:HWController

          属性:

            存储空间大小

          1)写方法(Write):传入一个虚拟硬件地址(自己映射的,从F000开始)和一个长度。映射后写入数据到内存。

          2)读方法(Read):传入一个虚拟硬件地址和一个长度。映射后从内存读出数据,并写到一个新的内存空间并返回该指针。

        2.2.2 缓存控制器:CacheController

          1)缓存单元查询器(CacheFinder):

          2)读方法(Read):传入一个硬件虚拟地址和长度,在缓存中查找对应的单元,如果找不到从硬件中读取数据写到缓存,并将数据写到内存新的空间中、返回该指针。

          3)写方法(Write):传入一个硬件虚拟地址和长度,将数据写入到硬件中再写到缓存里(实际上缓存会有多种策略、直写/不直写等等)。

          4)取下一个(Next):将传入缓存单元指针移动到相邻的下一个缓存单元,如果超出缓存范围则返回0x00。

      2.3 执行结果概述

      返回四大部分:

      1)总体介绍部分,会将地址空间、缓存的S、E、B、t几个主要参数值显示出来。

      

      2)内存查看部分,会将初始化后虚拟硬件存储和缓存存储的值都写出来。

    3)缓存大小显示

    4)缓存读值测试

    下面的集合是所有缓存单元的参数和右侧缓存单元字节块中的数据。

    上面的集合是根据指令从缓存中读取出来的数据内容。

    通过这两个集合可以验证读取数据是否正确。

     剩下没解决的问题:

    在写缓存的时候,如果该组所有缓存单元都已经初始化了,就需要通过一个科学的方式选择一个块覆盖或驱逐,目前是用随机数,不太合理。

    抽象不够,没有悟透和语言不熟导致很多复用问题比较多,有问题望指出。后续有时间我会继续完善。

    说不定有BUG,如果有客观指正。

    三、代码

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <math.h>
      4 #include <unistd.h>
      5 
      6 /*
      7  * 基本设定初始化
      8  */
      9 const unsigned int _memSize = 1024; //内存大小(字节)
     10 const unsigned int _memAddrLength = 16;//地址长度
     11 const unsigned int _cacheSize = 256;//缓存大小
     12 
     13 /*
     14  * 硬件控制器
     15  */
     16 typedef struct HWController{
     17     unsigned long _memStartAddr; //start addr 0XF0
     18     unsigned char* _memAddr;
     19     unsigned long _memOffset;
     20 
     21     unsigned char* (*Read)(unsigned long memOffset, unsigned long addr, unsigned long length);
     22     unsigned char (*Write)(unsigned long memOffset, unsigned long addr, unsigned char *data, unsigned long length);
     23 };
     24 
     25 /*
     26  * 缓存控制器:
     27  *      1)缓存单元集合指针 CacheUnitArrayPtr
     28  *      2)缓存查询函数 CacheFinder
     29  *      3)缓存读函数 Read
     30  *      4)缓存写函数 Write
     31  */
     32 typedef struct CacheController {
     33     unsigned int _s;
     34     unsigned long _sMask;
     35     unsigned int _S;
     36     unsigned int _E;
     37     unsigned int _b;
     38     unsigned long _bMask;
     39     unsigned int _B;
     40     unsigned int _t;
     41     unsigned long _tMask;
     42     unsigned int _C;
     43 
     44     unsigned long _unitCount;
     45     unsigned long _unitSize;
     46 
     47     unsigned long _cacheSize;
     48     unsigned long _cacheStartAddr;
     49     unsigned char* _cacheMemAddr;
     50     unsigned long _cacheOffset;
     51     struct CacheUnit* CacheUnitArrayPtr;
     52 
     53     struct CacheUnit* (*Next)(struct CacheController *ctrl,struct CacheUnit *unit);
     54     struct CacheUnit* (*CacheFinder)(struct CacheController *ctrl,unsigned long Addr);
     55     unsigned char* (*Read)(struct CacheController *ctrl,struct HWController *hwctrl,unsigned long addr, unsigned long length);
     56     unsigned char (*Write)(struct CacheController *ctrl,struct HWController *hwctrl,unsigned long addr, unsigned char *data, unsigned long length);
     57 };
     58 
     59 /*
     60  * 缓存单元
     61  *      1)数据块集合指针 BlockArrayPtr;
     62  *      2)t标志位 tCode;
     63  *      3)热标识位 hot;
     64  */
     65 typedef struct CacheUnit {
     66     unsigned char* BlockArrayPtr;
     67     unsigned long tCode;
     68     unsigned char Hot;
     69 };
     70 
     71 //HWController
     72 unsigned char _hwWrite(unsigned long memOffset, unsigned long addr, unsigned char *data, unsigned long length){
     73     unsigned char* ptr = (unsigned char*)(memOffset + addr);
     74     while(length--){
     75         *ptr = *data;
     76         ptr++;
     77         data++;
     78     }
     79     return 1;
     80 }
     81 unsigned char* _hwRead(unsigned long memOffset, unsigned long addr, unsigned long length){
     82     unsigned char *ptr = (unsigned char*)(memOffset + addr);
     83     unsigned char *retPtr = malloc(length);
     84     unsigned char *loopPtr = retPtr;
     85     while(length--){
     86         *loopPtr = *ptr;
     87         ptr++;
     88         loopPtr++;
     89     }
     90 
     91     return retPtr;
     92 }
     93 struct HWController* GetHWCtroller(){
     94     struct HWController *ctrl = malloc(sizeof(struct HWController));
     95     void *rPtr = malloc(_memSize);//get ptr point to Memory Space.
     96     (*ctrl)._memStartAddr = 0xF000;
     97     (*ctrl)._memOffset = (unsigned long) (rPtr - (*ctrl)._memStartAddr);
     98     (*ctrl)._memAddr = rPtr;
     99     (*ctrl).Write = _hwWrite;
    100     (*ctrl).Read = _hwRead;
    101 
    102     unsigned char *ptr = rPtr;
    103     int i = 0;
    104     while( i < _memSize ){
    105         *ptr = i + 1000;
    106         ptr++;
    107         i++;
    108     }
    109 
    110     printf("==>Memory:
     startAddr:%X,offset:%X",(unsigned int)(*ctrl)._memStartAddr,(unsigned int)((*ctrl)._memOffset ));
    111 
    112     return ctrl;
    113 }
    114 
    115 //CacheController
    116 struct CacheUnit* _next(struct CacheController *ctrl,struct CacheUnit *unit){
    117    unit = (struct CacheUnit *)((unsigned long)unit + ctrl->_unitSize);
    118    return unit >= (ctrl->_cacheSize + ctrl->_cacheMemAddr) ? 0x00 : unit;
    119 }
    120 struct CacheUnit* _cacheFinder(struct CacheController *ctrl,unsigned long addr){
    121     unsigned long _tBit = (addr&(*ctrl)._tMask)>>((*ctrl)._b+(*ctrl)._s);
    122     unsigned long _sBit = (addr&(*ctrl)._sMask)>>((*ctrl)._b);
    123     unsigned long _bBit = (addr&(*ctrl)._bMask);
    124 
    125 //    printf("
    
    ====>Find Addr:%X 
     tMask:%X,tVal:%X 	 sMask:%X,sVal:%X 	 bMask:%X,bVal:%X",addr,(*ctrl)._tMask,_tBit,(*ctrl)._sMask,_sBit,(*ctrl)._bMask,_bBit);
    126 
    127     struct CacheUnit* _unit = (struct CacheUnit*)((*ctrl)._cacheStartAddr + ctrl->_cacheOffset + _sBit * ((*ctrl)._E * ctrl->_unitSize));
    128     int e = (*ctrl)._E;
    129     while ( e-- )
    130     {
    131         if((*_unit).tCode == _tBit){
    132             return _unit;
    133         }
    134         _unit = (struct CacheUnit *)(((unsigned long)_unit)+ ctrl->_unitSize);
    135     }
    136     return 0;
    137 }
    138 unsigned char* _cacheRead(struct CacheController *ctrl,struct HWController *hwctrl,unsigned long addr, unsigned long length){
    139     struct CacheUnit *unit = ctrl->CacheFinder(ctrl,addr);
    140     //todo: 找时间把Loader抽象出来或者其他方式优化复用。
    141     if(!unit || !(*unit).Hot){
    142         unsigned char *read = hwctrl->Read(hwctrl->_memOffset,addr,length);
    143         ctrl->Write(ctrl,hwctrl,addr,read,length);
    144         unit = ctrl->CacheFinder(ctrl,addr);
    145         if(!unit || !(*unit).Hot){
    146             printf("
    ERROR::can not load cache by %X !!!! 
    " ,(unsigned int)addr);
    147             exit(0);
    148         }
    149     }
    150     unsigned char *memPtr = malloc(length);
    151     unsigned char *memLoopPtr = memPtr;
    152     unsigned char *blockPtr = (*unit).BlockArrayPtr + (ctrl->_bMask & addr);
    153     unsigned long i = 0;
    154     while(i < length){
    155         *memLoopPtr = *blockPtr;
    156         memLoopPtr++;
    157         blockPtr++;
    158         if(blockPtr >= (*unit).BlockArrayPtr + (*ctrl)._B){
    159             unit = ctrl->CacheFinder(ctrl,addr + i + 1);
    160             if(!unit || !(*unit).Hot){
    161                     printf("
    ERROR::can not load cache by %X !!!! 
    " ,(unsigned int)(addr + i));
    162                     exit(0);
    163             }
    164             blockPtr = unit->BlockArrayPtr;
    165         }
    166         i++;
    167     }
    168     return memPtr;
    169 }
    170 unsigned char _cacheWrite(struct CacheController *ctrl,struct HWController *hwctrl,unsigned long addr, unsigned char *data, unsigned long length){
    171     //写入底层内存先。
    172     hwctrl->Write(hwctrl->_memOffset,addr,data,length);
    173     //写入缓存
    174     unsigned char *ptr = data;
    175     unsigned long i = 0;
    176 
    177     while(i<length){
    178         struct CacheUnit *unit = ctrl->CacheFinder(ctrl,addr + i);
    179         if(!unit||!unit->Hot)
    180         {
    181             unsigned long startAddr = (unsigned long)(ctrl->_cacheMemAddr + (((ctrl->_sMask & (addr + i)) >> ((*ctrl)._b)) * ctrl->_E) * ctrl->_unitSize) ;
    182             unsigned long endAddr = (unsigned long)(ctrl->_cacheMemAddr + (((ctrl->_sMask & (addr + i)) >> ((*ctrl)._b)) * ctrl->_E)) + ctrl->_E * ctrl->_unitSize;
    183             unit = (struct CacheUnit *)startAddr;
    184             int hit = 0;
    185             while(unit){
    186                 if(!unit->Hot)
    187                 {
    188                     hit=1;
    189                     break;
    190                 }
    191                 unit = ctrl->Next(ctrl,unit);
    192                 if((unsigned long)unit >= endAddr){
    193                     break;
    194                 }
    195             }
    196             if(!hit)
    197             {
    198                 printf("
    
    nhit!!!
    ");
    199                int rm = rand() % ( ctrl->_E );
    200                unit = startAddr + rm * ctrl->_unitSize;
    201             }
    202             unit->tCode = ((addr + i) & ctrl->_tMask) >> ((*ctrl)._b+(*ctrl)._s);
    203             unit->Hot = 1;
    204         }
    205         unsigned char *blockPtr = unit->BlockArrayPtr + ((addr+i)&ctrl->_bMask);
    206         *blockPtr = *ptr;
    207         ptr++;
    208         i++;
    209     }
    210 }
    211 struct CacheController* GetCacheController(unsigned int _memAddrLength, unsigned int cacheSize, unsigned int blockSize,unsigned int E){
    212     struct CacheController *cache = malloc(sizeof(struct CacheController));
    213     (*cache)._b = (unsigned int)log2(blockSize);
    214     (*cache)._B = blockSize;
    215     (*cache)._bMask = (unsigned long) pow(2,(*cache)._b) - 1;
    216 
    217     (*cache)._E = E;
    218 
    219     (*cache)._S = cacheSize / (*cache)._B / (*cache)._E;
    220     (*cache)._s = (unsigned int)log2((*cache)._S);
    221     (*cache)._sMask = (unsigned long) pow(2,((*cache)._b + (*cache)._s)) - (*cache)._bMask - 1;
    222 
    223     (*cache)._C = (*cache)._B * (*cache)._E * (*cache)._S;
    224 
    225     (*cache)._t = _memAddrLength - (*cache)._s - (*cache)._b;
    226     (*cache)._tMask = (unsigned long) pow(2,_memAddrLength) - (*cache)._bMask - (*cache)._sMask - 1;
    227 
    228     (*cache)._unitCount = (*cache)._E * (*cache)._S;
    229     (*cache)._unitSize = sizeof(struct CacheUnit) + (*cache)._B;
    230 
    231     (*cache)._cacheSize = (*cache)._unitSize * (*cache)._unitCount;
    232     //apply mem
    233     (*cache)._cacheMemAddr = malloc((*cache)._cacheSize);
    234     (*cache)._cacheStartAddr = 0xA000;
    235     (*cache)._cacheOffset = (unsigned long)((*cache)._cacheMemAddr - cache->_cacheStartAddr);
    236 
    237     unsigned long counter = (*cache)._unitCount;
    238     struct CacheUnit *unit = (struct CacheUnit*)(*cache)._cacheMemAddr;
    239 
    240     while(counter){
    241         (*unit).Hot = 0x00;
    242         (*unit).tCode = counter;
    243         (*unit).BlockArrayPtr = (unsigned char *)(((unsigned long)unit) + sizeof(struct CacheUnit));
    244         int x;
    245         for(x = 0;x < cache->_B ; x++){
    246             *(unit->BlockArrayPtr + x) = (unsigned char)x;
    247         }
    248         unit = (struct CacheUnit*)((*unit).BlockArrayPtr + (*cache)._B);
    249         counter--;
    250     }
    251     (*cache).Next = _next;
    252     (*cache).CacheFinder = _cacheFinder;
    253     (*cache).Read = _cacheRead;
    254     (*cache).Write = _cacheWrite;
    255 
    256     printf("
    ==>CacheSize:
     MemAddrLength = %d. C = %d, 
    S = %d, E = %d, B = %d; 
     s = %d, b = %d, t = %d",_memAddrLength,(*cache)._C,(*cache)._S,(*cache)._E,(*cache)._B,(*cache)._s,(*cache)._b,(*cache)._t);
    257     printf("
    cacheAddr:%X,cacheStartAddr:%X, cacheOffset:%X, cacheSize:%d",(unsigned int)(*cache)._cacheMemAddr,(unsigned int)(*cache)._cacheStartAddr,(unsigned int)(*cache)._cacheOffset,(unsigned int) (*cache)._cacheSize);
    258     printf("
    bMask:%x,sMask:%x,tMask:%x",(unsigned int)(*cache)._bMask,(unsigned int)(*cache)._sMask,(unsigned int)(*cache)._tMask);
    259 
    260     return cache;
    261 }
    262 
    263 //utility
    264 void PrintMem(char* title, unsigned long addr, unsigned long length,int split){
    265     printf("
    
    =====> title::%s::  Printing Mem %X,Length:%d  <=======
    ",title,(unsigned int)addr,(unsigned int)length);
    266     unsigned char *ptr = (unsigned char *)addr;
    267 
    268     int i = 0;
    269     while(i < length){
    270         if( i % 16 == 0){
    271             printf("
    %d	%X	",i,(unsigned int)ptr);
    272         }
    273         else if( i > 0 && i % 4 == 0){
    274             printf("	");
    275         }
    276         printf("	%X",*ptr);
    277         ptr++;
    278         i++;
    279     }
    280 }
    281 void PrintCache(char* title, struct CacheController* ctrl){
    282     printf("
    
    =====> title::%s::  Printing Mem %X,Length:%d  <=======
    ",title,(unsigned int)(ctrl->_cacheStartAddr + ctrl->_cacheOffset),(unsigned int)ctrl->_unitCount);
    283 
    284     struct CacheUnit *unit = ( struct CacheUnit *)(ctrl->_cacheStartAddr + ctrl->_cacheOffset);
    285     unsigned char *blockPtr = unit->BlockArrayPtr;
    286     int i = 0;
    287     int j = 0;
    288     while(i < ctrl->_unitCount){
    289         printf("
    --Unit%d[[tCode:%d,BlockPtr:%X,Hot:%d]] Blocks:	",i+1,(unsigned int)unit->tCode,(unsigned int)unit->BlockArrayPtr,(unsigned int)unit->Hot);
    290         j = 0;
    291         while(j < ctrl->_B){
    292             printf("	%X",(unsigned int)*blockPtr);
    293             blockPtr++;
    294             j++;
    295         }
    296         unit = (struct CacheUnit *)(((unsigned long)unit) + sizeof(struct CacheUnit) + ctrl->_B);
    297         blockPtr = unit->BlockArrayPtr;
    298         i++;
    299     }
    300 }
    301 int main() {
    302     printf("Hello, World!
    ");
    303     struct HWController hwCtrl = *GetHWCtroller();
    304     struct CacheController cacheCtrl = *GetCacheController(_memAddrLength,_cacheSize,32,2);
    305 
    306 //HW Unit Test
    307     //    PrintMem("",(unsigned long)hwCtrl._memAddr,16,0);
    308     //    unsigned char temp = 0xAA;
    309     //    unsigned char *data = &temp;
    310     //    hwCtrl.Write(hwCtrl._memOffset,0XF002,data,1);
    311     //    PrintMem(" HWMEM 0~16 ",(unsigned long)hwCtrl._memAddr,16,0);
    312     //    unsigned char *retData = hwCtrl.Read(hwCtrl._memOffset,0XF002,1);
    313     //    PrintMem(" HWMEM 0XF002 ",(unsigned long)retData,1,0);
    314     //    unsigned char *retData = hwCtrl.Read(hwCtrl._memOffset,0XF002,1);
    315     PrintMem(" HWMEM ALL ",(unsigned long)hwCtrl._memAddr,_memSize,0);
    316 
    317 
    318     //Cache Unit Test
    319     PrintMem(" CACHE ALL ",(unsigned long)cacheCtrl._cacheMemAddr,cacheCtrl._cacheSize,0);
    320 
    321 
    322     //struct test
    323     struct CacheUnit cu = {
    324             0x00,
    325             0x00,
    326             0x00
    327     };
    328     printf("
     ============>> CacheUnitTypeSize %d 
    ",sizeof(struct CacheUnit));
    329     printf("
     ============>> CacheUnitSize %d 
    ",sizeof(cu));
    330     printf("
     ============>> CacheUnitSize.Hot %d 
    ",sizeof(cu.Hot));
    331     printf("
     ============>> CacheUnitSize.tCode %d 
    ",sizeof(cu.tCode));
    332     printf("
     ============>> CacheUnitSize ptr %d 
    ",sizeof(cu.BlockArrayPtr));
    333 
    334     //ReadCacheTest
    335     PrintMem("",cacheCtrl.Read(&cacheCtrl,&hwCtrl,0XF038,16),16,0);
    336     PrintCache("",&cacheCtrl);
    337     return 0;
    338 }
  • 相关阅读:
    Linux下C程序插入执行shell脚本
    #ifdef预编译相关用法
    LAMP开发之环境搭建(2014.12.7在ubuntu下)
    Qt在VS2010的安装与配置
    vs2010配备boost编程环境
    Ubuntu虚拟机与Window、Arm的通信
    大小端测试程序
    Ubuntu安装google Gtest
    设计模式之单例模式
    设计模式之原型模式
  • 原文地址:https://www.cnblogs.com/xiayongming/p/9502875.html
Copyright © 2011-2022 走看看