如何从C程序刷新Linux中的CPU缓存?

如何从C程序刷新Linux中的CPU缓存?,c,linux,unix,caching,flush,C,Linux,Unix,Caching,Flush,我正在写一个需要刷新内存的C程序。我想知道是否有任何UNIX系统命令来刷新CPU缓存 这是我的项目的一个要求,它涉及到计算我的逻辑所花费的时间 我已经读过关于cacheflush(char*s,int a,int b)函数的内容,但我不确定它是否合适,以及在参数中传递什么 我想你的意思是“CPU缓存”,不是内存缓存 上面的链接很好:建议“通过CPU写入大量数据”不是特定于Windows的 这是同一主题的另一个变体: 这里有一篇关于Linux和CPU缓存的文章: 注: 在这个(非常非常

我正在写一个需要刷新内存的C程序。我想知道是否有任何UNIX系统命令来刷新CPU缓存

这是我的项目的一个要求,它涉及到计算我的逻辑所花费的时间

我已经读过关于
cacheflush(char*s,int a,int b)
函数的内容,但我不确定它是否合适,以及在参数中传递什么

  • 我想你的意思是“CPU缓存”,不是内存缓存

  • 上面的链接很好:建议“通过CPU写入大量数据”不是特定于Windows的

  • 这是同一主题的另一个变体:

  • 这里有一篇关于Linux和CPU缓存的文章:

  • 注:


    在这个(非常非常低的)级别,“Linux”!=“Unix”

    如果您正在编写一个用户模式(而不是内核模式)程序,并且它是单线程的,那么您根本没有理由首先刷新缓存。你的用户模式程序可以忘记它的存在;它只是用来加速程序的执行,操作系统通过处理器的MMU来管理它

    我能想到的只有两个原因,即您实际上可能希望从用户模式应用程序中刷新缓存:

  • 您的应用程序计划在对称多处理器系统上运行,或与外部硬件进行数据事务)
  • 您只是在测试缓存以进行某种性能测试(在这种情况下,您可能真的应该编写测试以在内核模式下运行,可能作为驱动程序)
  • 在任何情况下,假设您正在使用Linux

    #include <asm/cachectl.h>
    
    int cacheflush(char *addr, int nbytes, int cache);
    
    #include <asm/cachectl.h>
    
    int cacheflush(char *addr, int nbytes, int cache);
    
    ...where cache is one of:
       ICACHE Flush the instruction cache.
       DCACHE Write back to memory and invalidate the affected valid cache lines.
       BCACHE Same as (ICACHE|DCACHE).
    
    通常,您只需要刷新DCACHE,因为当您将数据写入“内存”(即缓存)时,它通常是数据,而不是指令

    如果出于某种奇怪的测试原因,您想刷新“所有缓存”,您可以使用malloc()一个比您的CPU缓存大的大块(拍摄,使其大8倍!),将任何旧垃圾写入其中,然后只刷新整个块


    另请参见:

    好的,很抱歉我的第一个答案。稍后我阅读了您问题下方的后续评论,因此我现在意识到您希望刷新指令缓存以从缓存中引导程序(或其部分),以便在测试其性能时,还可以测试其从主内存到指令缓存的初始加载时间。您是否还需要将代码将要使用的任何数据刷新到主内存中,以便数据和代码都是新加载的

    在此之前,我想指出的是,主内存本身也是一种缓存形式,硬盘(磁盘上的程序或磁盘上的交换空间)是程序指令可能来自的最低、最慢的位置。这就是说,当您第一次运行例程时,如果由于靠近已执行的其他代码,该例程尚未从磁盘加载到主内存中,则必须首先从磁盘加载其CPU指令。这需要一个数量级,甚至比从主内存加载到缓存中的时间还要长。一旦加载到主存,从主存加载到缓存所需的时间要比从缓存加载到CPU的指令获取程序所需的时间长一个数量级。因此,如果您想测试代码的冷启动性能,您必须确定冷启动的含义。。。。将其从磁盘或主内存中拉出。我不知道有什么命令可以将指令/数据从主存中“刷新”出来以交换空间,所以将其刷新到主存是您所能做的(我知道),但请记住,您的测试结果可能仍然与第一次运行(当它可能从磁盘上拔下时)到后续运行不同,即使您确实刷新了指令缓存

    现在,如何刷新指令缓存以确保自己的代码被刷新到主内存

    如果我需要这样做(在我看来这是一件非常奇怪的事情),我可能会首先找到我的函数在内存中的长度和大致位置。因为我使用的是Linux,所以我会发出命令“objdump-d{myprogram}>myprogram.dump.txt”,然后在编辑器中打开myprogram.dump.txt,搜索我想要刷新的函数,并通过使用十六进制计算器从它们的开始地址减去它们的结束地址来计算它们的长度。我会记下每件衣服的尺寸。稍后,我会在代码中添加cacheflush()调用,将我要刷新的每个函数的地址指定为'addr',将找到的长度指定为'nbytes',并将其命名为ICACHE。为了安全起见,我可能会做一些修改&在大小上增加10%,以防万一我对代码做了一些调整而忘记调整nbytes。对于每个要刷新的函数,我都会这样调用cacheflush()。然后,如果我还需要清除数据,如果它使用全局/静态数据,我也可以清除这些数据(DCACHE),但是如果是堆栈或堆数据,我真的无法(或应该)从缓存中清除这些数据。试图这样做将是一种愚蠢的行为,因为这将创造一种在正常执行中永远不会或很少存在的条件。 假设您正在使用Linux

    #include <asm/cachectl.h>
    
    int cacheflush(char *addr, int nbytes, int cache);
    
    #include <asm/cachectl.h>
    
    int cacheflush(char *addr, int nbytes, int cache);
    
    ...where cache is one of:
       ICACHE Flush the instruction cache.
       DCACHE Write back to memory and invalidate the affected valid cache lines.
       BCACHE Same as (ICACHE|DCACHE).
    
    #包括
    intcacheflush(char*addr,intn字节,intcache);
    …其中缓存是以下内容之一:
    ICACHE刷新指令缓存。
    DCACHE写回内存并使受影响的有效缓存线无效。
    b与(ICACHE | DCACHE)相同。
    

    顺便说一句,这是课堂作业吗?

    英特尔建议刷新缓存的方式如下:

    mem_flush(const void *p, unsigned int allocation_size){
        const size_t cache_line = 64;
        const char *cp = (const char *)p;
        size_t i = 0;
    
        if (p == NULL || allocation_size <= 0)
                return;
    
        for (i = 0; i < allocation_size; i += cache_line) {
                asm volatile("clflush (%0)\n\t"
                             : 
                             : "r"(&cp[i])
                             : "memory");
        }
    
        asm volatile("sfence\n\t"
                     :
                     :
                     : "memory");
    }
    
    mem_flush(常量void*p,无符号整数分配大小){
    常量大小缓存线=64;
    常量字符*cp=(常量字符*)p;
    尺寸i=0;
    
    如果(p==NULL | |分配| U大小,为什么需要刷新缓存?这是我的项目的一个要求