繁体   English   中英

在 ARMv8-A Linux 上禁用 CPU 缓存 (L1/L2)

[英]Disable CPU caches (L1/L2) on ARMv8-A Linux

我想在运行 Linux 的 ARMv8-A 平台上禁用低级缓存,以测量优化代码的性能,独立于缓存访问。

对于 Intel 系统,我找到了以下资源( Is there a way to disable CPU cache (L1/L2) on a Linux system? ),但由于指令集不同,无法直接应用。

到目前为止,我有一个内核模块,它改变相应的系统寄存器以禁用指令和数据缓存。

#include <linux/module.h>

int init_module(void)
{
  int64_t value;

  asm volatile("\
    MRS %0, SCTLR_EL1     // Read SCTLR_EL1 into Xt\n\
    BIC %0, %0, (1<<2)    // clear bit 2, SCTLR_EL1.C\n\
    BIC %0, %0, (1<<12)   // clear bit 12, SCTLR_EL1.I\n\
    MSR SCTLR_EL1, %0     // Write Xt to SCTLR_EL1\n\
  " : "+r" (value));

  return 0;
}

void cleanup_module(void)
{
  int64_t value;

  asm volatile("\
    MRS %0, SCTLR_EL1    // Read SCTLR_EL1 into Xt\n\
    ORR %0, %0, (1<<2)   // set bit 2, SCTLR_EL1.C\n\
    ORR %0, %0, (1<<12)  // set bit 12, SCTLR_EL1.I\n\
    MSR SCTLR_EL1, %0    // Write Xt to SCTLR_EL1\n\
  ": "+r" (value));
}

MODULE_LICENSE("GPL");

但是,加载时会导致系统完全冻结(当我在系统寄存器中设置相应位时)。 我的猜测是我仍然需要某种缓存清除,但我在 ARM 手册中没有找到任何有用的东西。

任何人都有一些有用的提示,我如何才能成功禁用 ARM 上的缓存或我在这里缺少什么? 谢谢。

一般来说,这是行不通的,原因有几个。

首先,清除 SCTLR.C 位只会使所有数据访问不可缓存。 并防止分配到任何缓存中。 缓存中的任何数据仍然存在于缓存中,尤其是最近写入的任何内容的脏行; 考虑当您的函数返回并且调用者尝试恢复它现在正在访问的内存中甚至不存在的堆栈帧时会发生什么。

其次,单处理器ARMv8系统很少; 假设您正在运行 SMP Linux,并且突然禁用模块加载器恰好被安排在哪个 CPU 上的缓存,那么即使忽略第一点,事情也会很快走下坡路。 Linux 期望所有 CPU 彼此一致,如果违反该假设,通常会非常迅速地崩溃。 请注意,为此甚至不值得冒险使用 SMP 交叉调用; 可以说,即使尝试在禁用缓存的情况下运行 Linux 的唯一安全方法是确保它们从一开始就从未启用,除非......

第三,无法保证 Linux 甚至可以在禁用缓存的情况下运行。 在当前的硬件上,内核(更不用说用户空间)中的所有锁定和原子操作都依赖于独占访问指令。 虽然 CPU 集群将为可缓存内存实现架构上所需的本地和全局独占监视器(通常作为缓存机制本身的一部分),但是否实现了用于不可缓存访问的全局独占监视器取决于系统,因为这样的东西必须在 CPU 外部(通常在互连或内存控制器中)。 许多系统没有实现这样的全局监视器,在这种情况下,对外部存储器的独占访问可能会出错、不做任何事情或其他各种实现定义的行为,这将导致 Linux 崩溃或死锁。 在这样的系统上,在关闭缓存的情况下运行 Linux 实际上是不可能的——仅仅为了让 UP arm64 内核工作(SMP 实际上是不可能的)而进行的大量黑客攻击是不切实际的; 祝用户空间好运。

然而,碰巧的是,最糟糕的问题不是这些,而是​​:

...为了衡量优化代码的性能,独立于缓存访问。

如果代码打算在禁用缓存的部署中运行,那么从逻辑上讲,它不能在 Linux 下运行,因此花在破解 Linux 上的努力最好花在更现实的执行环境中的基准测试上,以便结果是其实有代表性。 在另一方面,如果打算与缓存运行启用(在Linux或任何其他操作系统),然后禁用会给无意义的结果,成为浪费时间的缓存标杆。 “优化”例如在实践中不存在的指令获取带宽瓶颈不会引导您走向正确的方向。

我已经在 armv8-a linux 上完成了。 我这样做不是为了衡量性能,而是为了验证 xilinx zcu104 平台可能存在潜在的一致性错误。 因此,xilinx 提供的 pynq 图像在 pl 和 ps 通信过程中必然存在一定的相干性错误。 这是我的解决方法:

  1. 我的平台是cortex-a53,ubuntu18从EL2开始,切换到EL1,在四核cpu上支持SMP。 因此,我需要关闭多核以确保 L2 缓存一致性。 多亏了 cpu-hot-plug 的特性,我才运行:

    回声'0'> /sys/devices/system/cpu/cpu1/online,

    回声'0'> /sys/devices/system/cpu/cpu2/online,

    回声'0'> /sys/devices/system/cpu/cpu3/online

    然后我运行 dmesg 来验证多核已关闭。

  2. 我构建了内核源代码树,因为我在我的 linux 中找不到它。 您可以运行 uname -r 来查看您的内核版本。 并在 /usr/src 中查找以查看您的 linux 是否已经拥有它。

  3. 我构建了 linux 模块。 使用 gcc inline asm ,我刷新所有缓存并设置 sctlr_el1.c 0。

  4. 我插入了模块。 我首先以正确的结果运行我的程序,尽管它比多核和 D 缓存慢 20 倍。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM