我们有一个性能不佳的算法,我们认为这是因为 CPU 缓存未命中。尽管如此,我们无法证明它,因为我们没有任何方法可以检测到它们。有什么方法可以告诉算法产生多少 CPU 缓存未命中?我们可以将其移植到任何可以让我们检测到它们的语言。
提前致谢。
某些体系结构具有“预取写入”指令,以在您实际执行之前向 CPU 指示您将要写入内存位置。我知道在多核机器上,这可以被内核用作暗示它现在应该尝试获取给定缓存行的所有权,以便以后可以更快地写入该位置。但是,AFAICT 仅在有两个内核可能争用缓存线的情况下才重要。对于仅由单核读取和写入的缓存线,预取写入有任何用处吗?
我正在尝试设计一个缓存模拟器。为了找到一个块的缓存命中/未命中,我将它的索引和偏移量与缓存中已经存在的块进行比较。在 n 关联缓存的情况下,我只检查该块可以去的那些缓存条目。
找到命中和冷未命中的数量是微不足道的。如果缓存已满(或者块可以进入的所有条目都已被占用),那么我们就会出现容量缺失。
有人可以告诉我如何找到冲突未命中的数量吗?冲突未命中的定义说:
Conflict misses are those misses that could have been avoided,
had the cache not evicted an entry earlier
Run Code Online (Sandbox Code Playgroud)
如何确定较早从缓存中删除的条目是否应该或不应该被删除?
memory caching cpu-architecture computer-architecture cpu-cache
在 NVIDIA Fermi 和 Kepler GPU(可能也是 Maxwell)中,L1 缓存线长 128 字节,而 L2 缓存线长 32 字节。不应该反过来吗?我的意思是,L1 小得多,难道它不应该尝试缓存较短的内存段以防止抖动吗?
这是对这个原始问题的跟进,增加了一些新信息.如果您感兴趣,请参见第一部分:数组结构,结构数组和内存使用模式
我第一次尝试为简单类设置数组结构时似乎存在很多问题.主要是针对指针的过多内存分配以及在上一个问题中从vec3_b分配这些指针可能导致的内存泄漏.
我虽然关于如何使用指针重新排列数据,但这需要我首先为我的数据桶的大小设置一些const变量,因此没有像指针这样的无界值,但也会将内存量减少到固定的数量.
const size_t batch_size = 100;
struct vec3_c
{
size_t x[batch_size];
size_t y[batch_size];
size_t z[batch_size];
};
struct vec3_c vec3_c(size_t x, size_t y, size_t z, size_t index)
{
struct vec3_c v;
v.x[index] = x;
v.y[index] = y;
v.z[index] = z;
return v;
}
struct vec3_c vc3;
for(int i = 0; i < batch_size; i++)
{
vc3 = vec3_c(i+1, i*i, i*10, i);
//printf("vec3c x:%zu, y:%zu, z:%zu\n",vc3.x[i], vc3.y[i], vc3.z[i]);
printf("vec3c x:%p, y:%p, z:%p\n",(void*)&vc3.x[i], (void*)&vc3.y[i], (void*)&vc3.z[i]);
}
---------------x-----------------|----------------y-----------------|----------------z-----------------|
0| 0x7fff57489f40 : …Run Code Online (Sandbox Code Playgroud) 我知道 CPU 会计算所有 L1/2/3 缓存未命中,并且原则上可以访问此信息。例如,有一个来自英特尔的性能查看器。我只是在 C# 中找不到示例。可以从 .NET 访问这些数据吗?
在总存储顺序 (TSO) 内存一致性模型下,x86 cpu 将有一个写入缓冲区来缓冲写入请求,并且可以为来自写入缓冲区的重新排序的读取请求提供服务。并且它说写缓冲区中的写请求将退出并以FIFO顺序向缓存层次结构发出,这与程序顺序相同。
我很好奇:
为了服务从写缓冲区发出的写请求,一级缓存控制器是否处理写请求,完成写请求的缓存一致性,并按照与发出顺序相同的顺序将数据插入一级缓存?
据我了解,_mm_clflush()/_mm_clflushopt()如果缓存行已更改,则在将其保存到内存时使缓存行无效。有没有一种方法可以简单地放弃缓存行,而不将对其进行的任何更改保存到内存中?
一个用例是在释放内存之前:我不再需要缓存行或它们的值。
我试图通过编写和运行测试程序来了解硬件缓存的工作原理:
#include <stdio.h>
#include <stdint.h>
#include <x86intrin.h>
#define LINE_SIZE 64
#define L1_WAYS 8
#define L1_SETS 64
#define L1_LINES 512
// 32K memory for filling in L1 cache
uint8_t data[L1_LINES*LINE_SIZE];
int main()
{
volatile uint8_t *addr;
register uint64_t i;
int junk = 0;
register uint64_t t1, t2;
printf("data: %p\n", data);
//_mm_clflush(data);
printf("accessing 16 bytes in a cache line:\n");
for (i = 0; i < 16; i++) {
t1 = __rdtscp(&junk);
addr = &data[i];
junk = *addr;
t2 = __rdtscp(&junk) - t1; …Run Code Online (Sandbox Code Playgroud) 较低级别的缓存是否可以具有更高的关联性并仍然包含包含?
假设我们有 2 级缓存。(L1 最靠近 CPU,L2 最靠近主内存)L1 缓存是与 4 个集合相关联的 2 路集合,假设 L2 缓存直接映射到 16 个缓存行,并假设两者缓存具有相同的块大小。然后我认为即使 L1(较低级别)具有比 L2(较高级别)更高的结合性,它也会遵循包含属性。
根据我的理解,较低级别的缓存可以具有更高的关联性(并且仍然保持包含)。这只会改变标记位的数量(如在每个级别的物理地址中看到的),要使用的比较器和 MUX 的数量。请让我知道这是否正确。