【问题标题】:Cache profiling with VS2012/VTune使用 VS2012/VTune 进行缓存分析
【发布时间】:2014-07-24 08:47:26
【问题描述】:

我正在使用以下代码进行测试:

const int num = 5000;
int test[num][num];

int _tmain(int argc, _TCHAR* argv[])
{
    while(true)
    {
        for (int i = 0; i < num; i++)
        {
            for (int j = 0; j < num; j++)
            {
                test[j][i] = 10;
            }
        }
    }
}

我有以下 Windows 计数器:

  • \Cache\Copy 读取命中 %
  • \Cache\Copy Read/sec
  • \Memory\Page Faults/sec

性能会话后的结果如下: http://pastebin.com/L78Pjs9W

有人可以解释为什么它仍然会出现页面错误吗? 我还运行了相同的程序,将 i 和 j 颠倒过来尝试滥用缓存。 由于我意识到我的 CPU 可能会检测到跨步访问,因此我也尝试了随机访问,但这些 windows 计数器的结果仍然没有太大变化。

我也在 VTune Amplifier 中尝试过这个,得到了类似的奇怪结果。 随机访问或翻转 i 和 j 可以减少缓存未命中,使用以下内容: 测试[i][j] = 20; not 是否给我 0 cachemiss(或关闭) 我正在使用以下计数器:

  • L2_RQSTS_MISS
  • L2_RQSTS_REFERENCES

所有 3 种方法都给了我大约 7,000,000 次引用和 3,800,000 次未命中。在 25 秒的样本上。 我预计 [i][j] 访问几乎不会丢失,因为它具有空间局部性并且是可预测的。

我是否使用了正确的计数器,有什么提示吗?

【问题讨论】:

  • 您是否禁用了优化?优化器可能会切换循环以优化缓存访问。
  • 是的,它是在完整的调试版本中捕获的(没有优化)我还提到我使用了随机访问(因为没有优化,CPU 可以为我正确检测跨步访问和缓存)
  • 初始化int test[num][num]={1}结果是否一样?
  • @dvasanth 这没有任何帮助:)

标签: c++ caching profiling


【解决方案1】:

您有一个包含 25,000,000 个元素的数组,即 100M。您还没有说明您的 L2 缓存大小,但它可能大约是几兆,那么您为什么会期望接近 0 的缓存未命中?您的数据不适合您的缓存,因此您需要交换数据(也就是缓存未命中)。

您的外部 while 为您的一次运行执行了多少个循环?

我建议首先修复运行大约您愿意等待的时间的迭代次数。这样你所有的运行都是一致的。

可能是您的随机探测运行执行的迭代次数要少得多,因为它们更频繁地错过缓存。事实上,鉴于您似乎正在根据时间停止基准测试,并且您的示例的瓶颈是缓存未命中,您可能会在类似数量的缓存未命中后停止运行,并且没有意识到好的订单正在执行更多的迭代。

【讨论】:

  • 在 num = 10 的情况下运行相同的 sn-p 会给我 100% 的缓存未命中(再次假设 L2_RQSTS_REFERENCESi 是对 L2 缓存的请求数量,而 L2_RQSTS_MISS 是未命中的数量)
  • 我还尝试将它移到自己的函数中以确保测量是隔离的,这给了我 600k 参考。800k 未命中。这怎么可能?)
  • 无论如何我都将其更改为运行 10 秒,并且时间似乎更好 - num = 100-150 给我大约 10% 的缓存未命中率,num=200 大约 30%,250+ 大约 50%错过。我的 CPU 是 Intel i5-4670K。 100-250 将导致最多 250k,这应该完全适合 L2,对吧?最重要的是,即使它不适合,我会假设它会按时预取,所以当它在缓存的末尾时,它会用额外的数据填充第一位,所以它可以继续,对吗?
  • 5000x5000 是 25,000,000 个整数,也就是 100M。您的 Intel i5-4670K 具有 6M L2 缓存,因此您的数据比缓存大得多。 L2 缓存使用 64 字节行。一点计算表明,每次执行 while 循环时,一次加载 25,000,000 个整数,64 个字节(16 个整数)将需要 1,562,500 次加载。听起来您缺少大约一半的负载。预取不是魔术,它会有所帮助,但不能让问题消失。
  • 一点建议,不要为了让数字看起来更好而调整基准。选择你的基准,运行它并处理结果。使基准保持一致,以便您可以在更改前后进行基准测试并进行有意义的比较。在此示例中,经过一定时间后停止是一种糟糕的基准测试方法。您需要固定循环数,以便使用不同的访问模式可以比较相同的工作量。总时间应该随着不同的访问模式而变化。这就是基准测试的重点
猜你喜欢
  • 2020-10-04
  • 2015-12-08
  • 2023-03-11
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-12
  • 1970-01-01
相关资源
最近更新 更多