到目前为止,我们的研究已经很明确了!我们希望通过默认的 Linux 调度器、"缓存优化" 调度器以及手动限制线程位置的方式,自动调度线程,来表征性能受到的影响。

正如许多学校项目一样,我们开始时离截止日期已经很近了,并遵循相当线性的思路立即开始测试。我们的实验设置是通过跨插槽发送的 read-for-ownership 请求来跟踪一致性操作,并跟踪各种配置下的延迟数据,试图精确找出运行时变化的哪些方面导致了性能的提升或下降。由于我们的基准测试都是在线程数量等于或低于单个核心容量的情况下运行的,我们使用 numactl 将基准测试限制在单个插槽上作为"理想化"跨核心放置的代理。

这导致了我们整个研究中最引人注目的结果之一:标准 Linux 调度器和专门的 LAVD 调度器在我们的基准测试上表现大致相同,但使用 numactl 将线程调度限制到单个插槽使运行时最多提高了 3 倍!

runtime_speedup_vs_eevdf_2s.png

Figure 1: 基准测试运行时的归一化加速比

所以我想,如果你们中的任何人目前正在使用多插槽机器以未充分利用的方式运行工作负载,我至少会建议尝试使用 numactl 将工作负载固定到单个 LLC 域或一组核心——你们可以在多线程共享内存程序中获得极致的加速。这主要是因为 Linux 负载均衡器会尽量确保所有插槽在线程数量允许的情况下大致负载均衡,即使这会主动对宿主程序造成不利影响。

这个观察结果的一个显著例外是 mediawiki 基准测试,它来自 DCPerf——为什么运行时几乎没有变化?也许是因为缓存命中率实际上并没有提高?

好的,我们可以检查这是否属实。让我们看看 read-for-ownership 未命中数量(例如 L3 想要写入某些内容,但没有数据,因此要求其他核心让其拥有数据)是否发生了变化。当我们有强烈的写共享时,我们预计这个数量会上升,因为共享的缓存行应该在两个插槽的 L3 缓存之间来回跳动。

l3_rfo_mpki_newdata.png

Figure 2: L3 缓存 Read-for-Ownership 未命中(每千条指令)

哎呀。现在我们有两个谜团了。

  1. 为什么 mediawiki 完全没有加速,即使 L3 RFOs 有所改善?
  2. perlbench 到底发生了什么?是什么让它加速这么多?

不幸的是,我们在截止日期前无法回答这两个问题——事实上,我们在论文到期当天才发现这种关系!在严重的睡眠不足和血液中大量咖啡因的情况下,我们采取了长期以来的做法,忽略了这个问题,在最终报告中写道我们无法确定问题,并继续生成更多图表。我们最终在晚上 11:45 完成报告,匆忙赶到 Siebel,把报告尽可能快地从教授的门下塞进去。我认为提交后我们都没有再想过这件事。

截止到学期结束几周后,我在清理我们用于这个项目的跟踪数据。由于后来忘记的某种原因,我对每个基准测试的 MIPS 感到好奇。

mips_newdata.png

Figure 3: 以每秒百万条指令(MIPS)衡量的吞吐量

这……完全说不通。吞吐量显著增加,但运行时却没有变化?我们用来运行基准测试的命令是什么?

cd /home/pradyun/pg_work/dcperf/
sudo ./perf_collect_mw "$JOBNAME" ./benchpress_cli.py run oss_performance_mediawiki_mlp \
    -i '{"scale_out": 1, "client_threads": 32, "duration": "10m"}' &

……哦天哪。Duration 被固定为 10 分钟。这个指令深深地埋在我们的测试基础设施中,并且在这个项目的过程中被重复使用如此多次,以至于我们完全忘记了它。

所以一下子犯了几个错误。加速比的计算假设指令保持不变,但这个基准测试并非如此。我们不仅意外地将另一个单插槽加速报告为虚幻的"无变化",还不知怎的掩盖了使 LAVD 看起来更好的那个数据点。对于后一点,我的理论是 mediawiki 的性质适合 LAVD 设计所针对的任务链模型。

旁注:LAVD 由 Changwoo Min 和 Igalia 的优秀伙伴为 Steam Deck 设计和优化。他在 OSPM25 上做了一场关于 LAVD 的精彩演讲,你们可以在这里找到 链接,推荐观看!