资源控制功能的用户界面 (resctrl)

版权所有:

© 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(缓存 QoS 监控)

“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 功能是正交的。 特定系统可能仅支持监控、仅支持控制,或者同时支持监控和控制。 缓存伪锁定是一种使用缓存控制来“固定”或“锁定”缓存中的数据的独特方法。 详细信息可以在“缓存伪锁定”中找到。

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

信息目录

“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”

在 Intel 系统上,指示在物理内核的线程上运行的任务请求不同的内存带宽百分比时,如何限制这些任务

“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”

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

以下是支持的事件类型

描述

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

资源分配和监控组

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

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

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

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

支持将 MON 组目录移动到新的父 CTRL_MON 组,以便更改 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 添加到此组或从此组中删除 CPU。 与任务文件一样,维护一个层次结构,其中 MON 组只能包含父 CTRL_MON 组拥有的 CPU。 当资源组处于伪锁定模式时,此文件将只能读取,反映与伪锁定区域关联的 CPU。

“cpus_list”

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

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

“schemata”

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

“size”

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

“mode”

资源组的“mode”决定了其分配的共享。 “shareable”资源组允许共享其分配,而“exclusive”资源组则不允许。 缓存伪锁定区域是通过首先将“pseudo-locksetup”写入“mode”文件,然后再将缓存伪锁定区域的模式写入资源组的“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。

当使用“mba_MBps”挂载选项时,所有 CTRL_MON 组也将包含

“mba_MBps_event”

读取此文件会显示哪个内存带宽事件用作软件反馈回路的输入,该回路使内存带宽低于 schemata 文件中指定的值。 写入 /sys/fs/resctrl/info/L3_MON/mon_features 中找到的支持的内存带宽事件之一的名称会更改输入事件。

资源分配规则

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

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

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

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

资源监控规则

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

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

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

有关缓存占用监控和控制的注意事项

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

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

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

max_threshold_occupancy - 通用概念

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

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

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

Schemata 文件 - 通用概念

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

缓存 ID

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

缓存位掩码 (CBM)

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

有关 Sub-NUMA Cluster 模式的注意事项

启用 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 节点数。 例如,在具有 100MB 缓存的系统上,具有 10 位分配掩码,通常每一位代表 10MB。 在启用了 SNC 模式且每个 L3 缓存有两个 SNC 节点的情况下,每一位仅代表 5MB。

内存带宽分配和监控

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

每个 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 个线程,每个线程消耗 5GBps,具有 50% 带宽”的工作负载消耗了 100GBps 的最大 L3 带宽,尽管指定的百分比值仅为 50% << 100%。 因此,增加带宽百分比不会产生更多的带宽。 这是因为尽管 L2 外部带宽仍然具有容量,但 L3 外部带宽已完全使用。 另请注意,这取决于基准测试运行的内核数量。

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

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

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

"actual bandwidth < user specified bandwidth".

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

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

禁用 CDP 后,L3 schemata 格式为

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

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

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

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

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>;...

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

内存带宽域为L3缓存。

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

以MiBps为单位指定的内存带宽分配

内存带宽域为L3缓存。

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

慢速内存带宽分配 (SMBA)

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

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

慢速内存的带宽域为L3缓存。 其模式文件格式如下:

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

读取/写入模式文件

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

# 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

读取/写入模式文件 (在 AMD 系统上)

读取模式文件将显示所有域上的当前带宽限制。 分配的资源以八分之一 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

读取/写入具有 SMBA 功能的模式文件 (在 AMD 系统上)

读取和写入模式文件与上面没有 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

缓存伪锁定

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

缓存伪锁定区域的创建由来自用户的请求触发,该请求附带要伪锁定的区域的模式。

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

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

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

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

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

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

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

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

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

伪锁定分两个阶段完成

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

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

缓存伪锁定接口

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

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

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

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

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

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

缓存伪锁定调试接口

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

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

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

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

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

1:

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

2:

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

3:

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

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

延迟调试接口的示例

在此示例中,创建了一个名为“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

缓存命中/未命中调试的示例

在此示例中,在平台的 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

RDT 分配用法的示例

  1. 示例 1

在一台双插槽机器(每个插槽一个 L3 缓存)上,缓存位掩码只有四个位,最小带宽为 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

默认资源组未修改,因此我们可以访问所有缓存的所有部分(其模式文件读取“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 在处理器 1 上运行,在 2 插槽双核机器上的插槽 0 上。为了避免嘈杂的邻居,两个实时任务中的每一个都独占插槽 0 上 L3 缓存的四分之一。

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

首先,我们重置默认组的模式,以便普通任务无法使用插槽 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 的相同 2 插槽系统,模式如下所示(假设 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

首先,我们重置默认组的模式,以便普通任务无法使用插槽 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

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

# 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

为了确保没有与另一个资源组重叠,必须更改默认资源组的模式,使新的资源组成为独占资源组成为可能。

# 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

缓存伪锁定的示例

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

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

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

# 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);
}

应用程序之间的锁定

由对多个文件的读/写组成的 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);
}

RDT 监控以及分配用法的示例

读取监控的数据

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

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

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

# 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

默认资源组未修改,因此我们可以访问所有缓存的所有部分(其模式文件读取“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

示例 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

示例 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

示例 4(监控实时任务)

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

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

将 cpus 4-7 移动到 p1

# echo f0 > p1/cpus

查看 llc 占用率快照

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

Intel RDT 勘误表

Intel MBM 计数器可能会错误地报告系统内存带宽

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

问题:Intel 内存带宽监控 (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. Intel Xeon 处理器可扩展系列规范更新中的勘误表 SKX99:http://web.archive.org/web/20200716124958/https://www.intel.com/content/www/us/en/processors/xeon/scalable/xeon-scalable-spec-update.html

2. Intel Xeon 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. 第 2 代 Intel Xeon 可扩展处理器参考手册中 Intel 资源导向技术 (Intel RDT) 中的勘误表:https://software.intel.com/content/www/us/en/develop/articles/intel-resource-director-technology-rdt-reference-manual.html

以获取更多信息。