让我们检查你的perf stat
输出:http://www.chr-breitkopf.de/tmp/perf-stat.A8.txt
内核版本为3.11.10
1805057.522096 task-clock
183,822 context-switches
109 cpu-migrations
40,451 page-faults
7,523,630,814,458 cycles
628,027,409,355 stalled-cycles-frontend
2,688,621,128,444 stalled-cycles-backend
5,607,337,995,118 instructions
825,679,208,404 branches
67,984,693,354 branch-misses
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/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 之间看到了一些 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
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,而旧的已经被标记。
brk()
调用次数相同(1096次)。我想我很快就得开始编译内核了... - Chris