许多 PC 游戏都围绕 8 核游戏机进行设计,并假设其软件线程系统在所有 PC 上都“正常工作”,尤其是在工作线程池中的线程数量方面。不久前,大多数 PC 的核心数量与游戏机相似时,这是一个合理的假设:CPU 的速度更快,性能只是扩展。
但近年来,CPU 格局发生了变化,现在有一个复杂的性能变量矩阵需要导航:
- 核心数量增加
- Intel 推出的异构 P/E 核心
- AMD 的非对称缓存
- 更复杂的调度算法
- Microsoft 等操作系统供应商提供的电源管理技术
这种复杂性意味着先前的线程计数确定算法(及其衍生算法)已不再足够:
num_worker_threads = num_logical_cores - 2
这种传统的线程数量确定算法基于逻辑核心数量,并为关键线程保留了两个核心。
当核心数量超过某个点时,许多受 CPU 限制的游戏实际上会降低性能,因此额外线程并行性的优势会被开销所抵消。
例如,在拥有 8 个以上物理核心的高端桌面系统中,一些游戏通过将其工作池的线程数量减少到 CPU 核心数量,可实现高达 15%的性能提升。
造成性能下降的原因十分复杂且多种多样。如果一款游戏的性能下降 10%,另一款游戏在同一系统上的性能就会提升 10%,这就凸显了在所有游戏和所有系统中提供一刀切解决方案的难度。
相反,游戏的线程数量应根据工作负载量身定制。轻量级 CPU 工作负载应使用更少的线程。
性能解决方案
如果您的游戏在核心数较高的机器上的性能未按预期扩展,甚至可能会降低其性能,则可能存在以下常见原因:
- 硬件性能:核心数较高的 CPU 有时会降低 CPU 速度。减少线程数量可以提高活动核心的频率。
- 硬件资源争用:减少线程数量通常可以减轻内存子系统的压力,减少延迟并提高 CPU 缓存的效率,特别是在没有统一 L3 缓存的基于小芯片的架构中。在不同的小芯片上执行线程会导致高缓存抖动。
- 在单个物理核心的两个逻辑核心(超线程或同步多线程)上执行线程会增加延迟,因为两个线程必须共享物理资源(缓存、指令管线等)。如果关键线程共享物理核心,则其性能可能会下降。针对物理核心数量而不是逻辑核心数量,有助于在核心数量更大的系统上减少延迟。
- 软件资源竞争:当多个线程同时访问时,锁和原子操作会有更高的延迟,这会增加内存压力。错误共享会使这种情况更加严重。
- 操作系统调度问题:线程对活动核心的超额订阅会导致大量上下文交换,这可能会非常昂贵,并可能给 CPU 内存子系统带来额外压力。
- 在具有 P/E 核心的系统上,工作将首先调度到物理 P 核心,然后是 E 核心,最后是超线程逻辑 P 核心。通过使用比总物理核心更少的线程,可以在 E 核心上执行后台线程(例如操作系统线程),而不会中断在 P 核心上运行的关键线程。具体方法是在其兄弟逻辑核心上执行。
- 电源管理:减少线程数量可以使更多核心保持活动状态,从而节省电量,并可能允许剩余核心以更高的频率运行。
- 核心停用对高线程数量很敏感,这会导致短时间爆发的线程无法触发启发式取消核心停用的的问题。运行时间越长,线程越少有助于核心停用算法。
此扩展问题有多种解决方案,具体取决于问题的根本原因:
- 线程数量的动态负载均衡
- 可随核心数量扩展的无锁定线程模型
- 使用 QoS 和线程优先级 API 帮助将线程引导到特定核心
- 其他解决方案 … …
最简单的方法可能是找到游戏实际需要的线程数量,然后让操作系统有效地调度线程。
图 1 显示,减少游戏使用的线程数量可能会减少部分开销(通常来自关键线程),这可能会直接提高游戏性能。
在不同的系统上以不同的设置和线程数测试您的游戏。您可能会发现线程计数的最佳点或适合您游戏的少量最佳点。
请务必测试超线程,以确定在列举不同系统上的线程时,您是否应与物理核心或逻辑核心保持一致。超线程通常有助于低核心数量系统,这些系统没有足够的物理核心来高效执行工作负载,但可能会影响更大的核心数量系统的性能。
您的测试可能会生成经修改的算法,您可以在其中定制max_thread_count
修改了以下线程数量确定算法,将线程数量限制在预定义的最大值内:
max_thread_count = ini_file.get(“max_thread_count”)
num_worker_threads = num_logical_cores - 2
if (num_worker_threads > max_thread_count )
num_worker_threads = max_thread_count
如果max_thread_count
已添加到您的游戏 。ini 文件中,您的 IHV 合作伙伴、QA 团队和游戏玩家都可以轻松找到适合自己 PC 设置的线程数量,以确保实现更高的性能。
总结
CPU 性能问题和工作线程数量是性能方程中不可或缺的一部分。在 CPU 矩阵上测量游戏的 CPU 性能并调整线程数量以适应工作负载是简单的优化,可以产生巨大的两位数性能提升。
在 .ini 文件中覆盖线程数,可确保游戏玩家找到合适的值,从而更大限度地提高 PC 性能。