从用户空间访问 ARM PLE(预加载引擎)(或如何获得全带宽内存访问)

Accessing the ARM PLE (preload engine) from userspace (or how to get full bandwidth memory accesses)

我在很多地方都问过这个问题,但我仍在努力寻找答案。转贴请大家见谅

这个问题归结为是否可以在 ARM Cortex A9 上全速顺序访问主内存,具体问题与我提出的方法有关。

我正在 667 MHz Cortex A9(在 Xilinx Zynq 中)上编写一些性能关键的数字代码 运行ning,目前缓存有限。我可以在小数据集(~530 MFlops)上实现每次内存访问 ~1 neon 乘法,当数据大小变大时(~180MFlops 在极限)下降到更少。这是在带有 GCC 堆栈的 ARM Linux 上。

上面的 180 MFlops 图是使用 PLD 指令(这绝对有帮助),但我仍然离主内存的理论内存带宽 (DDR2 @533MHz) 还差得很远。鉴于问题本质上是在完全先验定义的顺序内存访问上运行,我想知道我是否可以使用 L2 预加载引擎加快速度。

现在,我已经对此进行了一些试验,编写了一个小型内核驱动程序来翻转 PLEUAR 寄存器位以允许用户space 访问 PLE(以及摆弄 PLEPCR 寄存器位以减少 PLE 操作之间的周期),然后执行 PLE 操作(类似于 MCRR p15, 0, %[vect_addr], %[vect_config], c11;)。

从这里可以看出很多事情:

  1. 程序 运行 在大约 20% 的时间内成功,其余时间在第一次尝试设置 PLE 时几乎立即产生 "Illegal instruction"。
  2. 运行次不受影响。如果这是预期的,我很想知道是否有可能对以内存带宽访问的数据进行操作。
  3. 我可以监视(16 位长度)FIFO 并观察它在 space 中随着指令的添加而减少,然后恢复为空。

我的观察表明我没有做我认为我正在做的事情,或者至少,有些事情阻碍了我做我想做的事情的尝试。

我是不是漏掉了一些基本的东西?我是不是踩遍了内核的精心保护space?

与 运行ning 进程相比,PLE 查看的虚拟地址是否不同?

为什么会出现非法指令?

Xilinx 可靠地告诉我,所有 型号的 Zynq 都有一个双核 Cortex-A9,所以我猜你是 运行 SMP Linux 并且您的内核模块没有考虑到这一点。除非您使用 on_each_cpu* 调用之一在 每个 核心上执行启用,否则您将自己设置为与调度程序进行俄罗斯轮盘赌游戏。另请注意,如果您有 cpuidle 或任何其他 power/thermal 核心可能丢失状态的管理,那将增加乐趣,因为不能保证 idle/hotplug 代码会把事情恢复到他们的状态多管闲事的状态。

现在,除此之外,预加载引擎是特定于某些 Cortex-A9 配置的疯狂东西,没有人使用,尤其是在 Linux 中。我不确定它最初的设计意图,但我怀疑它更多地与为 GPU 或其他挂在 ACP 之外的设备供电有关,而不是与内核本身有关,它们完全能够管理自己的预取。无论如何,它也没有解决您的真正问题:DRAM 和 L2 之间世界上的所有带宽仍然不会阻止您在 L1 上丢失,它只会减轻一点伤害。在旧内核上实现最大 processing 带宽就是将循环展开恰到好处的数量,并微调 PLD 以寻找使 L1 尽可能热的最佳位置 - 即显然取决于许多特定于系统的因素,但通常会计算出大约提前 2-4 个缓存行的预取距离。