殡仪馆辱尸惊魂

admin · 2009-04-01

实质简介

  先容以一种翻新的体式格局优化HugeTLB对应的struct page内存占用。

  笃信大师对HugeTLB正在虚构化及DPDK等场景利用并不不懂,正在动不动就上百GB的任事器上,微微松松预留上百GB HugeTLB。笃信很多云厂商也留意到HugeTLB的内存办理上存正在必然的成绩。既然有成绩,为什么upstream上迟迟看不到联系的优化patch呢?

  谜底很简易:成绩辣手。

  Linux正在内存办理方面曾经兴盛了十几年,纵然某些机制不敷优越,思大改也不是简易的工作。内存办理贯彻整体Linux内核,与浩繁子编制交互。真相Linux正在HugeTLB的办理上存正在甚么成绩呢?

   何如办理物理内存

  现正在Linux Kernel厉重以页为单元办理内存,而页的巨细默许4 KB。为了利便办理物理内存,Linux为每一个页调配一个metadata构造体,即struct page构造,其巨细平常64 Bytes。struct page可能简易通晓成一个数组,数组的index便是PFN(物理页帧号)。我称这段地区vme妹妹ap。

  图片4KB页咱们称之为小页,与之相反的是大页。正在x86-64平台,硬件救援2 MB和1 GB大页。Linux为了利便用户利用大页,供应2种分别的机制,不同是THP (Transparent Huge Page) 和 HugeTLB。HugeTLB通常显示正在咱们的工程实验中,HugeTLB为咱们为咱们带来不错的功能提拔。

  然而也有一朵乌云常伴其身。尽管2 MB的HugeTLB page实践上也只要要1个struct page构造,然而,正在编制启动之初,全部的物理内存均以4 KB为单元调配struct page构造。是以每一个 HugeTLB page对应 512个struct page构造,占用内存32 KB(折合8个4 KB小页)。

  

  大概你会猎奇这能有若干内存。针对嵌入式编制,确切不足挂齿。然而别忘了,咱们有动不动就2 TB物理内存的任事器。

  现正在咱们可能简易的算一笔账了。假定正在一台1 TB的任事器上,咱们调配1 TB的2 MB大页(理思状况下),那末struct page自己占用的内存是若干呢?没错,是16 GB。假如有上千台,上万台,乃至上十万台机械呢?假如咱们可以优化掉16 GB的内存奢华或许尽大概的低落struct page的内存占用,咱们将会低落任事器平台本钱。咱们的目的便是只管即便遣散这朵乌云。

   面对的挑衅

  咱们试图找到一种最简易而且对其余模块影响最小的计划计划,正在这过程当中咱们碰到很多挑衅。

  1. 无须要用户适配

  理思状况下,咱们的优化不该当触及用户态的适配。假如引入一种全新的内存办理体式格局,全部的用户必要适配。咱们的目的是开箱即用。

  2. 不影响内核其余模块功效

  正在肯定无须要用户适配的条件下,咱们预期全部的代码编削只集聚合于内核。咱们懂得内存办理的简直满是盘绕着struct page办理,各个分别子编制的模块简直都和struct page息息联系。暴力的开释全部的HugeTLB联系的struct page构造体是不适应的,不然将会影响内核各个内存子编制。既要开释,但又不行开释。这可能是最辣手和抵触的成绩了。

  3. 代码编削最小化

  代码量直接的决意了bug的数目。内存办理子编制编削代码过量,必将影响内核的太平性。咱们既要完成功效,又要以致少的代码量完成。这不光可能低落bug显示的几率,同时也易于庇护和通晓。

   首次搜索

  图片

  一种最简易直接的步骤浮出水面。那便是静态调配和开释struct page。

  HugeTLB的利用步骤通常为先预留后利用。而且struct page只会被内核代码访谒,咱们偏向内核访谒struct page的几率较低。是以咱们第一次提出的计划是紧缩解紧缩的步骤。

  咱们懂得HugeTLB对应的512个struct page对应的音信可能紧缩到 100 个字节安排,是以咱们可认为每一个HugeTLB盘算一个全新的metadata构造体,而后将全部的音信紧缩到新的metadata构造体。而且将struct page地区对应的页外的present废除,而后便可能将其对应的物理页开释。是不是和zram机制一模一样?

  内核不才次访谒HugeTLB的struct page的时刻触发page fault,正在fault内里调配struct page必要的物理页,并解紧缩(重新的metadata构造体规复数据)。

  当内核利用达成后,会履行put_page操纵。咱们正在put_page内里做紧缩操纵,并开释vme妹妹ap对应的物理页。思绪很直接,然而这内里存正在良众挑衅。

  1. page fault内里无奈调配若何办(比如:OOM)?

  2. page fault大概爆发正在任何高低文,用GFP_NOWAIT调配内存?这只会减轻第一个成绩。

  3. 假如某一持有A锁的旅途触发page fault,page fault内里也考试持有A锁怎样?只会死锁。以是page fault的操纵必要非常当心。

  4. 紧缩妥协紧缩操纵何如做到原子?或许说紧缩操纵何如妥协紧缩操纵互斥同步?

  5. 每次put_page都必要紧缩操纵,功能影响何如?

  6. 假如某些内核旅途并无get操纵访谒struct page(天然也不会put),紧缩的机遇会是甚么时刻?

  咱们列出了良众成绩,但就第一个成绩来讲就很难明决。这不能不让咱们废弃了这个设法主意。咱们只可另寻他道。换个思绪恐怕山穷水尽。

   另辟门道

  俗话说相知知彼百战百胜。咱们先周详懂得struct page是何如构制和办理的,懂得每一处细节,才大概筹谋。

  咱们下面提到每一个HugeTLB page对应512个struct page构造,而HugeTLB只利用前3个struct page构造存储大页联系的metadata。那末其他509个struct page能否齐备没存心义呢?假如没存心义咱们是不是便可能直接开释这些内存。

  但是工作并无那末简易。这些509个struct page会存储第一个struct page的地方(struct page中compound_head字段)。假如第一个struct page称之为head page的话,那末其他的struct page都是tail page。正在Linux内核的内存办理的代码中充溢着多量的代码,这些代码都大概试图从tail page获取head page。以是咱们并不行简单的开释这些内存。

  

  上图显示的3个struct page的构造体示希图(第3个tail page至第511个struct page构造体利用的位域同图中2nd tail page)。咱们可能总结出如下特征:

  1. struct page构造体的巨细正在大大都状况下是64字节,是以每一个4 KB的物理页可能存储整数个数的struct page构造体。

  2. 第2个tail page至第511个struct page构造体的实质齐备相同。

  3. 内存办理的代码中只会编削head page,1st tail page的2nd tail page的构造体,其他的tail page构造体内存不会编削。

  4. 每一个2MB HugeTLB page对应512个struct page,内存占用8个页(4KB * 8)。

  5. struct page所正在的vme妹妹ap地区和内核的线性映照地方不重合。

  基于以上特征,咱们可能提出全新的处分计划:同享映照,将HugeTLB对应的后7个页的vme妹妹ap虚构地方映照到第1个vme妹妹ap页对应的物理页帧。第1-2点是同享映照计划的根蒂。基于第3点咱们可能将这7个物理页开释,交给buddy编制办理。而第5点是buddy可以办理这块物理内存的根蒂。内核经由过程线性地方访谒物理内存,以是这个地方不行和vme妹妹ap共用。其道理如下图所示。基于第3点,咱们将同享映照属性改为只读,抗御显示分外状况。

  

   内存收益

  始末下面的优化,咱们告捷的低落了任事器平台本钱,而且收益不错。针对1 GB和2 MB分别size的HugeTLB page,内存收益也同样分别。简易概括外格如下:

  

 

  

Total Size of HugeTLB Page

  

HugeTLB Type

  

Memory Gain

  

512 GB

  

1 GB

  

~8 GB

  

1024 GB

  

1 GB

  

~16 GB

  

512 GB

  

2 MB

  

~7 GB

  

1024 GB

  

2 MB

  

~14 GB

  

  假如利用1 GB HugeTLB,内存收益约为HugeTLB总量的1.6%。假如利用2 MB HugeTLB,内存收益约为HugeTLB总量的1.4%。

  

  是以,正在咱们1台1 TB内存的任事器上,假如利用1 GB大页,struct page内存占用优化提拔贴近100%。假如利用2MB大页,struct page内存占用优化提拔约87.5%。

   功能了解

  咱们懂得vme妹妹ap地区映照的单元是2 MB。然而咱们必要以4 KB页为单元编削页外,是以务必编削vme妹妹ap地区为小页映照。这相称于正在内核访谒vme妹妹ap地区时,MMU会众访谒一级 PTE 页外。然而有TLB的存正在,以是查找的功能丧失并不大。

  然而咱们同样也有功能提拔的处所,因为咱们裁减了vme妹妹ap对应的物理页。实践下去说,咱们更轻易掷中cache。现实上也确切如许,始末upstream的测试数据外现,对HugeTLB page停止get_user_page操纵功能可能提拔贴近 4 倍。

   开源宗旨

  为了低落代码review的难度,咱们决意将一齐patch拆分红3笔patchset。现在第一步根蒂功效曾经合入linux-next分支(代码参考: [v23,0/9] Free some vme妹妹ap pages of HugeTLB page,点击文末左下角浏览原文可达),不出无意的话,估计Linux 5.14会和大师会面。

  

  后续咱们不断放出接上去的patchset。那末接上去有哪些功效呢?

  最先第一个功效是开释7个page。甚么?这不是下面曾经说的功效吗?是的,然而咱们的第一个patchset只开释了6个page。以是正在下面的patchset中,咱们筑设的映照闭联实在如下图所示。这才是最简易的状况。由于咱们head page和tail page的构造体实质实在是不相同的,假如要完成下面的图的映照闭联,肯定要有少少trick才行。另一组patchset是拆分vme妹妹ap页外。第一组patchset的完成并不包括拆分vme妹妹ap页外,而是编制启动时使vme妹妹ap页外以PTE体式格局筑设映照,而非PMD映照。

  

  作家简介

  宋牧春,字节跳动编制技能与工程团队,Linux内核工程师。

  本文转载自微信民众号「Linux阅码场」,可能经由过程如下二维码体贴。转载本文请接洽Linux阅码场民众号。

  

文章推荐:

2022 年中国人工智能行业发展现状与市场规模分析 市场规模超 3000 亿元

该来的总要来! 切尔西老板将彻底退出英国市场

雷神黑武士四代开售:i7搭RTX3060不到9千元

智慧城市中 5G 和物联网的未来