是否可以帮助我找出当有更多核心/缓存持有该行副本时,缓存写入是否需要更长时间才能完成。 我还想测量/量化它实际需要多长时间。
我在谷歌上找不到任何有用的东西,我自己测量它有困难加上解释我测量的因为现代处理器上可能发生的许多事情。 (重新排序,预取,缓冲和上帝知道什么)
详细信息:
我测量它的基本过程大致如下:
write soemthing to the cacheline on processor 0
read it on processors 1 to n.
rdtsc
write it on process 0
rdtsc
我甚至不确定在进程0上实际用于读/写的指令,以确保在最终时间测量之前完成写/无效。
目前我摆弄了原子交换(__sync_fetch_and_add()),但似乎线程数本身对于此操作的长度很重要(不是要使无效的线程数) - 这可能不是我想要衡量的是什么?!。
我也尝试过读取,然后写入,然后是内存屏障(__sync_synchronize())。这看起来更像我期望看到的, 但是在这里我也不确定在最终的rdtsc发生时是否完成了写入。
您可以猜测我对CPU内部的了解有些限制。
非常感谢任何帮助!
PS: *我使用linux,gcc和pthreads进行测量。 *我想知道这是为我的并行算法建模。
修改
在一个星期左右(明天去度假)我会做更多的研究并发布我的代码和笔记并在此链接(如果有人有兴趣),因为我可以花在这上面的时间是有限的。
答案 0 :(得分:4)
我开始写一个很长的答案,详细描述了它是如何工作的,然后意识到,我可能对确切的细节知之甚少。所以我会做一个较短的答案......
因此,当您在一个处理器上写入内容时,如果它不在处理器缓存中,则必须将其取入,并且在处理器读取数据之后,它将执行实际写入。在这样做时,它将向系统中的所有其他处理器发送缓存无效消息。这些将丢弃任何内容。如果另一个处理器具有“脏”内容,它本身会写出数据,并要求失效 - 在这种情况下,第一个处理器必须在完成其写入之前RELOAD数据(否则,同一个高速缓存行中的某些其他元素)可能会被摧毁)。
在对该缓存行感兴趣的每个其他处理器上都需要将其读回缓存。
__sync_fetch_and_add()wilol使用“lock”前缀[在x86上,其他处理器可能会有所不同,但支持“每条指令”锁定的处理器上的一般想法是完全相同的] - 这将发出“我想要这个高速缓存专属,其他人请放弃并使其无效“。就像第一种情况一样,处理器可能必须重新读取另一个处理器可能弄脏的任何东西。
内存屏障无法确保数据“安全”更新 - 它只会确保“在此指令完成之前,所有处理器之前发生的任何事情(对内存)都是可见的”。
优化处理器使用的最佳方法是尽可能少地共享,特别是避免“错误共享”。在许多年前的基准测试中,有一个像[简化]这样的结构:
struct stuff {
int x[2];
... other data ... total data a few cachelines.
} data;
void thread1()
{
for( ... big number ...)
data.x[0]++;
}
void thread2()
{
for( ... big number ...)
data.x[1]++;
}
int main()
{
start = timenow();
create(thread1);
create(thread2);
end = timenow() - start;
}
因为每次thread1写入x [0],thread2的处理器必须摆脱它的x [1]副本,反之亦然,结果是SMP测试[vs刚刚运行的thread1]正在运行大约慢15倍。通过改变这样的结构:
struct stuff {
int x;
... other data ...
} data[2];
和
void thread1()
{
for( ... big number ...)
data[0].x++;
}
我们得到了1个线程变量的200%[给出或拿走了几个百分点]
是的,因此处理器具有缓冲区队列,其中当处理器写入存储器时存储写入操作。存储器屏障(mfence,sfence或lfence)指令用于确保在处理器进入下一条指令之前完成任何未完成的读/写,写或读类型操作。通常情况下,处理器只会通过以下任何指令继续执行,并最终以某种方式满足内存操作。由于现代处理器在整个地方都有大量的并行操作和缓冲区,因此可能需要花费相当长的时间才能实现最终结束的操作。因此,如果确保在继续操作之前确实已经完成某些事情是很关键的(例如,如果我们已经向视频内存写了一堆指令,我们现在想要开始执行这些指令,我们需要制作确保'指令'写入实际上已经完成,并且处理器的其他部分仍然没有完成。所以使用sfence
来确保写入确实发生 - 可能不是非常现实的例子,但我认为你明白了。)
答案 1 :(得分:4)
缓存写入必须在弄脏缓存行之前获得行所有权。取决于 在处理器体系结构中实现的高速缓存一致性模型,该步骤所花费的时间各不相同。我所知道的最常见的一致性协议是:
大多数cpu架构都支持PMU(perf监控单元)。这个单位出口 许多事情的计数器:缓存命中,未命中,缓存写入延迟,读取延迟,tlb命中等。请参阅cpu手册以查看此信息是否可用。