gpt4 book ai didi

C 中的缓存管理

转载 作者:行者123 更新时间:2023-12-03 05:21:34 28 4
gpt4 key购买 nike

我一直在阅读有关多核系统中的缓存的内容,我想知道当我们使用 C/C++ 进行编程时,是否可以对哪些页面在缓存中或不在缓存中进行一些控制。

例如,我知道我们可以使用内置函数__builtin_prefetch将数据移动到缓存,以减少缓存未命中和延迟。我在这里找到了它: https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html#Other-Builtins

我还发现了 x86 和 x86-64 Intel 的这个:

#include <xmmintrin.h>
enum _mm_hint
{
_MM_HINT_T0 = 3,
_MM_HINT_T1 = 2,
_MM_HINT_T2 = 1,
_MM_HINT_NTA = 0
};
void _mm_prefetch(void *p, enum _mm_hint h);

这里: http://lwn.net/Articles/255364/

我们还可以使用哪些其他函数来为我们提供一些缓存“控制”。例如,我们可以做一些与缓存页面替换相关的事情吗?或者这是操作系统的专有功能?

非常感谢!

最佳答案

缓存预取提示通常会发出一条特殊的预取指令,该指令通知预取器在不久的将来将需要这 block 内存。预取器可能(也可能不)接受这个建议。因此从这个意义上说,软件预取实际上并不是“缓存控制”或“缓存管理”。

据我所知,当前广泛使用的指令集架构没有提供用于逐出特定高速缓存行或将特定内存块放入高速缓存行等指令。大多数当代架构中缓存的要点是对程序员透明。

但是,您可以编写缓存友好的程序。这完全取决于数据和指令的空间和时间局部性:

  • 数据的空间局部性意味着您应该努力实现连续的内存访问,并且彼此之间的距离不会太远。这是最自然的优化方式。

  • 指令的空间局部性意味着代码中的跳转和分支不应走得太远。编译器和链接器应该尝试这样做。

  • 数据的时间局部性意味着在单个时间片中访问相同的内存位置(尽管可能彼此不接近)。这个时间片有多长的定义可能很棘手;

  • 指令的时间局部性意味着即使代码跳转很长的距离,它也会在单个时间片中跳转到相同的位置。这通常非常不直观,而且优化起来也没什么返回。

一般来说,您应该优化数据,而不是指令局部性。在大多数对性能敏感的程序中,数据量远远超过代码量。

此外,对于多核,您应该尽量避免错误共享并尽可能使用线程本地存储。请记住,每个 CPU 核心都有自己的专用缓存,并且诸如缓存行在核心缓存之间弹跳之类的事情可能会产生非常负面的影响。

为了说明错误共享,请考虑以下代码:

int counts[NUM_THREADS]; // a global array where each thread writes to its slot

...

for (int i = 0; i < NUM_THREADS; ++i) {
spawn_thread(thread_start);
}

...

void thread_start(void)
{
for (a_large_number_of_iterations) {
int some_condition = some_calculation();

if (some_condition) {
counts[THREAD_ID]++;
}
}
}

每个线程都会频繁修改 counts 数组的一个元素。问题是,数组的各个元素是相邻的,并且它们的大组将落在单个缓存行上。典型的缓存行为 64 字节,典型的 int 大小为 4 字节,这意味着单个缓存行可以为 16 个元素腾出空间。当多个核心仅更新其 4 字节计数时,它们也会使其他核心中相应的缓存行失效,这将导致缓存行在核心之间反弹,即使线程看似使用独立的内存位置。

关于C 中的缓存管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26755980/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com