背景

1、存储金字塔

  • Cache高速缓存(包括寄存器)都是临时缓存。
  • 随机存取存储器(英语:Random Access Memory,缩写:RAM),也叫主存,是与CPU直接交换数据的内部存储器。它可以随时读写(刷新时除外),而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储介质。DRAM用于管理一些进程临时存储。DRAM内存颗粒,其存储组织结构为深度(Depth)加上位宽(Width)。动态随机存取存储器(DRAM)一个电容器和一个晶体管组成一对叫储存单元,需要周期性补充电子保持状态故称“动态”存储器。静态随机存取存储器(SRAM)需要6个晶体管组成一个储存单元。SRAM 快、DRAM慢。SRAM 贵、DRAM便宜。平常的内存芯片的用就是DRAM。高端的内存条都会有外壳包裹着,其实那个壳是人家的散热片也叫马甲。越是高频率的内存条一般都会加壳,频率越高,宽带越大,发热量越大。来自文章什么是内存颗粒?三星,海力士,镁光是市场三大供商内存颗粒供应商,那些高质量半导体芯片没有坏块的被原厂家保留,淘汰的称为白片卖给其他厂家,其他厂家再挑剩下坏块较多的做成了U盘。(DDR=Double Data Rate双倍速率,DDR SDRAM=双倍速率同步动态随机存储器,人们习惯称为DDR,其中,SDRAM 是Synchronous Dynamic Random Access Memory的缩写,即同步动态随机存取存储器。)
  • SSD、U盘,SD卡等都是Flash结构,但其主控电路不同。

2、频率和带宽

存储器的带宽指单位时间内从存储器进出信息的最大数量。若存储器的数据总线宽度为 32 位,存取周期为 200ns ,则存储器的带
宽 =1/200ns ×32bit= 5MHz×32bit = 160 Mb/s = 20MB/ s(1 MHz = $10^6 Hz$,1s = $10^6ns$ )

3、Page 页

逻辑内存称之为页,物理内存称之为帧(page frame),由页表做映射,每个进程独立维护。操作系统通过物理地址帧来判断属于哪一层的。有的页应映射去磁盘了,产生缺页异常由用户态变为内核态(申请外部资源时发生),就去磁盘找数据,涉及页迁移与替换。
图片来自硬件茶谈
图片来自硬件茶谈视频(固态硬盘的缓存)
再补充一下用户态到内核态的几个操作,后面论文会提到相关的。读写文件:先open,之后read或者write(这三个既是C内置函数名称,也是系统调用名称);申请内存(堆内存)C用malloc,只是函数名,没有系统调用是这个名字,实际是通过brk小于128k内存时在edata游标下申请或者mmap,都申请的是虚拟内存空间。在第一次访问时,发现才申请的虚拟地址没有映射到物理地址,于是触发缺页中断(缺页异常)。cpp和java通过new一个对象也会经历类似过程,

  • 分页使得每个程序都有很大的逻辑地址空间,通过映射磁盘和高效的置换算法,使内存“无限大”。
  • 分页使不同的进程的内存隔离,保证了安全。
  • 分页降低了内存碎片问题。
    来自free-coder
    来自【OS】操作系统的内存管理简介

4、持久内存PM

持久内存(PMem)科普来自 memark.io 技术社区

允许应用程序直接从持久性内存中访问他们的数据,而不需要先分页到DRAM中。即可以当做内存使用,也可以当做持久化外存设备使用。对本篇文章来说有帮助的知识:
正是因为持久内存具有传统内存的特性,又兼具有外存的持久化特性,造就了其特殊的双模式使用方式。注意,两种模式不能混合使用,并且模式之间切换具有一定成本,无法做到程序运行时动态切换。文章希望将DRAM和PM配置成多层次内存系统中的独立层。

简单粗暴的内存模式(Memory Mode)
就是把持久内存直接当做内存使用,不利用其非易失特性。操作系统将会直接看到持久内存的容量,而原来的DRAM将会作为持久内存的一层cache。程序无需改动任何代码,可以直接利用持久内存的大内存优势来运行内存消耗大的应用。
内存模式使用简单,但是也带来了一些问题:
	由于DRAM被当做了PM的一层cache,并且被CPU自动管理,但是PM其在性能参数上是略低于DRAM的,所以在某些对于cache不友好的情况下,可能会带来性能较大的衰减。
	无法使用持久化特性。内存模式丢失了内存数据持久化的特性,无法用作对数据持久化有要求的场景。
App Direct 模式(AD Mode)
AD Mode 实际上是把内存层级完全暴露给了应用。程序员需要自己控制将数据存放在DRAM或者持久内存,自己掌握是否要进行内存数据的持久化操作。
其优势正好是克服了内存模式的两个问题:
	存储层级对程序员可见,因此应用可以根据数据的特点进行存储性能优化,比如冷热数据的分级存储,以及使用缓存敏感的数据结构(cache conscious)
	数据持久性在AD Mode下可用,程序员可以选择是否将数据在持久内存上做持久化操作。

5、LRU等页面置换算法

缺页中断发生时就要开始啦(本节摘取一文看懂页面置换算法

  • 最优页面置换算法(OPT、optimal)对于保存在内存当中的每一个逻辑页面,计算在它的下一次访问之前,还需要等待多长时间,从中选择等待时间最长的那个,作为被置换的页面。属于理想状况,现实无法实现

  • 先进先出算法(FIFO)系统维护着一个链表,记录了所有位于内存当中的逻辑页面。从链表的排列顺序来看,链首页面的驻留时间最长,链尾页面的驻留时间最短。当发生一个缺页中断时,把链首页面淘汰出局,并把新的页面添加到链表的末尾。即使这个页面在内存被经常调用,但它来的早也会躺枪,所以性能差。

  • 最近最久未使用算法(LRU,Least Recently Used)选择最久未使用的那个页面,并淘汰之。(实现方式就是最近使用过就放最前面,放在最后的自然就是最久没使用过的)。

  • 时钟页面置换算法(Clock)① 需要用到页表项当中的访问位,当一个页面被装入内存时,把该位初始化为0。然后如果这个页面被访问(读/写),则把该位置置1。② 把各个页面组织形成环形链表(类似钟表面),把指针指向最老的页面(最先进来)。③ 当发生一个缺页中断时,考察指针所指向的最老页面。若它的访问位为0,立即淘汰;若访问位为1,则把该位置为0,然后指针往下移动一格。如此下去,直到找到被淘汰的页面,然后把指针移动到它的下一格。MULTI-CLOCK通过对每个内存层分别运行Linux的页框回收算法(PFRA)的修改版(该算法基于CLOCK算法)来确定各层内和各层间的页面的相对重要性。

  • 最不常用算法(LFU,Least Frequently Used)当一个缺页中断发生时,选着访问次数最少的那个页面,并淘汰之。被访问的次数也会很少。
    LRU考察的是多久未访问,时间越短越好;而LFU考察的是访问的次数或频度,访问次数越多越好。这也对应着文章多次提到的性能指标frequency & recency的含义,前者指一段时间内的访问次数,后者指离上次访问过多久了。

6、字节寻址

内存的寻址粒度是Byte级别的 [字节, B,由8个位组成(bit,电子计算机中最小的数据单位。每一位的状态只有两种:0或1),字节是存储空间的基本计量单位] ,也就是说每个字节都有它的内存地址,CPU可以直接通过这个地址获取到相应的内容。对于SSD来说就不是这样了,SSD是以块的粒度来管理数据的,CPU没有办法直接访问文件中某个特定的字节。(混合内存还会用到NVM非易失性内存,人为啥有资格做内存,就是可以让软件以字节粒度进行寻址访问)
再补充一个小点:摘取自 按字寻址和按字节寻址

字一定为字节的整数倍,所以称之为字由若干个字节组成。
字的位数称为字长(字不等于字长乘以字节!字=字长×位)
比如一个8位的CPU,这里的8位指其字长为8位,即单位时间内可以处理8位二进制数,即一个字节数。
现在的CPU大部分为64位,即单位时间内可以处理64位二进制数,即8个字节数。

7、预取Prefetching

现代处理器速度的快速发展和存储器速度的慢速发展导致处理器要花费大量的时间等待存储器数据的返回,这就是存储墙问题。为了解决这些问题,已提出多种技术方案, 其中最主要的有缓存和预取技术两种

缓存技术是利用局部性原理, 使速度更快的上层存储器成为下层存储器的缓冲。缓存技术能否通过较快的存储器屏蔽对较慢的存储器的访问, 完全取决于上层存储器的命中率。 提高相联度、Victim Cache、伪相联 Cache 等技术以及好的缓存替换算法都可降低缓存冲突失效,从而提高缓存命中率。 随着应用规模的不断扩大和上述技术的不断成熟, 容量失效和强制性失效在总的缓存失效次数当中所占的比例越来越大,成为影响缓存性能的主要因素。

预取技术可以通过计算和访存的重叠,隐藏因为缓存延时而引起的缓存失效,被认为是解决容量失效和强制性失效的有效手段。 硬件预取是由硬件根据访存的历史信息,对未来可能的访存单元预先取入Cache,从而在数据真正被用到时不会造成Cache失效。但是由于只是基于访存的历史信息,硬件预取会取回大量无用的Cache块,占用访存带宽,还会导致严重的Cache污染问题。由于硬件预取是基于访存的历史信息来预测未来的访存模式,从而可以在数据使用之前将其从下一级的存储器中取回软件预取是指在编译时由编译器显示加入预取指令,提前将下一级存储器中的数据取回。因为加入了大量的预取指令,同时显示的预取指令需要计算出准确的预取地址,从而导致不能及时的发出预取指令以足够隐藏访存延时,影响了性能的提高。并且必须使额外的预取指令开销不能超过预取所能带来的效益, 否则得不偿失。

8、UMA与NUMA

UMA是指多个cpu通过一个总线去访问内存,存在内存访问冲突,cpu资源浪费在争用地址上。

Non Uniform Memory Access 非统一内存访问架构NUMA,主板会分成不同的插槽,每一个插槽一组cpu,以及和这组cpu离得近的内存。在这种设计里面存在和处理器相近的内存,通常称作本地内存;还有和处理器相对远的内存,通常称之为远端内存。优先访问离得近的,也能访问离得远的。把CPU+RAM+BUS+其他=一个NUMA节点。

每个CPU核独享L1、L2级缓存,L3级缓存为共享缓存。一个SOCKET称之为一个NUMA结点,不同NUMA节点之间通过总线连接。NUMA结点的内存分配方式

  • Local分配:分配本地内存,就是指分在最靠近他的那里;
  • InterLeaved分配:交错分配内存,指的是当前进程需要48G但是我的本地内存只有32G,那我可以放在远端一部分,而不是直接放入硬盘这样会缺页中断浪费很多时间。

9、持久化指令

应该是intel公司提供的包里面可以用的,这些指令直接从缓存写回PM。持久化内存
模拟PM的主流方法包括在软件中添加内存访问延迟,使用软硬件仿真器,比如 Intel 的PMEP,通过限制延迟和带宽来模拟PM

1. 论文信息

  • 文章来自IEEE International Symposium on High-Performance Computer Architecture, (HPCA), 2022
  • MULTI-CLOCK: Dynamic Tiering for Hybrid Memory Systems

所有作者及单位

  • Adnan Maruf, 佛罗里达国际大学(FIU)奈特基金会计算与信息科学学院
  • Ashikee Ghosh, 佛罗里达国际大学(FIU)奈特基金会计算与信息科学学院
  • Janki Bhimani, 佛罗里达国际大学(FIU)奈特基金会计算与信息科学学院
  • Daniel Campello, Google
  • Andy Rudoff, 英特尔公司
  • Raju Rangaswami, 佛罗里达国际大学(FIU)奈特基金会计算与信息科学学院

2. Background

将PM作为第二级内存直接暴露给CPU是目前比较有希望的一个做法:如何把数据在正确时间放入正确分层中去。于是面临一个是大家关注的问题。

3. 解决了什么问题

动机:通过四个工作负载,统计归类50个采样页面的访问模式,得出层级友好页面是需要迁移的对象(空间局部性)。热力图
同时一段时间访问过的页面在下一段时间被访问概率也很大(时间局部性)
相线图表示被访问的概率在不同时间窗口的变化
然后说明了用frequency&recency识别到的页面也具有层级友好的特征。相比于静态分层,说明了动态分层的必要。最后把整个比较模糊的大问题转化为:试图解决分层系统中:如何根据frequency&recency来识别升级的热点页?如何在内核中设计一个简单、低开销而又高效的系统?

4. 其他学者解决这个问题的思路和缺陷

这些都是分层技术上的对比:
静态分层即一个内存页一旦被映射到一个分层,在其生命周期内就不会被重新分配到不同的分层。
现有内存分层技术的比较
[11]Nimble:只根据recency来选择页面,这篇的作者为了解决frequency决定把工作负载执行期分为观察窗口和性能窗口。得出观察窗口频率高的,在性能窗口概率也高。专注于透明大页(THP)迁移。应用程序需要通过Nimble的启动器运行以利用其页面迁移技术。MC在内置内核实现的功能。Nimble需要一个额外的启动器来运行内核上的任何工作负载。

[12]AutoTieringhint page fault的缺页异常来跟踪页面访问,并使用recency来识别热点页进行升级。尽管缺页异常可以提供高准确度的页面访问跟踪,但跟踪所有页面的成本很高,因为每一个页面故障都必须在访问页面之前进行处理。这是因为基于缺页的软件页面访问跟踪成本很高,而且跟踪页面历史位以识别冷页面的开销也很大。所以在后面工作负载测试中表现很差。

[19]Thermostat源代码不可用没有评估,通过poisoning页表项(PTE)和触发缺页异常来跟踪巨大的页面,并将冷页面迁移到较低的内存层。

[22]AMP(非统一内存访问架构NUMA,主板会分成不同的插槽,每一个插槽一组cpu,以及和这组cpu离得近的内存。)这在两个插座的NUMA机器中是不现实的,因为每个节点通常有自己的DRAM、PM和CPU。AMP使用一个节点,只用于DRAM的分配,其他节点只用于PM的分配。AMP是在Linux内核4.15版本上实现的,它不支持所需的KMEM DAX驱动(从内核v5.1开始提供),以便PM作为主内存在分层系统中使用。AMP的核心设计原则要求它扫描和剖析来自DRAM和PM层的所有内存页,这在实际系统的内核中是不现实的,因为在我们评估的工作负载中,内存页的数量可以增长到数亿。
对比于PM当前这款硬件的两种用法。

[7]Memory-mode:数据不能持久化,dram作为缓存不透明。缓存是需要从高层获取数据的,而这里提出的分层是两层都能被直接访问的。

[44]对象级需要改变应用程序API,而内核级别的修改不需要应用程序有何变化。

[32]提出了一种有效使用持久性内存作为NUMA节点的设计。这个分层设计同时意识到了DRAM和PM节点 ,并且只通过NUMA平衡处理匿名页面的升级/移动。

[33-36]不需要硬件,而且都是主存没有缓冲。

5. 围绕该问题作者如何构建解决思路

设计MULTI-CLOCK的主要假设是,最近被访问过一次以上的页面,在不久的将来更有可能被访问。

具体升级降级要求门槛就是那张图。(但是频繁程度不够吧?)及时更新页面引用状态的方式根据对内存页的访问模式不同而不同。无监督式:CPU在进程的页表入口中设置的页面引用位。 文章的idea

与CLOCK类似,升级是由每次系统守护程序kpromoted去完成的。它定期被唤醒,以扫描列表,更新它们,并将最近由无监督访问产生的升级列表中页迁移到更高层的页。

降级机制基于今天的虚拟内存系统中的页面驱逐技术。当内存达到内存压力时(该层与系统总内存量来计算)会去扫描每个列表。活动列表中的页面相对于非活动列表的比例超过了一个与该层可用内存量相关的阈值时,那么在活动列表中没有被标记为引用的页面将被移至非活动列表。最后,非活动列表被扫描,以寻找未被标记为引用的页面,并将其迁移到较低的层级。当没有更低层级列表可以迁移,就写回块存储。

6. 从结果看,作者如何有力证明他解决了问题

评估的目的是确定MULTI-CLOCK是否、何时以及如何能够提高应用工作负载的性能。

使用雅虎云服务基准(YCSB)[13]的六个不同的工作负载和GAP基准套件(GAPBS) [14] 的六个工作负载来讨论我们的结果。Memcached[3],一个使用大量主内存来维护其数据的内存缓存服务,作为YCSB的键值存储后端。 配置时内存要被全部消耗,并且消耗一部分PM。

MULTI-CLOCk在所有YSCB工作负载上都优于静态分层、Nimble、AT-CPM和AT-OPM。对GAPBS的执行时间也比其他方案减少。

分析了MULT-CLOCK和Nimble所升级的页面数量。MULTI-CLOCK每次扫描平均升级758页,最多扫描1024。而N是把1024作为固定值。如果那些将来不会再被重新访问的页面被提升到DRAM中,那么提升这些页面的开销会损害系统性能。第二次再次被访问的百分比比N高15%

实现了目标,低开销,特别是密集型应用。

7. 缺陷和改进思路

  1. 能耗方面摘要提了一下,后面也没说呀。
  2. 作者源码有一些问题,在运行高性能计算用MIP的时候会内核崩溃。
  3. 后面的性能评估对比了几种相关的工作,但是选择的workload也是比较局限的,GAPBS的论文都没有正式发出来。

8. 创新点

  1. 在内核上修改代码,不需要其他程序有什么修改。
  2. 使用升级列表和频率可以很好的利用层级友好页面的局部性。

9. 相关链接

10. 积累

当使用PM作为主存储器时,其持久性能力变得无关紧要(这里作者遵循原先的主存的设计,即易失性,抛弃了NVM数据持久的特点,后面提到的该产品Memory Mode,并且文献[10]说PMEP想要持久性靠的是clflush指令,这个指令由于要排序开销很大),从而完全避免了其最大的性能开销[10]

有开源内核好像有一个选项可以计数随时间变化页面在层级间迁移的数量。


文章作者: 易百分
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 易百分 !
  目录