Подтвердить что ты не робот

Анализ причины регрессии производительности с другой версией ядра

Я столкнулся с странной регрессией производительности ядра Linux с 3.11 по 3.12 в системах x86_64. Запуск Mark Stock Radiance на Fedora 20, 3.12 заметно медленнее. Ничего другого не изменилось - идентичный двоичный, идентичный glibc - я просто загружаю другую версию ядра, и производительность меняется. Временная программа, rpict, представляет собой код пользователя на уровне 100%.

Прежде чем сообщить об этом как об ошибке, я хотел бы найти причину такого поведения. Я не знаю много о ядре Linux, и журнал изменений с 3.11 по 3.12 не дает мне подсказки.

Я наблюдал это на двух системах: Intel Haswell (i7-4771) и AMD Richland (A8-6600K). В системе Haswell пользовательское время перешло от 895 с с 3.11 до 962 с 3.12. На Ричленд, с 1764 по 1844 год. Эти времена повторяются в течение нескольких секунд.

Я сделал некоторое профилирование с perf, и обнаружил, что IPC снизился в той же пропорции, что и замедление. В системе Хасуэлла это, по-видимому, вызвано более пропущенными ветвями, но почему должен снижаться уровень прогноза? Radiance действительно использует генератор случайных чисел - может ли "лучшая" случайность вызвать пропущенные ветки? Но помимо поддержки OMAP4, RNG не должен казаться измененным в 3.12.

В системе AMD perf просто указывает на более холостые ходовые циклы, но причина не ясна.

Система Хасуэлла:

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

Я также посмотрел на diff от вывода dmesg обоих ядер, но не видел ничего, что могло бы вызвать такое замедление программы, связанной с процессором.

Я попытался переключить регулятор cpufreq из значения по умолчанию по умолчанию, но это не повлияло.

Исполняемый файл был скомпилирован с использованием gcc 4.7.3, но не с использованием инструкций AVX. libm по-прежнему использует некоторый AVX (например, __ieee754_pow_fma4), но эти функции составляют всего 0,3% от общего времени выполнения.

Дополнительная информация:

Любые идеи (кроме деаэробных изменений ядра)?

4b9b3361

Ответ 1

Проверьте свои выходы 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 Гбайт больше для 3.12.6; и только 6,5 Гбайт были лотками фронтэнда, и 261 Gcycles были остановлены в бэкэнде. У вас есть только 0,2 G дополнительных пропусков веток (каждый из них стоит около 20 циклов - на optim.manual page 597, поэтому 4Gcycles), поэтому я думаю, что ваши проблемы с производительностью связаны с проблемами подсистемы памяти (более реалистичное бэкэнд-событие, которое может зависит от ядра). Ограничения на количество ошибок в файлах и подсчеты невелики, и я думаю, что они не будут замедлять тест напрямую (но миграции могут переместить программу в худшее место).

Вы должны углубиться в счетчики 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. С изменениями в /proc/pid/maps (много коротких секций [heap] вместо одиночного [heap], по-прежнему нет точной информации о том, почему), я думаю, что могут быть различия в прозрачной огромной странице (THP; с 2 миллионами огромных страниц там меньше Записи 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 (которая меняет только начало кучи). Это отказ объединения VMA в do_brk; не знаю почему, но некоторые изменения для VM_SOFTDIRTY были видны в mm между 3.11.10 - 3.12.6.

UPDATE2: Возможная причина не слияния VMA:

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

http://lxr.missinglinkelectronics.com/linux+v3.11/mm/mmap.c#L2577 do_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#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 → is_mergeable_vma...

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

Но во время проверки новый vma не помечен как VM_SOFTDIRTY, а старый уже отмечен.

Ответ 2

Это изменение может быть вероятным кандидатом http://marc.info/?l=linux-kernel&m=138012715018064. Я говорю это свободно, поскольку у меня нет ресурсов для подтверждения. Стоит отметить, что это было единственным существенным изменением планировщика между 3.11.10 и 3.12.6.

Во всяком случае, мне очень интересно видеть конечные результаты ваших результатов, поэтому держите нас в курсе.