针对掉电保护,Intel 提出了 Asynchronous DRAM Refresh(ADR)的概念,负责在掉电时把 Data in-flight 回写到 PMem 上,保证数据持久性。目前 ADR 只能保护 iMC 里的 Write Pending Queue(WPQ)和 PMem 的缓存中的数据,但无法保护 CPU Cache 中的数据。在 Intel 下一代的产品中,将推出 Enhanced ADR(eADR),可以进一步做到对 CPU Cache 中数据的保护。

由于 ADR 概念的存在,所以简单的 MOV 指令并不能保证数据持久化,因为指令结束时,数据很可能还停留在 CPU Cache 中。为了保证数据持久化,我们必须调用 CLFLUSH 指令,保证 CPU Cache Line 里的数据写回到 PMem 中。

然而 CLFLUSH 并不是为 PMem 设计的。CLFLUSH 指令一次只能 Flush 一个 Cache Line,且只能串行执行,所以执行效率非常低。为了解决 CLFLUSH 效率低的问题,Intel 推出了一个新的指令 CLFLUSHOPT,从字面意思上看就是 CLFLUSH 的优化版本。CLFLUSHOPT 和 CLFLUSH 相比,多个 CLFLUSHOPT 指令可以并发执行。可以大大提高 Cache Line Flush 的效率。当然,CLFLUSHOPT 后面还需要跟随一个 SFENCE 指令,以保证 Flush 执行完成。

和 CLFLUSHOPT 对应的,是 CLWB 指令,CLWB 和 CLFLUSHOPT 的区别是,CLWB 指令执行完成后,数据还保持在 CPU Cache 里,如果再次访问数据,就可以保证 Cache Hit,而 CLFLUSHOPT 则相反,指令执行完成后,CPU Cache 中将不再保存数据。

此外 Non-temporal stores(NTSTORE)指令(经专家更提醒,这是一个 SSE2 里面就添加的指令,并不是一个新指令)可以做到数据写入的时候 bypass CPU Cache,这样就不需要额外的 Flush 操作了。NTSTORE 后面也要跟随一个 SFENCE 指令,以保证数据真正可以到达持久化区域。

看起来很复杂对吧,这还只是个入门呢,在 PMem 上写程序的复杂度相当之高。Intel 最近出了一本书 “Programming Persistent Memory”,专门介绍如何在 PMem 上进行编程,一共有 400 多页,有兴趣的小伙伴可以读一读。

为了简化使用 PMem 的复杂度,Intel 成立了 PMDK 项目,提供了大量的封装好的接口和数据结构,这里我就不一一介绍了。

PMem 发布以后,不少的机构都对它的实际性能做了测试,因为毕竟之前大家都是用内存来模拟 PMem 的,得到的实验结果并不准确。其中 UCSD 发表的 “Basic Performance Measurements of the Intel Optane DC Persistent Memory Module” 是比较有代表性的。这篇文章帮我们总结了 23 个 Observation,其中比较重要的几点如下: