24. 资源控制功能的用户界面

版权:

© 2016 英特尔公司

作者:

英特尔将此功能称为英特尔资源导向技术(Intel(R) RDT)。AMD 将此功能称为 AMD 平台服务质量(AMD QoS)。

此功能由 CONFIG_X86_CPU_RESCTRL 和 x86 /proc/cpuinfo 标志位启用

RDT(资源导向技术)分配

“rdt_a”

CAT(缓存分配技术)

“cat_l3”, “cat_l2”

CDP(代码和数据优先级)

“cdp_l3”, “cdp_l2”

CQM(缓存服务质量监控)

“cqm_llc”, “cqm_occup_llc”

MBM(内存带宽监控)

“cqm_mbm_total”, “cqm_mbm_local”

MBA(内存带宽分配)

“mba”

SMBA(慢速内存带宽分配)

“”

BMEC(带宽监控事件配置)

“”

历史上,新功能默认在 /proc/cpuinfo 中可见。这导致人类难以解析功能标志。如果用户空间可以从 resctrl 的 info 目录获取有关该功能的信息,则应避免向 /proc/cpuinfo 添加新标志。

要使用该功能,请挂载文件系统

# mount -t resctrl resctrl [-o cdp[,cdpl2][,mba_MBps][,debug]] /sys/fs/resctrl

挂载选项是

“cdp”

在 L3 缓存分配中启用代码/数据优先级。

“cdpl2”

在 L2 缓存分配中启用代码/数据优先级。

“mba_MBps”

启用 MBA 软件控制器 (mba_sc) 以 MiBps 为单位指定 MBA 带宽

“debug”

使调试文件可访问。可用的调试文件标有“仅在调试选项下可用”。

L2 和 L3 CDP 是单独控制的。

RDT 功能是正交的。特定系统可能仅支持监控、仅支持控制或同时支持监控和控制。缓存伪锁定是一种独特的缓存控制使用方式,用于“固定”或“锁定”缓存中的数据。详细信息可以在“缓存伪锁定”中找到。

如果存在分配或监控,则挂载成功,但只会创建系统支持的文件和目录。有关监控和分配期间接口行为的更多详细信息,请参见“资源分配和监控组”部分。

24.1. 信息目录

“info”目录包含有关已启用资源的信息。每个资源都有自己的子目录。子目录名称反映了资源名称。

每个子目录都包含以下与分配相关的文件

缓存资源(L3/L2)子目录包含以下与分配相关的文件

“num_closids”

对此资源有效的 CLOSID 数量。内核使用所有已启用资源中最小的 CLOSID 数量作为限制。

“cbm_mask”

对此资源有效的位掩码。此掩码相当于 100%。

“min_cbm_bits”

写入掩码时必须设置的最小连续位数。

“shareable_bits”

与其他执行实体(例如 I/O)共享资源的位掩码。用户可以在设置独占缓存分区时使用此掩码。请注意,某些平台支持具有自己的缓存使用设置的设备,这些设置可能会覆盖这些位。

“bit_usage”

带注释的容量位掩码,显示了资源的所有实例的使用方式。图例是

“0”

相应的区域未使用。当系统资源已分配并且在“bit_usage”中找到“0”时,这表明资源被浪费了。

“H”

相应区域仅由硬件使用,但可供软件使用。如果资源在“shareable_bits”中设置了位,但并非所有这些位都出现在资源组的模式中,则在“shareable_bits”中出现但没有资源组的位将被标记为“H”。

“X”

相应的区域可用于共享,并由硬件和软件使用。这些位既出现在“shareable_bits”中,也出现在资源组的分配中。

“S”

相应区域由软件使用,可用于共享。

“E”

相应区域由一个资源组独占使用。不允许共享。

“P”

相应区域被伪锁定。不允许共享。

“sparse_masks”

指示是否支持 CBM 中不连续的 1s 值。

“0”

仅支持 CBM 中连续的 1s 值。

“1”

支持 CBM 中不连续的 1s 值。

内存带宽 (MB) 子目录包含以下与分配相关的文件

“min_bandwidth”

用户可以请求的最小内存带宽百分比。

“bandwidth_gran”

分配内存带宽百分比的粒度。分配的带宽百分比将四舍五入到硬件上可用的下一个控制步骤。可用的带宽控制步骤为:min_bandwidth + N * bandwidth_gran。

“delay_linear”

指示延迟缩放是线性的还是非线性的。此字段仅供参考。

“thread_throttle_mode”

在英特尔系统上,指示在请求不同内存带宽百分比的情况下,物理核心线程上运行的任务如何受到限制

“max”

最小的百分比应用于所有线程

“per-thread”

带宽百分比直接应用于核心上运行的线程

如果 RDT 监控可用,则将有一个包含以下文件的“L3_MON”目录

“num_rmids”

可用的 RMID 数量。这是可以创建的“CTRL_MON” + “MON”组数量的上限。

“mon_features”

如果为资源启用了监控,则列出监控事件。示例

# cat /sys/fs/resctrl/info/L3_MON/mon_features
llc_occupancy
mbm_total_bytes
mbm_local_bytes

如果系统支持带宽监控事件配置 (BMEC),则带宽事件将是可配置的。输出将是

# cat /sys/fs/resctrl/info/L3_MON/mon_features
llc_occupancy
mbm_total_bytes
mbm_total_bytes_config
mbm_local_bytes
mbm_local_bytes_config
“mbm_total_bytes_config”, “mbm_local_bytes_config”

读/写文件,其中包含分别用于 mbm_total_bytes 和 mbm_local_bytes 事件的配置,当支持带宽监控事件配置 (BMEC) 功能时。事件配置设置是特定于域的,并影响域中的所有 CPU。当任一事件配置更改时,该域的两个事件(mbm_total_bytes 以及 mbm_local_bytes)的所有 RMID 的带宽计数器都将被清除。每个 RMID 的下一次读取将报告“不可用”,随后的读取将报告有效值。

以下是支持的事件类型

说明

6

来自 QOS 域到所有类型内存的脏牺牲

5

读取到非本地 NUMA 域中的慢速内存

4

读取到本地 NUMA 域中的慢速内存

3

非临时写入到非本地 NUMA 域

2

非临时写入到本地 NUMA 域

1

读取到非本地 NUMA 域中的内存

0

读取到本地 NUMA 域中的内存

默认情况下,mbm_total_bytes 配置设置为 0x7f,以计算所有事件类型,mbm_local_bytes 配置设置为 0x15,以计算所有本地内存事件。

示例

  • 要查看当前配置:

    # cat /sys/fs/resctrl/info/L3_MON/mbm_total_bytes_config
    0=0x7f;1=0x7f;2=0x7f;3=0x7f
    
    # cat /sys/fs/resctrl/info/L3_MON/mbm_local_bytes_config
    0=0x15;1=0x15;3=0x15;4=0x15
    
  • 要将 mbm_total_bytes 更改为仅计算域 0 上的读取,则需要设置位 0、1、4 和 5,即二进制的 110011b(十六进制为 0x33)

    # echo  "0=0x33" > /sys/fs/resctrl/info/L3_MON/mbm_total_bytes_config
    
    # cat /sys/fs/resctrl/info/L3_MON/mbm_total_bytes_config
    0=0x33;1=0x7f;2=0x7f;3=0x7f
    
  • 要将 mbm_local_bytes 更改为计算域 0 和 1 上的所有慢速内存读取,则需要设置位 4 和 5,即二进制的 110000b(十六进制为 0x30)

    # echo  "0=0x30;1=0x30" > /sys/fs/resctrl/info/L3_MON/mbm_local_bytes_config
    
    # cat /sys/fs/resctrl/info/L3_MON/mbm_local_bytes_config
    0=0x30;1=0x30;3=0x15;4=0x15
    
“max_threshold_occupancy”

读/写文件,提供先前使用的 LLC_occupancy 计数器可以考虑重用的最大值(以字节为单位)。

最后,在“info”目录的顶层,有一个名为“last_cmd_status”的文件。此文件会在通过文件系统发出每个“command”时重置(创建新目录或写入任何控制文件)。如果命令成功,它将读取为“ok”。如果命令失败,它将提供可以通过文件操作的错误返回传达的更多信息。例如

# echo L3:0=f7 > schemata
bash: echo: write error: Invalid argument
# cat info/last_cmd_status
mask f7 has non-consecutive 1-bits

24.2. 资源分配和监控组

资源组在 resctrl 文件系统中表示为目录。默认组是根目录,该目录在挂载后立即拥有系统中的所有任务和 cpu,并且可以充分利用所有资源。

在具有 RDT 控制功能的系统上,可以在根目录中创建其他目录,这些目录指定每个资源的不同数量(请参见下面的“模式”)。根目录和这些其他顶层目录在下面称为“CTRL_MON”组。

在具有 RDT 监控的系统上,根目录和其他顶层目录包含一个名为“mon_groups”的目录,可以在其中创建其他目录,以监控 CTRL_MON 组中作为其祖先的任务子集。在本文档的其余部分中,这些被称为“MON”组。

删除目录会将该目录所代表的组拥有的所有任务和 CPU 移动到父组。 删除创建的 CTRL_MON 组之一将自动删除其下的所有 MON 组。

为了在不影响 MON 组的监控数据或分配任务的情况下更改 MON 组的资源分配,支持将 MON 组目录移动到新的父 CTRL_MON 组。此操作不允许用于监控 CPU 的 MON 组。目前不允许其他移动操作,仅允许重命名 CTRL_MON 或 MON 组。

所有组都包含以下文件:

“tasks”

读取此文件会显示属于此组的所有任务的列表。将任务 ID 写入文件会将任务添加到该组。可以通过用逗号分隔任务 ID 来添加多个任务。任务将按顺序分配。不支持多个失败。在尝试分配任务时遇到的单个失败将导致操作中止,并且在失败之前已经添加的任务将保留在该组中。失败将记录到 /sys/fs/resctrl/info/last_cmd_status 中。

如果该组是 CTRL_MON 组,则该任务将从以前拥有该任务的任何 CTRL_MON 组以及拥有该任务的任何 MON 组中删除。如果该组是 MON 组,则该任务必须已属于此组的 CTRL_MON 父组。该任务将从任何以前的 MON 组中删除。

“cpus”

读取此文件会显示此组拥有的逻辑 CPU 的位掩码。将掩码写入此文件将在此组中添加和删除 CPU。与 tasks 文件一样,维护一个层次结构,其中 MON 组只能包含父 CTRL_MON 组拥有的 CPU。当资源组处于伪锁定模式时,此文件将仅可读,反映与伪锁定区域关联的 CPU。

“cpus_list”

与“cpus”类似,只是使用 CPU 范围而不是位掩码。

启用控制后,所有 CTRL_MON 组还将包含:

“schemata”

此组可用的所有资源的列表。每个资源都有其自己的行和格式 - 请参阅下面的详细信息。

“size”

镜像“schemata”文件的显示,以显示每个分配的大小(以字节为单位),而不是表示分配的位。

“mode”

资源组的“mode”决定了其分配的共享方式。“shareable”资源组允许共享其分配,而“exclusive”资源组则不允许。缓存伪锁定区域的创建方法是,先将“pseudo-locksetup”写入“mode”文件,然后再将缓存伪锁定区域的 schemata 写入资源组的“schemata”文件。成功创建伪锁定区域后,模式将自动更改为“pseudo-locked”。

“ctrl_hw_id”

仅在调试选项可用时可用。硬件用于控制组的标识符。在 x86 上,这是 CLOSID。

启用监控后,所有 MON 组还将包含:

“mon_data”

这包含一组按 L3 域和 RDT 事件组织的文件。例如,在具有两个 L3 域的系统上,将有子目录“mon_L3_00”和“mon_L3_01”。这些目录中的每个目录都包含每个事件一个文件(例如,“llc_occupancy”、“mbm_total_bytes”和“mbm_local_bytes”)。在 MON 组中,这些文件提供了组中所有任务的事件当前值的读取。在 CTRL_MON 组中,这些文件提供了 CTRL_MON 组中所有任务和 MON 组中所有任务的总和。有关使用方法的更多详细信息,请参见示例部分。在启用 Sub-NUMA Cluster (SNC) 的系统上,每个节点都有额外的目录(位于它们占用的 L3 缓存的“mon_L3_XX”目录中)。这些目录被命名为“mon_sub_L3_YY”,其中“YY”是节点号。

“mon_hw_id”

仅在调试选项可用时可用。硬件用于监控组的标识符。在 x86 上,这是 RMID。

24.2.1. 资源分配规则

当任务运行时,以下规则定义了可供其使用的资源:

  1. 如果该任务是非默认组的成员,则使用该组的 schemata。

  2. 否则,如果该任务属于默认组,但运行在分配给某个特定组的 CPU 上,则使用该 CPU 组的 schemata。

  3. 否则,使用默认组的 schemata。

24.2.2. 资源监控规则

  1. 如果任务是 MON 组或非默认 CTRL_MON 组的成员,则该任务的 RDT 事件将在该组中报告。

  2. 如果任务是默认 CTRL_MON 组的成员,但运行在分配给某个特定组的 CPU 上,则该任务的 RDT 事件将在该组中报告。

  3. 否则,该任务的 RDT 事件将在根级别的“mon_data”组中报告。

24.3. 关于缓存占用监控和控制的说明

在将任务从一个组移动到另一个组时,您应该记住,这只会影响该任务的缓存分配。例如,您可能有一个监控组中的任务显示 3 MB 的缓存占用。如果您移动到新组并立即检查旧组和新组的占用情况,您可能会看到旧组仍然显示 3 MB,而新组显示 0。当任务访问移动之前仍在缓存中的位置时,硬件不会更新任何计数器。在繁忙的系统上,您可能会看到旧组中的占用率下降,因为缓存行被逐出并重新使用,而新组中的占用率上升,因为该任务访问内存并将缓存加载到缓存中是根据新组中的成员关系进行计数的。

缓存分配控制也适用。将任务移动到具有较小缓存分区的组不会逐出任何缓存行。该进程可能会继续使用旧分区中的缓存行。

硬件使用 CLOSid(服务类 ID)和 RMID(资源监控 ID)分别标识控制组和监控组。每个资源组都根据组的类型映射到这些 ID。CLOSid 和 RMID 的数量受硬件限制,因此,如果我们用完 CLOSID 或 RMID,则创建“CTRL_MON”目录可能会失败,如果我们用完 RMID,则创建“MON”组可能会失败。

24.3.1. max_threshold_occupancy - 通用概念

请注意,一旦释放 RMID,可能不会立即可用,因为 RMID 仍然标记着 RMID 先前用户的缓存行。因此,此类 RMID 被放置在临时列表中,并在缓存占用率下降后重新检查。如果系统在一段时间内有很多处于临时状态但尚未准备好使用的 RMID,则用户在 mkdir 期间可能会看到 -EBUSY。

max_threshold_occupancy 是用户可配置的值,用于确定可以释放 RMID 的占用率。

mon_llc_occupancy_limbo 跟踪点给出了未立即用于分配的 RMID 子集的精确占用率(以字节为单位)。不能依赖此跟踪点每秒产生输出,可能需要尝试创建一个空的监控组来强制更新。仅当控制组或监控组的创建失败时,才会生成输出。

24.3.2. Schemata 文件 - 通用概念

文件中的每一行描述一个资源。该行以资源名称开头,后跟要在系统上的每个资源实例中应用的特定值。

24.3.3. 缓存 ID

在当前一代系统中,每个插槽有一个 L3 缓存,L2 缓存通常只由内核上的超线程共享,但这并非架构要求。我们可以在一个插槽上有多个独立的 L3 缓存,多个内核可以共享一个 L2 缓存。因此,我们不使用“插槽”或“内核”来定义共享资源的逻辑 CPU 集,而是使用“缓存 ID”。在给定的缓存级别,这将是整个系统中唯一的数字(但不能保证是连续的序列,可能会有间隔)。要查找每个逻辑 CPU 的 ID,请查看 /sys/devices/system/cpu/cpu*/cache/index*/id

24.3.4. 缓存位掩码 (CBM)

对于缓存资源,我们使用位掩码来描述可用于分配的缓存部分。掩码的最大值由每个 CPU 型号定义(对于不同的缓存级别可能会有所不同)。它使用 CPUID 查找,但也位于 resctrl 文件系统的“info”目录中的“info/{resource}/cbm_mask”中。一些 Intel 硬件要求这些掩码的所有“1”位都在一个连续的块中。因此,0x3、0x6 和 0xC 是合法的 4 位掩码,其中设置了两位,但 0x5、0x9 和 0xA 不是。如果支持非连续 1 值,请检查 /sys/fs/resctrl/info/{resource}/sparse_masks。在具有 20 位掩码的系统上,每个位表示缓存容量的 5%。您可以使用掩码将缓存划分为四个相等的部分:0x1f、0x3e0、0x7c00、0xf8000。

24.4. 关于 Sub-NUMA 集群模式的说明

启用 SNC 模式后,Linux 可能会比在常规 NUMA 节点之间更容易地在 Sub-NUMA 节点之间进行任务负载均衡,因为 Sub-NUMA 节点上的 CPU 共享相同的 L3 缓存,并且系统可能会报告 Sub-NUMA 节点之间的 NUMA 距离,其值比用于常规 NUMA 节点的值低。

每个“mon_L3_XX”目录中的顶层监控文件提供了共享 L3 缓存实例的所有 SNC 节点的数据总和。将任务绑定到特定 Sub-NUMA 节点的 CPU 的用户可以读取“mon_sub_L3_YY”目录中的“llc_occupancy”、“mbm_total_bytes”和“mbm_local_bytes”以获取节点本地数据。

内存带宽分配仍然在 L3 缓存级别执行。也就是说,节流控制应用于所有 SNC 节点。

L3 缓存分配位图也适用于所有 SNC 节点。但请注意,每个位表示的 L3 缓存量除以每个 L3 缓存的 SNC 节点数。例如,在具有 10 位分配掩码的系统上,如果缓存为 100MB,则每个位通常表示 10MB。如果启用了 SNC 模式,并且每个 L3 缓存有两个 SNC 节点,则每个位仅表示 5MB。

24.5. 内存带宽分配和监控

对于内存带宽资源,默认情况下,用户通过指定总内存带宽的百分比来控制资源。

每个 CPU 型号的最小带宽百分比值是预定义的,可以通过 “info/MB/min_bandwidth” 查找。分配的带宽粒度也取决于 CPU 型号,可以在 “info/MB/bandwidth_gran” 中查找。可用的带宽控制步长为:min_bw + N * bw_gran。中间值会四舍五入到硬件上可用的下一个控制步长。

带宽限制在某些 Intel SKU 上是一个核心特定的机制。在共享一个核心的两个线程上使用高带宽和低带宽设置可能会导致两个线程都被限制使用低带宽(请参阅 “thread_throttle_mode”)。

内存带宽分配 (MBA) 可能是一个核心特定的机制,而内存带宽监控 (MBM) 是在封装级别完成的,这可能会导致用户尝试通过 MBA 应用控制,然后监控带宽以查看控制是否有效时产生混淆。以下是这种情况的示例:

  1. 当百分比值增加时,用户可能不会看到实际带宽增加。

当聚合 L2 外部带宽大于 L3 外部带宽时,可能会发生这种情况。考虑一个封装上有 24 个核心的 SKL SKU,其中 L2 外部带宽为 10GBps(因此聚合 L2 外部带宽为 240GBps),而 L3 外部带宽为 100GBps。现在,一个具有 “20 个线程,每个线程具有 50% 的带宽,每个线程消耗 5GBps” 的工作负载,消耗了最大 100GBps 的 L3 带宽,尽管指定的百分比值仅为 50% << 100%。因此,增加带宽百分比不会产生更多带宽。这是因为虽然 L2 外部带宽仍然有容量,但 L3 外部带宽已完全使用。另请注意,这取决于基准测试运行的核心数量。

  1. 相同的带宽百分比可能意味着不同的实际带宽,具体取决于线程数。

对于 #1 中的同一 SKU,“具有 10% 带宽的单个线程”和“具有 10% 带宽的 4 个线程”可以分别消耗高达 10GBps 和 40GBps 的带宽,尽管它们的带宽百分比均为 10%。这仅仅是因为随着线程开始在 rdtgroup 中使用更多的核心,实际带宽可能会增加或变化,即使用户指定的带宽百分比相同。

为了缓解这种情况并使接口更易于用户使用,resctrl 添加了以 MiBps 为单位指定带宽的支持。底层内核将使用软件反馈机制或“软件控制器 (mba_sc)”,该机制使用 MBM 计数器读取实际带宽并调整内存带宽百分比,以确保

"actual bandwidth < user specified bandwidth".

默认情况下,schemata 将采用带宽百分比值,而用户可以使用挂载选项 ‘mba_MBps’ 切换到 “MBA 软件控制器” 模式。schemata 格式在以下部分中指定。

24.5.1. L3 schemata 文件详细信息(代码和数据优先级禁用)

禁用 CDP 后,L3 schemata 格式为

L3:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...

24.5.2. L3 schemata 文件详细信息(通过 resctrl 的挂载选项启用 CDP)

启用 CDP 后,L3 控制将分为两个单独的资源,因此您可以为代码和数据指定独立的掩码,如下所示

L3DATA:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
L3CODE:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...

24.5.3. L2 schemata 文件详细信息

使用 ‘cdpl2’ 挂载选项在 L2 上支持 CDP。schemata 格式为以下两者之一

L2:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...

L2DATA:<cache_id0>=<cbm>;<cache_id1>=<cbm>;... L2CODE:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...

24.5.4. 内存带宽分配(默认模式)

内存带宽域是 L3 缓存。

MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;...

24.5.5. 以 MiBps 指定的内存带宽分配

内存带宽域是 L3 缓存。

MB:<cache_id0>=bw_MiBps0;<cache_id1>=bw_MiBps1;...

24.5.6. 慢速内存带宽分配 (SMBA)

AMD 硬件支持慢速内存带宽分配 (SMBA)。CXL.memory 是唯一支持的“慢速”内存设备。通过对 SMBA 的支持,硬件可以在慢速内存设备上启用带宽分配。如果系统中有多个此类设备,则限制逻辑会将所有慢速源分组在一起,并对它们整体应用限制。

SMBA(带 CXL.memory)的存在与慢速内存设备是否存在无关。如果系统上没有此类设备,则配置 SMBA 不会对系统的性能产生任何影响。

慢速内存的带宽域是 L3 缓存。其 schemata 文件格式为

SMBA:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;...

24.5.7. 读取/写入 schemata 文件

读取 schemata 文件将显示所有域上所有资源的状态。写入时,您只需要指定要更改的值。例如

# cat schemata
L3DATA:0=fffff;1=fffff;2=fffff;3=fffff
L3CODE:0=fffff;1=fffff;2=fffff;3=fffff
# echo "L3DATA:2=3c0;" > schemata
# cat schemata
L3DATA:0=fffff;1=fffff;2=3c0;3=fffff
L3CODE:0=fffff;1=fffff;2=fffff;3=fffff

24.5.8. 读取/写入 schemata 文件(在 AMD 系统上)

读取 schemata 文件将显示所有域上的当前带宽限制。分配的资源以八分之一 GB/s 的倍数表示。写入文件时,您需要指定要配置带宽限制的缓存 ID。

例如,要在第一个缓存 ID 上分配 2GB/s 的限制

# cat schemata
  MB:0=2048;1=2048;2=2048;3=2048
  L3:0=ffff;1=ffff;2=ffff;3=ffff

# echo "MB:1=16" > schemata
# cat schemata
  MB:0=2048;1=  16;2=2048;3=2048
  L3:0=ffff;1=ffff;2=ffff;3=ffff

24.5.9. 读取/写入带有 SMBA 功能的 schemata 文件(在 AMD 系统上)

读取和写入 schemata 文件与上述部分中没有 SMBA 的情况相同。

例如,要在第一个缓存 ID 上分配 8GB/s 的限制

# cat schemata
  SMBA:0=2048;1=2048;2=2048;3=2048
    MB:0=2048;1=2048;2=2048;3=2048
    L3:0=ffff;1=ffff;2=ffff;3=ffff

# echo "SMBA:1=64" > schemata
# cat schemata
  SMBA:0=2048;1=  64;2=2048;3=2048
    MB:0=2048;1=2048;2=2048;3=2048
    L3:0=ffff;1=ffff;2=ffff;3=ffff

24.6. 缓存伪锁定

CAT 使用户可以指定应用程序可以填充的缓存空间量。缓存伪锁定建立在这样一个事实之上:CPU 仍然可以读取和写入在其当前分配区域之外预分配的数据,前提是缓存命中。通过缓存伪锁定,可以将数据预加载到缓存的保留部分,任何应用程序都无法填充该部分,并且从那时起将仅服务缓存命中。缓存伪锁定内存可以供用户空间访问,应用程序可以将其映射到其虚拟地址空间中,从而拥有一个具有降低的平均读取延迟的内存区域。

缓存伪锁定区域的创建由用户请求触发,该请求附带有要伪锁定的区域的 schemata。缓存伪锁定区域的创建方式如下:

  • 创建一个 CAT 分配 CLOSNEW,其 CBM 与用户提供的 schemata 匹配,该 schemata 来自将包含伪锁定内存的缓存区域。此区域不得与系统上任何当前的 CAT 分配/CLOS 重叠,并且在伪锁定区域存在时,不允许将来与此缓存区域重叠。

  • 创建与缓存区域大小相同的连续内存区域。

  • 刷新缓存,禁用硬件预取器,禁用抢占。

  • 使 CLOSNEW 成为活动 CLOS,并触摸已分配的内存以将其加载到缓存中。

  • 将先前的 CLOS 设置为活动状态。

  • 此时,可以释放 closid CLOSNEW - 只要其 CBM 不出现在任何 CAT 分配中,缓存伪锁定区域就会受到保护。即使从那时起,缓存伪锁定区域都不会出现在任何 CLOS 的任何 CBM 中,但使用任何 CLOS 运行的应用程序都将能够访问伪锁定区域中的内存,因为该区域会继续服务缓存命中。

  • 加载到缓存中的连续内存区域以字符设备的形式暴露给用户空间。

缓存伪锁定通过仔细配置 CAT 功能并控制应用程序行为来提高数据保留在缓存中的概率。不能保证数据放置在缓存中。诸如 INVD、WBINVD、CLFLUSH 等指令仍然可以从缓存中逐出“锁定”数据。电源管理 C 状态可能会缩小或关闭缓存。在伪锁定区域创建时,将自动限制更深的 C 状态。

使用伪锁定区域的应用程序必须运行在与伪锁定区域所在的缓存关联的核心(或核心子集)的亲和性下。代码中的健全性检查将不允许应用程序映射伪锁定内存,除非它在与伪锁定区域所在的缓存关联的核心的亲和性下运行。健全性检查仅在初始 mmap() 处理期间执行,之后没有强制执行,应用程序自身需要确保它仍然与正确的核心保持关联。

伪锁定分两个阶段完成

  1. 在第一阶段,系统管理员分配应专用于伪锁定的部分缓存。此时,分配等效的内存部分,将其加载到已分配的缓存部分中,并将其作为字符设备公开。

  2. 在第二阶段,用户空间应用程序将其伪锁定内存映射 (mmap()) 到其地址空间中。

24.6.1. 缓存伪锁定接口

使用 resctrl 接口创建伪锁定区域,如下所示:

  1. 通过在 /sys/fs/resctrl 中创建一个新目录来创建一个新的资源组。

  2. 通过将 “pseudo-locksetup” 写入 “mode” 文件,将新资源组的模式更改为 “pseudo-locksetup”。

  3. 将伪锁定区域的 schemata 写入 “schemata” 文件。根据 “bit_usage” 文件,schemata 中的所有位都应为 “unused”。

成功创建伪锁定区域后,“mode” 文件将包含 “pseudo-locked”,并且在 /dev/pseudo_lock 中将存在一个与资源组同名的新字符设备。用户空间可以 mmap() 此字符设备,以便访问伪锁定内存区域。

下面可以找到缓存伪锁定区域的创建和使用示例。

24.6.2. 缓存伪锁定调试接口

默认情况下启用伪锁定调试接口(如果启用了 CONFIG_DEBUG_FS),可以在 /sys/kernel/debug/resctrl 中找到。

内核没有显式方法来测试提供的内存位置是否存在于缓存中。伪锁定调试接口使用跟踪基础设施来提供两种方法来测量伪锁定区域的缓存驻留情况:

  1. 使用 pseudo_lock_mem_latency 跟踪点的内存访问延迟。这些测量的最佳可视化效果是使用 hist 触发器(请参阅下面的示例)。在此测试中,以 32 字节的步幅遍历伪锁定区域,同时禁用硬件预取器和抢占。这也提供了缓存命中和未命中的替代可视化效果。

  2. 如果可用,则使用特定于模型的精密计数器测量缓存命中和未命中。根据系统上缓存的级别,可以使用 pseudo_lock_l2 和 pseudo_lock_l3 跟踪点。

当创建一个伪锁定区域时,会在 debugfs 中为其创建一个新的目录,路径为 /sys/kernel/debug/resctrl/<newdir>。此目录中有一个单独的只写文件 pseudo_lock_measure。伪锁定区域的测量取决于写入此 debugfs 文件中的数值。

1:

向 pseudo_lock_measure 文件写入“1”将触发在 pseudo_lock_mem_latency 跟踪点中捕获的延迟测量。请参见下面的示例。

2:

向 pseudo_lock_measure 文件写入“2”将触发在 pseudo_lock_l2 跟踪点中捕获的 L2 缓存驻留(缓存命中和未命中)测量。请参见下面的示例。

3:

向 pseudo_lock_measure 文件写入“3”将触发在 pseudo_lock_l3 跟踪点中捕获的 L3 缓存驻留(缓存命中和未命中)测量。

所有测量都使用跟踪基础设施记录。这需要在触发测量之前启用相关的跟踪点。

24.6.2.1. 延迟调试接口示例

在此示例中,创建了一个名为“newlock”的伪锁定区域。下面是如何测量从此区域读取数据的延迟周期,并使用直方图可视化此数据,如果设置了 CONFIG_HIST_TRIGGERS,则可以使用直方图。

# :> /sys/kernel/tracing/trace
# echo 'hist:keys=latency' > /sys/kernel/tracing/events/resctrl/pseudo_lock_mem_latency/trigger
# echo 1 > /sys/kernel/tracing/events/resctrl/pseudo_lock_mem_latency/enable
# echo 1 > /sys/kernel/debug/resctrl/newlock/pseudo_lock_measure
# echo 0 > /sys/kernel/tracing/events/resctrl/pseudo_lock_mem_latency/enable
# cat /sys/kernel/tracing/events/resctrl/pseudo_lock_mem_latency/hist

# event histogram
#
# trigger info: hist:keys=latency:vals=hitcount:sort=hitcount:size=2048 [active]
#

{ latency:        456 } hitcount:          1
{ latency:         50 } hitcount:         83
{ latency:         36 } hitcount:         96
{ latency:         44 } hitcount:        174
{ latency:         48 } hitcount:        195
{ latency:         46 } hitcount:        262
{ latency:         42 } hitcount:        693
{ latency:         40 } hitcount:       3204
{ latency:         38 } hitcount:       3484

Totals:
    Hits: 8192
    Entries: 9
  Dropped: 0

24.6.2.2. 缓存命中/未命中调试示例

在此示例中,在平台的 L2 缓存上创建了一个名为“newlock”的伪锁定区域。下面是如何使用平台的精确计数器获取缓存命中和未命中的详细信息。

# :> /sys/kernel/tracing/trace
# echo 1 > /sys/kernel/tracing/events/resctrl/pseudo_lock_l2/enable
# echo 2 > /sys/kernel/debug/resctrl/newlock/pseudo_lock_measure
# echo 0 > /sys/kernel/tracing/events/resctrl/pseudo_lock_l2/enable
# cat /sys/kernel/tracing/trace

# tracer: nop
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
pseudo_lock_mea-1672  [002] ....  3132.860500: pseudo_lock_l2: hits=4097 miss=0

24.6.2.3. RDT 分配使用示例

  1. 示例 1

在一台双插槽机器(每个插槽一个 L3 缓存)上,缓存位掩码只有 4 位,最小带宽为 10%,内存带宽粒度为 10%。

# mount -t resctrl resctrl /sys/fs/resctrl
# cd /sys/fs/resctrl
# mkdir p0 p1
# echo "L3:0=3;1=c\nMB:0=50;1=50" > /sys/fs/resctrl/p0/schemata
# echo "L3:0=3;1=3\nMB:0=50;1=50" > /sys/fs/resctrl/p1/schemata

默认资源组未修改,因此我们可以访问所有缓存的所有部分(其 schemata 文件读取为“L3:0=f;1=f”)。

受组“p0”控制的任务只能从缓存 ID 0 上的“较低” 50% 和缓存 ID 1 上的“较高” 50% 分配。组“p1”中的任务使用两个插槽上缓存的“较低” 50%。

同样,受组“p0”控制的任务在插槽 0 上最多可以使用 50% 的内存带宽,在插槽 1 上最多可以使用 50% 的内存带宽。组“p1”中的任务也可以在两个插槽上使用 50% 的内存带宽。请注意,与缓存掩码不同,内存带宽无法指定这些分配是否可以重叠。分配指定了该组可能使用的最大带宽,系统管理员可以相应地配置带宽。

如果 resctrl 使用软件控制器 (mba_sc),则用户可以输入最大带宽,单位为 MB 而不是百分比值。

# echo "L3:0=3;1=c\nMB:0=1024;1=500" > /sys/fs/resctrl/p0/schemata
# echo "L3:0=3;1=3\nMB:0=1024;1=500" > /sys/fs/resctrl/p1/schemata

在上面的示例中,插槽 0 上的“p1”和“p0”中的任务将使用最大带宽 1024MB,而在插槽 1 上将使用 500MB。

  1. 示例 2

同样是两个插槽,但这次使用更实际的 20 位掩码。

两个实时任务,pid=1234 在处理器 0 上运行,pid=5678 在双插槽双核机器的插槽 0 上的处理器 1 上运行。为了避免嘈杂的邻居,两个实时任务中的每一个都独占插槽 0 上四分之一的 L3 缓存。

# mount -t resctrl resctrl /sys/fs/resctrl
# cd /sys/fs/resctrl

首先,我们重置默认组的 schemata,以便普通任务无法使用插槽 0 上 L3 缓存的“较高” 50% 和 50% 的内存带宽

# echo "L3:0=3ff;1=fffff\nMB:0=50;1=100" > schemata

接下来,我们为第一个实时任务创建一个资源组,并允许它访问插槽 0 上缓存的“顶部” 25%。

# mkdir p0
# echo "L3:0=f8000;1=fffff" > p0/schemata

最后,我们将第一个实时任务移到此资源组中。我们还使用 taskset(1) 来确保任务始终在插槽 0 上的专用 CPU 上运行。资源组的大多数用途也会限制任务运行的处理器。

# echo 1234 > p0/tasks
# taskset -cp 1 1234

第二个实时任务也是如此(使用剩余 25% 的缓存)。

# mkdir p1
# echo "L3:0=7c00;1=fffff" > p1/schemata
# echo 5678 > p1/tasks
# taskset -cp 2 5678

对于具有内存带宽资源和 CAT L3 的相同双插槽系统,schemata 看起来像这样(假设 min_bandwidth 为 10,bandwidth_gran 为 10)

对于我们的第一个实时任务,这将请求插槽 0 上 20% 的内存带宽。

# echo -e "L3:0=f8000;1=fffff\nMB:0=20;1=100" > p0/schemata

对于我们的第二个实时任务,这将请求插槽 0 上另外 20% 的内存带宽。

# echo -e "L3:0=f8000;1=fffff\nMB:0=20;1=100" > p0/schemata
  1. 示例 3

一个单插槽系统,实时任务在内核 4-7 上运行,非实时工作负载分配给内核 0-3。实时任务共享文本和数据,因此不需要每个任务的关联,并且由于与内核的交互,希望这些内核上的内核与任务共享 L3。

# mount -t resctrl resctrl /sys/fs/resctrl
# cd /sys/fs/resctrl

首先,我们重置默认组的 schemata,以便普通任务无法使用插槽 0 上 L3 缓存的“较高” 50% 和插槽 0 上 50% 的内存带宽

# echo "L3:0=3ff\nMB:0=50" > schemata

接下来,我们为我们的实时内核创建一个资源组,并允许它访问插槽 0 上缓存的“顶部” 50% 和插槽 0 上 50% 的内存带宽。

# mkdir p0
# echo "L3:0=ffc00\nMB:0=50" > p0/schemata

最后,我们将内核 4-7 移到新组,并确保内核和在那里运行的任务获得 50% 的缓存。假设内核 4-7 是 SMT 对等体,并且只有实时线程安排在内核 4-7 上,它们也应该获得 50% 的内存带宽。

# echo F0 > p0/cpus
  1. 示例 4

前面示例中的资源组都处于默认的“可共享”模式,允许共享其缓存分配。如果一个资源组配置了缓存分配,则没有任何东西阻止另一个资源组与该分配重叠。

在此示例中,将在具有两个 L2 缓存实例的 L2 CAT 系统上创建一个新的独占资源组,该实例可以使用 8 位容量位掩码进行配置。新的独占资源组将配置为使用每个缓存实例的 25%。

# mount -t resctrl resctrl /sys/fs/resctrl/
# cd /sys/fs/resctrl

首先,我们观察到默认组配置为分配给所有 L2 缓存

# cat schemata
L2:0=ff;1=ff

我们可以在此时尝试创建新的资源组,但由于与默认组的 schemata 重叠,它将失败

# mkdir p0
# echo 'L2:0=0x3;1=0x3' > p0/schemata
# cat p0/mode
shareable
# echo exclusive > p0/mode
-sh: echo: write error: Invalid argument
# cat info/last_cmd_status
schemata overlaps

为了确保不与其他资源组重叠,必须更改默认资源组的 schemata,从而使新的资源组成为独占资源组。

# echo 'L2:0=0xfc;1=0xfc' > schemata
# echo exclusive > p0/mode
# grep . p0/*
p0/cpus:0
p0/mode:exclusive
p0/schemata:L2:0=03;1=03
p0/size:L2:0=262144;1=262144

创建时,新的资源组不会与独占资源组重叠

# mkdir p1
# grep . p1/*
p1/cpus:0
p1/mode:shareable
p1/schemata:L2:0=fc;1=fc
p1/size:L2:0=786432;1=786432

bit_usage 将反映缓存的使用方式

# cat info/L2/bit_usage
0=SSSSSSEE;1=SSSSSSEE

不能强制资源组与独占资源组重叠

# echo 'L2:0=0x1;1=0x1' > p1/schemata
-sh: echo: write error: Invalid argument
# cat info/last_cmd_status
overlaps with exclusive group

24.6.2.4. 缓存伪锁定示例

使用 CBM 0x3 从缓存 ID 1 中锁定 L2 缓存的一部分。伪锁定区域在 /dev/pseudo_lock/newlock 中公开,可以提供给应用程序作为 mmap() 的参数。

# mount -t resctrl resctrl /sys/fs/resctrl/
# cd /sys/fs/resctrl

确保有可用于伪锁定的位,因为只有未使用的位才能伪锁定,因此需要从默认资源组的 schemata 中删除要伪锁定的位

# cat info/L2/bit_usage
0=SSSSSSSS;1=SSSSSSSS
# echo 'L2:1=0xfc' > schemata
# cat info/L2/bit_usage
0=SSSSSSSS;1=SSSSSS00

创建一个将与伪锁定区域关联的新资源组,指示它将用于伪锁定区域,并配置请求的伪锁定区域容量位掩码

# mkdir newlock
# echo pseudo-locksetup > newlock/mode
# echo 'L2:1=0x3' > newlock/schemata

成功后,资源组的模式将更改为伪锁定,bit_usage 将反映伪锁定区域,并且将存在公开伪锁定区域的字符设备

# cat newlock/mode
pseudo-locked
# cat info/L2/bit_usage
0=SSSSSSSS;1=SSSSSSPP
# ls -l /dev/pseudo_lock/newlock
crw------- 1 root root 243, 0 Apr  3 05:01 /dev/pseudo_lock/newlock
/*
* Example code to access one page of pseudo-locked cache region
* from user space.
*/
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

/*
* It is required that the application runs with affinity to only
* cores associated with the pseudo-locked region. Here the cpu
* is hardcoded for convenience of example.
*/
static int cpuid = 2;

int main(int argc, char *argv[])
{
  cpu_set_t cpuset;
  long page_size;
  void *mapping;
  int dev_fd;
  int ret;

  page_size = sysconf(_SC_PAGESIZE);

  CPU_ZERO(&cpuset);
  CPU_SET(cpuid, &cpuset);
  ret = sched_setaffinity(0, sizeof(cpuset), &cpuset);
  if (ret < 0) {
    perror("sched_setaffinity");
    exit(EXIT_FAILURE);
  }

  dev_fd = open("/dev/pseudo_lock/newlock", O_RDWR);
  if (dev_fd < 0) {
    perror("open");
    exit(EXIT_FAILURE);
  }

  mapping = mmap(0, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
          dev_fd, 0);
  if (mapping == MAP_FAILED) {
    perror("mmap");
    close(dev_fd);
    exit(EXIT_FAILURE);
  }

  /* Application interacts with pseudo-locked memory @mapping */

  ret = munmap(mapping, page_size);
  if (ret < 0) {
    perror("munmap");
    close(dev_fd);
    exit(EXIT_FAILURE);
  }

  close(dev_fd);
  exit(EXIT_SUCCESS);
}

24.6.3. 应用程序之间的锁定

对 resctrl 文件系统执行的某些操作(由对多个文件的读取/写入组成)必须是原子性的。

例如,独占保留 L3 缓存的分配涉及

  1. 从每个目录或每个资源的“bit_usage”读取 cbmmasks

  2. 在全局 CBM 位掩码中找到一组连续的位,这些位在任何目录 cbmmasks 中都清除

  3. 创建一个新目录

  4. 将步骤 2 中找到的位设置为新的目录“schemata”文件

如果两个应用程序尝试同时分配空间,则它们最终可能会分配相同的位,因此保留是共享的而不是独占的。

为了协调 resctrlfs 上的原子操作并避免上述问题,建议执行以下锁定过程

锁定基于 flock,该锁定在 libc 中可用,也可以作为 shell 脚本命令使用

写锁定

  1. 对 /sys/fs/resctrl 执行 flock(LOCK_EX)

  2. 读取/写入目录结构。

  3. 解锁

读锁定

  1. 对 /sys/fs/resctrl 执行 flock(LOCK_SH)

  2. 如果成功,则读取目录结构。

  3. 解锁

bash 示例

# Atomically read directory structure
$ flock -s /sys/fs/resctrl/ find /sys/fs/resctrl

# Read directory contents and create new subdirectory

$ cat create-dir.sh
find /sys/fs/resctrl/ > output.txt
mask = function-of(output.txt)
mkdir /sys/fs/resctrl/newres/
echo mask > /sys/fs/resctrl/newres/schemata

$ flock /sys/fs/resctrl/ ./create-dir.sh

C 示例

/*
* Example code do take advisory locks
* before accessing resctrl filesystem
*/
#include <sys/file.h>
#include <stdlib.h>

void resctrl_take_shared_lock(int fd)
{
  int ret;

  /* take shared lock on resctrl filesystem */
  ret = flock(fd, LOCK_SH);
  if (ret) {
    perror("flock");
    exit(-1);
  }
}

void resctrl_take_exclusive_lock(int fd)
{
  int ret;

  /* release lock on resctrl filesystem */
  ret = flock(fd, LOCK_EX);
  if (ret) {
    perror("flock");
    exit(-1);
  }
}

void resctrl_release_lock(int fd)
{
  int ret;

  /* take shared lock on resctrl filesystem */
  ret = flock(fd, LOCK_UN);
  if (ret) {
    perror("flock");
    exit(-1);
  }
}

void main(void)
{
  int fd, ret;

  fd = open("/sys/fs/resctrl", O_DIRECTORY);
  if (fd == -1) {
    perror("open");
    exit(-1);
  }
  resctrl_take_shared_lock(fd);
  /* code to read directory contents */
  resctrl_release_lock(fd);

  resctrl_take_exclusive_lock(fd);
  /* code to read and write directory contents */
  resctrl_release_lock(fd);
}

24.7. RDT 监控以及分配使用示例

24.7.1. 读取监控数据

读取事件文件(例如:mon_data/mon_L3_00/llc_occupancy)将显示相应 MON 组或 CTRL_MON 组的 LLC 占用率的当前快照。

24.7.2. 示例 1(监控 CTRL_MON 组和 CTRL_MON 组中的任务子集)

在一台双插槽机器(每个插槽一个 L3 缓存)上,缓存位掩码只有 4 位

# mount -t resctrl resctrl /sys/fs/resctrl
# cd /sys/fs/resctrl
# mkdir p0 p1
# echo "L3:0=3;1=c" > /sys/fs/resctrl/p0/schemata
# echo "L3:0=3;1=3" > /sys/fs/resctrl/p1/schemata
# echo 5678 > p1/tasks
# echo 5679 > p1/tasks

默认资源组未修改,因此我们可以访问所有缓存的所有部分(其 schemata 文件读取为“L3:0=f;1=f”)。

受组“p0”控制的任务只能从缓存 ID 0 上的“较低” 50% 和缓存 ID 1 上的“较高” 50% 分配。组“p1”中的任务使用两个插槽上缓存的“较低” 50%。

创建监控组,并将任务子集分配给每个监控组。

# cd /sys/fs/resctrl/p1/mon_groups
# mkdir m11 m12
# echo 5678 > m11/tasks
# echo 5679 > m12/tasks

获取数据(数据显示为字节)

# cat m11/mon_data/mon_L3_00/llc_occupancy
16234000
# cat m11/mon_data/mon_L3_01/llc_occupancy
14789000
# cat m12/mon_data/mon_L3_00/llc_occupancy
16789000

父 ctrl_mon 组显示聚合数据。

# cat /sys/fs/resctrl/p1/mon_data/mon_l3_00/llc_occupancy
31234000

24.7.3. 示例 2(从创建开始监控任务)

在一台双插槽机器(每个插槽一个 L3 缓存)上

# mount -t resctrl resctrl /sys/fs/resctrl
# cd /sys/fs/resctrl
# mkdir p0 p1

RMID 在创建后分配给该组,因此从创建开始监控下面的 <cmd>。

# echo $$ > /sys/fs/resctrl/p1/tasks
# <cmd>

获取数据

# cat /sys/fs/resctrl/p1/mon_data/mon_l3_00/llc_occupancy
31789000

24.7.4. 示例 3(在没有 CAT 支持或创建 CAT 组之前进行监控)

假设像 HSW 这样的系统只有 CQM 而没有 CAT 支持。在这种情况下,resctrl 仍将挂载,但无法创建 CTRL_MON 目录。但是,用户可以在根组内创建不同的 MON 组,从而能够监控包括内核线程在内的所有任务。

这也可以用于在将作业分配给不同的分配组之前,分析作业的缓存大小占用空间。

# mount -t resctrl resctrl /sys/fs/resctrl
# cd /sys/fs/resctrl
# mkdir mon_groups/m01
# mkdir mon_groups/m02

# echo 3478 > /sys/fs/resctrl/mon_groups/m01/tasks
# echo 2467 > /sys/fs/resctrl/mon_groups/m02/tasks

分别监控这些组并获取每个域的数据。从下面的信息可以明显看出,这些任务主要是在域(插槽)0 上执行工作。

# cat /sys/fs/resctrl/mon_groups/m01/mon_L3_00/llc_occupancy
31234000
# cat /sys/fs/resctrl/mon_groups/m01/mon_L3_01/llc_occupancy
34555
# cat /sys/fs/resctrl/mon_groups/m02/mon_L3_00/llc_occupancy
31234000
# cat /sys/fs/resctrl/mon_groups/m02/mon_L3_01/llc_occupancy
32789

24.7.5. 示例 4(监控实时任务)

一个单插槽系统,实时任务在内核 4-7 上运行,非实时任务在其他 CPU 上运行。我们想要监控这些内核上实时线程的缓存占用率。

# mount -t resctrl resctrl /sys/fs/resctrl
# cd /sys/fs/resctrl
# mkdir p1

将内核 4-7 移至 p1

# echo f0 > p1/cpus

查看 llc 占用率快照

# cat /sys/fs/resctrl/p1/mon_data/mon_L3_00/llc_occupancy
11234000

24.8. 英特尔 RDT 勘误表

24.8.1. 英特尔 MBM 计数器可能会错误地报告系统内存带宽

Skylake 服务器的勘误表 SKX99 和 Broadwell 服务器的勘误表 BDF102。

问题:英特尔内存带宽监控 (MBM) 计数器根据为该逻辑内核分配的资源监控 ID (RMID) 来跟踪指标。用于报告这些指标的 IA32_QM_CTR 寄存器 (MSR 0xC8E) 可能会为某些 RMID 值报告不正确的系统带宽。

含义:由于此勘误表,系统内存带宽可能与报告的不匹配。

解决方法:根据以下校正因子表校正 MBM 总读取值和本地读取值

内核计数

rmid 计数

rmid 阈值

校正因子

1

8

0

1.000000

2

16

0

1.000000

3

24

15

0.969650

4

32

0

1.000000

6

48

31

0.969650

7

56

47

1.142857

8

64

0

1.000000

9

72

63

1.185115

10

80

63

1.066553

11

88

79

1.454545

12

96

0

1.000000

13

104

95

1.230769

14

112

95

1.142857

15

120

95

1.066667

16

128

0

1.000000

17

136

127

1.254863

18

144

127

1.185255

19

152

0

1.000000

20

160

127

1.066667

21

168

0

1.000000

22

176

159

1.454334

23

184

0

1.000000

24

192

127

0.969744

25

200

191

1.280246

26

208

191

1.230921

27

216

0

1.000000

28

224

191

1.143118

如果 rmid > rmid 阈值,MBM 总值和局部值应乘以校正因子。

请参阅

1. 英特尔至强可扩展处理器家族规范更新中的勘误 SKX99: http://web.archive.org/web/20200716124958/https://www.intel.com/content/www/us/en/processors/xeon/scalable/xeon-scalable-spec-update.html

2. 英特尔至强 E5-2600 v4 处理器产品家族规范更新中的勘误 BDF102: http://web.archive.org/web/20191125200531/https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/xeon-e5-v4-spec-update.pdf

3. 第二代英特尔至强可扩展处理器参考手册中关于英特尔资源调配技术 (Intel RDT) 的勘误: https://software.intel.com/content/www/us/en/develop/articles/intel-resource-director-technology-rdt-reference-manual.html

以获取更多信息。