首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何以及何时对齐高速缓存线大小?

如何以及何时对齐高速缓存线大小?
EN

Stack Overflow用户
提问于 2011-12-12 10:50:09
回答 1查看 33K关注 0票数 71

在Dmitry Vyukov用C++编写的优秀的有界mpmc队列中,请参阅:http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue

他添加了一些填充变量。我假设这是为了使它与缓存线对齐以提高性能。

我有几个问题要问。

  1. 为什么要这样做?
  2. 是一种可移植的方法,在
  3. 中总是有效的,在什么情况下最好改用__attribute__ ((aligned (64)))
  4. 为什么在缓冲区指针前填充有助于提高性能?不只是指针被加载到缓存中,所以它实际上只有指针的大小?

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代码下能行吗?

EN

回答 1

Stack Overflow用户

发布于 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是一位教授曾经引用给我的)。因此,您实际上是要将性能从数组索引中分离出来,而不是像这样加载变量:

代码语言:javascript
复制
int faster_way = 12345678;

与较慢的方式相反:

代码语言:javascript
复制
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内存对齐算法

代码语言:javascript
复制
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替换:

代码语言:javascript
复制
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
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8469427

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档