【问题标题】:Analyzing cause of performance regression with different kernel version不同内核版本性能回归原因分析
【发布时间】:2014-01-26 16:20:34
【问题描述】:

我在 x86_64 系统上遇到了从 Linux 内核 3.11 到 3.12 的奇怪性能回归。 在 Fedora 20、3.12 上运行 Mark Stock's Radiance benchmark 明显变慢。没有其他任何改变 - 相同的二进制文件,相同的 glibc - 我只是启动了不同的内核版本,并且性能发生了变化。 定时程序 rpict 是 100% CPU 绑定的用户级代码。

在我将此作为错误报告之前,我想找出导致此行为的原因。我对Linux内核了解不多,从3.11到3.12的更改日志也没有给我任何线索。

我在 Intel Haswell (i7-4771) 和 AMD Richland (A8-6600K) 这两个系统上观察到了这种情况。 在 Haswell 系统上,用户时间从 3.11 的 895 秒变为 3.12 的 962 秒。在里奇兰,从 1764 年到 1844 年。这些时间可以在几秒钟内重复。

我用 perf 做了一些分析,发现 IPC 下降的比例与减速的比例相同。在 Haswell 系统上,这似乎是由于更多的错过分支造成的,但为什么预测率会下降呢? Radiance 确实使用了随机数生成器——“更好”的随机性会导致丢失的分支吗?但除了 OMAP4 支持之外,RNG 在 3.12 中似乎不需要更改。

在 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

里奇兰系统:

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 切换到 peformance,但没有任何效果。

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

附加信息:

有什么想法(除了将内核更改一分为二)?

【问题讨论】:

  • 您可以尝试使用几个不同的基准,看看它们与 Radiance 基准的比较。了解运行速度较慢的工作负载中的哪些内容可能会有所帮助。
  • @superdesk 我已经尝试了一些较小的程序(bzip2 和流),但无法检测到任何减速。
  • 我还尝试了不同的 cpufreq 调节器,但无济于事。编辑问题以提及这一点。
  • 两个内核的 brk() 调用次数相同(1096 次调用)。我想我很快就要开始编译内核了……
  • 我认为这可能是由于 brk 随机化导致 3.11 上的大页面使用和 3.12 上的不使用。检查 /proc/PID/smaps 的 AnonHugePages 和 /proc/vmstat 的 thp* 值;记录在这里kernel.org/doc/Documentation/vm/transhuge.txt

标签: performance linux-kernel perf radiance


【解决方案1】:

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

无论如何,我很想看到您的调查结果的最终结果,因此请随时关注我们。

【讨论】:

  • 刚刚测试了上游 3.12.6 w/Fedora config + make oldconfig,它没有显示问题。所以看来这个补丁是不负责任的。
【解决方案2】:

让我们检查您的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

“周期”字段中的 3.12.6 多出近 300 个 Gcycle;只有 6,5 个 Gcycles 是前端的停顿,而 261 个 Gcycles 是在后端停顿的。您只有 0,2 G 的额外分支未命中(每个花费大约 20 个周期 - 每个 optim.manual 第 597 页;所以 4Gcycles),所以我认为您的性能问题与内存子系统问题有关(更现实的后端事件,它可以受内核影响)。页面错误差异和迁移计数很低,我认为它们不会直接减慢测试速度(但迁移可能会将程序移动到更糟糕的地方)。

您应该更深入地了解perf 计数器以找到问题的确切类型(如果您的测试运行时间较短,这会更容易)。英特尔手册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 未命中。随着 /proc/pid/maps 的变化(很多短 [heap] 部分而不是单个 [heap],仍然没有确切的信息为什么),我认为透明大页(THP;有 2M 个大页)可能会有所不同相同数量的内存和更少的 tlb 未命中所需的 TLB 条目),例如在 3.12 中,由于堆段短,它无法应用。

您可以检查 /proc/PID/smaps 中的 AnonHugePages/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 之间,mm 中出现了 VM_SOFTDIRTY 的一些变化。

UPDATE2:未合并 VMA 的可能原因:

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

http://lxr.missinglinkelectronics.com/linux+v3.11/mm/mmap.c#L2577do_brk 在 3.12

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#L9943.11

http://lxr.missinglinkelectronics.com/linux+v3.12/mm/mmap.c#L9943.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 --> is_mergeable_vma ...

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

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

【讨论】:

  • 性能日志来自 AMD Richland 系统 - 很抱歉没有指出这一点(尽管您可以通过经过的时间看到它)。但是,不会使您的答案无效-记忆似乎是罪魁祸首。顺便说一句,上游 3.12.6 没有显示问题。所以我今天会看看 Fedora 补丁。
  • @Chris,快速修复是通过 CONFIG_MEM_SOFT_DIRTY 禁用 CRIU 的软脏 - 它将 define VM_SOFTDIRTY 0
  • 现在也使用当前的 Fedora 3.12.8 内核进行了验证:注释掉 CONFIG_MEM_SOFT_DIRTY=y 修复了回归问题。
  • LKML 中有相关线程:lkml.org/lkml/2014/1/22/378 "[Bug 67651] Bisected:大量碎片化的 mmap 导致 gimp 在超过 vm_max_map_count 后在 3.12 中失败",并进行了一些修复。
  • 由 Cyrill 修复:git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/… commitid 34228d473efe764d4db7c0536375f0c993e6e06a “mm:在 VMA 合并时忽略 VM_SOFTDIRTY”。等待向后移植到 3.12 和 3.13
猜你喜欢
  • 2016-10-11
  • 2019-04-10
  • 1970-01-01
  • 2017-09-17
  • 2019-03-29
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 2020-05-25
相关资源
最近更新 更多