我想在ARM Cortex A8处理器上移植一小段代码.L1缓存和L2缓存都非常有限.我的程序中有3个数组.其中两个是按顺序访问的(大小>阵列A:6MB,阵列B:3MB),第三个阵列(大小>阵列C:3MB)的访问模式是不可预测的.虽然计算不是很严格,但是访问阵列C时存在巨大的缓存未命中.我认为一种解决方案是为阵列C分配更多的缓存(L2)空间,而对于阵列A和B则分配更少.但我不能找到任何方法来实现这一目标.我经历了ARM的预加载引擎但找不到任何有用的东西.
我是一名学生,最近在研究超线程。我对这个功能有点困惑——L1 数据缓存上下文模式。
在架构优化手册中,描述了L1缓存可以在两种模式下运行:
一级缓存可以根据上下文 ID 位以两种模式运行:
共享模式:L1 数据缓存由两个逻辑处理器完全共享。
自适应模式:在自适应模式下,使用页目录的内存访问在共享 L1 数据缓存的逻辑处理器之间被完全映射。
但是,我很好奇缓存如何根据描述在自适应模式下进行分区。
我有这样的循环
start = __rdtsc();
unsigned long long count = 0;
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
count += tab[i][j];
stop = __rdtsc();
time = (stop - start) * 1/3;
Run Code Online (Sandbox Code Playgroud)
需要检查预取数据如何影响效率.如何在计算之前强制从内存中预取一些值到缓存中?
最新的英特尔XEON处理器拥有30MB的L3内存,足以容纳薄型1管理程序.
我有兴趣了解如何在CPU中保留这样的Hypervisor,即防止被刷新到RAM,或者至少在发送到内存/磁盘之前加密数据.
假设我们使用裸机运行,我们可以使用DRTM(延迟启动)来引导它,例如我们从不受信任的内存/磁盘加载,但是如果我们可以解密()用于解密的秘密,我们只能加载真实的操作系统.操作系统,在设置了适当的规则以确保发送到RAM的任何内容都已加密后进行.
ps我知道TXT的ACEA又称ACRAM(认证代码执行区域又称认证代码RAM)据说有这样的保证(即它限制在CPU缓存中)所以我想知道是否可以在此周围做一些技巧.
pps这似乎超出了目前的研究范围,所以我实际上并不确定答案是否可行.
我不确定,但如果我没记错的话 Intel 使用 VIPT(虚拟索引物理标记)缓存,我想知道这个选择的原因,为什么它比 VIVT 或 PIPT 更好,它有什么优势,也许是什么缺点。谢谢。
高速缓存行通常为64 字节,也存在其他大小。
我非常简单的问题是:这个数字背后是否有任何理论,或者它只是背后的工程师无疑所做的大量测试和测量的结果?
不管怎样,我想知道这些是什么(理论,如果有的话,以及决定背后的各种测试)。
我想知道链接列表与C中的连续数组相比有什么优缺点.因此,我读了一篇关于链表的维基百科文章. https://en.wikipedia.org/wiki/Linked_list#Disadvantages
根据这篇文章,缺点如下:
- 由于指针使用的存储空间,它们使用的内存多于数组.
- 必须从头开始按顺序读取链接列表中的节点,因为链接列表本质上是顺序访问.
在反向遍历方面,链表中出现了困难.例如,单个链表很难向后导航,而双链表更容易阅读,内存浪费在分配上.
节点存储不明确,大大增加了访问列表中各个元素所需的时间,尤其是CPU缓存.
我理解前3分,但我最后一点很难:
节点存储不明确,大大增加了访问列表中各个元素所需的时间,尤其是CPU缓存.
关于CPU Cache的文章没有提到任何关于非连续内存阵列的内容.据我所知,CPU缓存仅缓存经常使用的地址,总共10 ^ -6缓存未命中.
因此,我不明白为什么CPU缓存在非连续内存阵列方面的效率会降低.
一个普遍的说法是,缓存中的字节存储可能导致内部读 - 修改 - 写周期,或者与存储完整寄存器相比会损害吞吐量或延迟.
但我从未见过任何例子.没有x86 CPU是这样的,我认为所有高性能CPU也可以直接修改缓存行中的任何字节.一些微控制器或低端CPU是否有不同之处,如果它们有缓存的话?
(我不计算字可寻址的机器,或者字节可寻址但没有字节加载/存储指令的Alpha.我说的是ISA本身支持的最窄的存储指令.)
在我的研究中回答现代x86硬件可以不将单个字节存储到内存中吗?,我发现Alpha AXP省略字节存储的原因假设它们被实现为真正的字节存储到缓存中,而不是包含字的RMW更新.(因此,它会使L1d缓存的ECC保护更加昂贵,因为它需要字节粒度而不是32位).
所有现代架构(早期Alpha除外)都可以对不可缓存的内存(而不是RMW周期)进行真正的字节加载/存储,这对于为具有相邻字节I/O寄存器的设备编写设备驱动程序是必需的.(例如,使用外部启用/禁用信号来指定更宽总线的哪些部分保存实际数据,例如此ColdFire CPU /微控制器上的2位TSIZ(传输大小),或者像PCI/PCIe单字节传输,或者像DDR一样SDRAM控制信号掩盖选定的字节.)
对于微控制器设计,可能需要在缓存中为字节存储执行RMW循环,即使它不是针对像Alpha这样的SMP服务器/工作站的高端超标量流水线设计?
我认为这种说法可能来自可以用字寻址的机器.或者来自未对齐的32位存储,需要在许多CPU上进行多次访问,并且人们错误地将其从一般存储到字节存储.
为了清楚起见,我希望到同一地址的字节存储循环将在每次迭代中以与字存储循环相同的周期运行.因此,对于填充阵列,32位存储可以比8位存储快4倍.(也许如果少了32位门店饱和的内存带宽,但8位店家没有.)但是,除非字节存储有一个额外的惩罚,你不会得到更超过4倍的速度差.(或者无论宽度是多少).
而我在谈论asm.一个好的编译器会自动向量化C中的字节或int存储循环,并使用更宽的存储或目标ISA上的最佳存储.
; x86-64 NASM syntax
mov rdi, rsp
; RDI holds at a 32-bit aligned address
mov ecx, 1000000000
.loop: ; do {
mov byte [rdi], al
mov byte [rdi+2], dl ; store two bytes in the same dword
; no pointer increment, this is the same 32-bit dword every time
dec ecx
jnz …Run Code Online (Sandbox Code Playgroud) 考虑以下循环:
loop:
movl $0x1,(%rax)
add $0x40,%rax
cmp %rdx,%rax
jne loop
Run Code Online (Sandbox Code Playgroud)
whererax被初始化为大于 L3 缓存大小的缓冲区的地址。每次迭代都会对下一个缓存行执行存储操作。我希望从 L1D 发送到 L2 的 RFO 请求数量或多或少等于访问的缓存线数量。问题是,即使程序在用户模式下运行,这似乎也只是当我计算内核模式事件时的情况,除非我在下面讨论的一种情况。缓冲区的分配方式似乎无关紧要(.bss、.data 或来自堆)。
我的实验结果如下表所示。所有实验都是在禁用超线程和启用所有硬件预取器的处理器上进行的。
我测试了以下三种情况:
NoInit. 在这种情况下只有一个循环。LoadInit. 在这种情况下有两个循环。StoreInit. 在这种情况下有两个循环。下表显示了英特尔 CFL 处理器上的结果。这些实验是在 Linux 内核版本 4.4.0 上进行的。
下表显示了英特尔 HSW 处理器上的结果。请注意,HSW 未记录事件L2_RQSTS.PF_HIT、L2_RQSTS.PF_MISS和OFFCORE_REQUESTS.ALL_REQUESTS。这些实验是在 Linux 内核版本 4.15 上进行的。
每个表的第一列包含性能监控事件的名称,其计数显示在其他列中。在列标签中,字母U和 分别K代表用户模式和内核模式事件。对于有两个循环的情况,数字1和2分别用于指代初始化循环和主循环。例如,LoadInit-1K代表LoadInit案例初始化循环的内核模式计数。
表中显示的值按高速缓存行的数量标准化。它们也按以下颜色编码。绿色越深,该值相对于同一表中的所有其他单元格就越大。但是,CFL 表的最后三行和 HSW 表的最后两行未进行颜色编码,因为这些行中的某些值太大。这些行被涂成深灰色,以表明它们不像其他行那样进行颜色编码。
我期望用户模式L2_RQSTS.ALL_RFO事件的数量等于访问的缓存行的数量(即标准化值为 1)。该事件在手册中描述如下:
计算对 L2 缓存的 …
这是关于跨不同层的缓存一致性协议cache。我的理解(X86_64)L1是,它由一个核心独占,L2介于两个核心之间,并且L3适用于一个CPU插槽中的所有核心。我已经阅读了MESI协议功能,关于存储缓冲区、无效队列、无效消息等。我的疑问是,它仅MESI适用于L1还是适用于L2并且L3也适用。L2或者 for和之间是否有不同的缓存同步L3。
cpu-cache ×10
caching ×3
intel ×3
arm ×2
cpu ×2
performance ×2
x86 ×2
c ×1
c++ ×1
hypervisor ×1
intel-pmu ×1
linked-list ×1
low-level ×1
memory ×1
mesi ×1
optimization ×1
prefetch ×1
x86-64 ×1