使用 VS2012/VTune 进行缓存分析

Posted

技术标签:

【中文标题】使用 VS2012/VTune 进行缓存分析【英文标题】:Cache profiling with 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 这没有任何帮助:) 【参考方案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 次加载。听起来您缺少大约一半的负载。预取不是魔术,它会有所帮助,但不能让问题消失。 一点建议,不要为了让数字看起来更好而调整基准。选择你的基准,运行它并处理结果。使基准保持一致,以便您可以在更改前后进行基准测试并进行有意义的比较。在此示例中,经过一定时间后停止是一种糟糕的基准测试方法。您需要固定循环数,以便使用不同的访问模式可以比较相同的工作量。总时间应该随着不同的访问模式而变化。这就是基准测试的重点

以上是关于使用 VS2012/VTune 进行缓存分析的主要内容,如果未能解决你的问题,请参考以下文章

缓存系统 - Redis vs Geode/GemFire

是否可以使用 VS2010 分析器对 C# 中的主线程以外的线程进行采样

Redis 缓存 vs 直接使用内存

在 VS2010 中使用 Nvidia NSight 进行 CUDA 性能分析 - 时间线上的片段

在 VS Code 中使用 GraalVM 和 VisualVM 进行性能和内存分析

在 VS Code 中使用 GraalVM 和 VisualVM 进行性能和内存分析