程序员人生 网站导航

Hugepages详解

栏目:框架设计时间:2015-04-22 08:45:11

IBM的开创人Thomas J. Watson曾说: “全球只需要5台电脑就足够了”。

Microsoft的开创人Bill Gates曾在1次演讲中说:“个人用户的计算机内存只需640K ”。

Intel开创人之1Gordon Moore曾说:“当价格不变时,集成电路上可容纳的晶体管数目,约每隔18个月便会增加1倍,性能也会增加1倍”。

前面两句话在今天看来实际上是10分荒诞的,而最后那条就是著名的摩尔定律。

hugepages的出现一样也是由于摩尔定律致使了主机内存愈来愈大,最后不能不对标准pages的改进以提高效力。要了解hugepages首先必须清楚Unix/Linux内存的分配机制。本文从入门的角度介绍Linux的内存分配机制,固然这1部份内容相信很多人都在计算机体系结构这门课程中学到过,这里就重新复习1下。

初期由于程序非常简单并且使用的内存也非常小,程序的内存地址都是使用程序地址对应物理地址这类这类直接映照的模式,通俗的说就是物理地址是在程序中写死的。想一想使用汇编直接操作物理地址是多么壮观的工程呀。对1个大型的软件系统来讲,这部份工作几近是不可能完成的。后来开始使用“段页式”的方式来管理内存的寻址。用1个时兴的词来讲就是引入了“虚拟化”技术。现代操作系统都会使用受保护的虚拟地址模式(protected virtual address mode)来管理内存,Linux下分为3类地址:逻辑地址(Logic Address)、线性地址(Linear Address)与物理地址(Physics Address)。这3者的对应关系以下所示:    

segmentation and paging

简单的说就是逻辑地址通过分段机制映照转化为线性地址,然后线性地址通过分页机制映照转化为物理地址。由于这里是介绍hugepages,所以我这里不打算介绍分段机制,主要对分页机制做简单的论述。 事实上,地址映照的进程远远不止上图中这么简单。例如在分页机制映照中,1般需要经过4级映照,也就是将线性地址映照为物理地址的进程中,需要从内存中读取最少4次页目录表(Page Directory)和页表 (Page Table)。尽人皆知,CPU寄存器与内存的访问速率相差最少1个数量级,所以如果使用传统的分页机制的开消将会非常大。所以在现代的X86架构中,集成了1种被成为TLB(Translation Lookaside Buffer)的硬件级缓存。TLB读写速度非常快,基本和CPU寄存器的速率在1个数量级,而TLB中保缓存了最近使用过的线性地址和物理地址的映照关系。以下图所示:

tlb 

那末将线性地址映照为物理地址的进程以下:首先到TLB中找到这个条目是不是存在,如果不存在则为TLB miss,然后使用页表的方式进行寻址,最后把这个映照关系更新到TLB中以备下次使用。由于TLB是大小有限,而1旦出现TLB miss,则其查询的代价很高,所以现代CPU架构基本都进行了1些优化以提高地址映照的效力。例如:

  • 线性地址到物理地址转换1开始就选择同时在TLB和页表进行查询,而不经过TLB查找是不是成功的等待;
  • 使用多级TLB和软TLB,
  • 在CPU context swtch的时候不flush全部TLB。

下面用例子来讲明为何使用传统的 4k大小的页表相比hugepages对大内存的管理效力会很低。在x86平台,1条PTE的大小为4Byte;而在x86_64平台,1条PTE的大小为8Byte。 以下这类场景其实不罕见:

Linux x86_64, SGA大小为100G,使用常规的4k的page,连接到数据库的进程数约1000。page table1共需要100×1024×1024K/4K=26214400条PTE;

那末26214400条PTE需要100×1024×1024K/4K×8Byte=209715200Byte=200M;

从而1000个进程需要100×1024×1024K/4K×8Byte×1000=209715200000Byte=200G。

计算出来的结果真是使人崩溃,但是事实上在你没有崩溃之前,数据库就已由于没有内存而崩溃了。一样条件下,如果使用2M的hugepages进行对照,则以上的计算方法变成:

page table1共需要100×1024M/2M=51200条PTE;

那末51200条PTE需要100×1024M/2M×8Byte=409600Byte=400K;

从而1000个进程需要100×1024M/2M×8Byte×1=409600Byte=400K。

综上,可以看到一样是1000个进程,一样是管理100G的SGA,结果却大不相同。使用传统的4k大小的page开消居然会到达惊人的200G;而使用2M的hugepages,开消只有400K。 这其中不单单只是对由于单个进程而言,2M page需要的PTE小于4K  page的PTE,最大的1个缘由是在于使用4K page的话,有多少进程使用SGA,就需要多少套PTE,相反如果使用2M page则不管有多少进程使用SGA,同享的都是同1套PTE。

尽人皆知,x86是32位的,所以默许情况下,其可寻址的空间为2的32次方――4G。在X86设计之初,4G内存似乎是1个遥不可及的天文数字,但是摩尔定律打破了这1切,所以软硬件的设计和开发商必须想出1个对策来解决4G以上不可寻址的问题。注意:这里没有说4G以上的内存不可寻址,而是说4G以上的地址空间不可寻址,这二者实际上有区分的。例如4G内存的CPU在32bit的Windows(非server版本)能辨认到的内存1般在3G左右。 这其中的主要是主板或操作系统的限制。由于计算机上1些其他的装备一样需要可寻址,而这1部份地址需要从总的可寻址空间中预留,例如BIOS芯片的ROM,显卡上的显存(RAM)和BIOS(ROM),和PCI、PCI-E装备上的RAM和ROM都需要占用1定的可寻址的空间。这个叫MMIO(Memory-mapped I/O)。这里有点off the topic了,所以不再赘述,要了解更详细的缘由和机制,请参考以下链接:(RAM limit    PCI hole,   Conventional memory,   3GB barrier )

CPU的设计者碰到了困难了:既要解决4G以上可寻址,又要兼容已有的架构和程序,那该怎样办呢?1种最可行的方式就是通过增加扩大地址来解决4G以上的寻址问题。因而Intel引入1个workaround PAE (Physical Address Extensions)机制:增加20位扩大地址,将原来的32位的物理地址扩大为52位,那末可寻址的空间就增加到了2的52次方――4PB,但是实际上x86只使用了其中的36位,也就是X86实际可寻址的物理地址为64G,而转化的进程为操作系统通过使用页表将4GB的地址空间映照到大小为64GB的物理地址空间。虽然物理地址为52位,但是线性地址还是32位,所以在这类架构下单个程序/进程使用的内存限制实际上依然还是4G。    注:PSE(Page Size Extension)使得用户可使用4M的页表。PAE(Physical Address Extension)使得32位的系统就可以够使用接近64GB的内存的1种技术。如果PAE和PSE同时使用,则只能使用2M的页表。x86_64默许使用PAE的扩大―― long mode。

 

pae

通过上图可知:是不是使用分页是通过CR0寄存器的PG表示来控制的,如果只使用传统的分段模式,则将CR0.PG置为0, 如果启用分页则需要将PG设置为1。使用page的大小则是由IA32_EFER寄存器LME标志和CR4寄存器的PAE标志和PSE标志控制的,其中IA32_EFER.LME标志控制是不是是不是启用IA⑶2e模式,而CR4.PAE标志为控制是不是启用PAE, CR4.PSE标志控制是不是启用PSE。但是其实不是这3者的任意组合都是存在的,现实中存在的情况为以下几种: 当前x86/x86_64架构支持的page的大小包括: 4k, 2M, 4M, 1G (操作系统到目前还不支持1G的page table) 以下以x86_64的Linux为例,说明page的大小是如何得到的:在内核源代码include/asm-x86_64/pgtable.h文件中,可以找到以下宏定义:

#define PMD_SHIFT 21 ... #define PMD_SIZE (1UL <<PMD_SHIFT)

可知使用long mode的page的大小为:

1 << 21 = 2097152

这个移位运算的结果,请参考 http://www.wolframalpha.com/input/?i=1%3C%3C21

需要注意的是page table的大小用户没法自定义,在Linux中即便修改这个宏定义,重新编译内核,也没法修改page的大小。

Architecture Page Size Huge Page Size Large Page Size
i386 4 KB 4M (2M in PAE mode) 1 GB
IA⑹4 4 KB 4K, 8K, 64K, 256K, 1M, 4M, 16M, 256M -
ppc64 4 KB - 16M
sparc 8 KB - 8K, 64K, 4M, 256M, 2G

在Exadata乃至所有的大内存Linux平台, hugepages的重要性怎样强调都不过分。那末为什需要配置hugepages呢?使用hugepages的好处,总结起来包括以下5个方面:

Not swappable (使得SGA不可交换)

为啥SGA是可以被换到虚拟内存的?? Bug 160033 - Kernel swaps out Oracle instead of releasing cache 这个bug终究关闭的状态为Not a bug, 但是同时在这个bug中提到:   The basic design of the VM in RHEL 4 and RHEL 5 will not allow a complete fix for this issue, only tweaks to make it behave better most of the time.In the upstream kernel (and for RHEL 6), this problem has been addressed with the split LRU VM, which was merged in 2.6.28 and continues to get small fixes and tweaks.  In RHEL 6 this issue should be resolved. Oracle SGA区的内存被swap到磁盘只有到Linux Kernel2.6.28或RHEL 6以后才通过引入新的机制得到解决。而1旦SGA区被换出内存会造成很大的性能抖动。所以在这个问题完全解决之前,绝大多数版本的Linux仍然需要通过hugepages来固定SGA区。(Linux平台其实不支持通过设置lock_sga和参数的方法来固定SGA, pre_page_sga这个参数存在太多的弊端已强烈不推荐使用)

Relief of TLB pressure: (减轻TLB的压力)

我们知道TLB是直接缓存虚拟地址到物理地址的缓存表,用于提升性能,省去查找page table减少开消,但是如果出现的大量的TLB miss,必定会给系统的性能带来较大的负面影响,特别对连续的读操作。从第2篇文章中我们知道如果使用hugepages能大量减少PTE的数量,也就意味着访问一样多的内容需要的PTE会更少,而通常TLB的槽位是有限的,1般只有512个,所以更少的PTE也就意味着更高的TLB的命中率。

Decreased page table overhead: (减少页表的开消)

在前面的内容中我们通过计算,对4k page和hugepages的页表开消的进行对比发现,使用hugepages可以极大的减少保护页表的开消。这篇文章中也提到了1个计算方法:

Each page table entry can be as large as 64 bytes and if we are trying to handle 50GB of RAM, the pagetable will be approximately 800MB in size which is practically will not fit in 880MB size lowmem (in 2.4 kernels

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐