如何解决操纵 mips 汇编代码以降低缓存未命中率火星模拟器
如何优化汇编代码以降低缓存的未命中率?我知道更改放置策略/块大小/块替换策略会影响缓存未命中率,但我特别要求修复 mars 上的设置。
我们目前被要求使用直接映射、块大小字 2 和缓存大小 128 字节,而是专注于提高未命中率的代码。
我的数据段目前是这样的:
.data #data segment
X: .word 1,1,2,3,4,8,1 #X[]
H: .word 1,5,1 #H[]
Y: .word 0:8 #Y[]
m: .word 8 #m = 8
n: .word 24 #n = 24
我注意到将 X[]
数组移动到 n
下可以将未命中率从 53% 降低到 44%。我可以进一步操纵我的代码以降低未命中率吗?只能通过操作数据段来完成吗?为什么将 X
数组向下移动几行时命中率会提高?
我希望得到更多“为什么会发生这种情况以及如何利用它”的解释,但为了示例,我将保留我的全部代码。
.data #data segment
H: .word 1,1 #H[]
n: .word 24 #n = 24
Y: .word 0:8 #Y[]
m: .word 8 #m = 8
X: .word 1,1 #X[]
.text
fir: #void fir
la $t0,X #address of X[]
la $t1,H #address of H[]
la $t2,Y #address of Y[]
lw $t3,n
lw $t4,m
add $t5,$zero,$zero #set j counter to 0
addi $s4,4
j for1 #go to for1 loop
for1:
beq $t5,$t4,exit #when j is equal to m loop stops and goes to the exit function
add $t6,$zero #y0 = r6 = 0
add $t7,$zero #set i counter to 0 for every loop
bne $t5,for2 #go to the nested loop for2
for2:
beq $t7,$t3,afterfor2 # for(i=0,i<n,i++)
#making X[i+j]
add $t8,$t5,$t7 #i+j stored in r8
mul $t9,$t8,$s4 #(i+j)*8 to find address stored in r9
addu $t9,$t9,$t0
lw $s0,($t9) #load x[i+j] to $s0
#making H[i]
mul $s1,$s4,$t7 #8*i
addu $s1,$s1,$t1 #adding 8*i to the base address
lw $s2,($s1) #load h[i] to $s2
mul $s3,$s0,$s2 #x[i+j] * h[i]
add $t6,$t6,$s3 #y0 = y0 + x[i+j]*h[i]
addi $t7,$t7,1 # i++
j for2 # repeat loop
afterfor2:
mul $s5,$s4 #8*j stored to $s5
addu $s5,$s5,$t2
sw $t6,($s5) #Y[j] = y0
addi $t5,1 #j++
j for1 #go back to start of loop for1
exit:
li $v0,10
syscall #exit program
是否有任何命令(例如 sw
或 la
)可以更改以提高命中率还是仅取决于数据段?
解决方法
命中率取决于数据放置和代码的访问模式。
在直接映射缓存中,每个内存字节只有一个地方可以缓存,并且该位置由字节的内存地址决定。
具体来说,地址分解为以下字段:
+--------+-------+--------+
| tag | index | offset | field name
+--------+-------+--------+
25 3 4 field size
有 8 个块/行,因此索引大小为 3 位(8 个值)。每块/行有 4 个字,即 16 字节,因此偏移量为 4 位(16 个值)。
当两个关闭的内存变量(通过它们的地址)具有相同的 index
和 tag
时,当它们交替访问时,缓存性能良好。
当两个远距离内存变量,根据它们的地址,具有相同的index
(但具有不同的tag
),那么当它们交替访问时,直接映射缓存必须逐出一个以便缓存另一个。
如果程序的访问模式在两个远程内存变量之间交替,那么它会破坏缓存。
例如,让我们关注单个缓存块,索引 0 处的第一个:
假设我们访问位置 0x10010000。这将被缓存在块/行 0 中,因为该地址的索引字段是 0002。接下来我们访问位置 0x10010080。这是一个不同的地址,但也解析为索引 0。直接映射缓存别无选择,只能从块 0 中驱逐地址 0x10010000,以便它可以在那里缓存地址 0x10010080。如果程序接下来再次访问 0x10010000,因为它不再被缓存,那么这是一次未命中,它具有从块 0 中驱逐 0x10010080 的副作用。每次程序在这两个地址之间移动时,都会发生一次未命中。
相对于另一个数组移动一个数组会改变两个数组的哪些元素共享相同的索引,从而在缓存中发生冲突。
改变数组的大小也会产生影响:一个 24 字的数组有 96 个字节,这是缓存的一大块。
改变算法会改变访问模式,因此也会产生影响。有时我们可以更改算法以一次处理数组的较小部分,这样可以减少冲突。
更改缓存设计可以以增加硬件为代价显着改善抖动。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。