CPU访问物理内存

有了之前linux内核对内存管理这块知识后,接下来,我想通过这篇文章分析下cpu如何获取内存数据以及如何缓存数据.在这里要感谢国外的一位大神Gustavo Duarte,我在一次偶然之间遇到了他的博客,然后学到了很多关于linux内核以及架构的知识,包括这篇文章.

我们在计算机体系结构课上有学过cpu在获取数据时,是先在cpu内的缓存中查找,如果缓存有,则无需到主存中获取数据;如果缓存没有数据,则需要先到主存获取数据,并存入cpu缓存中,然后从cpu缓存中将数据返回.这篇文章主要想说说这这个过程的具体执行情况.

先说下cpu中的缓存为什么比主存快?我当初想当然的以为是因为离的近,可能这是一方面(虽然影响微乎其微),最主要还是主存使用的态存储功能的存储器(DRAM),而缓存使用的是具有静态存取功能的存储器(SRAM).DRAM内存需要每隔一段时间刷新充电一次,否则内部数据会消失.而SRAM不需要刷新电路即能保存内部存储的数据,所以SRAM性能高于DRAM.StackExchange有一帖子也有关于SRAM比DRAM的原因Why is SRAM faster than DRAM?

在介绍之前,先看下CPU内部图: CPU内部图 这是Intel Core 2 Duo Processor处理器,目前的处理器和这个相差不大,可能增加一个L3缓存或者增加核数,但不影响我们分析原理.

由图可知,cpu的两个核是统一的一个整体,每个核都有执行单元,指令获取解码单元以及32kb的数据和指令缓存.在CPU内部,核外有一个6M的L2缓存,是两个核共享的缓存.接下来是bus接口单元.在整个CPU外部,有775个引脚(pins),用于CPU外部和CPU内部传输数据,其中有一半是提供电,并不传输数据.如果按功能分的话,其中有三类重要的引脚,可以分为33个地址线引脚,64个数据线引脚以及请求控制线引脚,这些引脚涉及内存或IO端口操作,而这些操作发生在front side bus事务上下文中.

fsb(front side bus)事务有5个过程,仲裁(arbitration),请求(request),探测(snoop),回复(response),数据(data).在不同的过程中,FSB对于处理器和北桥(northbridge)扮演着不同的角色.在这里,我们只看下cpu请求过程,cpu请求过程,处理器将会发送两个包,两个包都是由地址总线引脚和请求总线引脚发出,我们来看下第一个包Packet A的所包含的信息: 请求包结构 由第一张图可知,地址总线占有33个bits(35-3),其中2-0bits为0.因此这个cpu有36位地址总线,并且以8字节对齐,64G可寻址物理内存.而请求引脚的5个bits则解释了这次事务是什么类型,如下图. 请求控制信息 由这个图,可以知道cpu的这次事务可能为内存访问或者IO请求,取决于请求引脚5位包含的信息.

在第一个包发出之后的下一个bus clock cycle,在相同的引脚上,就发出了第二个包Packet B Packet B 对于第二包,我们主要关注的是Attribute Signals这块内容,因为这影响着访问内存区域的缓存行为.将这块信息放入FSB,请求的agents就可以让其他处理器知道这次事务影响了他们的缓存以及内存控制器(northbridge)应该怎么处理.处理器通过查看页表决定访问的内存区域的类型.

通常内核将所有的内存看作是write-back,因为这有很好的性能.在这种模式下,cpu访问内存单元是一块内存行,在上图core 2中是64字节.如果一个进程需要读取一个字节的数据,那么处理器会将这个字节所在的64字节内存行载入L2和L1缓存中.当处理器需要向内存写数据时,也是先修改缓存中的数据,并未修改内存中的数据.之后,当必须将修改的数据写回主存时,那么整个缓存行会一次全部写进物理内存.下面图展示了处理器向内存读取数据的过程: 处理器向内存取数据过程 Intel计算机中的一些物理内存是映射到设备的,例如硬盘和网卡.这就允许这些设备的驱动器通过读写这些内存来和设备进行交流.对于这些内存区域,内核在页表中标注为uncacheable不可缓存的,所以每次需要访问不可缓存的内存,即使每次都是一个字节,都必要到主存中访问,不能在L1或L2中缓存.对于每次读取一字节的,可以通过上述的Packet B的enable mask来设置.

上述原语有许多的含义,例如:

  1. 对于性能敏感的应用程序尽量将相关联的数据打包在同一个cache行.这样一来,当这块内存行被载入缓存时,读取缓存行中的其他数据会更快,而且避免了额外的主存访问.例如C++的数组和vector在一定条件下会比list速度块,因为前者的数据是存储在线性空间,而后者是离散的.
  2. 任何的内存访问(假设这些访问都落在同一个缓存行中)都保证是原子的,这样的访问是通过处理器的L1缓存提供的而且数据的读或写都是同时完成的,不能被其他处理器或者线程影响.
  3. front bus是所有处理器共享的,所以每个处理器在开始事务之前都需要仲裁谁获取front bus的控制权.而且所有的处理器必须监听所有的事务,为的是保证每个缓存的一致性.由于CPU向更多核发展,因此bus竞争将会是个很严重的问题.

以上就是物理内存请求的重点,这在以后理解锁,多线程和缓存一致性有很大的帮助.

注:Frontside Bus(FSB)是计算机架构中一个重要的组件,允许CPU与不同的计算机系统资源交流.FSB连接了CPU和系统内存,input/output(I/O)外围设备以及其他一些主板组件.

上图中的northbridge就是连接内存和FSB组件,还有一个southbridge是连接IO设备和FSB的组件