Cache架构以及X86&ARM @Linux平台cache eviction功能测试

经典的ARM处理器高速缓存工作原理:

Cache架构以及X86&ARM @Linux平台cache eviction功能测试_第1张图片

注意:如果TLB失中,Page Table Walk(PTW)电路不走Cache,直接从物理内存中查找页表。

一个8路组相联的高速缓存的结构示意图:

Cache架构以及X86&ARM @Linux平台cache eviction功能测试_第2张图片

基本参数包括:

  1. 地址,根据Cache的设计不同,地址可能是虚拟地址VA(VIVT),物理地址PA(PIPT),或者物理地址和虚拟地址都要用到(VIPT)。
  2. 高速缓存行,高速缓存中最小的访问单元,包括一小段主存储器中的数据,常见的高速缓存行是32或者64字节。
  3. 索引域,高速缓存地址编码的一部分,用于索引和查找数据在高速缓存的哪一行。
  4. 组,由相同索引域的高速缓存行组成,组相连的情况下,在refill和替换时,可以选中组内任意一路来进行。组的个数等于索引条目数。
  5. 路,在组相联的高速缓存中,高速缓存由大小相同的几个块组成。它表是组内高速缓存行的个数。对于只有一路的高速缓存,其实就是直接映射的高速缓存。多路设计可以减少高速缓存颠簸(cache thrashing).
  6. 标记,高速缓存地址编码的一部分,通常是高速缓存地址的高位部分,用于判断高速缓存缓存行的数据的地址是否和处理器寻找的地址一致。
  7. 偏移量,高速缓存中的偏移量,用于按照字节或者字准确定位要访问的数据内容。

在cortex-a7和cortex-a9的处理器中,可以看到32KB大小的四路组相连高速缓存,下面来分析一下这个高速缓存的结构:

高速缓存的总大小为32KB,并且是4路的,所以每一路的大小为8KB.

way\_size = \frac{32KB}{4 way}=8KB/way

高速缓存行的大小为32字节所以每一路包含的高速缓存行数量如下:

num\_cache\_line=\frac{8KB}{32B}=256

所以在高速缓存编码的地址中,Bit[4:0]用于选择高速缓存行中的32B的数据,其中Bit[4:2]可以用于寻址8个字,Bit[1:0]可以寻址每个字中的字节。Bit[12:5]一共8位用于在索引域中选择每一路上的高速缓存行。剩下的Bit[31:13]用作标记域。

Cache架构以及X86&ARM @Linux平台cache eviction功能测试_第3张图片

如果任意两个va命中同一个组的不同路中,则一定满足如下同余关系:

(va1 >> 5)\equiv (va2>>5)(\ mod \ groupnumber)

从另一个角度看,cache本身是拥有足够的信息可以推算出每个cache line对因的物理内存的,这样可以保证在全CACHE回写时,不需要用户提供地址信息。比如通过TAG以及自身索引和 数据在cacheline中的偏移,就可以组合成对应的物理地址进行回写。

可以把一个N行M路的cache想象成一个很大的停车场,加入每辆车的车牌号均为数字,要求每辆车必须停在 车牌号 mod 总行数的那一行的任意一个车位上,也就是说,所有停在同以行的车辆要求模总行数同余,则其结构与CACHE比较类似。

Cache架构以及X86&ARM @Linux平台cache eviction功能测试_第4张图片

OR1200 ICACHE架构

Cache架构以及X86&ARM @Linux平台cache eviction功能测试_第5张图片

和ICACHE相关的特殊寄存器为ICBIR(Instruction Cache Block Invalidate Register).即指令块无效寄存器,且是不可读,只可写的寄存器,如果向ICBIR写入一个地址,设为Aaddr,那么将会使得ICACHE目录表中第Aaddr[12:4]项的V设置为0。

Cache架构以及X86&ARM @Linux平台cache eviction功能测试_第6张图片

需要注意的是,系统中是没有为CACHE分配物理地址的,无法被寻址。

体系结构中的内存一致性测试

在Linux上设计如下图所示的测试方案:

  1. 用户态测试代码基于普通malloc分配一片堆内存,并且初始化一些特征数据。
  2. 借助一个用户子自定义模块驱动开放的设备节点,将buffer地址传递给内核驱动,内核驱动通过get_user_page接口获取到malloc 内存映射的页面。
  3. 用vmap/kmap将第二步得到的页面在内核重新映射,映射到一个内核地址,使内核可以访问。
  4. 内核通过重新映射的内核地址确认特征数据是否match用户态写的内容。如果不符合,则说明cache一致性在当前架构下是可见的。
Cache架构以及X86&ARM @Linux平台cache eviction功能测试_第7张图片

x86测试:


#include 
#include 
#include 
#include 
#include 
#include   
#include   
#include   
#include   
#include   
#include 
#include 
#define MISC_NAME   "miscdriver"
 
static int temp_data = 0;
 
static int misc_open(struct inode *inode, struct file *file)
{
    printk("misc_open.\n");
    return 0;
}
 
static void page_count_output(struct page** page, int cnt)
{
    int i;
 
    for(i = 0; i < cnt; i ++)
    {
        printk("%s line %d, page count %d, page map count %d.\n", __func__, __LINE__, page_count(page[i]), page_mapcount(page[i]));
    }
}

int dump_memory(unsigned int *p, int len)
{
    int i = 0;
    
    for(i = 0; i < len; i ++)
    {
        if(i % 16 == 0)
            printk("\n 0x%px:", p + i);
        printk("0x%08x ", p[i]);
    }

    printk("\n");

    return 0;
}
 
static long misc_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{    
    switch(cmd)
    {
        case 0x100:
            if(copy_from_user(&temp_data,  (int *)arg, sizeof(int))) 
                return -EFAULT;
            break;
        
        case 0x101:
            if(copy_to_user( (int *)arg, &temp_data, sizeof(int))) 
                return -EFAULT;
            break;
 
        case 0x102:
        {
            int pined = 4;
            int ret, i;
            int page_cache_pins = 0;
            struct page *user_pages[4];
        unsigned char *pvmap = NULL;
 
            ret = get_user_pages(arg, pined, FOLL_WRITE | FOLL_GET, user_pages, NULL);
            if(ret == pined) {
                printk("%s line %d, pined 4 user pages success.\n", __func__, __LINE__);
            } else {
                printk("%s line %d, pined 4 user pages failure.\n", __func__, __LINE__);
                return -EFAULT;
            }
 
            page_cache_pins = PageTransHuge(user_pages[0]) && PageSwapCache(user_pages[0]) ? 1

你可能感兴趣的:(嵌入式系统,DEBUG,Linux,linux,1024程序员节)