分析不同内核版本导致性能回归的原因

19

我在x86_64系统上从Linux内核3.11到3.12发现了性能回归的问题。在Fedora 20上运行Mark Stock的Radiance基准测试,3.12明显变慢。除了内核版本不同外,其他都没有改变 - 二进制文件相同,glibc相同。耗时程序rpict是100% CPU绑定用户级代码。

在报告此问题之前,我想找出其原因。我对Linux内核不太了解,而从3.11到3.12的更改日志并没有给我任何线索。

我在两个系统上观察到了这一点,一个是英特尔Haswell(i7-4771),另一个是AMD Richland(A8-6600K)。在Haswell系统上,用户时间从3.11的895秒增加到了3.12的962秒。在Richland上,从1764秒到1844秒。这些时间可以重复多次测试,误差在几秒之内。

我使用perf进行了一些分析,并发现IPC下降与放缓成比例。在Haswell系统上,这似乎是由于未命中分支更多,但为什么预测率会下降呢?Radiance确实使用随机数生成器 - “更好”的随机性是否导致了未命中的分支?但除了OMAP4的支持外,在3.12中似乎没有改变RNG。

对于AMD系统,perf只指出更多的空闲后端周期,但原因不明确。

Haswell系统:

3.11.10  895s user, 3.74% branch-misses, 1.65 insns per cycle
3.12.6   962s user, 4.22% branch-misses, 1.52 insns per cycle

Richland 系统:

3.11.10  1764s user, 8.23% branch-misses, 0.75 insns per cycle
3.12.6   1844s user, 8.26% branch-misses, 0.72 insns per cycle

我还查看了两个内核的dmesg输出的差异,但没有发现可能导致CPU密集型程序如此减速的任何问题。

我尝试将cpufreq管理器从默认的ondemand切换到performance,但并没有产生任何效果。

可执行文件是使用gcc 4.7.3编译的,但未使用AVX指令。 libm仍然似乎使用一些AVX(例如__ieee754_pow_fma4),但这些函数仅占总执行时间的0.3%。

其他信息:

除了二分内核更改之外,还有什么想法吗?


1
我也尝试了不同的cpufreq调节器,但都没有用。我编辑了问题以提到这一点。 - Chris
@osgx 感谢您的建议。我会在周一尝试完成所有操作(这些系统都在我的办公室)。正如提到的那样,我正在使用 Fedora 内核,因此配置应该在源 RPM 中可用。 - Chris
你所报告的基准测试是在用户空间、内核空间还是两者都运行?这很重要!运行仅在用户空间中运行的基准测试将会很有趣。 - Tomas
1
两个内核的brk()调用次数相同(1096次)。我想我很快就得开始编译内核了... - Chris
1
我认为这可能是由于3.11版本上的hugepage使用和3.12版本上的非使用,导致了brk随机化。请检查/proc/PID/smaps中的AnonHugePages和/proc/vmstat中的thp*值;文档在此处https://www.kernel.org/doc/Documentation/vm/transhuge.txt。 - osgx
显示剩余13条评论
2个回答

9

让我们检查你的perf stat输出:http://www.chr-breitkopf.de/tmp/perf-stat.A8.txt

内核版本为3.11.10

    1805057.522096 task-clock                #    0.999 CPUs utilized          
           183,822 context-switches          #    0.102 K/sec                  
               109 cpu-migrations            #    0.000 K/sec                  
            40,451 page-faults               #    0.022 K/sec                  
 7,523,630,814,458 cycles                    #    4.168 GHz                     [83.31%]
   628,027,409,355 stalled-cycles-frontend   #    8.35% frontend cycles idle    [83.34%]
 2,688,621,128,444 stalled-cycles-backend    #   35.74% backend  cycles idle    [33.35%]
 5,607,337,995,118 instructions              #    0.75  insns per cycle        
                                             #    0.48  stalled cycles per insn [50.01%]
   825,679,208,404 branches                  #  457.425 M/sec                   [66.67%]
    67,984,693,354 branch-misses             #    8.23% of all branches         [83.33%]

    1806.804220050 seconds time elapsed

内核 3.12.6

    1875709.455321 task-clock                #    0.999 CPUs utilized          
           192,425 context-switches          #    0.103 K/sec                  
               133 cpu-migrations            #    0.000 K/sec                  
            40,356 page-faults               #    0.022 K/sec                  
 7,822,017,368,073 cycles                    #    4.170 GHz                     [83.31%]
   634,535,174,769 stalled-cycles-frontend   #    8.11% frontend cycles idle    [83.34%]
 2,949,638,742,734 stalled-cycles-backend    #   37.71% backend  cycles idle    [33.35%]
 5,607,926,276,713 instructions              #    0.72  insns per cycle        
                                             #    0.53  stalled cycles per insn [50.01%]
   825,760,510,232 branches                  #  440.239 M/sec                   [66.67%]
    68,205,868,246 branch-misses             #    8.26% of all branches         [83.33%]

    1877.263511002 seconds time elapsed

在“cycles”字段中,3.12.6有近300 Gcycles的额外循环;仅有6.5 Gcycles是前端停顿,261 Gcycles是后端停顿。您只有0.2 G的附加分支失误(每个成本约为20个周期-每个优化手册第597页),因此我认为您的性能问题与内存子系统问题有关(更现实的后端事件,可以受到内核的影响)。页面错误差异和迁移计数很低,我认为它们不会直接减慢测试速度(但迁移可能会将程序移到更糟糕的位置)。
你应该深入探究perf计数器,以找到确切的问题类型(如果测试运行时间短,则会更容易)。Intel手册http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf可以帮助你。查看第587页(B.3.2)获取整体事件层次结构(FE和BE中断也在这里),B.3.2.1-B.3.2.3获取有关后端中断的信息以及如何开始挖掘(检查缓存事件等)。
内核如何影响内存子系统?它可以设置不同的虚拟到物理映射(几乎不是你的情况),或者将进程移动远离数据。你没有NUMA机器,但Haswell并不是精确的UMA——有一个环形总线,一些核心更接近内存控制器或共享LLC(末级缓存)的某些部分。你可以使用taskset实用程序测试你的程序,并绑定到某个核心——内核不会将它移动到其他核心。
更新:在检查了来自A8的新性能统计数据后,我们发现3.12.6有更多的DLTB-misses。由于/proc/pid/maps中的更改(许多短的[heap]段而不是单个[heap],仍然没有确切的信息原因),我认为在透明巨大页面(THP;使用2M巨大页面时,相同数量的内存需要更少的TLB条目和较少的tlb misses)可能存在差异,例如,在3.12中,由于堆栈较短,无法应用它。

您可以检查/proc/PID/smapsAnonHugePages/proc/vmstat的thp*值以查看thp结果。这里记录了这些值的文档kernel.org/doc/Documentation/vm/transhuge.txt

@osgx您找到了原因!在echo never > /sys/kernel/mm/transparent_hugepage/enabled之后,3.11.10所花费的时间与3.12.6一样长!

好消息!

欢迎提供有关如何禁用随机化以及在哪里报告此问题作为错误的其他信息(7%的性能退步非常严重)。

我错了,这个多堆区效应不是 brk 随机化(只改变堆的开头)。这是在 do_brk 中 VMA 合并失败的原因;不知道为什么,在 3.11.10 - 3.12.6 之间看到了一些 VM_SOFTDIRTY 的更改。
更新2:VMA 未合并的可能原因: http://lxr.missinglinkelectronics.com/linux+v3.11/mm/mmap.c#L2580 3.11 中的 do_brk http://lxr.missinglinkelectronics.com/linux+v3.11/mm/mmap.c#L2577 3.12 中的 do_brk
3.12 在 do_brk 结尾添加了以下内容
2663        vma->vm_flags |= VM_SOFTDIRTY;
2664        return addr;

而上面我们有一点

2635        /* Can we just expand an old private anonymous mapping? */
2636        vma = vma_merge(mm, prev, addr, addr + len, flags,
2637                                        NULL, NULL, pgoff, NULL);

vma_merge 内部有一个针对 vm_flags 的测试。

http://lxr.missinglinkelectronics.com/linux+v3.11/mm/mmap.c#L994 3.11

http://lxr.missinglinkelectronics.com/linux+v3.12/mm/mmap.c#L994 3.12

1004        /*
1005         * We later require that vma->vm_flags == vm_flags,
1006         * so this tests vma->vm_flags & VM_SPECIAL, too.
1007         */

vma_merge --> 可以合并前 can_vma_merge_before --> 是可合并的vma ...

 898        if (vma->vm_flags ^ vm_flags)
 899                return 0;

但是在检查时,新的vma没有被标记为VM_SOFTDIRTY,而旧的已经被标记。


1
性能日志来自 AMD Richland 系统-很抱歉没有指出(不过你可以通过经过的时间看到)。不过这并不使你的答案无效——内存似乎是一个可能的罪魁祸首。顺便说一下,上游版本 3.12.6 没有显示出该问题,所以我会在今天查看 Fedora 的补丁。 - Chris
2
@Chris,快速解决方法是通过CONFIG_MEM_SOFT_DIRTY禁用CRIU的软脏数据 - 它将define VM_SOFTDIRTY 0 - osgx
1
现在也已经验证了当前的Fedora 3.12.8内核:注释掉CONFIG_MEM_SOFT_DIRTY=y可以修复这个回归问题。 - Chris
1
由Cyrill修复:http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34228d473efe764d4db7c0536375f0c993e6e06a 提交ID 34228d473efe764d4db7c0536375f0c993e6e06a “mm: ignore VM_SOFTDIRTY on VMA merging”。等待3.12和3.13的回溯。 - osgx
1
最终在Linux 3.13.3和Linux 3.12.11中修复,发布于2014年02月13日。 - osgx
显示剩余4条评论

0

这个变化可能是一个很有可能的候选者http://marc.info/?l=linux-kernel&m=138012715018064。我这么说是因为我没有资源来确认。值得注意的是,在3.11.10和3.12.6之间,这是调度程序中唯一的重大变化。

无论如何,我非常有兴趣看到你的研究结果,所以请随时告诉我们。


1
刚刚测试了上游3.12.6版本,使用Fedora配置和make oldconfig命令,没有出现问题。因此看起来这个补丁不是造成问题的原因。 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接