您可以使用程序集直接访问缓存吗?

时间:2020-06-05 17:29:11

标签: performance assembly caching cpu-architecture cpu-cache

关于效率,缓存是核心。

我知道缓存通常会自动发生。

但是,我想自己控制缓存的使用,因为我认为我可以做得比一些不知道确切程序的试探法要好。

因此,我需要汇编指令才能直接在高速缓存存储单元之间移动。

喜欢:

movL1 address content

我知道有一些指令可以给“缓存系统”提示,但是我不确定这是否足够,因为这些提示可能会被忽略,或者它们可能不足以表达这样的表示方式。 /从缓存顺序开始。

有没有可以对缓存进行完全控制的汇编程序?

旁注:为什么我要改善缓存:

考虑一个假设的CPU,该CPU具有1个寄存器和一个包含2个单元的缓存。

请考虑以下两个程序:

(其中x,y,z,a是存储单元)

"START"
"move 1 to x"
"move 2 to y"
"move 3 to z"
"move 4 to a"
"move z to x"
"move y to x"
"END"

"START"
"move 1 to x"
"move 2 to y"
"move 3 to z"
"move 4 to a"
"move a to x"
"move y to x"
"END"

在第一种情况下,您将使用寄存器x,y,z的缓存(a仅写入一次) 在第二种情况下,您将使用寄存器和缓存来存储a,x,y(z仅写入一次)

如果CPU进行缓存,它根本无法提前决定要面对上述两种情况中的哪一种。

在知道程序是否执行之前,必须为每个存储单元x,y,z决定是否应缓存其内容。 1或否。 2,因为两个程序开始时都是相同的。

另一方面,程序员会提前知道哪些存储单元被重新使用以及何时重新使用。

3 个答案:

答案 0 :(得分:5)

彼得·科德斯(Peter Cordes)写道:

在大多数ISA的大多数微体系结构上,不能,您不能将行固定在缓存中以阻止其退出。使用缓存的唯一方法是作为加载/存储的透明缓存。

这是正确的,但是有趣的例外。...

在DSP(“数字信号处理”)芯片中常见的是,在“缓存”和“便笺本存储器”功能之间划分SRAM的能力有限。关于此主题的白皮书和参考指南很多,例如http://www.ti.com/lit/ug/sprug82a/sprug82a.pdf。该芯片中包含三个SRAM块:一个小的“ Level-1指令” SRAM,一个小的“ Level-1数据” SRAM和一个更大的“ Level-2” SRAM。这三者中的每一个都可以在Cache和直接寻址的存储器之间进行分区,具体细节取决于特定的芯片。例如,芯片可能不允许高速缓存,1/4 SRAM作为高速缓存,1/2 SRAM作为高速缓存或所有SRAM作为高速缓存。 (比率受到限制,因此可以有效地索引允许的缓存大小。)

IBM“ Cell”处理器(在2006年发布的Sony PlayStation 3中使用)是一种多核芯片,具有一个普通的通用内核和八个协处理器内核。协处理器内核的指令集有限,其加载和存储指令只能访问其专用的128KiB“暂存器”内存。为了访问主内存,协处理器必须对DMA引擎进行编程,以执行主内存到本地暂存器内存的块复制(反之亦然)。这种方法提供了(并且是必需的)对数据运动的完美控制,从而产生了(非常少量)非常高性能的软件。

某些GPU还具有小型片上SRAM,可以将其配置为L1缓存或显式控制的本地内存。

所有这些都被认为“非常难以使用”(或更糟),但是如果产品需要非常低的成本,完全可预测的性能或非常低的功耗,则这是正确的方法。

答案 1 :(得分:4)

在大多数ISA的大多数微体系结构上,不能,您不能将行固定在缓存中以阻止其退出。使用缓存的唯一方法是作为加载/存储的透明缓存。

当然,正常负载肯定会至少在临时时间内将缓存行带入L1d缓存。但是,没有什么可以阻止它随后被驱逐的。例如在x86-64上:mov eax, [rdi]而不是prefetcht0 [rdi]

在存在专用的预取指令之前,有时会使用普通加载作为预取操作(例如,在进入循环之前会先进行一些循环边界计算,然后再开始循环遍历数组)。出于性能目的,CPU可以忽略的尽力而为的软件预取指令通常更好

普通加载的缺点是,直到实际加载的数据到达之前,才能从无序的后端退出。 (至少我认为它不能在具有x86高度有序内存模型的x86 CPU上使用。允许无序装载的弱排序ISA可能使装载退休,即使尚未真正完成也是如此。)软件预取指令存在以允许作为提示进行预取,而不会在等待加载完成时造成CPU瓶颈。

在现代x86上,可以强制逐出缓存。 NT存储保证在Pentium-M或更高版本上,或者在Pentium-M之后的 CPU上,我忘记了哪一个。此外,clflushclflushopt专门用于此目的。

clflush不仅仅是CPU可能掉线的暗示;像Optane DC PM一样,它可以保证non-volatile DIMMs的正确性。 Why does CLFLUSH exist in x86?

得到保证,不仅是提示,还会使其变慢。通常,您不希望这样做是为了提高性能。 就像@old_timer所说的那样,刻录指令/周期以微方式管理缓存几乎总是在浪费时间。将事情留给硬件来进行伪LRU替换和硬件预取算法通常可以长期取得良好结果跑。 SW预取在某些情况下会有所帮助。


Xeon Phi可以将其MCDRAM配置为大型的最后一级缓存,或配置为物理地址空间一部分的结构上可见的“本地内存”。但是,在6至16GiB的速度下,它远远大于裸片上的L1 / L2缓存或现代主流CPU的L1 / L2 / L3缓存。

此外,x86 CPU可以以RAM填充模式运行,BIOS在配置DRAM控制器之前的早期启动中使用了这种模式。但这实际上只是在读取或写入过程中不进行填充,而对于无效行则为零读取,因此,在激活非填充模式时,您根本无法使用DRAM。也就是说,仅 缓存可用,并且您必须注意不要驱逐任何已缓存的内容。除早启动外,它不能用于任何实际目的。

What use is the INVD instruction?Cache-as-Ram (no fill mode) Executable Code有一些详细信息。

我知道有一些指令可以给“缓存系统”提示,但是我不确定这是否足够,因为这些提示可能会被忽略,或者它们可能不足以表达这样的表示方式。 /从缓存顺序开始。

答案 2 :(得分:2)

直接访问缓存sram与指令集无关,如果您具有访问权限,则可以访问并且可以访问它,但是由芯片/系统设计者来实现。它可能像地址空间一样简单,也可能是诸如访问的间接外围设备,您可以在其中访问控制寄存器,而逻辑可以为您访问缓存中的该项。

这并不意味着所有ARM处理器都可以以相同的方式访问其缓存。 (arm是一家IP公司,而不是一家芯片公司),但这可能意味着没有,您不能在任何现有的x86上做到这一点。我知道产品本身就是我们的一部分,我们可以做到这一点,因为我们在那些SRAM上具有ECC,并且有一种访问方法可以在启用监视器之前从软件初始化ram。您可以通过常规访问来完成某些操作,但是例如,我们使用的臂是通过奇偶校验而不是ECC实现的,因此我们在SRAM上添加了ECC,并为初始化添加了侧门访问,因为尝试通过常规访问缓存访问并获得100%的覆盖率是PITA,并且最终没有正确的解决方案。

还致力于将dram控制器高速缓存用作片上ram直接访问的产品,由软件决定如何将其用作L2缓存或片上ram。

它已经并且可以做到,这些都是孤立的示例。作为筛选零件的一部分,有运行的mbist测试,但是通常是通过jtag驱动的,并且不能直接提供给处理器和/或ram不能使用,有时可以通过软件启动和检查mbist,但是ram可以不是,在某些实现中,设计人员做了它,以便软件可以触摸所有内容,包括标签ram。

如果您认为自己可以做得比硬件更好,并且想要移动东西,那么您也可能还需要访问标记ram,以便可以在需要高速缓存行的地方跟踪/驱动,其状态等。

基于此评论:

对不起,我是Assembly的[入门],请您简单说明一下吗?什么是CPU“模式”?那是什么HBM?如何设置CPU模式?什么是NDA? – KGM

有两件事,你不能比缓存做得更好,还有两件事,你还没准备好完成这项任务。

即使有经验,一般也不能比缓存做得更好,如果要操纵缓存,您将使用与如何编写代码,将代码放置在内存中的位置以及数据在何处相同的知识。您正在使用,则逻辑实现可以为您更好地工作。试图重新定位运行时的燃烧指令和周期将无济于事。通常,您需要以普通公众无法访问的级别访问设计。因此,一份NDA(非公开协议),即使在那时,您也极不可能获得所需的信息和/或获得的收益微乎其微,可能仅适用于一种实现方式,而不适用于整个产品系列,等等。

更有趣的是,您认为自己可以做得更好,怎么认为自己可以做得更好? (还要了解,我们中的许多人都可能使任何高速缓存实现失败,并且运行速度会比不存在的慢,即使您创建了更好的更新缓存,根据定义,它也只能在某些情况下提高性能。)