У меня есть тестовая программа
void task()
{
long sum=0;
while(true) {
for(int i=0; i<100000;++i)
for(int j=0; j < 10000; ++j)
sum += j
}
}
int main()
{
boost::thread t(task);
t.join();
return true;
}
и я использую perf record -t -e intel_pt// для профилирования потока. Я вижу много вызовов НМИ, например, 2(?) вызова каждые несколько миллисекунд. Есть ли способ избавиться от этого типа прерываний? Centos 7, ядро 3.10.0, kernel.watchdog = 0.
РЕДАКТИРОВАТЬ на основе комментария @Zulan: версия gcc: 4.8.5.
строка компиляции: g++ -I//include/ -L//lib -lboost_system -lboost_thread test.cpp
Процессор Intel серии Platinum 8xxx/Gold 6xxx.
фрагмент вывода скрипта perf:
a.out 25192 [009] 3976.829805: 1 branches: ffffffff816ac7f5 nmi ([kernel.kallsyms]) => ffffffff816ad500 do_nmi ([kernel.kallsyms])
a.out 25192 [009] 3976.829805: 1 branches: ffffffff816ad54f do_nmi ([kernel.kallsyms]) => ffffffff816ad5f3 do_nmi ([kernel.kallsyms])
a.out 25192 [009] 3976.829805: 1 branches: ffffffff816ad5fa do_nmi ([kernel.kallsyms]) => ffffffff8103dc10 is_debug_stack ([kernel.kallsyms])
a.out 25192 [009] 3976.829805: 1 branches: ffffffff8103dc62 is_debug_stack ([kernel.kallsyms]) => ffffffff816ad5ff do_nmi ([kernel.kallsyms])
a.out 25192 [009] 3976.829805: 1 branches: ffffffff816ad60e do_nmi ([kernel.kallsyms]) => ffffffff816ad558 do_nmi ([kernel.kallsyms])
a.out 25192 [009] 3976.829805: 1 branches: ffffffff816ad573 do_nmi ([kernel.kallsyms]) => ffffffff8113a3f0 rcu_nmi_enter ([kernel.kallsyms])
a.out 25192 [009] 3976.829805: 1 branches: ffffffff8113a41e rcu_nmi_enter ([kernel.kallsyms]) => ffffffff810ba170 __smp_mb__before_atomic ([kernel.kallsyms])
a.out 25192 [009] 3976.829805: 1 branches: ffffffff810ba17a __smp_mb__before_atomic ([kernel.kallsyms]) => ffffffff8113a423 rcu_nmi_enter ([kernel.kallsyms])
a.out 25192 [009] 3976.829805: 1 branches: ffffffff8113a427 rcu_nmi_enter ([kernel.kallsyms]) => ffffffff810ba180 __smp_mb__after_atomic ([kernel.kallsyms])
...
a.out 25192 [009] 3976.829807: 1 branches: ffffffff8113a4aa rcu_nmi_exit ([kernel.kallsyms]) => ffffffff8113a48a rcu_nmi_exit ([kernel.kallsyms])
a.out 25192 [009] 3976.829807: 1 branches: ffffffff8113a48c rcu_nmi_exit ([kernel.kallsyms]) => ffffffff816ad592 do_nmi ([kernel.kallsyms])
a.out 25192 [009] 3976.829807: 1 branches: ffffffff816ad5ed do_nmi ([kernel.kallsyms]) => ffffffff816ad760 do_nmi ([kernel.kallsyms])
a.out 25192 [009] 3976.829807: 1 branches: ffffffff816ad76e do_nmi ([kernel.kallsyms]) => ffffffff816ac7fa nmi ([kernel.kallsyms])
a.out 25192 [009] 3976.829807: 1 branches: ffffffff816ac804 nmi ([kernel.kallsyms]) => ffffffff816ac23c restore_args ([kernel.kallsyms])
a.out 25192 [009] 3976.829808: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
Еще один:
a.out 25192 [009] 3976.829808: 1 branches: ffffffff816b6718 irq_work_interrupt ([kernel.kallsyms]) => ffffffff8102f620 smp_irq_work_interrupt ([kernel.kallsyms])
a.out 25192 [009] 3976.829808: 1 branches: ffffffff8102f629 smp_irq_work_interrupt ([kernel.kallsyms]) => ffffffff81090d20 irq_enter ([kernel.kallsyms])
a.out 25192 [009] 3976.829808: 1 branches: ffffffff81090d29 irq_enter ([kernel.kallsyms]) => ffffffff8113a360 rcu_irq_enter ([kernel.kallsyms])
a.out 25192 [009] 3976.829808: 1 branches: ffffffff8113a3a0 rcu_irq_enter ([kernel.kallsyms]) => ffffffff8113a3b8 rcu_irq_enter ([kernel.kallsyms])
a.out 25192 [009] 3976.829808: 1 branches: ffffffff8113a3c0 rcu_irq_enter ([kernel.kallsyms]) => ffffffff81137e10 rcu_eqs_exit_common.isra.31 ([kernel.kallsyms])
...
a.out 25192 [009] 3976.829809: 1 branches: ffffffff8113a27d rcu_irq_exit ([kernel.kallsyms]) => ffffffff8113a260 rcu_irq_exit ([kernel.kallsyms])
a.out 25192 [009] 3976.829809: 1 branches: ffffffff8113a26e rcu_irq_exit ([kernel.kallsyms]) => ffffffff81090e4e irq_exit ([kernel.kallsyms])
a.out 25192 [009] 3976.829809: 1 branches: ffffffff81090e50 irq_exit ([kernel.kallsyms]) => ffffffff8102f653 smp_irq_work_interrupt ([kernel.kallsyms])
a.out 25192 [009] 3976.829809: 1 branches: ffffffff8102f654 smp_irq_work_interrupt ([kernel.kallsyms]) => ffffffff816b671d irq_work_interrupt ([kernel.kallsyms])
a.out 25192 [009] 3976.829809: 1 branches: ffffffff816b671d irq_work_interrupt ([kernel.kallsyms]) => ffffffff816ac1ed ret_from_intr ([kernel.kallsyms])
a.out 25192 [009] 3976.829809: 1 branches: ffffffff816ac234 retint_swapgs ([kernel.kallsyms]) => ffffffff816ac23c restore_args ([kernel.kallsyms])
a.out 25192 [009] 3976.829809: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
grep'g для irq_return() из вывода скрипта perf показывает 3 прерывания за 20 мс.
a.out 25192 [009] 3976.809174: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 405764 task (a.out)
a.out 25192 [009] 3976.809178: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 405764 task (a.out)
a.out 25192 [009] 3976.829808: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
a.out 25192 [009] 3976.829809: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
a.out 25192 [009] 3976.850317: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 405764 task (a.out)
a.out 25192 [009] 3976.850393: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 405764 task (a.out)
a.out 25192 [009] 3976.850395: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 405764 task (a.out)
a.out 25192 [009] 3976.870945: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 405764 task (a.out)
a.out 25192 [009] 3976.870984: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
a.out 25192 [009] 3976.870985: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
a.out 25192 [009] 3976.891571: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
a.out 25192 [009] 3976.891609: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
a.out 25192 [009] 3976.891611: 1 branches: ffffffff816ac26c irq_return ([kernel.kallsyms]) => 40576f task (a.out)
в grub isolcpus, nohz_full, rcu_nocbs устанавливаются на конкретный процессор, а nmi_watchdog=0. тестовая программа запускалась с набором задач -c a.out.
Какое железо/материнская плата? Получаете ли вы то же самое на разных аппаратных средствах с аналогичным программным обеспечением (если у вас есть другие машины с таким старым ядром)?
NMI является механизм, используемый perf
. Не используйте perf
будет решением.
@ 0andriy, вы говорите, что они вставляются перфорационным процессом, а не самой программой? как это работает - a.out работает на ядре набора задач, а запись perf работает на другом. не могли бы вы уточнить? Спасибо
Не процесс пользовательского пространства perf
; аппаратный PMU сообщает (программному коду ядра), что его буфер заполнен, используя прерывание NMI. Или для событий, не относящихся к PEBS, для выборки типа perf-record, прерывайте каждый раз, когда счетчик события переворачивается, потому что нет буфера. NMI-watchdog в Linux использует один из программируемых счетчиков PMU, так что это еще одно подтверждение того, что использование счетчиков производительности может генерировать NMI. (Есть и другие способы их использования, например, просто позволить им подсчитывать и собирать данные в конце, как это делает perf stat
, но периодически может потребоваться сбор данных.)
@Peter Cordes Спасибо, Питер. Изначально моя цель — сделать так, чтобы цикл спина не отнимал время у вызовов ядра или как можно меньше, поэтому параметр nohz_full. Так что же это за фиксированный таймер на 20 мс — он работает, настраивается? Спасибо
Как вы можете использовать intel_pt и получать доступ к grub на AWS?
@BeeOnRope: посмотреть здесь
Прежде всего, если вы хотите трассировать ядро, вы получите много вызовов функций ядра в трассировке, включая, помимо прочего, связанные с NMI.
Если вы хотите отслеживать свою программу пользовательского пространства, как вы написали выше, используйте
perf record -t -e intel_pt//u ...
Лучше проконсультироваться с документацией https://elixir.bootlin.com/linux/latest/source/tools/perf/Documentation/intel-pt.txt
Однако эти вызовы, как сообщается, происходят на ЦП 9, на том же ЦП, что и моя программа, и за один раз они занимают микросекунды. Разве это не означает, что время тратится на вызовы NMI ядра вне моего спин-цикла? И если да, то как можно избавиться от прерываний nmi — моя цель — максимально убрать прерывания из спин-цикла. Первое, что я попробовал, это указать nohz_full в команде загрузки.
@surfcode: вы можете избавиться от них, нет запустив свою программу под perf record
. Они являются частью того, как ядро собирает данные PMU. то есть они являются частью накладных расходов, связанных с использованием intel_pt
. Могут быть варианты использования больших буферов, чтобы они случались реже или что-то в этом роде...
хорошо -- позвольте мне посмотреть, правильно ли я понимаю это. эти прерывания исходят от производительная запись. поэтому они обычно не существуют, если я не запускаю программу под производительная запись. звучит так, будто я хочу проверить прерывания по времени/аппаратным/часам/и т. д. после настройки системы, мне лучше использовать производительность или какие-то другие инструменты. Это правильно?
Пожалуйста, предоставьте 1) версию компилятора 2) команду компиляции 3) фрагмент фактического
perf script
вывода 4) спецификацию процессора 4) сравнение с непоточной версией этого кода.