一般我们的开发同学们都知道自己机器的CPU是几核、内存是多大。但是对于CPU内部对程序性能影响较大的缓存却是一知半解。有些开发同学都是计算机的缓存有L1、L2、L3,但是再详细一点的问题,可能就很少有同学能答的完整了。如果下面这几个问题你能脱口而出,请跳过本节。例如:
-
缓存究竟在哪里? -
L1有几种? -
你的缓存有几级,分别是多大? -
你的24核的机器,一二三级缓存分别有几个,存在共享的情况吗?x1
其实缓存对计算机程序运行性能影响极大,但是他们在开发同学心目中的存在感却不如内存高。要知道CPU缓存以及缓存算法的设计是现代CPU设计的核心任务之一。飞哥觉得缓存们一定感到很伤心。
Intel CPU体系结构
其实在286之前的时代的CPU本是没有缓存的,因为当时的CPU和内存速度差异没有现在这么大,CPU直接访问内存。但是到386时代,CPU和内存的速度不匹配了,第一次出现了缓存。而且最早的缓存并没有放在CPU模块里,而是放在主板上的。再往后CPU越来越快,现在CPU的速度比内存要快百倍以上,所以就逐步演化出了L1、L2、L3三级缓存结构,而且都集成到的CPU芯片里,以进一步提高访问速度。
我们来看下现代Intel的CPU架构的基本结构。
L1最接近于CPU,速度也最快,但是容量最小。一般现代CPU的L1会分成两个,一个用来cache data,一个用来cache code,这是因为code和data的更新策略并不相同,而且因为CISC的变长指令,code cache要做特殊优化。 一般每个核都有自己独立的data L1和code L1。
越往下,速度越慢,容量越大。L2一般也可以做到每个核一个独立的。但是L3一般就是整颗CPU共享的了。 UEFIBlog里提供了一个比较好的物理解剖图,比较好地展示了出来:
实际查看
上面介绍的只是笼统的概念。但是每个CPU的缓存都是不一样的,而且“纸上得来终觉浅”,我觉得我们还是有必要进行下一步的实机勘探工作。
Linux的内核的开发者定义了一套框架模型来完成这一目的,它就是CPUFreq系统。 CPUFreq提供的sysfs接口,可以让我们看到比/proc/cpuinfo更为详细的CPU详细信息。
# cd /sys/devices/system/cpu/;ll
drwxr-xr-x 7 root root 0 Apr 15 15:29 cpu0
drwxr-xr-x 7 root root 0 Apr 15 15:29 cpu1
......
-
L1一级缓存查看:
# cat cpu0/cache/index0/level
1
# cat cpu0/cache/index0/size
32K
# cat cpu0/cache/index0/type
Data
# cat cpu0/cache/index0/shared_cpu_list
0,12
# cat cpu0/cache/index1/level
1
# cat cpu0/cache/index1/size
32K
# cat cpu0/cache/index1/type
Instruction
# cat cpu0/cache/index1/shared_cpu_list
0,12
从上面的level接口可以看出index0和index1都是一级缓存,只不过一个是Data数据缓存,一个是Instruction也就是代码缓存。
等等,上面提到的是每个Core是独立的L1缓存,为什么shared_cpu_list显示有共享?对了我们这里看到的cpu0并不是物理Core,而是逻辑核,都是超线程技术虚拟出来的。 实际上cpu0和cpu12是属于一个物理Core,所以每个Data L1和Instruction是这两个逻辑核共享的。
我的这台电脑里,总共是有12个Data L1,12个Instrunction L1,大小都是32K。
-
L2二级缓存查看:
# cat cpu0/cache/index2/size
256K
# cat cpu0/cache/index2/type
Unified
# cat cpu0/cache/index2/shared_cpu_list
0,12
二级缓存要比一级缓存大不少,有256K,但是不分Data和Instruction。另外L2和L1一样,也是总共有12个,每两个逻辑核共享一个L2。
-
L3三级缓存查看:
# cat cpu0/cache/index3/size
12288K
# cat cpu0/cache/index3/type
Unified
# cat cpu0/cache/index3/shared_cpu_list
0-5,12-17
#cat cpu6/cache/index3/shared_cpu_list
6-11,18-23
L3达到了12M,你去买CPU的时候商品里能看到的缓存属性一般告诉你的就是这个L3属性。因为L3要比L2和L1看起来要大的多,能激发你购买的欲望。但实际上我的这台电脑里L3只有两个,每个CPU各一个,不像是L2、L1有很多。第0-5,12-17号逻辑核共享一个L3,因为它们是在一个物理CPU上。6-11,18-23共享另一个。
另外,Linux上还有个dmidecode命令,也能查看到一些关于CPU缓存的信息,感兴趣的小伙伴们可以试试
# dmidecode -t cache
可能有的同学会问了,我用的操作系统是windows啊,怎么看?打开cmd命令行,输入以下命令试试吧,飞哥在windows上知道的就这么多了,感兴趣的话你自己google上搜搜吧。
# wmic cpu get L2CacheSize,L3CacheSize
扩展知识
**Cache Line:**我们前面只介绍了各个级别的缓存,但是这里面有个很重要的概念就是Cache Line,就是本级缓存向下一层取数据时的基本单位。可以通过如下方式查看:
# cd /sys/devices/system/cpu/;ll
# cat cpu0/cache/index0/coherency_line_size
64
# cat cpu0/cache/index1/coherency_line_size
64
# cat cpu0/cache/index2/coherency_line_size
64
# cat cpu0/cache/index3/coherency_line_size
64
可以看到L1、L2、L3的Cache Line大小都是64字节(注意是字节)。就是说每次cpu从内存获取数据的时候,都是以该单位来进行的,哪怕你只取一个bit,CPU也是给你取一个Cache Line然后放到各级缓存里存起来。请大家牢牢记住这个概念,以后的文章中我们会用到。