什么是 CUDA 11 中引入的 L2 缓存 accessPolicyWindow

Posted

技术标签:

【中文标题】什么是 CUDA 11 中引入的 L2 缓存 accessPolicyWindow【英文标题】:What is the L2 cache accessPolicyWindow introduced in CUDA 11 【发布时间】:2021-09-22 08:17:23 【问题描述】:

CUDA 11 中引入了新的运行时 API 以微调 L2 access policy。

但我不完全理解 hitRatio 这样的策略的含义以及如何在实践中使用它们。

特别是我在CUDA API Documentation看到cudaAccessPolicyWindow

指定一个窗口的访问策略,一个连续的内存范围 从 base_ptr 开始,到 base_ptr + num_bytes 结束。划分 分成许多段并分配这样的段。 “命中”的总和 段”/窗口 == 大约比率。“未命中段”/窗口的总和 == 大约 1 比。段和比率规范适合架构的功能。命中段中的访问应用 hitProp 访问策略。未命中段中的访问应用了missProp 访问策略。

我的问题:

    内存的连续范围是如何“划分”成段的?这些分区是基于 hit prop 静态决定的,以便段的命中或未命中属性在分配后将保持不变,或者有一些正在运行的计数器动态调整分配,例如在每个访问基础上?

    在实践中应该如何应用这些属性来优化性能?例如。用一种过于简单和幼稚的方式来说,假设我留出了 1 MB L2 缓存,我应该为我最常用的数据创建一个 1 MB 的窗口并将 hitRatio 设置为 1 还是应该创建一个 2 MB 的窗口并将hitRatio设置为0.5?为什么?

【问题讨论】:

我并不是建议它回答你所有的问题,但this 可能会引起你的兴趣,尤其是“内存管理”部分,还有幻灯片 22-26 here。 【参考方案1】:

内存的连续范围是如何“划分”成段的?这些分区是基于 hit prop 静态决定的,以便段的命中或未命中属性在分配后将保持不变,或者有一些正在运行的计数器动态调整分配,例如在每个访问基础上?

我认为没有任何明确规定。但是,我们可以基于两个想法做出一些非常可靠(我相信)的猜想:

    “很长一段时间”以来,NVIDIA GPU L2 缓存都具有 32 字节的基本行大小。这旨在与具有 32 字节段边界的 DRAM 子系统的设计保持一致。

    documentation 将选择哪些行作为“随机”选择在缓存中持久化。这几乎意味着它与访问模式无关。

集合这些想法,那么我会说分区是在不小于 L2 行(32 字节)的粒度上完成的,如果 L2 标签/TLB 系统需要,它可能是更高的粒度。这些 L2 细节中的大多数通常是 NVIDIA 未发布的。一旦随机选择,我不希望选择会根据访问模式而改变。

在实践中应该如何应用这些属性来优化性能?例如。用一种过于简单和幼稚的方式来说,假设我留出了 1 MB L2 缓存,我应该为我最常用的数据创建一个 1 MB 的窗口并将 hitRatio 设置为 1 还是应该创建一个 2 MB 的窗口并将hitRatio设置为0.5?为什么?

没有足够的信息来给出这个问题的具体答案。您决定保留 1MB L2 缓存的知识是第一个关键信息,但第二个关键信息是您实际上需要缓存多少数据?此外,预期的访问模式很重要。让我们介绍几种情况:

    预留 1MB 缓存,1MB 窗口,hitRatio 1。这意味着您只有 1MB 的数据要使用此机制进行缓存。对于 1MB 缓存和 1MB 窗口,没有任何理由为 hitRatio 选择 1 以外的任何值。如果您只有 1MB 的数据要缓存,并且您有能力切出 1MB 的 L2,那么这是一个完全明智的选择。您实质上是在保证没有其他活动可以“驱逐”这些“受保护”数据,一旦它出现在缓存分割中。

    预留 1MB 缓存,2MB 窗口,hitRatio 0.5。这当然意味着您至少有 2MB 的数据要使用此机制进行缓存,因此这与上述情况 1 无法直接比较。 0.5的hitRatio可以被认为是防止抖动的“后卫”。让我们考虑几个子案例:

    A.假设您的 2MB 数据分为 1MB 区域 A 和 B,并且您的代码访问区域 A 中的所有数据(一次),然后访问区域 B 中的所有数据(一次),然后访问区域 A 中的所有数据(一次),等等。如果您选择命中率为 1 并使用 1MB 缓存分割但有 2MB 窗口,则此设置将失败。您将用区域 A 填充缓存,然后用区域 B 逐出并填充,然后用区域 A 逐出并填充,等等。如果没有“hitRatio”机制/控制,这种情况下的这种行为将是不可避免的。因此,如果您预计这种循环访问模式,0.5 的命中率会更好(50% 的数据访问将受益于 L2 剥离,50% 不会)而不是完全没有从缓存中受益。

    B.假设您的 2MB 数据是通过高时间局部性访问的。您的代码重复访问 2MB 数据中的 1MB(例如区域 A),然后重复访问另一个(区域 B)。在这种情况下,可能根本不需要拆分。如果您想使用分割,则命中率 1 可能是有意义的,因为这意味着该分割或多或少像普通缓存一样,除了可缓存窗口是用户定义的。在此示例中,您的缓存将填满您的前 1MB 区域 A 数据,然后您的代码将受益于缓存,因为它重用了该数据。当您的代码切换模式并开始使用第二个 1MB 数据(区域 B)时,第二个 1MB 将驱逐第一个 1MB,然后当您的代码重复使用第二个 1MB 时,它将再次从缓存中获得 100% 的收益。

【讨论】:

以上是关于什么是 CUDA 11 中引入的 L2 缓存 accessPolicyWindow的主要内容,如果未能解决你的问题,请参考以下文章

为什么CPU缓存会分为一级缓存L1L2L3?有什么意义?

在哪设置 cuda

CUDA:啥时候使用共享内存,啥时候依赖 L1 缓存?

是否可以检查变量是否位于 L1/L2/L3 缓存中

每天AC系列:合并两个有序链表

每天AC系列:合并两个有序链表