Tag: cpu cache

使用时间戳计数器和clock_gettime进行缓存未命中

作为本主题的后续内容 ,为了计算内存未命中延迟,我使用_mm_clflush , __rdtsc和_mm_lfence (基于此问题/答案的代码)编写了以下代码。 正如您在代码中看到的,我首先将数组加载到缓存中。 然后我刷新一个元素,因此缓存行从所有缓存级别逐出。 为了在-O3期间保留顺序,我放了_mm_lfence 。 接下来,我使用时间戳计数器来计算延迟或读取array[0] 。 正如您在两个时间戳之间看到的那样,有三个指令:两个lfence和一个read 。 所以,我必须减去lfence开销。 代码的最后一部分计算开销。 在代码结束时,打印开销和未命中延迟。 但是,结果无效! #include #include #include int main() { int array[ 100 ]; for ( int i = 0; i < 100; i++ ) array[ i ] = i; uint64_t t1, t2, ov, diff; _mm_lfence(); _mm_clflush( &array[ 0 ] ); _mm_lfence(); […]

预取L1和L2的数据

在Agner Fog的手册“ C ++中的优化软件 ”第9.10节“大数据结构中的Cahce争论”中,他描述了当矩阵宽度等于称为临界步幅的情况时转置矩阵的问题。 在他的测试中,当宽度等于临界步幅时,L1中矩阵的成本增加40%。 如果矩阵更大并且仅适用于L2,则成本为600%! 这在表9.1中的文字中得到了很好的总结。 这与在为什么将512×512的矩阵转置比转换513×513的矩阵要慢得多一样是必不可少的。 后来他写道: 这种效果对于二级高速缓存争用而言比一级高速缓存争用强得多的原因是二级高速缓存不能一次预取多行。 所以我的问题与预取数据有关。 根据他的评论,我推断L1可以一次预取多个缓存行。 预取了多少? 据我所知,尝试编写代码来预取数据(例如使用_mm_prefetch)很少有用。 我读过的唯一例子是Prefetching Examples? 并且它只有O(10%)的改进(在某些机器上)。 Agner后来解释了这个: 原因是现代处理器由于无序执行和高级预测机制而自动预取数据。 现代微处理器能够自动预取包含具有不同步幅的多个流的常规访问模式的数据。 因此,如果可以使用固定步幅以常规模式排列数据访问,则不必显式预取数据。 那么CPU如何决定预取哪些数据,以及有哪些方法可以帮助CPU为预取做出更好的选择(例如“具有固定步幅的常规模式”)? 编辑:根据Leeor的评论,让我添加我的问题并使其更有趣。 与L1相比,为什么关键步幅对L2的影响要大得多? 编辑:我试图使用代码重现Agner Fog的表格为什么转换512×512的矩阵要比转置513×513矩阵慢得多? 我在Xeon E5 1620(Ivy Bridge)上以MSVC2013 64位版本模式运行它,它具有L1 32KB 8路,L2 256 KB 8路和L3 10MB 20路。 L1的最大矩阵大小约为90×90,L3的最大矩阵大小为256×256,L3的最大矩阵大小为1619。 Matrix Size Average Time 64×64 0.004251 0.004472 0.004412 (three times) 65×65 0.004422 0.004442 0.004632 (three […]

了解CPU缓存和缓存行

我试图了解CPU缓存是如何运行的。 让我们说我们有这个配置(作为一个例子)。 缓存大小1024字节 缓存行32个字节 1024/32 = 32个缓存行全部在一起。 Singel缓存行可以存储32/4 = 8个整数。 1)根据这些配置,标签的长度应为32-5 = 27位,索引大小为5位(2 ^ 5 =高速缓存行中每个字节的32个地址)。 如果总缓存大小为1024且有32个缓存行,那么标记+索引存储在哪里? (还有另外4 * 32 = 128字节。)这是否意味着缓存的实际大小是1024 + 128 = 1152? 2)如果在这个例子中高速缓存行是32字节,这意味着当CPU需要从RAM获取新字节时,32个字节被复制到高速缓存中。 我是否正确地假设所请求字节的缓存行位置将由其地址确定? 这就是我的意思:如果CPU在[FF FF 00 08]请求字节,则可用的高速缓存行将填充从[FF FF 00 00]到[FF FF 00 1F]字节。 我们需要的单字节将位于[08]位置。 3)如果前面的语句是正确的,是否意味着用于索引的5位在技术上是不需要的,因为所有32个字节都在缓存行中? 如果我出错了,请告诉我。 谢谢

WBINVD指令用法

我正在尝试在linux上使用WBINV指令来清除处理器的L1缓存。 以下程序编译,但在我尝试运行它时会产生分段错误。 int main() {asm (“wbinvd”); return 1;} 我正在使用gcc 4.4.3并在我的x86机器上运行Linux内核2.6.32-33。 处理器信息:Intel(R)Core(TM)2 Duo CPU T5270 @ 1.40GHz 我按如下方式构建了程序: $ gcc $ ./a.out 分段故障 有人能告诉我我做错了什么吗? 我如何让它运行? PS:我正在运行一些性能测试,并希望确保处理器缓存的先前内容不会影响结果。

x86指令缓存是如何同步的?

我喜欢这个例子,所以我在c中写了一些自修改代码… #include #include // linux int main(void) { unsigned char *c = mmap(NULL, 7, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE| MAP_ANONYMOUS, -1, 0); // get executable memory c[0] = 0b11000111; // mov (x86_64), immediate mode, full-sized (32 bits) c[1] = 0b11000000; // to register rax (000) which holds the return value // according to linux x86_64 calling convention c[6] […]

系统上的缓存大小估算?

我从这个链接( https://gist.github.com/jiewmeng/3787223)获得了这个程序。我一直在网上搜索,以便更好地理解处理器缓存(L1和L2)。我想成为能够编写一个程序,让我能够猜测我的新笔记本电脑上L1和L2缓存的大小。(仅用于学习目的。我知道我可以查看规格。) #include #include #include #define KB 1024 #define MB 1024 * 1024 int main() { unsigned int steps = 256 * 1024 * 1024; static int arr[4 * 1024 * 1024]; int lengthMod; unsigned int i; double timeTaken; clock_t start; int sizes[] = { 1 * KB, 4 * KB, 8 * KB, 16 […]

clflush通过C函数使缓存行无效

我试图使用clflush手动驱逐缓存行,以确定缓存和行大小。 我没有找到关于如何使用该指令的任何指南。 我所看到的,是一些使用更高级别function的代码。 有一个内核函数void clflush_cache_range(void *vaddr, unsigned int size) ,但我仍然不知道在我的代码中包含什么以及如何使用它。 我不知道该function的size是多少。 更重要的是,我怎样才能确定该行被驱逐以validation我的代码的正确性? 更新: 这是我想要做的初始代码。 #include #include #include #include int main() { int array[ 100 ]; /* will bring array in the cache */ for ( int i = 0; i < 100; i++ ) array[ i ] = i; /* FLUSH A LINE */ /* […]