如何以及何时alignment高速caching行大小?
在Dmitry Vyukov用C ++编写的优秀有界mpmc队列见: http ://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmcqueue
他添加了一些填充variables。 我认为这是为了使其与高速caching行alignment以达到性能。
我有一些疑问。
- 为什么这样做呢?
- 这是一个便携式的方法,将始终工作
- 在什么情况下最好使用
__attribute__ ((aligned (64)))
来代替。 -
为什么在缓冲区指针帮助性能之前填充? 是不是只是加载到caching的指针,所以它只是一个指针的大小?
static size_t const cacheline_size = 64; typedef char cacheline_pad_t [cacheline_size]; cacheline_pad_t pad0_; cell_t* const buffer_; size_t const buffer_mask_; cacheline_pad_t pad1_; std::atomic<size_t> enqueue_pos_; cacheline_pad_t pad2_; std::atomic<size_t> dequeue_pos_; cacheline_pad_t pad3_;
这个概念是否在gcc的c代码下工作?
这样做是为了让修改不同字段的不同内核不必在高速caching之间反弹包含它们的高速caching行。 通常,对于处理器访问内存中的某些数据,包含它的整个caching行必须位于该处理器的本地caching中。 如果正在修改该数据,则该caching条目通常必须是系统中任何caching中唯一的副本(MESI / MOESI样式caching一致性协议中的独占模式)。 当单独的内核尝试修改发生在同一个caching行上的不同数据,从而浪费时间来回移动整个行时,这就是所谓的虚假共享 。
在你给出的特定例子中,一个核心可以排队一个入口(读取(共享) buffer_
和写入(排除) enqueue_pos_
),而另一个核心dequeue_pos_
(共享buffer_
和独占dequeue_pos_
) 。
填充开头意味着buffer_
和buffer_mask_
结束在同一个caching行上,而不是分成两行,因此需要双倍的内存访问量来访问。
我不确定这种技术是否完全可移植。 假定每个 cacheline_pad_t
本身将被alignment到一个64字节(它的大小)的caching线边界,因此它将在下一个caching线之后。据我所知,C和C ++语言标准只需要整个结构的这种标准,这样他们就可以很好地生活在数组中,而不违反任何成员的alignment要求。 (看评论)
attribute
方法会更具体的编译器,但可能会减less一半的结构的大小,因为填充将被限制为将每个元素四舍五入到一个完整的caching行。 如果有很多这些,这可能是相当有益的。
C和C ++一样适用于同样的概念。