GPU浅见
首发于GPU浅见

GPU存储体系

GPU作为一个外围设备,最初出现在计算机体系中,是为了专门做图形显示使用的。随着GPU功能的不断发展壮大,GPU也逐渐成长为另外一个相比于CPU的计算核心,甚至于在某些特定的领域,其运算能力还超过了CPU。计算需要数据,大规模的计算更需要大规模的数据支持。在这方面,GPU的存储体系给程序员们带来了很大的困扰,其根本原因在于很多时候GPU的存储体系与CPU相似却又不同,容易让人混淆一些概念。在这里我简单讲一下我所理解的GPU的存储体系,以期能够抛砖引玉。如有不当之处,敬请指正。

说到概念混淆,本文的标题即是一例。在这里,我们说GPU存储体系,而不说GPU内存体系,因为一般概念上来讲,内存指的是CPU专用的存储,比如说一台电脑上插着8G的DDR4,那么这8G DDR4就是CPU能用的内存。现在很多手机标榜自己32G内存64G内存,还真的是把内存当内部存储来解释,为此有人还发明了运存的概念,希望各位能够分辨。在GPU存储体系中,CPU的内存一般称为主存, main memory(mm)。为啥GPU看CPU的内存叫main呢,因为驱动程序之类实质上是运行于CPU上的。GPU自己的存储称之为video memory(vm),起源于最初的时候这块存储就是为了解决显示问题,有时候也有术语叫做local memory,取其位于GPU本地的含义。此外,video memory/local memory还有另一个不是很直观的别名,frame buffer,虽然还有其他非frame的东西也buffer在里头。

GPU的vm可能是逻辑上的,也可能是物理上的,根据GPU的类别来区分。例如,对于英特尔的Iris系列GPU,其和CPU位于一个DIR内,这就是我们传统意义上讲的集成显卡,也有叫核显的。这种显卡一般没有自己的存储系统,一般会从CPU的主存中分出一部分(物理空间连续)的存储,给GPU模拟为VM。这个空间的大小是可调整的,一般在BIOS中可以设置,典型的值是256MB,或者512MB,再大就不一定支持了。手机上的GPU一般都属于这种类型,即GPU共享CPU的一部分内存作为自己的local memory。

与之对立,NV和AMD的GPU则是典型的拥有自己的独立存储实体。我们经常说的2G显存,4G显存,说的就是显卡(GPU带存储以及其他一大堆外围东西)上为GPU准备的存储部分的大小。这种GPU就是我们经常谈论的GPU,也就是独立显卡。

无论在哪种GPU中,GPU都有自己的一套地址空间,用来访问和管理资源。GPU地址空间的管理通过核心部分的驱动来完成,例如Windows上的KMD。对于GPU而言,访问地址0x08008000处的资源,可不同于CPU上访问0x08008000处的东西,因为两者处于不同的地址空间。

首先我们看一下integrated GPU,也就是intel,arm等和CPU处于同一个DIE的GPU,它们的存储体系是如何的。首先,这些GPU自己的video memory都是从CPU可用的主存中分出来的,例如一个PC有4G的物理存储,分给intel核显512MB后,就只剩下3.5G可以给CPU用了。

在这些integrated GPU中,GPU和CPU处于一个DIE中,所以很多时候GPU和CPU可以共享总线。GPU自己的video memory也是在总线上走的。除了GPU自己的video memory之外,CPU和GPU有时候需要共享一些数据,例如,CPU将Vertex Buffer/Index Buffer放入主存中,然后让GPU使用。如我们之前所说,主存是CPU的存储,GPU是无法看到这部分的。为了解决这个问题,业界引入了一个叫做GART的东西,Graphics Address Remapping Table。这个东西长得和CPU用来做地址翻译的page table很像,作用也很类似,就是将GPU用的地址重新映射到CPU的地址空间。有了GART,CPU中的主存就可以对GPU可见了。但是反方向呢?GPU的local memory是否对CPU可见?

integrated GPU的local memory是从主存中分配出来,受限于主存的大小,能够分配出来的空间并不大,一般是256M/512M,最多的也就1GB。这么点儿地址空间,完全可以全部映射到CPU的地址空间中。如果OS是32位系统,可以寻址的地址空间有4G,分出256M/512M来全部映射GPU的local memory也不是多么难的事情。但是分出1G的话似乎有点儿过分了,所以还是建议OS上64位地址空间,这样integrated GPU的local memory就可以全部映射到CPU地址空间中了。

对于独立显卡,也就是所谓的dedicated GPU,情况就又不一样了。一般独立的GPU都有自己独立的存储实体,就是拥有不同于主存的video memory chip。而且目前来看,这些GPU所用的video memory chip都是板载的,也就意味着无法升级和替换。这些GPU自带的video memory有时候太大了,例如拥有4G或者6G的显存,将之完全映射到CPU的地址空间既不现实,也无可能。想象一下,一个带6G显存的显卡,在一个32位OS上,OS整个4G的地址空间都放不下全部6G的显存。所以,这些独立显卡拥有和另一套稍微有点儿不同的存储和地址空间映射机制,来解决这个问题。

一般的解决方法是,只映射一部分区域到CPU的地址空间,典型的大小是256MB/512MB。这段地址空间会通过PCIe的bar获取一个CPU可见的地址空间,所以一般来说,同样也是BIOS设置,并且开机后不可变的。最近PCIe支持resize bar的技术,支持这项技术的GPU可以动态调整大小,因此使用起来也就更加灵活了。

除了暴露给CPU可见部分的video memory之外,其他部分都是CPU不可见的。这部区域一般被驱动用来做一些只有GPU可见的资源的存储,例如临时的Z buffer等。

理解GPU的存储体系结构,对于深刻理解3D渲染管线,以及其他使用GPU的场景时,资源创建的标志位有着非常重要的作用。本系列文章后续会进一步尝试解释其中的一些细节。

编辑于 2018-04-21

文章被以下专栏收录