使用局部变量缓存多次访问的全局变量
【说明】 CPU上,不存在多线程访问的前提下,两次或以上使用某一个全局变量时,通过使用局部变量转存其内容以提升访问数据的局部性。
【注意事项】 当全局变量过大时,对于全局变量的缓存可能带来额外拷贝过程的指令开销,以及栈空间的消耗,使用时需要结合收益和开销进行权衡。具体地,
- 由于全局变量的作用域是全局的,一般编译器不轻易对全局变量的相关操作做优化,通过使用该全局变量的局部变量副本,可以帮助编译器明确可以优化的范围;
- 减少不必要的访存开销,以DSP为例,读写DDR上的全局变量存在xxcycle的开销,造成处理器指令流水中断,降低IPC,使用局部变量转存能大幅减少不必要的DDR读取开销;另外,在DSP上,使用局部变量转存或者使用DMA搬移将频繁访问的DDR数据搬移到PL2等,都可以提升访问数据局部性。由于PL2内存有限,使用时也需要权衡收益和开销;
【案例】
优化前:
int *g_test = (int *)0x1234;
void Func(void)
{
int maxLoop = GetSumSize();
for (int i = 0; i < maxLoop; i++) {
*g_test = *g_test + i;
}
}
对应的汇编指令:
Func():
push {r4, lr}
bl GetSumSize()
cmp r0, #0
pople {r4, pc}
mov r3, #0
ldr r2, .L7
ldr r1, [r2]
ldr r2, [r1]
.L3:
add r2, r2, r3
add r3, r3, #1
cmp r0, r3
bne .L3
str r2, [r1]
pop {r4, pc}
.L7:
.word .LANCHOR0
g_test:
.word 4660
优化后:
int *g_test = (int *)0x1234;
void Func(void)
{
int temp = *g_test;
int maxLoop = GetSumSize();
for (int i = 0; i < maxLoop; i++) {
temp = temp + i;
}
*g_test = temp;
}
对应的汇编指令如下,其中for循环中对全局变量的读取过程被消减:
Func():
push {r4, r5, r6, lr}
ldr r5, .L7
ldr r3, [r5]
ldr r4, [r3]
bl GetSumSize()
cmp r0, #0
ble .L2
mov r3, #0
.L3:
add r4, r4, r3
add r3, r3, #1
cmp r0, r3
bne .L3
.L2:
ldr r3, [r5]
str r4, [r3]
pop {r4, r5, r6, pc}
.L7:
.word .LANCHOR0
g_test:
.word 4660
父主题: 变量