当前位置: 首页 > 知识库问答 >
问题:

了解如何编写对缓存友好的代码

陆建木
2023-03-14

下面是我使用的代码片段:

#include "time.h"
#include <stdio.h>

#define S 512
#define M S
#define N S

int main() {
    // Summing in the row major order
    int x = 0;
    int iter = 25000;
    int i, j;
    int k[M][N];
    int sum = 0;    
    clock_t start, end;

    start = clock();
    while(x < iter) {
        for (i = 0; i < M; i++) {
            for(j = 0; j < N; j++) {
                sum += k[i][j];
            }
        }

        x++;
    }
    end = clock();
    printf("%i\n", end-start);

    // Summing in the column major order
    x = 0;
    sum = 0;
    int h[M][N];

    start = clock();
    while(x < iter) {
        for (j = 0; j < N; j++) {
            for(i = 0; i < M; i++){
                sum += k[i][j];
            }
        }

        x++;
    }
    end = clock();
    printf("%i\n", end-start);
}

问:有人能告诉我我的错误是什么吗?为什么我会得到这个结果?

共有1个答案

马梓
2023-03-14

我真的不知道你为什么会有这种行为,但让我澄清一些事情。

在考虑缓存时至少要考虑两件事:缓存大小和缓存行大小。例如,我的Intel i7920处理器有一个256KB的L2缓存,行大小为64字节。如果您的数据适合缓存,那么您访问它的顺序并不重要。优化代码使其对缓存友好的所有问题都必须针对两件事:如果可能,将对内存的访问拆分到块中,这样块就适合缓存了。对那个块做所有可能的计算,然后带来下一个块,用它做计算,等等。另一件事,(您正在尝试做的一件事)是以连续的方式访问内存。当您从内存请求一个数据(比方说一个int-4字节)时,整个缓存行被带到缓存中(在我的例子中是64字节:即16个相邻的整数(包括您请求的整数)被带到缓存中)。下面是行顺序对列顺序的播放。在行顺序中,每16个内存请求有1个缓存丢失;在列顺序中,每一个请求都有一个缓存丢失(但仅当数据不适合缓存;如果数据适合缓存,那么得到的比率与行顺序相同,因为从请求行中的第一个元素开始,这些行仍然在缓存中;当然,相关性可以发挥作用,即使不是所有缓存都被数据填满,也可以重写缓存行)。

关于你的问题,当数据放入缓存时,正如我所说的,访问顺序并不重要,但当你做第二次求和时,数据已经在缓存中,从你做第一次求和时开始,所以这就是它更快的原因。如果先进行列序求和,您应该会看到行序求和变得更快,这仅仅是因为行序求和是在行序求和之后进行的。但是,当数据足够大时,您不应该得到相同的行为。尝试以下操作:在两个和之间,对另一个大数据执行一些操作,以便使整个缓存无效。

 类似资料:
  • 根据包括维基百科在内的几个来源,实现二叉树最常用的两种方法是: 每个节点显式保存其子节点的节点和指针(或引用) 子节点的位置由其父节点的索引隐式给定的数组 第二种方法在内存使用和引用的局部性方面明显优越。但是,如果希望以可能导致树不平衡的方式允许从树中插入和删除,则可能会导致问题。这是因为这种设计的内存使用是树深度的指数函数。 假设您希望支持这种插入和删除。如何实现树,使树遍历充分利用CPU缓存。

  • 这就是它看起来的样子。 它工作得很好,等待数据加载,然后开始操作。但这是相当多的代码,有没有更好的方法来做它?

  • 目标 遵循类大小、方法大小和方法名称的最佳实践 了解重构的重要性 保持一致的编码风格和注释用法 使用内置记录功能 最佳编码实践 您现在已经学习了本学习路径的一半内容,已经掌握了足够多的 Java 语法来编写基本 Java 程序。在继续学习更高级的主题之前,目前是一个了解一些最佳编码实践的不错时机。阅读一些可帮助您编写更干净、更可维护的 Java 代码的必要建议。 保持类小巧 目前您已经创建了一些类

  • 问题内容: 我是Laravel的新手。我已经对该主题进行了研究,但似乎找不到找到可以解决问题的答案。 我知道Laravel的默认缓存驱动程序设置为 file ,可以更改。它还有一些手工缓存命令,例如: 1) 即使Laravel具有一些自动处理某些缓存的内置命令和功能(无法确切了解哪些部分),我仍然必须在查询结果上手动使用Cache Facade,对吗? 它不会自动执行操作,仅在我想更改某些内容时才

  • 本文向大家介绍spring缓存代码详解,包括了spring缓存代码详解的使用技巧和注意事项,需要的朋友参考一下 本文研究的主要是spring缓存的相关内容,具体介绍如下。 这篇文章是根据谷歌翻译大致修改出来的,由于原文不知道是什么语,所以可能导致翻译的有错误和不准确的地方,但是大致的方向感觉还是蛮不错的,所以在这里整理了一下,希望能够有所帮助。 高速缓存一直是一个非常需要这两个提高应用程序性能并降

  • 使用友好的 MAC 编号 默认情况下,主机跟交换机启动后分配的 MAC 地址是随机的,这在某些情况下不方便查找问题。 可以使用 --mac 选项,这样主机跟交换机分配到的 MAC 地址跟他们的 ID 是一致的,容易通过 MAC 地址较快找到对应的节点。