在Dmitry Vyukov用C++编写的优秀的有界mpmc队列中,请参阅:http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
他添加了一些填充变量。我假设这是为了使它与缓存线对齐以提高性能。
我有几个问题要问。
__attribute__ ((aligned (64)))
。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 enqueue_pos_;cacheline_pad_t pad2_;std::atomic dequeue_pos_;cacheline_pad_t;
这个概念在gcc的c代码下能行吗?
发布于 2018-08-23 01:28:44
在处理中断或高性能数据读取时,您可能需要对齐高速缓存线边界,每个高速缓存线通常为64字节,并且在处理进程间套接字时必须使用它们。对于进程间套接字,有一些控制变量不能分布在多个缓存线或DDR字中,否则它将导致L1、L2等或缓存或DDR充当低通滤波器,并过滤掉中断数据!这太糟糕了!这意味着当你的算法很好的时候,你会得到奇怪的错误,它有可能让你发疯!
DDR RAM几乎总是要读入128位字(DDR RAM字),即16字节,因此环形缓冲区变量不应分布在多个DDR RAM字中。有些系统确实使用64位DDR RAM字,从技术上讲,您可以在16位CPU上获得32位DDR RAM字,但在这种情况下会使用SDRAM。
当在高性能算法中读取数据时,人们可能只对最小化所使用的高速缓存线的数量感兴趣。在我的例子中,我开发了世界上最快的整数到字符串算法(比以前最快的算法快40%),我正在优化Grisu算法,这是世界上最快的浮点算法。为了打印浮点数,你必须打印整数,所以为了优化Grisu,我已经实现了一个优化,我已经实现了高速缓存线对齐的Grisu的查找表(LUT)到恰好15个缓存线,这是相当奇怪的,它实际上是这样对齐的。这将从.bss部分(即静态内存)获取but,并将它们放到堆栈(或堆,但堆栈更合适)上。我还没有对此进行基准测试,但可以提出来,我学到了很多关于这方面的知识,最快的加载值的方法是从i-cache而不是d-cache加载它们。不同之处在于,i-cache是只读的,并且具有更大的缓存线,因为它是只读的(2KB是一位教授曾经引用给我的)。因此,您实际上是要将性能从数组索引中分离出来,而不是像这样加载变量:
int faster_way = 12345678;
与较慢的方式相反:
int variables[2] = { 12345678, 123456789};
int slower_way = variables[0];
不同之处在于,int variable = 12345678
将通过从函数开始时偏移到i-cache中的变量来从i-cache行加载,而slower_way = int[0]
将使用慢得多的数组索引从较小的d-cache行加载。正如我刚刚发现的,这个特殊的巧妙之处实际上减慢了我和其他许多人的整数到字符串算法。我之所以这么说,是因为你可能认为你是在通过缓存对齐只读数据来进行优化。
通常在C++中,您将使用std::align
函数。我建议不要使用这个函数,因为it is not guaranteed to work optimally。这是对齐到缓存线的最快方法,说实话,我是作者,这是一个无耻的插头:
Kabuki Toolkit内存对齐算法
namespace _ {
/* Aligns the given pointer to a power of two boundaries with a premade mask.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number of bits in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param mask The mask for the Least Significant bits to align. */
template <typename T = char>
inline T* AlignUp(void* pointer, intptr_t mask) {
intptr_t value = reinterpret_cast<intptr_t>(pointer);
value += (-value ) & mask;
return reinterpret_cast<T*>(value);
}
} //< namespace _
// Example calls using the faster mask technique.
enum { kSize = 256 };
char buffer[kSize + 64];
char* aligned_to_64_byte_cache_line = AlignUp<> (buffer, 63);
char16_t* aligned_to_64_byte_cache_line2 = AlignUp<char16_t> (buffer, 63);
下面是更快的std::align替换:
inline void* align_kabuki(size_t align, size_t size, void*& ptr,
size_t& space) noexcept {
// Begin Kabuki Toolkit Implementation
intptr_t int_ptr = reinterpret_cast<intptr_t>(ptr),
offset = (-int_ptr) & (align - 1);
if ((space -= offset) < size) {
space += offset;
return nullptr;
}
return reinterpret_cast<void*>(int_ptr + offset);
// End Kabuki Toolkit Implementation
}
https://stackoverflow.com/questions/8469427
复制相似问题