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

KGM*_*KGM 1 performance assembly caching cpu-architecture cpu-cache

谈到效率,缓存是核心。

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

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

因此,我需要汇编指令来直接移入或移出高速缓存单元。

喜欢:

movL1 address content
Run Code Online (Sandbox Code Playgroud)

我知道有一些指令会给出“缓存系统”提示,但我不确定这是否足够,因为这些提示可能会被忽略,或者它们可能不足以表达任何可以通过这种移入/移出缓存来表达的内容命令。

是否有任何允许完全缓存控制的汇编程序?

旁注:为什么我想改进缓存:

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

考虑以下两个程序:

(其中 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"
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,您将寄存器和缓存用于 x,y,z(a 只写入一次)在第二种情况下,您将寄存器和缓存用于 a,x,y (z只写入一次)

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

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

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

Pet*_*des 5

在大多数 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 等 非易失性 DIMM的正确性。为什么 x86 中存在 CLFLUSH?

得到保证,而不仅仅是提示,会使速度变慢。您通常不想为了性能而这样做。 正如@old_timer所说,刻录指令/周期对缓存进行微观管理几乎总是浪费时间。 从长远来看,将事情留给硬件的伪 LRU 替换和硬件预取算法通常会提供良好的结果。软件预取在某些情况下会有所帮助。


Xeon Phi可以将其MCDRAM配置为大型末级缓存,或作为物理地址空间一部分的架构上可见的“本地内存”。但在 6 到 16GiB 的范围内,它比现代主流 CPU 的片上 L1/L2 缓存或 L1/L2/L3 缓存大得多。

此外,x86 CPU 可以在缓存即 RAM 无填充模式下运行,BIOS 在配置 DRAM 控制器之前的早期启动中使用该模式。但这实际上只是在读取或写入时不填充,并且将无效行读为零,因此当激活无填充模式时,您根本无法使用 DRAM。即只有缓存可用,并且您必须小心不要逐出缓存的任何内容。除了早期启动之外,它不能用于任何实际目的。

INVD指令有什么用?Cache-as-Ram(无填充模式)可执行代码有一些详细信息。

我知道有一些指令给出了“缓存系统”提示,但我不确定这是否足够,因为这些提示可能会被忽略,或者它们可能不足以表达通过这种移入/移出缓存可以表达的任何内容命令。


Joh*_*pin 5

彼得科德斯写道:

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

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

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