高上下文切换速率

使用本主题了解如何查找频繁切换上下文的线程,以降低游戏性能。 上下文切换是一种存储会话状态的过程,这样它可稍后恢复为恢复执行。 就CPU利用率而言,线程之间的快速上下文切换代价很高。 每次上下文切换花费内核大约5μs(平均)的时间来处理。 然而,由此产生的缓存未命中增加了难以量化的额外执行时间。 上下文切换越频繁,CPU利用率下降越多。 每个标题都不同,但合理的目标是每个内核每秒的上下文切换少于1,000个。

PIX

PIX 无法提供标题每秒执行的上下文切换数,但是可以十分了解上下文切换速度何时太高。

确定上下文切换速度何时太高

  1. 生成计时捕获。 有关更多信息,请参阅 通用步骤

  2. 将焦点放在"日程表"视图 CPU 上(请参阅图 1)。 红色刻度线表示上下文切换。 在这种情况下,核心 1 到核心 5 将在整个捕获过程中显示实红线。 尽管这是一个极不均的示例,高密度的红色区域表明标题中的上下文切换太多。

    图 1. PIX 计时捕获,显示哪些 CPU 核心具有大量的上下文切换。

    PIX 计时捕获的屏幕截图,显示哪些 CPU 核心具有大量上下文开关。

  3. 放大检查一个框(图 2)。 此示例只涉及 30 毫秒。 大多数日程表看起来完全红色,这指示许多快速上下文切换。 如此非常红色的日程表能非常表明上下文切换速度太高。

    图 2。 放大显示大量上下文开关的计时捕获的 30 毫秒区域。

    显示大量上下文开关的 30 毫秒“计时捕获”分区的放大视图的屏幕截图。

  4. 显示项目,选择 上下文开关,然后查看 区域详细信息 选项卡(请参阅图 3)。 在这里你可以看到在所选时间范围内发生的上下文开关的列表。 此视图可帮助你选择和调查计时捕获中的特定上下文开关。

    图 3. PIX"区域详细信息"选项卡,显示一个计时捕获中的上下文开关列表。

    显示 PIX

    可以通过选择上下文开关,然后检查面板中的"元素详细信息",确定 切换 的原因。

Windows Performance Analyzer (WPA)

用于评估使用 WPA 的上下文开关率的最佳窗口是 CPU 使用率(精确)按进程和线程 的上下文切换计数(请参阅图 4)。 它是 WPA ThreadContextSwitch.wpaProfile 的一部分。 图 4 中的图形基于图形的可见部分显示上下文切换的速率。 可见量非常重要,因为放大会更改在图形上生成点所使用的时区。 此图最适合在上下文切换数高峰时标识时间段。 通过关注这些时间段中发生的情况,此表可帮助你查看发生多少个上下文切换。

使用 WPA 查找高上下文切换线程

  1. 生成事件跟踪日志 (ETL) 文件。 有关详细信息,请参阅 通用步骤

  2. 应用 ThreadContextSwitch.wpaProfile WPA 配置文件,按照常见步骤中的说明。 图 4 显示了新的"分析"选项卡应如下所示。

    图 4. 按进程线程视图进行的 WPA CPU 使用率(精确)上下文切换计数,显示高上下文切换计数。

    显示 WPA CPU 使用率精确上下文切换计数(按进程线程视图)的屏幕截图,显示高上下文切换计数。

    注意

    你可能注意到,图 4 中的系统也具有大量上下文切换,并且使用 CPU 资源的 1.34%。 这是因为收集 ETL 数据的开销。 虽然 ETL 事件很轻型,但跟踪仍会每个上下文开关上收集调用堆栈数据。 在这种情况下,30秒内超过800万次,可以起到很小的效果。

  3. 放大看起来可能具有高上下文切换实例的一秒区域。

  4. 通过查看图 5 中数据表中的"计数 列,可以看到哪些线程拥有最高数量的上下文切换。 可能有一些具有相似计数的线程,这表示这些线程 相互 切换。

    图 5. 一个时间间隔,显示上下文切换率较高时的外观。 请注意,调整刻度以适应视图。

    时间间隔的屏幕截图,显示上下文切换速率较高时的外观。请注意,调整了比例以适应视图。

  5. 展开具有最高计数的调用堆栈,在代码中查找相关位置。

  6. 在表格右键单击菜单上的" 查找列" 查找,查找可能会使用相同的方法或函数的其他线程(请参阅图 6)。

    图 6. 使用搜索功能定位到 AcquireLock 函数的所有调用,此函数发现会导致频繁进行上下文切换。

    显示如何使用搜索功能定位到 AcquireLock 函数的所有调用的屏幕截图,此函数发现会导致频繁上下文切换。

高上下文切换计数的常见原因

下表列出了上下文切换率过高的常见原因。

原因 原因
线程基元上的争用。 例如,严重部分 太多游戏线程正在使用相同的 CRITICAL_SECTION
SwitchToThread 与其他已*准备好运行*的线程紧密循环。 每当另一个线程准备运行时,它始终会生成上下文切换。
快速切换高优先级线程以准备好运行。 每当取消阻止优先级较高的线程时,OS 会自动执行上下文切换。