前面搭建好了dpdk的开发环境,现在了解一下dpdk的具体细节。
系统架构的演变
经典的计算计体系中,都有北桥和南桥,这种架构如图:
从图中可以得知一个多核处理器访问内存,需要经过北桥,处理器访问外设(USB、SATA等)时也需要经过北桥,外设访问内存也需要内存。可以看出,北桥和内存单独联系,而内存的访问频率非常高,为了改善北桥带宽引起的性能瓶颈,架构演变为如下:
增加了内存控制器(MC)来协调北桥与内存直接的交互,还可以和多个内存相连,这种架构有所改进,但是还是没有解决北桥如果带宽不够。最终架构演变为下图结构:
这种架构一个核与一个内存联系,称为本地内存,缺点在与访问其他核管理的内存需要跨核心,访问本地内存十分快速。
Cache系统
- Cache种类
处理器和内存之前速度存在非常大的差异,通过在处理器和内存直接加一层的方式,用于缓冲一下数据,缓解两者性能上的差异,这个缓冲就是Cache,这个缓存又分为三级,一级最快但是容量小,三级最慢,但是是缓冲里面最大的。为什么不直接使用最快的一级缓存呢?因为贵,以及技术问题。如果处理器访问内存时,在Cache中没有命中就会访问内存。 - TLB Cache种类
现在操作系统使用分页管理内存,当进程访问虚拟地址时,处理器需要找到虚拟机地址和物理地址做映射关系,这个关系存在多级页表里面,如果未找到映射关系,就触发中断。
页表也是存在内存里面的,前面说了内存和处理器的性能存在差异,还是采用加一层的方式,TLB Cache就诞生了。同样如果没有命中此缓存,就会访问内存,降低速度。
Cache地址映射和变换
Cache的容量也不大,相对于内存来说,所以需要一个映射算法和分块算法来把内存中的内容放到Cache中。
分块机制就是说,以一个什么单位进行数据交换,通常以一个存储周期能够访问的数据长度为限。
映射算法是吧内存地址映射到Cache中去。处理器访问数据块时,则需要把内存地址转化成为Cache地址,从而找到数据。Cache和内存的映射关系有三种,全关联型、直接关联型、组关联型。
Cache的写策略
内存的数据被加载到Cache后,再某个时候还需要将新的结果写会内存
- 直写:就是处理器就改了就写入到内存,会造成总线繁忙。
- 回写:简单说就是处理器第一次对Cache的写入不里面写到内存,第二次才会。会造成缓存不一致问题。
- WC
- UC
Cache预取
Cache可以在访问一个指令、内存时,将相邻的数据从内存预取到Cache中,dpdk在读取报文时,通过多种技术实现了预取。
Cache一致性
a). 当数据不是Cache对齐的时候,比如占用了两个Cache Line。一个核修改了一个Line,然后会写的时候,就会有同步问题。
b). 当数据是对齐的,但是对核对一个Line进行读写,回写时也会有冲突。
第一个原因,dpdk在定义结构体的时候,就可以进行Line对齐。
第二个原因,Cache的一二级缓存在每个处理器核心都有,导致一个内存有多个备份,如果是单核处理器就Cache只有一个,就不存在问题了。如果是多核处理器,所有处理器共享Cache,或者采用直写的方式。
为了解决问题,但是又不降低性能,找到了一个解决方法,一致性协议。
一致性协议
介绍两种:基于目录的协议,总线窥探协议。
- 基于目录的协议:就是用一个目录把Cache内存管理起来,当处理器需要数据从内存加载到自己独占的Cache时,需要向目录提出申请。当处理器改变这种内存的时候,交给目录,目录会使其他处理器独占的那个备份失效或更新。
- 总线窥探协议:通过总线广播的方式,如果处理器改变了独占Cache的内容,则发出一个广播,通知其他处理器进行更改。如果处理器接收到广播就进行更新。
dpdk解决方案,减少多个核心访问同一个内存或数据结构,避免共享数据。
TLB和大页
可以了解一下虚拟地址和物理地址的转化过程。TLB加速了这个查找过程,把虚拟地址的前20位和页框号直接对应起来,可以迅速找到物理地址的起始地址,再与虚拟地址的后12位组合,就可以得到最终的物理地址,这里是按32位操作系统来说的,地址是32位。如果虚拟地址的前20位不能再TLB中找到对应关系,这种就称为miss。就需要从页表慢慢进行匹配。常规使用4k做一个页的大小,对应出来的的页表项是把内存按4k进行划分,如果使用2M做一个页的大小,页表项就会减少,TLB命中率就会提升。