我正在编写一个 C 语言程序,需要清空内存。请问是否有任何 UNIX 系统命令可以用于清空 CPU 缓存。
这是我的项目要求,因为它涉及到计算逻辑所需的时间。
我已经阅读了 cacheflush(char *s, int a, int b)
函数的相关内容,但我不确定它是否适用以及参数该如何传递。
我正在编写一个 C 语言程序,需要清空内存。请问是否有任何 UNIX 系统命令可以用于清空 CPU 缓存。
这是我的项目要求,因为它涉及到计算逻辑所需的时间。
我已经阅读了 cacheflush(char *s, int a, int b)
函数的相关内容,但我不确定它是否适用以及参数该如何传递。
我理解你的意思是“CPU缓存”,而不是内存缓存。
上面的链接很好:建议“通过CPU写入大量数据”不是特定于Windows。
以下是同一主题的另一种变体:
这是一篇关于Linux和CPU缓存的文章:
注意:
在这个(非常,非常低的)级别上,“Linux” != “Unix”。
echo 3 > /proc/sys/vm/drop_caches
,并提供一个小的示例代码。 - Rose BEckfopen("/proc/sys/vm/drop_caches", "w"); fprintf(fp, "3"); fclose(fp);
。PS:如果这是作业,请在问题中使用“作业”标签。 - paulsm4
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");
}
#include <asm/cachectl.h>
int cacheflush(char *addr, int nbytes, int cache);
假设您有一块刚写入的内存,您希望确保它从缓存刷新到主内存中。该块开始于addr,nbytes长,并且在两个缓存(或两者皆有)中:
ICACHE Flush the instruction cache.
DCACHE Write back to memory and invalidate the affected valid cache lines.
BCACHE Same as (ICACHE|DCACHE).
好的,抱歉我的第一次回答有误。我后来读了你问题下面的跟进评论,所以我现在明白你想要清除指令缓存来启动程序(或其中的部分),这样当你测试它的性能时,你也测试了它最初从主内存加载到指令缓存中的加载时间。你是否还需要将代码将使用的任何数据刷新到主内存中,以便数据和代码都是新的加载?
首先,我想提到的是,主内存本身也是一种缓存,你的硬盘(无论是磁盘上的程序还是磁盘上的交换空间)是程序指令可能来自的最低、最慢的地方。话虽如此,当你第一次运行一个例程时,如果它还没有通过已经执行的其他代码从磁盘加载到主内存中,那么它的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);
...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).
void __builtin___clear_cache(void *begin, void *end)
int cacheflush(void addr, int nbytes, int cache)
https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/aarch64/sync-cache.c#L31
对于Clang,它在这里:https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/clear_cache.c#L123