所以让我们试试吧。 NUCLEO-F767ZI
一般的Cortex-M7:
Prefetch Unit
The Prefetch Unit (PFU) provides:
1.2.3
• 64-bit instruction fetch bandwidth.
• 4x64-bit pre-fetch queue to decouple instruction pre-fetch from DPU pipeline operation.
• A Branch Target Address Cache (BTAC) for the single-cycle turn-around of branch predictor state and target address.
• A static branch predictor when no BTAC is specified.
• Forwarding of flags for early resolution of direct branches in the decoder and first execution stages of the processor pipeline.
对于此测试,分支预测会妨碍您将其关闭:
将 ACTLR 设置为 00003000(十六进制,这里的大多数数字都是十六进制)
不知道如何禁用 PFU 无论如何也不希望有这样的控制。
所以我们希望预取一次读取 64 位,对齐的 4 条指令
边界。
来自 ST
DBANK 位被设置,表示单个银行
指令预取
在单组模式的情况下(nDBANK 选项位设置)256 位代表 8 条 32 位指令到 16 位 16 位指令根据启动的程序。因此,在顺序代码的情况下,至少需要 8 个 CPU 周期才能执行上一条读取的指令行。
所以 ST 将把它变成 256 位或 16 条指令
使用 systick 计时器。我以 16Mhz 运行,因此闪存处于零等待状态。
08000140 <inner>:
8000140: 46c0 nop ; (mov r8, r8)
8000142: 46c0 nop ; (mov r8, r8)
8000144: 46c0 nop ; (mov r8, r8)
8000146: 46c0 nop ; (mov r8, r8)
8000148: 46c0 nop ; (mov r8, r8)
800014a: 46c0 nop ; (mov r8, r8)
800014c: 3901 subs r1, #1
800014e: d1f7 bne.n 8000140 <inner>
00120002
所以每个循环有 12 个时钟。来自 ARM 的两个预取,第一个成为单个 ST 取指。应该是零等待状态。请注意这是 AXIM 的地址
如果我减少 nop 的数量,它会一直保持在 0x1200xx 直到这里:
08000140 <inner>:
8000140: 46c0 nop ; (mov r8, r8)
8000142: 46c0 nop ; (mov r8, r8)
8000144: 3901 subs r1, #1
8000146: d1fb bne.n 8000140 <inner>
00060003
一个手臂取而不是两个。时间减半,所以预取主导了我们的
性能。
08000140 <inner>:
8000140: 46c0 nop ; (mov r8, r8)
8000142: 46c0 nop ; (mov r8, r8)
8000144: 46c0 nop ; (mov r8, r8)
8000146: 46c0 nop ; (mov r8, r8)
8000148: 3901 subs r1, #1
800014a: d1f9 bne.n 8000140 <inner>
000 (zero wait states)
00120002
001 (1 wait state)
00140002
002 (2 wait states)
00160002
202 (2 wait states enable ART)
0015FFF3
为什么这会影响 AXIM?
所以每个等待状态每个循环增加 2 个时钟,每个循环有两个取指,所以也许每次取指都会导致 st 执行它的 256 位取指之一,但这似乎被打破了。
切换到 ITCM
00200140 <inner>:
200140: 46c0 nop ; (mov r8, r8)
200142: 46c0 nop ; (mov r8, r8)
200144: 46c0 nop ; (mov r8, r8)
200146: 46c0 nop ; (mov r8, r8)
200148: 3901 subs r1, #1
20014a: d1f9 bne.n 200140 <inner>
000
00070004
001
00080003
002
00090003
202
00070004
ram
00070003
所以单独使用 ITCM,零等待状态,ART 关闭是每循环 7 个时钟,对于 6 条指令
用一个分支循环。似乎有道理。对于这个小测试,开启 ART 并有 2 个等待状态让我们回到每个循环 7 个。
请注意,从 ram 开始,此代码也以每个循环 7 次运行。让我们试试另一对
00F
00230007
20F
00070004
我没有寻找除 BTAC 之外的其他分支预测器
首先要注意的是,您不想让 MCU 运行得比您必须的更快,会消耗电力,许多您需要添加闪存等待状态,许多 CPU 和外围设备具有不同的最大时钟速度,因此存在界限它变成非线性的(以慢时钟速率占用 X 个时钟周期,外围时钟 = CPU 时钟,有一个地方 N 倍快是 N X 个时钟来做某事,但它需要一个或多个边界当 CPU 时钟快 N 倍时,多于 NX 做某事)。这个特定的部分有这个非线性问题。如果您使用 ST 的库来设置时钟,那么您可能会遇到最坏的闪存等待状态,如果您设置它并阅读文档,您可能会刮掉一两个/几个。
Cortex-M7 有可选的 L1 缓存,这次没有搞砸它,但 ST 在这些东西出来之前就有这个 ART 东西,我相信他们至少会打败/禁用 i 缓存,它会变得更好还是更糟糕的是两者兼而有之?如果它拥有它,那么即使在 AXIM 空间中,第一个过去的速度也会变慢,然后剩下的速度可能会更快。欢迎您尝试一下。似乎记得他们在处理器内核上做了一些棘手的事情,很难看出它是如何被打败的,而且可能不是这个芯片/内核,但绝对是 ST。 M4没有缓存,所以它必须是我弄乱的M7(特别是这个)。
因此,简短的回答是,如果您不使用 ART 和/或用完 AXIM,性能不会那么糟糕。 ST 实施了闪存,使得 ITCM 接口比 AXIM 更快。如果您启用分支预测,我们可以看到 ARM 获取自身的效果,如果您打开它,您也可以看到。
创建一个不符合这些功能的基准应该不难,就像您可以创建一个使 L1 缓存(或任何其他缓存)损害性能的基准一样。 ART 与任何其他缓存一样,会降低性能的可预测性,并且当您更改代码、添加一行、删除一行时,性能可能会从无变化到很多变化。
根据处理器和获取大小和对齐方式,您的代码性能可能会因在项目的性能敏感部分上方添加或删除代码而有所不同,但这取决于我们很少能看到的一些因素。
很难说他们声称 ART 会降低功率。我希望它能够增加这些 sram 的开启/计时功能。如果您关闭闪光灯并从 ram 运行,则看不到明显节省了多少。 M7 部件并不是真正意义上的低功率部件,如一些 STM32L 部件,您可以达到几微安/几十微安(微不是毫,已经做到了)。
少量时钟 0x70004 而不是 0x70000 与一些获取开销有关,无论是 ARM 还是 ST 或两者的组合。要查看内存/闪存性能,您需要禁用尽可能多的功能,例如分支预测、可以禁用的缓存等。否则,很难衡量性能,然后对闪存/内存/总线的功能做出假设。我怀疑还有一些东西我没有关闭以进行干净的测量,和/或无法关闭。简单的 nop 循环(尝试了其他非 nop 指令,没有改变它)不会告诉你一切。使用文档作为指南,您可以尝试缓存 ART 或其他内容,看看会发生什么样的命中。
对于性能关键代码,您可以从 RAM 运行并避免所有这些问题,我没有搜索它,但假设这些部分 SRAM 可以像 CPU 一样快地运行。答案不是在我身上跳出来,你自己想办法。
注意我的测试实际上看起来像
ldr r2,[r0]
inner:
nop
nop
nop
nop
sub r1,#1
bne inner
ldr r3,[r0]
sub r0,r2,r3
bx lr
systick 的采样就在前面和后面。分店前。要测量 ART,您需要对尚未读取的内存范围的分支之前的时间进行采样,因此不可能神奇地读取速度更快,第一次读取缓存应该更慢。如果我将时间采样移得更远,我可以看到它从 0x7000A 变为 0x70027,用于 0 到 15 个等待状态,同时开启 ART。对于分支到尚未运行/缓存的代码来说,这是一个明显的性能损失。知道艺术提取的大小,应该很容易进行跳跃很多的测试,并且艺术特征开始变得无关紧要。
简短的回答,ITCM 是 ARM 内核上的不同总线接口,ST 已经实现了他们的设计,从而提高了性能。因此,即使没有启用 ART,使用 ITCM 也比 AXIM 更快(可能是 ARM 总线而不是 ST 闪存)。如果您运行的时钟频率足够快,不得不向闪存添加等待状态,那么 ART 基本上可以擦除这些。