你可以直接使用程序集访问缓存吗?
Can you directly access the cache using assembly?
缓存是效率的核心。
我知道缓存通常会自动发生。
但是,我想自己控制缓存的使用,因为我认为我可以比一些不知道确切程序的启发式方法做得更好。
因此我需要汇编指令来直接移入或移出高速缓存单元。
喜欢:
movL1 address content
我知道有一些指令给出了“缓存系统”的提示,但我不确定这是否足够,因为这些提示可能会被忽略,或者它们可能不足以表达任何可以通过这种方式表达的东西移动 to/from 缓存顺序。
是否有允许完全缓存控制的汇编程序?
旁注:为什么我想改进缓存:
考虑具有 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"
在第一种情况下,您将使用 x、y、z 的寄存器和缓存(a 只写入一次)
在第二种情况下,您将为 a、x、y 使用寄存器和缓存(z 只写入一次)
如果CPU做缓存,它根本无法提前决定它面对的是上面两种情况中的哪一种。
在知道程序是否执行之前,它必须决定每个存储单元 x、y、z 是否应该缓存其内容,是否。 1 或没有。 2,因为两个程序的开始是一样的。
另一方面,程序员提前知道哪些内存单元被重用,以及它们何时被重用。
直接访问缓存 srams 与指令集无关,如果你有访问权限,那么你就可以访问它,但是 chip/system 设计者实现了它。它可以像地址一样简单space,也可以是一些间接的外围设备,例如访问控制寄存器,逻辑会为您访问缓存中的该项目。
这并不意味着所有 ARM 处理器都可以以相同的方式访问其缓存。 (arm 是一家 IP 公司而不是芯片公司)但这可能意味着不,你不能在任何现有的 x86 上执行此操作。我知道关于我参与的产品的一个事实,我们可以做到这一点,因为我们在这些 SRAM 上有 ECC,并且有一种访问方法可以在启用监视器之前从软件初始化 ram。一些 srams 你可以通过正常访问来完成,但是例如我们使用的 arm 是通过奇偶校验而不是 ECC 实现的,所以我们在 SRAM 上添加了 ECC 并为 init 添加了侧门访问,因为试图通过正常访问缓存访问并获得 100% 的覆盖率是一个 PITA,最终不是正确的解决方案。
还开发了一种产品,其中 dram 控制器缓存可以直接用作片上 ram,由软件决定如何将其用作 L2 缓存或片上 ram。
所以它已经并且可以做到,这些都是孤立的例子。作为筛选部件的一部分,有 运行 的 mbist 测试,但通常这些测试是通过 jtag 驱动的,并且处理器不能直接使用 and/or ram 不是,有时可以启动和检查 mbist通过软件,但 ram 不能,在一些实现中,设计人员做到了,因此软件可以触及所有内容,包括标签 ram。
这导致如果您认为自己可以比硬件做得更好并且想要四处移动东西,那么您也可能需要访问标签 ram,这样您就可以 trace/drive想要缓存行、它的状态等
基于此评论:
Sorry, I'm a [beginner] at assembly, could you please explain this simpler? whats a CPU "mode"? What's that HBM? How to set a CPU mode? what are NDAs? – KGM
两件事,你不能比缓存做得更好,第二,你还没有为这项任务做好准备。
即使有经验,您通常也不会比缓存做得更好,如果您想操纵缓存,您需要使用与编写代码的方式、将代码放在内存中的位置以及缓存的位置相同的知识。您正在使用数据,然后逻辑实现可以更好地为您工作。试图重新定位事物的刻录指令和周期 运行 时间无济于事。您通常需要在一般 public 无法访问的级别访问设计。因此,NDA(保密协议),即便如此,您也极不可能获得所需的信息 and/or 收益将微乎其微,可能仅适用于一种实施方式,而不适用于整个产品系列,等等
更有趣的是你认为你可以做得更好的是什么,你认为你可以怎么做? (也明白我们这里的许多人可以使任何缓存实现失败并且 运行 比不存在时慢,即使您创建更新更好的缓存,根据定义它只会在某些情况下提高性能)。 =11=]
在大多数 ISA 的大多数微体系结构中,不,您不能在缓存中固定一行以阻止它被逐出。使用缓存的唯一方法是作为透明缓存,您 load/store 通过。
当然,一个正常的加载肯定会将一个缓存行带入L1d缓存,至少是暂时的。不过,没有什么能阻止它后来被驱逐。例如在 x86-64 上:mov eax, [rdi]
而不是 prefetcht0 [rdi]
.
在专用预取指令存在之前,有时会使用普通加载作为预取(例如,在进入将开始遍历数组的循环之前进行一些循环边界计算之前)。出于性能目的,CPU 可以忽略的尽力而为的软件预取指令通常 更好 。
普通加载的缺点是在加载的数据实际到达之前无法从无序后端退出。 (至少我认为它不能在 x86 CPUs 上使用 x86 的强序内存模型。允许乱序加载的弱序 ISA 可能会让加载退出,即使它还没有真正完成.) 存在软件预取指令以允许预取作为 提示 而不会在等待加载完成时 CPU 出现瓶颈。
在现代 x86 上,可以强制逐出缓存。 NT 商店保证在 Pentium-M 或更新版本上,或 CPUs after Pentium-M,我忘了是哪个。此外,clflush
和 clflushopt
专门为此而存在。
clflush
不仅仅是暗示 CPU 可以掉落;它保证 non-volatile DIMMs like Optane DC PM.
的正确性
有保证,而不仅仅是提示,这会使它变慢。您通常不想为了性能而这样做。 正如@old_timer所说,燃烧指令/循环微管理缓存几乎总是浪费时间。将事情留给硬件的伪LRU替换和硬件预取算法通常在长 运行 中提供良好的结果。 SW 预取在某些情况下会有所帮助。
Xeon Phi can configure its MCDRAM 作为大型最后一级缓存,或作为物理地址 space 的一部分的体系结构可见 "local memory"。但在 6 到 16GiB 时,它比片上 L1/L2 缓存或现代主流 CPU 的 L1/L2/L3 缓存大得多。
此外,x86 CPUs 可以 运行 在缓存即 RAM 无填充模式下,在配置 DRAM 控制器之前由 BIOS 在早期启动时使用。但这实际上只是在读取或写入时没有填充,无效行读取为零,因此当激活无填充模式时,您根本无法使用 DRAM。即 只有 缓存可用,您必须小心不要驱逐缓存的任何内容。除了早期启动外,它不能用于任何实际目的。
and Cache-as-Ram (no fill mode) Executable Code有一些细节。
I know that there are some instructions that give the "caching system" hints, but I'm not sure if that's enough because the hints could be ignored or they maybe aren't sufficient to express anything expressable by such a move to/from cache order.
彼得科德斯写道:
On most microarchitectures for most ISAs, no, you can't pin a line in cache to stop it from being evicted. The only way to use cache is as a transparent cache that you load/store through.
这是正确的,但例外情况很有趣....
在 DSP ("Digital Signal Processing") 芯片中,提供在 "cache" 和 "scratchpad memory" 功能之间划分 SRAM 的有限能力是很常见的。有很多关于这个主题的白皮书和参考指南——一个例子是 http://www.ti.com/lit/ug/sprug82a/sprug82a.pdf。在这个芯片中,有三个 SRAM 块——一个小的 "Level-1 Instruction" SRAM、一个小的 "Level-1 Data" SRAM 和一个更大的 "Level-2" SRAM。三者中的每一个都可以在高速缓存和直接寻址内存之间进行分区,具体取决于具体芯片。例如,一个芯片可能不允许缓存,1/4 SRAM 作为缓存,1/2 SRAM 作为缓存,或者所有 SRAM 作为缓存。 (比率是有限的,因此可以有效地索引允许的缓存大小。)
IBM "Cell" 处理器(用于 2006 年发布的索尼 PlayStation 3)是一种多核芯片,具有一个普通的通用核心和八个协处理器核心。协处理器内核的指令集有限,加载和存储指令只能访问其私有的 128KiB "scratchpad" 内存。为了访问主内存,协处理器必须对 DMA 引擎进行编程,以将主内存块复制到本地暂存器内存(反之亦然)。这种方法提供(并且需要)对数据移动的完美控制,从而产生(非常少量的)非常高性能的软件。
一些 GPU 也有小型片上 SRAM,可以配置为 L1 缓存或显式控制的本地内存。
所有这些都被认为是 "very hard"(或更糟)使用,但如果产品需要非常低的成本、完全可预测的性能或非常低的功耗,这可能是正确的方法。
缓存是效率的核心。
我知道缓存通常会自动发生。
但是,我想自己控制缓存的使用,因为我认为我可以比一些不知道确切程序的启发式方法做得更好。
因此我需要汇编指令来直接移入或移出高速缓存单元。
喜欢:
movL1 address content
我知道有一些指令给出了“缓存系统”的提示,但我不确定这是否足够,因为这些提示可能会被忽略,或者它们可能不足以表达任何可以通过这种方式表达的东西移动 to/from 缓存顺序。
是否有允许完全缓存控制的汇编程序?
旁注:为什么我想改进缓存:
考虑具有 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"
在第一种情况下,您将使用 x、y、z 的寄存器和缓存(a 只写入一次) 在第二种情况下,您将为 a、x、y 使用寄存器和缓存(z 只写入一次)
如果CPU做缓存,它根本无法提前决定它面对的是上面两种情况中的哪一种。
在知道程序是否执行之前,它必须决定每个存储单元 x、y、z 是否应该缓存其内容,是否。 1 或没有。 2,因为两个程序的开始是一样的。
另一方面,程序员提前知道哪些内存单元被重用,以及它们何时被重用。
直接访问缓存 srams 与指令集无关,如果你有访问权限,那么你就可以访问它,但是 chip/system 设计者实现了它。它可以像地址一样简单space,也可以是一些间接的外围设备,例如访问控制寄存器,逻辑会为您访问缓存中的该项目。
这并不意味着所有 ARM 处理器都可以以相同的方式访问其缓存。 (arm 是一家 IP 公司而不是芯片公司)但这可能意味着不,你不能在任何现有的 x86 上执行此操作。我知道关于我参与的产品的一个事实,我们可以做到这一点,因为我们在这些 SRAM 上有 ECC,并且有一种访问方法可以在启用监视器之前从软件初始化 ram。一些 srams 你可以通过正常访问来完成,但是例如我们使用的 arm 是通过奇偶校验而不是 ECC 实现的,所以我们在 SRAM 上添加了 ECC 并为 init 添加了侧门访问,因为试图通过正常访问缓存访问并获得 100% 的覆盖率是一个 PITA,最终不是正确的解决方案。
还开发了一种产品,其中 dram 控制器缓存可以直接用作片上 ram,由软件决定如何将其用作 L2 缓存或片上 ram。
所以它已经并且可以做到,这些都是孤立的例子。作为筛选部件的一部分,有 运行 的 mbist 测试,但通常这些测试是通过 jtag 驱动的,并且处理器不能直接使用 and/or ram 不是,有时可以启动和检查 mbist通过软件,但 ram 不能,在一些实现中,设计人员做到了,因此软件可以触及所有内容,包括标签 ram。
这导致如果您认为自己可以比硬件做得更好并且想要四处移动东西,那么您也可能需要访问标签 ram,这样您就可以 trace/drive想要缓存行、它的状态等
基于此评论:
Sorry, I'm a [beginner] at assembly, could you please explain this simpler? whats a CPU "mode"? What's that HBM? How to set a CPU mode? what are NDAs? – KGM
两件事,你不能比缓存做得更好,第二,你还没有为这项任务做好准备。
即使有经验,您通常也不会比缓存做得更好,如果您想操纵缓存,您需要使用与编写代码的方式、将代码放在内存中的位置以及缓存的位置相同的知识。您正在使用数据,然后逻辑实现可以更好地为您工作。试图重新定位事物的刻录指令和周期 运行 时间无济于事。您通常需要在一般 public 无法访问的级别访问设计。因此,NDA(保密协议),即便如此,您也极不可能获得所需的信息 and/or 收益将微乎其微,可能仅适用于一种实施方式,而不适用于整个产品系列,等等
更有趣的是你认为你可以做得更好的是什么,你认为你可以怎么做? (也明白我们这里的许多人可以使任何缓存实现失败并且 运行 比不存在时慢,即使您创建更新更好的缓存,根据定义它只会在某些情况下提高性能)。 =11=]
在大多数 ISA 的大多数微体系结构中,不,您不能在缓存中固定一行以阻止它被逐出。使用缓存的唯一方法是作为透明缓存,您 load/store 通过。
当然,一个正常的加载肯定会将一个缓存行带入L1d缓存,至少是暂时的。不过,没有什么能阻止它后来被驱逐。例如在 x86-64 上:mov eax, [rdi]
而不是 prefetcht0 [rdi]
.
在专用预取指令存在之前,有时会使用普通加载作为预取(例如,在进入将开始遍历数组的循环之前进行一些循环边界计算之前)。出于性能目的,CPU 可以忽略的尽力而为的软件预取指令通常 更好 。
普通加载的缺点是在加载的数据实际到达之前无法从无序后端退出。 (至少我认为它不能在 x86 CPUs 上使用 x86 的强序内存模型。允许乱序加载的弱序 ISA 可能会让加载退出,即使它还没有真正完成.) 存在软件预取指令以允许预取作为 提示 而不会在等待加载完成时 CPU 出现瓶颈。
在现代 x86 上,可以强制逐出缓存。 NT 商店保证在 Pentium-M 或更新版本上,或 CPUs after Pentium-M,我忘了是哪个。此外,clflush
和 clflushopt
专门为此而存在。
clflush
不仅仅是暗示 CPU 可以掉落;它保证 non-volatile DIMMs like Optane DC PM.
有保证,而不仅仅是提示,这会使它变慢。您通常不想为了性能而这样做。 正如@old_timer所说,燃烧指令/循环微管理缓存几乎总是浪费时间。将事情留给硬件的伪LRU替换和硬件预取算法通常在长 运行 中提供良好的结果。 SW 预取在某些情况下会有所帮助。
Xeon Phi can configure its MCDRAM 作为大型最后一级缓存,或作为物理地址 space 的一部分的体系结构可见 "local memory"。但在 6 到 16GiB 时,它比片上 L1/L2 缓存或现代主流 CPU 的 L1/L2/L3 缓存大得多。
此外,x86 CPUs 可以 运行 在缓存即 RAM 无填充模式下,在配置 DRAM 控制器之前由 BIOS 在早期启动时使用。但这实际上只是在读取或写入时没有填充,无效行读取为零,因此当激活无填充模式时,您根本无法使用 DRAM。即 只有 缓存可用,您必须小心不要驱逐缓存的任何内容。除了早期启动外,它不能用于任何实际目的。
I know that there are some instructions that give the "caching system" hints, but I'm not sure if that's enough because the hints could be ignored or they maybe aren't sufficient to express anything expressable by such a move to/from cache order.
彼得科德斯写道:
On most microarchitectures for most ISAs, no, you can't pin a line in cache to stop it from being evicted. The only way to use cache is as a transparent cache that you load/store through.
这是正确的,但例外情况很有趣....
在 DSP ("Digital Signal Processing") 芯片中,提供在 "cache" 和 "scratchpad memory" 功能之间划分 SRAM 的有限能力是很常见的。有很多关于这个主题的白皮书和参考指南——一个例子是 http://www.ti.com/lit/ug/sprug82a/sprug82a.pdf。在这个芯片中,有三个 SRAM 块——一个小的 "Level-1 Instruction" SRAM、一个小的 "Level-1 Data" SRAM 和一个更大的 "Level-2" SRAM。三者中的每一个都可以在高速缓存和直接寻址内存之间进行分区,具体取决于具体芯片。例如,一个芯片可能不允许缓存,1/4 SRAM 作为缓存,1/2 SRAM 作为缓存,或者所有 SRAM 作为缓存。 (比率是有限的,因此可以有效地索引允许的缓存大小。)
IBM "Cell" 处理器(用于 2006 年发布的索尼 PlayStation 3)是一种多核芯片,具有一个普通的通用核心和八个协处理器核心。协处理器内核的指令集有限,加载和存储指令只能访问其私有的 128KiB "scratchpad" 内存。为了访问主内存,协处理器必须对 DMA 引擎进行编程,以将主内存块复制到本地暂存器内存(反之亦然)。这种方法提供(并且需要)对数据移动的完美控制,从而产生(非常少量的)非常高性能的软件。
一些 GPU 也有小型片上 SRAM,可以配置为 L1 缓存或显式控制的本地内存。
所有这些都被认为是 "very hard"(或更糟)使用,但如果产品需要非常低的成本、完全可预测的性能或非常低的功耗,这可能是正确的方法。