Linux性能学习(1.2):CPU_如何提高CPU缓存命中率
Posted Stoneshen1211
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux性能学习(1.2):CPU_如何提高CPU缓存命中率相关的知识,希望对你有一定的参考价值。
文章目录
在上一篇文章中简单介绍了CPU缓存的相关知识,并且引申出了一个概念—“CPU缓存命中”,那么如何让我们编写的程序尽可能的被CPU缓存命中,从而尽可能的提高运行效率?
1 数组访问测试
代码测试如下:
#include <stdio.h>
#include <sys/time.h>
#define Len 1024
void main()
float time_use = 0;
struct timeval start;
struct timeval end;
int s32Array[Len][Len];
int i = 0;
int j = 0;
gettimeofday(&start,NULL);
#if 0 //方法1
for (i = 0; i < Len; i++)
for(j = 0; j < Len; j++)
s32Array[i][j] = 0;
#else //方法2
for (j = 0; j < Len; j++)
for(i = 0; i < Len; i++)
s32Array[i][j] = 0;
#endif
gettimeofday(&end,NULL);
time_use=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec);
printf("time_use is %f\\n",time_use);
编译上面的程序,进行测试,使用方法1中的方式:
# perf stat -e cache-references,cache-misses,instructions,cycles,L1-dcache-load-misses,L1-dcache-loads ./test
time_use is 5095.000000
Performance counter stats for './test':
<not supported> cache-references
<not supported> cache-misses
<not supported> instructions
<not supported> cycles
<not supported> L1-dcache-load-misses
<not supported> L1-dcache-loads
0.007139561 seconds time elapsed
使用方法2中的方式:
# perf stat -e cache-references,cache-misses,instructions,cycles,L1-dcache-load-misses,L1-dcache-loads ./test
time_use is 22464.000000
Performance counter stats for './test':
<not supported> cache-references
<not supported> cache-misses
<not supported> instructions
<not supported> cycles
<not supported> L1-dcache-load-misses
<not supported> L1-dcache-loads
0.025807438 seconds time elapsed
PS:因为是在虚拟中测试,所以没法测试出缓存命中率等信息。
通过上面的测试,可以得出,使用方法1时间大约是5ms左右,而使用方法2则大约是22ms左右。
为啥有这么大的差距,因为数组在内存中是连续的,并且按照前面说的cache line,CPU加载数组时候会一次加载一块的数据进缓存中。因此按照方法1的方式,CPU在加载[0][0]时候,会一次性的将[0][1]、[0][2]等后续内存中的数组加载进来,则进行[0][1]运算的时候,不需要从内存中读取[0][1]了,所以运行时间就会大大减小;按照方法2的方式,CPU在加载[0][0]时候,会一次性的将[0][1]、[0][2]等后续内存中的数组加载进来,但是下一个计算的不是[0][1],而是[1][0],没有在缓存中,则需要重新从内存中读取,运行时间就会减慢。
但是,如果数组很小,即一次可以将全部的数据加载进缓存,那么其实两种方法时间上没有很明显的差异,如果数组很大,则会看到明显的差异。
因此在进行数据操作的时候,我们可以尽可能的按照内存布局顺序来进行操作,可以大大提高性能。
2 其它规则
基于以上的结论,我们在定义数据结构的时候,如果按照cache line的大小进行对齐,就可能减少读写内存的次数,提高性能,即空间换取时间。
函数循环体内的代码尽量精简,因为指令是放在指令缓存中的,大小是有限的,如果对某段代码需要多次读取,超过指令缓存大小,那么就无法发挥优势。
对于if/switch等语句,有规律的数据(比如递增、递减)能够让CPU的分支预测器发挥作用,从而提高效率。
如果有多个核,则可以尽量将进程绑定到一个核上,这样避免进程在核A中运行,因为任务调度要在核B中运行,则需要将数据重新缓存到B的缓存中。
以上是关于Linux性能学习(1.2):CPU_如何提高CPU缓存命中率的主要内容,如果未能解决你的问题,请参考以下文章
Linux性能学习(1.2):CPU_如何提高CPU缓存命中率
Linux性能学习(1.5):CPU_如何找到CPU使用率高原因
Linux性能学习(1.5):CPU_如何找到CPU使用率高原因
Linux性能学习(1.4):CPU_如何查看CPU上下文切换参数