Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1542614
  • 博文数量: 596
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 173
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-06 15:50
个人简介

在线笔记

文章分类

全部博文(596)

文章存档

2016年(1)

2015年(104)

2014年(228)

2013年(226)

2012年(26)

2011年(11)

分类: LINUX

2013-05-14 16:19:27

原文地址:CPU如何操作内存? 作者:garyybl

原文标题:Getting Physical With Memory

原文地址:http://duartes.org/gustavo/blog/

 

[注:本人水平有限,只好挑一些国外高手的精彩文章翻译一下。一来自己复习,二来与大家分享。]

 

在你试图理解一个复杂的系统时,如果能揭去表面的抽象并专注于最低级别的概念,往往会有不小的收获。在这个精神的指导下,让我们看看对于内存和I/O端口操作来说最简单、最基础的概念,即CPU与总线之间的接口。其中的细节是很多上层概念的基础,比如线程同步。当然了,既然我是个程序员,就暂且忽略那些只有电子工程师才会去关注的东西吧。下图是我们的老朋友,Core 2

 

Core 2

 

Core 2 处理器有775个管脚,其中约半数仅仅用于供电而不参与数据传输。当你把这些管脚按照功能分类后,就会发现这个处理器的物理接口惊人的简单。本图展示了参与内存和I/O端口操作的重要管脚:地址线,数据线,请求线。这些操作均发生在前端总线的事务上下文结构(the context of a transaction)中。前端总线事务的执行包含五个阶段:仲裁,请求,侦听,响应,数据操作。在执行事务的过程中,前端总线上的各个部件扮演着不同的角色。这些部件称之为agent。通常,agent就是全部的处理器外加北桥。

 

本文只分析请求阶段。在此阶段中,发出请求的agent往往是一个处理器,它输出两个数据包。下图列出了第一个数据包中最为重要的位,这些数据位通过处理器的地址线和请求线输出:

 

 

请求包1

 

地址线输出指定了事务发生的物理内存起始地址。我们有33条地址线,他们指定了数据包的第35至第3位,第2至第0位为0。因此,实际上这33条地址线构成了一个36位的、以8字节对齐的地址,正好覆盖的物理内存。这种设定从奔腾Pro就开始了。请求线指定了事务的类型。当事务类型为I/O请求时,地址线指出的是I/O端口地址而不是内存地址。当第一个数据包被发送以后,同样由这组管脚,在下一个总线时钟周期发送第二个数据包:

 

请求包2

 

属性信号(attribute signal A[31:24])很有趣,它反映了Intel处理器所支持的5种内存缓冲功能。把这些信息发布到前端总线后,发出请求的agent就可以让其他处理器知道如何根据当前事务处理他们自己的cache,以及让内存控制器(也就是北桥)知道该如何应对。一块指定内存区域的缓存类型由处理器通过查询页表(page table)来决定,页表由OS内核维护。

 

典型的情况是,内核把全部内存都视为“回写”类型(write-back),从而获得最好的性能。在回写模式下,内存的最小访问单元为一个缓存线cache line),在Core 2中是64字节。当程序想读取内存中的一个字节时,处理器会从L1/L2 cache读取包含此字节的整条缓存线的内容。当程序做写入内存操作时,处理器只是修改cache中的对应缓存线,而不会更新主存中的信息。之后,当真的需要更新主存时,处理器会把那个被修改了的缓存线整体放到总线上,一次性写入内存。所以大部分的请求事务,其数据长度字段都是11REQ[1:0]),对应64 字节。下图展示了当cache中没有对应数据时,内存读取访问的过程:

 

未命中时的内存读取流程

 

Intel计算机上,有些物理内存范围被映射为设备地址而不是实际的RAM存储器地址,比如硬盘和网卡。这使得驱动程序可以像读写内存那样,方便的与设备通信。内核会在页表中标记出这类内存映射区域为不可缓存的uncacheable)。对不可缓存的内存区域的访问操作会被总线原封不动的按顺序执行,其操作与应用程序或驱动程序所发出的请求完全一致。因此,这时程序可以精确控制读写单个字节、字、或其它长度的信息。这都是通过设置第二个数据包中的字节使能掩码(byte enable mask A[15:8])来完成的。

 

前面讨论的这些基本知识还包含很多关联的内容。比如:

1、  如果应用程序想要尽可能高的运行速度,就应该把会被一起访问的数据尽量组织在同一条缓存线中。一旦这条缓存线被载入,之后的读取操作就会加快很多,不再需要额外的内存访问了。

2、  对于回写式内存访问,作用于一条缓存线的任何内存操作都一定是原子的(atomic)。这种能力是由处理器的L1 cache提供的,所有数据被同时读写,中途不会被其他处理器或线程打断。特别的,32位和64位的内存操作,只要不跨越缓存线的边界,就都是原子操作。

3、  前端总线是被所有的agent所共享的。这些agent在开启一个事务之前,必须先进行总线使用权的仲裁。而且,每一个agent都需要侦听总线上所有的事务,以便维持cache的一致性。因此,随着部署更多的、多核的处理器到Intel计算机,总线竞争问题会变得越来越严重。为解决这个问题,Core i7将处理器直接连接于内存,并以点对点的方式通信,取代之前的广播方式,从而减少总线竞争。

 

本文讲述的都是有关物理内存请求的重要内容。当涉及到内存锁定、多线程、缓存一致性的问题时,总线这个角色又将浮出水面。当我第一次看到前端总线数据包的描述时,会有种恍然大悟的感觉,所以我希望您也能从本文中获益。下一篇文章,我们将从底层爬回到上层去,研究一个抽象概念:虚拟内存。

http://blog.csdn.net/drshenlei/article/details/4243733

阅读(842) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~