缓存未命中?我怎么能看到那个?

标签 c performance optimization

给出以下代码:

for (int i=0; i<n; i++)
{
  counter += myArray[i];
}

以及循环展开版本:

for (int i=0; i<n; i+=4)
{
  counter1 += myArray[i+0];
  counter2 += myArray[i+1];
  counter3 += myArray[i+2];
  counter4 += myArray[i+3];
}

total = counter1+ counter2 + counter3+ counter4;
  1. 为什么我们在第一个版本中会出现缓存未命中的情况?
  2. 第二个版本的性能确实比第一个版本更好吗?为什么?

问候

最佳答案

Why do we have a cache miss in the first version ?

正如奥利在评论中指出的那样。这个问题毫无根据。如果数据已经在缓存中,那么就不会出现缓存未命中的情况。

除此之外,您的两个示例之间的内存访问没有区别。因此,这不太可能成为它们之间任何性能差异的因素。

Is the second version has indeed a better performance than the 1st ? why ?

通常,要做的就是实际测量。但在这个特定的例子中,我想说它可能会更快。不是因为更好的缓存访问,而是因为循环展开。

您正在进行的优化称为“节点分割”,您可以在其中分离 counter 变量以打破依赖链。

但是,在这种情况下,您正在执行一个简单的归约操作。许多现代编译器都能够识别这种模式并为您执行节点分割。

那么速度更快吗?最有可能。但您应该检查编译器是否为您执行此操作。

<小时/>

郑重声明:我刚刚在 Visual Studio 2010 上对此进行了测试。
令我感到非常惊讶的是它无法 进行此优化。

; 129  : 
; 130  :     int counter = 0;
; 131  : 
; 132  :     for (int i=0; i<n; i++)
    mov ecx, DWORD PTR n$[rsp]
    xor edx, edx
    test    ecx, ecx
    jle SHORT $LN1@main
$LL3@main:

; 133  :     {
; 134  :         counter += myArray[i];

    add edx, DWORD PTR [rax]
    add rax, 4
    dec rcx
    jne SHORT $LL3@main
$LN1@main:

; 135  :     }

Visual Studio 2010 似乎无法为此(简​​单的)示例执行“节点拆分”...

关于缓存未命中?我怎么能看到那个?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10065843/

相关文章:

c - 在 Windows 上获取 c 目录中的每个文件

jquery - CSS 过渡不适用于 ajax 内容

indexing - 什么索引可以加快 X-Hive/Documentum xDB 中的 XQuery?

php - 最优化的 MySQL 语法

c - 需要帮助优化函数调用

java - 如何在不循环的情况下将 Java 中的结果集拆分为 block (每个 block 500 行)?

c - C语言中指针操作的理解问题

c - 在c中获取输入字符串

C - 在多个函数中使用结构

multithreading - 为什么线程越多这个程序越慢?