我在不同的地方问过这个问题,但我仍然试图得到任何答案。如果你遇到交叉投递,请原谅。
这个问题可以归结为是否有可能在一个ARM皮层A9上以全速顺序访问主存储器,以及我提出的方法的具体问题。
我正在研究一些性能关键的数字代码,运行在667兆赫的Cortex A9(在Xilinx Zynq中)上,目前缓存有限。我可以在小数据集(约530个MFlops)上实现~1个neon乘法/内存访问,当数据大小变得更大时(约180MFlops在限制范围内)会降到更低。这是在带有GCC堆栈的ARM Linux上。
上面的180mflops图有PLD指令(这肯定有帮助),但是我仍然没有达到主存储器的理论内存带宽(533MHz下的DDR2)。考虑到问题本质上是在完全预先定义的顺序内存访问上操作,我想知道是否可以使用L2预加载引擎加快速度。
现在,我对此做了一些实验,编写了一个小的内核驱动程序,该驱动程序翻转PLEUAR寄存器位以允许用户空间访问PLE(以及修改PLEPRC寄存器位以减少PLE操作之间的周期),然后执行PLE操作(类似于MCRR p15, 0, %[vect_addr], %[vect_config], c11;
)。
从这一点上可以看出各种各样的事情:
程序成功运行了大约20%的时间,剩余的时间几乎在第一次尝试设置PLE时立即产生“非法指令”。
运行时间丝毫不受影响。如果这是意料之中的,我很想知道是否有可能操作在内存带宽上访问的数据。
我可以监视(16长度)的FIFO,并观察它随着指令的添加而减小,然后恢复为空。
我的观察结果表明我没有做我认为我在做的事情,或者至少,有些事情阻碍了我做我想做的事情的尝试。
我是不是错过了一些基本的东西?我是不是在内核精心保护的空间里到处乱跑?
与正在运行的进程相比,PLE查看的虚拟地址是否不同?
为什么会出现非法指令?
最佳答案
Xilinx可靠地告诉我,Zynq的所有型号都有一个双核Cortex-A9,所以我猜你运行的是SMP-Linux,而你的内核模块没有考虑到这一点。除非您使用其中一个on_each_cpu*
调用对每个核心执行enable,否则您将自己设置为与调度程序进行俄罗斯轮盘赌的游戏。还要注意的是,如果你有cpuidle或任何其他电源/热管理,核心可能会失去状态,这将增加乐趣,因为没有保证空闲/热插拔代码会使事情回到它们的干扰状态。
现在,在这种情况下,预加载引擎对于某些Cortex-A9配置来说是一件疯狂的事情,没有人使用它,特别是在Linux中。我不确定它最初的设计意图,但我怀疑它更多的是与给挂在ACP上的GPU或其他设备供电有关,而不是与核心本身有关,核心本身完全能够管理自己的预取。它也不能解决你真正的问题:在DRAM和L2之间的所有带宽仍然不能阻止你在L1上的丢失,它只会让你少受一点伤害。在较老的内核上实现最大的处理带宽都是通过正确的量来展开循环,并且微调你的PLD来搜索L1的热点,这使得L1尽可能地热——这显然取决于大量的系统特定因素,但是通常会提前到大约2-4个缓存行的预取距离。