CPU读取数据的时候,不是直接访问内存,而是先访问缓存,缓存没有命中的情况下才会去访问内存,如果缓存命中则直接从缓存中读取数据,由于缓存的速度要远高于内存,因此充分利用CPU的cache来缓存数据,提高cache命中率能够大幅度提高程序的运行速度。
下面是一个实际的测试代码:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10000
//#define DEBUG
int main(){
double a[SIZE][SIZE];
double b[SIZE][SIZE];
double c[SIZE][SIZE];
#ifdef DEBUG
for(int j = 0; j < SIZE; j++){
for(int i = 0; i < SIZE; i++){
#else
for(int i = 0; i < SIZE; i++){
for(int j = 0; j < SIZE; j++){
#endif
a[i][j] = 8.3 * i + 1.2 * j;
b[i][j] = 12.3 * i + 3.4 * j;
}
}
#ifdef DEBUG
for(int j = 0; j < SIZE; j++){
for(int i = 0; i < SIZE; i++){
#else
for(int i = 0; i < SIZE; i++){
for(int j = 0; j < SIZE; j++){
#endif
c[i][j] = a[i][j] + b[i][j];
}
}
return 0;
}
在上述代码中,我们使用宏定义来实现两种不同的数组访问顺序。
我们根据不同的标识来进行编译
编译的第一个二进制是利用cache的t1
gcc -o t1 t.c
编译的第二个二进制是t2
gcc -o t2 t.c -DDEBUG
首先我们测试这两个程序的运行时间,可以看到在相同的环境下,t2运行的时长是t1的四倍
使用perf stat查看两个程序运行时的IPC,可以看到在相同的环境下,t2运行的ipc只有t1的四分之一
使用perf stat命令查看两个进程的L1 cache miss数量,能够看到二者的显著差别
perf stat -e L1-dcache-load-misses ./t1
perf stat -e L1-dcache-load-misses ./t2