我在IvyBridge上,想测试L1d缓存组织。我的理解如下:
在IvyBridge上,L1d缓存具有32K容量,64B缓存行,与8种方式相关的集合。因此,它具有32K /(64 * 8)= 64组,给定主存储器addr
,则可以通过(addr/64) % 64
计算组索引。
因此,如果我将主存储器步进64 * 64(4K),则我将始终触摸相同的L1d集。一个集合只有8个缓存行,因此,如果我用16个步骤循环它,我将得到几乎100%的L1d缓存未命中。
我编写了以下程序进行验证:
section .bss
align 4096
buf: resb 1<<26
%define gap 64 * 64 ; no L1 cache miss
; %define gap 64 * 64 * 256 ; 41% L1 cache miss
; %define gap 64 * 64 * 512 ; 95% L1 cache miss
; however, total cycle suggests this gap is already at L3 latency level with complete L2 cache miss.
section .text
global _start
_start:
mov rcx, 10000000
xor rax, rax
loop:
mov rax, [buf+rax]
mov rax, [buf+rax+gap*1]
mov rax, [buf+rax+gap*2]
mov rax, [buf+rax+gap*3]
mov rax, [buf+rax+gap*4]
mov rax, [buf+rax+gap*5]
mov rax, [buf+rax+gap*6]
mov rax, [buf+rax+gap*7]
mov rax, [buf+rax+gap*8]
mov rax, [buf+rax+gap*9]
mov rax, [buf+rax+gap*10]
mov rax, [buf+rax+gap*11]
mov rax, [buf+rax+gap*12]
mov rax, [buf+rax+gap*13]
mov rax, [buf+rax+gap*14]
mov rax, [buf+rax+gap*15]
dec rcx,
jne loop
xor rdi, rdi
mov rax, 60
syscall
令我惊讶的是,perf
显示根本没有丢失L1缓存:
160,494,057 L1-dcache-loads
4,290 L1-dcache-load-misses # 0.00% of all L1-dcache hits
我的理解有什么问题?
答案 0 :(得分:3)
所有BSS页面最初都映射为写时复制到相同的物理零页面。您会遇到TLB遗漏(甚至可能是软页面错误),但没有L1d遗漏。
为避免这种情况并将其映射到不同的物理页面:
mmap(MAP_POPULATE)
进行分配,而不使用BSS。这样至少可以对它们进行故障修复,从而避免出现软页面错误,但仍然可以恢复到相同的物理零页面。buf
或.data
部分中将.rodata
放入其中,它实际上将与文件支持进行映射。 (您必须使其更小,因为零实际上将出现在可执行文件中。) (对我而言)更有趣的结果是,您开始开始大步跨入缓存未命中。然后,您将访问更多的4k页面,这可能导致内核开始为您的BSS使用2M巨大页面,具有讽刺意味的是,它不再使它们成为同一4k物理页面的别名,从而损害了它。您可以检查/proc/PID/smaps
以查看是否存在非零的AnonHuge
用于该映射。
L2可能会丢失,因为它也是8位关联的,但是L3更具关联性,并使用非简单的索引函数,该函数将2个步幅的简单幂分布在多个集合上。 (Which cache mapping technique is used in intel core i7 processor?)
顺便说一句,您可能想要的间隔不是2的幂。只是L1别名跨度的倍数,而不是L2别名跨度的倍数,因此您的数据可以通过L2中的许多集合分布。
我一直在寻找重复项,但没有找到确切的重复项,尽管我很确定我之前已经在SO>。<的某处进行了解释。可能我在想How can I obtain consistently high throughput in this loop?,这与malloc而不是BSS完全相同。
相关:
mremap
的零页虚拟内存/ COW有一些了解。