如何确定缓存的阻塞因子
How to determine blocking factor for caching
我正试图找到一种方法来缓存我的元素数组的应用程序,使用最接近对算法(目前蛮力)。根据阻塞算法的缓存性能和优化论文说:
阻塞是一种通用的优化技术内存层次结构的有效性。通过更快地重用数据层次结构的级别,它减少了平均访问延迟。它的较慢级别的引用次数也会减少层次结构。因此,阻塞优于诸如预取,隐藏延迟,但不减少内存带宽的需求。这种减少对于由于多处理器的内存带宽往往是瓶颈系统。阻塞已被证明对许多算法是有用的线性代数。
本文给出了一个矩阵乘法代码,并将其修改为阻塞,减少了缓存缺失:
for kk = 1 to N by B
for j = 1 to N by B
for i = 1 to N
for k = kk to min(kk + B-1, N)
r = X[i,k]; // register allocated
for j = jj to min(jj + B-1, N)
Z[i,j] += r * Y[k,j];
这里,B是阻断因子,但是我们如何确定它呢?是否有一种通用的方法来找到cpu缓存可以处理的特定限制?可能不是所有的cpu都有相同的缓存。泛型过程表示:
- 首先是重构代码,以阻止那些携带重用的循环。
- 第二步是选择能够最大化局部性的阻塞因子。
最接近对算法(蛮力)为:
minDist = infinity
for i = 1 to length(P) - 1
for j = i + 1 to length(P)
let p = P[i], q = P[j]
if dist(p, q) < minDist:
minDist = dist(p, q)
closestPair = (p, q)
return closestPair
总结:
- 我如何优化B因子,而不必手动测试特定cpu缓存大小的限制。是否有一种方法来返回当前可用的缓存使用C语言?
- 如何优化使用1D数组的最接近对算法?我的意思是,哪些元素应该被存储和重用,因为它是一个包含x,y坐标的结构元素的1D数组,每个点都必须与所有其他点进行比较(让坚持蛮力算法)。
提前感谢!
第一个问题
没有简单的方法可以确定B,而不是在您打算优化的机器上进行实际测试。话虽如此,您可以通过一些实验找到一些"适合大多数系统"的数字(我在大约12-15年前从事过这类工作),我发现使用大约8-16KB的块效果非常好。"一有内存就遍历"answers"遍历块"之间的效果是非常显著的,如果你从很小的块开始,你可以看到一些很大的改善。然后"返回"下降,直到你达到B太大的水平,你回到你开始的地方(抛出好的缓存来获取其他东西,在它被抛出之前你永远不会使用)。我很确定,如果您为代码选择B的"大小",并测试您得到的性能,如果您绘制图形,如果您绘制"花费的时间",您可能会发现它看起来像一个"浴缸"(或者颠倒的浴缸,如果您绘制"每单位时间处理的项目数量")。只要在浴缸的"平"部分找到某个点。但是一定要在一些不同的机器上尝试它,以确保您在所有(或至少大多数)机器上都处于"平坦位"。
对于你的第二个问题,像这样:
minDist = infinity
for i = 1 to length(P) - 1 by B
for j = i + 1 to length(P) by B
for ib = i to i+B-1
for jb = j to j+B-1
let p = P[ib], q = P[jb]
if dist(p, q) < minDist:
minDist = dist(p, q)
closestPair = (p, q)
return closestPair
如果length(P)
不是B的倍数,则有一些额外的工作来处理最后几个元素,因此ib
循环中的i+B-1
可能需要max(length(P), i+B-1)
和类似的jb
循环。
缓存将自己决定哪些数据保存在缓存中,您几乎无法改变这里发生的事情。您可以更改的是正在处理的数据块。
"阻塞"的关键是将正在处理的数据保存在(L1)缓存中。
假设整个数据锁有100000个元素,每个元素4字节,所以大约400KB。这将不适合任何现代处理器的L1缓存,因为它最多64KB,通常是32KB。因此,当我们使用i
循环遍历项时,j
循环将通过加载数组的后部分来"抛出"所有好的L1缓存内容。当然,当下一次j
循环开始时,当前缓存中的数据都没有用了,因为它们都是数组的高下标。
如果我们以块为单位一次遍历数组的一小部分,则可以在每个循环中遍历数组B大小的平方,其中B元素占用的空间不会超过缓存的容量。因此,jb
循环不会为ib
循环抛出数据(反之亦然)。这意味着每个内部循环的运行速度都要快得多(我见过执行速度快3倍以上的代码,而且这是在已经被认为是"好的"的代码上)。
- 如何确定我已使用非编码文件到达 EOF?
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 如何在C++中确定文本文件中的元素是字符还是数字
- cmake更新缓存的变量
- 试图对缓存进行跨步测试,但程序并没有结束
- Python中的for循环与C++有何不同
- 在clang++预处理器中确定gcc工具链版本
- 不确定要在我的main中放入什么才能使我的代码正常工作
- C++setiosflags函数操纵器-未确定的缩进
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 如何使用url确定网站协议
- 缓存std::数组的选定元素,并在c++中自动保持其一致性
- 通过ccmake在cmake中缓存依赖选项
- 通过构造函数动态确定类实现
- C ICU库如何确定要缓存的日历对象
- 如何确定数据是从磁盘还是从缓存中检索的
- 什么是C++中的不确定行为?它与未定义的行为有何不同
- 如何确定缓存的阻塞因子
- 缓存刷新后的计时非常不确定
- 如何确定地址是否与缓存对齐