栈对齐是如何工作的?

3

我之前从未完全理解函数中的堆栈对齐和堆栈上的“对齐加载/存储”之间的区别。

我正在阅读一些PTX代码,我看到了这个:

 function()

   .local .align 16 .byte stack_memory[200];
   // This should mean the stack memory starts at an address aligned to 16 (why would this be necessary?)

   load_byte_from_stack reg, [stack_memory+1];
   // It seems reading 1 byte is always safe (why?)

   load_float32_from_stack reg, [stack_memory+8];
   // It also seems that reading 32 bit from an address aligned to 32 bit (4 bytes) is also safe (why??)

   load_two_float32_from_stack reg, [stack_memory+12];
   // This should not be right (why?)

我的问题在代码中,但关键是:

我不太明白为什么堆栈分配应该对齐到一个地址,以及如果我可以从完全不对齐的地址读取1个字节并从地址只是4的倍数的地方读取float32,那么为什么这很重要。


1
并非所有的架构都允许未对齐的访问,即使对于那些允许的架构,也往往存在性能惩罚。 - Paul R
好的,如果我将堆栈内存对齐到16,为什么我可以在任何对齐到4的地方读取浮点数?这听起来很奇怪...为什么一开始要将整个东西对齐到16呢? - user129506
1个回答

1

这是一个有趣的问题。让我试着解释一下你的代码:

.local .align 16 .byte stack_memory[200]; 

问:这应该意味着堆栈内存从一个地址开始对齐到16个字节(为什么需要这样做?)

答:答案是因为优化和数据一致性。将缓冲区对齐到16B确保缓冲区分布在最少的缓存行中。如果一个缓存行是16B(它们通常是64B的当前架构),对齐缓冲区将确保前16B存储在第一行,接下来的16B存储在下一行,以此类推。现在,如果你想在16B上执行SIMD操作,只需要访问一个单独的缓存行。如果没有对齐,你可能会访问2个缓存行,很可能在你访问第一行时,其他计算单元修改了第二行,那么会发生什么?

load_byte_from_stack reg, [stack_memory+1];

问题:为什么读取一个字节总是安全的?

回答:因为一个字节不会跨越两个不同的缓存行。

load_float32_from_stack reg, [stack_memory+8]; 

问题:似乎从一个32位对齐的地址读取32位(4个字节)也是安全的(为什么?)

回答:同样的原因。由于对齐,你可以确信你的4B值不会跨越两个连续的缓存行。

load_two_float32_from_stack reg, [stack_memory+12];

问题: 这不应该是正确的(为什么?)

答案: 是的,这是有问题的,特别是对于具有宽松内存模型的架构。如果缓存行只有16B,那么将偏移量对齐到16B并从偏移量12处读取2 x 4B,将从第1行读取第一个4B,然后从第2行读取下一个4B。如果程序员没有意识到第二个4B在读取之前可能已被其他人修改(因为读取指令不能阻塞2个缓存行),那么可能会引起一些相关性问题。

希望这可以帮到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接