为何两单线程应用共驻同一逻辑核时wrmem运行速度更快
问题背景
我有两个单线程应用:
- 其一为单词重索引应用
wrmem; - 另一个是按固定步长遍历数组的简单循环程序。
我在测试中观察到如下现象:
- 若将两个应用同时绑定到同一个逻辑核,且该核对应的兄弟超线程处于空闲状态时,
wrmem的运行速度更快; - 但如果将两个应用分别运行在同一物理核的两个兄弟超线程上,
wrmem的执行耗时会明显增加。
现有两个技术疑问:
- 为何将两个应用分配到同一个逻辑核运行时,wrmem的运行速度反而更快?
- 是否存在可行方法(例如通过性能计数器分析)判断两个应用应当绑定到同一个超线程运行,还是分别部署在兄弟超线程上?
以下为perf工具采集的不同场景下的性能事件统计结果:
wrmem运行在兄弟超线程上的性能数据
4036814116 dTLB-loads (23.52%) 74228013 dTLB-load-misses # 1.84% of all dTLB cache hits (23.56%) 31356167246 cycles (23.61%) 2356371896 dtlb_load_misses.walk_active (23.65%) 18110002 cache-misses # 6.865 % of all cache refs (23.62%) 263804080 cache-references (23.57%) 70217803 branch-misses # 2.62% of all branches (23.53%) 2679691364 branches (23.49%) 211970964 bus-cycles (23.49%) 13 context-switches 175707 page-faults 3996104598 L1-dcache-loads (23.49%) 527053354 L1-dcache-load-misses # 13.19% of all L1-dcache hits (23.50%) 2437399504 dTLB-stores (23.50%) 34857064 dTLB-store-misses (23.50%) 0 mem-loads (23.50%) 77522441 dtlb_load_misses.miss_causes_a_walk (23.49%) 37317020 dtlb_store_misses.miss_causes_a_walk (23.49%) 3481625263 dtlb_store_misses.walk_active (23.49%) 8.534166029 seconds time elapsed
wrmem与另一应用同跑在单个逻辑核上的性能数据
4021938226 dTLB-loads (23.45%) 1339043 dTLB-load-misses # 0.03% of all dTLB cache hits (23.58%) 14092062606 cycles (23.69%) 87412240 dtlb_load_misses.walk_active (23.79%) 15980810 cache-misses # 32.547 % of all cache refs (23.84%) 49100039 cache-references (23.82%) 77863788 branch-misses # 2.86% of all branches (23.76%) 2725709999 branches (23.66%) 95364600 bus-cycles (23.55%) 246 context-switches 175706 page-faults 3989720332 L1-dcache-loads (23.44%) 453219493 L1-dcache-load-misses # 11.36% of all L1-dcache hits (23.30%) 2459754128 dTLB-stores (23.30%) 28088729 dTLB-store-misses (23.30%) 0 mem-loads (23.30%) 1996539 dtlb_load_misses.miss_causes_a_walk (23.40%) 37192560 dtlb_store_misses.miss_causes_a_walk (23.40%) 1694922205 dtlb_store_misses.walk_active (23.40%) 7.684306529 seconds time elapsed
另一测试应用为按4096字节步长遍历数组的简单循环程序,其在不同场景下的性能数据如下:
另一应用与wrmem同跑在同一逻辑核上的性能数据
1509514481 dTLB-loads (23.47%) 1345520064 dTLB-load-misses # 89.14% of all dTLB cache hits (23.50%) 52986473567 cycles (23.52%) 51187627462 dtlb_load_misses.walk_active (23.55%) 24803686 cache-misses # 0.771 % of all cache refs (23.56%) 3218128188 cache-references (23.56%) 624235 branch-misses # 0.04% of all branches (23.57%) 1483035278 branches (23.57%) 358401846 bus-cycles (23.58%) 251 context-switches 262239 page-faults 1630995048 L1-dcache-loads (23.58%) 2707508863 L1-dcache-load-misses # 166.00% of all L1-dcache hits (23.57%) 194944978 dTLB-stores (23.57%) 1773489 dTLB-store-misses (23.53%) 0 mem-loads (23.50%) 1344962228 dtlb_load_misses.miss_causes_a_walk (23.47%) 2721695 dtlb_store_misses.miss_causes_a_walk (23.45%) 78331814 dtlb_store_misses.walk_active (23.46%) 18.162205841 seconds time elapsed
另一应用运行在兄弟超线程上的性能数据
1570720041 dTLB-loads (23.50%) 1342959305 dTLB-load-misses # 85.50% of all dTLB cache hits (23.50%) 59079247016 cycles (23.50%) 56895513621 dtlb_load_misses.walk_active (23.53%) 37209980 cache-misses # 1.115 % of all cache refs (23.54%) 3336817534 cache-references (23.54%) 626337 branch-misses # 0.04% of all branches (23.54%) 1457502744 branches (23.54%) 399413773 bus-cycles (23.54%) 10 context-switches 262239 page-faults 1523989098 L1-dcache-loads (23.54%) 2714388590 L1-dcache-load-misses # 178.11% of all L1-dcache hits (23.54%) 150322599 dTLB-stores (23.54%) 1832015 dTLB-store-misses (23.54%) 0 mem-loads (23.54%) 1341108173 dtlb_load_misses.miss_causes_a_walk (23.54%) 2718493 dtlb_store_misses.miss_causes_a_walk (23.53%) 78263090 dtlb_store_misses.walk_active (23.51%) 16.042126229 seconds time elapsed
问题解答
为什么同逻辑核绑定运行时wrmem速度更快
超线程(SMT)的核心设计是同一物理核的两个兄弟线程共享几乎所有微架构资源,包括L1/L2缓存、dTLB(数据页表缓存)、页表遍历硬件、指令执行端口,仅寄存器等少量资源为线程私有;而两个程序绑定到同一个逻辑核时,由操作系统时间片轮转调度串行执行,程序运行期间不会有其他线程同时抢占核心共享资源。
结合perf数据,现象根因非常清晰:
- 4096字节步长的遍历程序是典型的TLB密集型负载:4096字节为系统默认内存页大小,该程序每次内存访问都会命中新页,单跑时
dtlb_load_misses.walk_active(页表遍历占用周期)占总周期比例超过95%,会持续打满dTLB和页表遍历单元,不停替换dTLB中的旧条目。 - 两个程序跑在兄弟超线程上时,步长程序会持续把wrmem需要的dTLB条目挤出缓存,导致wrmem的dTLB加载miss率从同逻辑核场景的0.03%暴涨到1.84%,对应的页表遍历周期从8700万涨到23.5亿,涨幅近27倍。虽然此时wrmem可以持续占用超线程执行时间,但TLB miss带来的访存开销暴涨直接拉低执行效率,总耗时达到8.53秒。
- 两个程序跑在同一个逻辑核上时,wrmem运行期间没有其他线程抢占dTLB、缓存等共享资源,TLB命中率极高,执行效率是SMT场景的2倍以上;哪怕需要和步长程序分时间片,总耗时也只有7.68秒,反而比SMT场景更快。
注意:同逻辑核场景下wrmem的
cache-misses占比显示为32.5%是统计口径误导,该数值是cache miss占总cache访问请求的比例,实际该场景下wrmem的cache miss绝对值仅1598万,比SMT场景的1811万更低。
如何判断应用适合同逻辑核绑定还是兄弟超线程部署
判断核心是对比「SMT并行带来的收益」和「共享资源竞争带来的开销」的高低,可直接通过perf性能计数器完成量化判断,步骤如下:
- 第一步:单独测试每个程序的资源瓶颈
- 如果程序的
dtlb_load_misses.walk_active/总cycles占比超过10%,或者L2缓存miss率超过20%,或者核心执行端口长期处于打满状态,说明它是核心共享资源密集型负载,对SMT共置的竞争非常敏感。 - 如果程序大部分周期处于IO等待、分支依赖等待状态,核心执行单元、TLB、缓存的平均利用率低于30%,说明存在大量空闲执行槽,适合SMT共置。
- 如果程序的
- 第二步:测试两个程序共置在兄弟超线程时的实际开销
- 共置后分别统计两个程序的核心指标:如果任意一个程序的dTLB miss率、L1/L2缓存miss率较单物理核独占时上涨超过30%,IPC(每周期指令数)下跌超过40%,说明资源竞争开销已经超过SMT并行收益,此时把两个程序绑定到同一个逻辑核分时运行的总性能更好。
- 如果共置后两个程序的IPC总和超过单逻辑核满负载IPC的1.2倍,且TLB、缓存miss率没有明显上涨,说明两个程序资源瓶颈互补,SMT并行收益更高,适合部署在兄弟超线程上。
结合本次测试场景来看:步长遍历程序单跑时已经把dTLB和页表遍历单元完全打满,和wrmem共置SMT时带来的TLB竞争开销远大于并行收益,显然更适合绑定到同一个逻辑核运行。
内容的提问来源于stack exchange,提问作者Mohammad Siavashi
相关产品推荐
相关产品推荐

