January 19

Как проверить переключение контекста в Linux

В предыдущей статье мы обсудили принцип работы переключений контекста CPU. Кратко резюмируя, переключение контекста CPU — это основная функция, которая обеспечивает нормальную работу системы Linux. Его можно разделить на переключения контекста процесса, переключения контекста потока и переключения контекста прерывания на основе различных сценариев.

Подписывайтесь на канал usr_bin, где я публикую много полезного по Linux, в том числе ссылки на статьи в этом блоге.

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

Как просмотреть системные контекстные переключатели

Слишком большое количество переключений контекста может привести к высокому потреблению процессорного времени на сохранение и восстановление данных, таких как регистры, стеки ядра и виртуальная память, тем самым сокращая фактическое время выполнения процессов и становясь основной причиной снижения производительности системы.

В статье мы будем использовать инструмент vmstat для вывода переключений контекста системы.

vmstat— это инструмент анализа производительности системы, в основном применяемый для анализа использования памяти системой, а также для анализа количества переключений контекста CPU и прерываний.

Например, вот пример использования vmstat:

# вывод 1 набора данных каждые 5 секунд
$ vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r b swpd free buff cache si so bi bo in cs us sy id wa st
 0 0 0 7005360 91564 818900 0 0 0 0 25 33 0 0 100 0 0

Вот четыре столбца, которые требуют особого внимания:

  • cs (переключение контекста) — количество переключений контекста в секунду.
  • in (прерывание) — количество прерываний в секунду.
  • r (запущено) — длина очереди выполнения, т. е. количество процессов, которые в данный момент запущены или ожидают CPU.
  • b (заблокировано) — количество процессов, находящихся в состоянии непрерывного сна.

В этом примере видно, что количество переключений контекста cs равно 33, а количество прерываний in — 25 в секунду. Длина очереди выполнения r и количество процессов в состоянии непрерывного сна b равны 0.

vmstat предоставляет обзор ситуации переключения контекста системы. Если вы хотите изучить подробную информацию о переключении контекста для каждого процесса, можено использовать pidstat. Добавив опцию -w, вы можете просмотреть информацию о переключении контекста для каждого процесса.

Например:

# вывод 1 набора данных каждые 5 секунд
$ pidstat -w 5
Linux 4.15.0 (ubuntu)  09/23/18  _x86_64_  (2 CPU)
 
08:18:26      UID       PID   cswch/s nvcswch/s  Command
08:18:31        0         1      0.20      0.00  systemd
08:18:31        0         8      5.40      0.00  rcu_sched
...

В этом результате есть два столбца, на которых мы в первую очередь сосредоточены. Один из них — cswch, который представляет количество произвольных переключений контекста в секунду, а другой — nvcswch, который представляет количество непроизвольных переключений контекста в секунду.

Крайне важно запомнить эти два понятия, поскольку они указывают на разные проблемы с производительностью:

  • Добровольные переключения контекста — это переключения контекста, которые происходят, когда процесс не может получить требуемые ресурсы, например, из-за нехватки ввода-вывода или памяти.
  • Недобровольные переключения контекста происходят, когда процесс принудительно запланирован системой по таким причинам, как истечение его временного среза. Это часто происходит, когда между процессами идет интенсивная конкуренция за CPU.

Рассмотрим пример

Понимая, как проверить эти метрики, возникает еще один вопрос: что считается нормальной частотой переключений контекста? Не торопитесь с ответом. Давайте сначала рассмотрим пример переключения контекста.

Подготовка

Для моделирования ситуации чрезмерного переключения контекста в системе используется sysbench.

  • Конфигурация машины: 2 CPU, 8 ГБ ОЗУ
  • Предварительно установленные пакеты sysbench и sysstat

Перед началом откроем три терминала на одной и той же машине Linux, а также установим два упомянутых выше пакета программного обеспечения.

После установки, можно при помощи vmstat проверить количество переключений контекста в неактивной системе:

# вывод 1 набора данных каждую секунду
$ vmstat 1 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r b swpd free buff cache si so bi bo in cs us sy id wa st
 0 0 0 6984064 92668 830896 0 0 2 19 19 35 1 0 99 0 0

Здесь можно видеть, что текущее количество переключений контекста cs равно 35, тогда как количество прерываний in равно 19, а оба значения r и b равны 0. Поскольку в данный момент не запущено никаких других задач, это количество переключений контекста для бездействующей системы.

Далее приступим к практической работе.

Сначала запустим sysbench в первом терминале, чтобы смоделировать узкое место многопоточного планирования системы:

# запустим тест производительности с 10 потоками на 5 минут, чтобы смоделировать проблему переключения нескольких потоков
$ sysbench --threads=10 --max-time=300 threads run

Далее запустим vmstat во втором терминале, чтобы понаблюдать за ситуацией переключения контекста:

# выводим 1 набор данных каждую секунду (используйте Ctrl+C для остановки)
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r b swpd free buff cache si so bi bo in cs us sy id wa st
 6 0 0 6487428 118240 1292772 0 0 0 0 9019 1398830 16 84 0 0 0
 8 0 0 6487428 118240 1292772 0 0 0 0 10191 1392312 16 84 0 0 0

Заметно, что количество переключений контекста в столбце cs резко возросло с 35 до 1,39 млн. Также обратите внимание на следующие показатели:

  • Столбец r: Длина очереди выполнения достигла 8, что намного превышает количество системных CPU (2), поэтому наверняка возникнет большая конкуренция за CPU.
  • Столбцы us (пользователь) и sy (система): общее использование CPU этими двумя столбцами возросло до 100%, а использование CPU системой (столбец sy) достигло 84%, что указывает на то, что CPU в основном занят ядром.
  • в столбце in: количество прерываний также возросло примерно до 10 000, что указывает на то, что обработка прерываний также является потенциальной проблемой.

Рассматривая эти показатели вместе, мы можем сделать вывод, что очередь выполнения системы слишком длинная, то есть слишком много процессов запущено и ждет CPU. Это приводит к большому количеству переключений контекста, что в свою очередь приводит к более высокому использованию CPU системой.

Итак, какой именно процесс вызывает эти проблемы?

Давайте продолжим анализ, используя pidstat в третьем терминале, чтобы посмотреть на ситуацию с переключением контекста CPU и процесса:

# вывод 1 набора данных каждую секунду (используйте Ctrl+C для остановки)
# параметр `-w` указывает, что будут выводиться метрики переключения процессов, а параметр `-u` указывает, что будут выводиться метрики использования CPU
$ pidstat -w -u 1
08:06:33      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
08:06:34        0     10488   30.00  100.00    0.00    0.00  100.00     0  sysbench
08:06:34        0     26326    0.00    1.00    0.00    0.00    1.00     0  kworker/u4:2
 
08:06:33      UID       PID   cswch/s nvcswch/s  Command
08:06:34        0         8     11.00      0.00  rcu_sched
08:06:34        0        16      1.00      0.00  ksoftirqd/1
08:06:34        0       471      1.00      0.00  hv_balloon
08:06:34        0      1230      1.00      0.00  iscsid
08:06:34        0      4089      1.00      0.00  kworker/1:5
08:06:34        0      4333      1.00      0.00  kworker/0:3
08:06:34        0     10499      1.00    224.00  pidstat
08:06:34        0     26326    236.00      0.00  kworker/u4:2
08:06:34     1000     26784    223.00      0.00  sshd

Из выходных данных pidstat можно видеть, что увеличение загрузки CPU действительно вызвано sysbench, нагрузка на CPU которым достигла 100%. Однако, переключения контекста происходят и из других процессов, с самой высокой частотой непроизвольного переключения контекста от pidstat, а самая высокая частота произвольного переключения контекста — от потока ядра kworkerи sshd.

Количество переключений контекста, о котором сообщает, pidstat составляет всего несколько сотен, что значительно меньше 1,39 миллиона, о котором сообщает vmstat. Что происходит? Может ли это быть проблемой самого инструмента?

Прежде чем делать выводы об инструменте, давайте вспомним различные сценарии переключения контекста, обсуждавшиеся ранее. Один важный момент, упомянутый здесь, заключается в том, что базовой единицей планирования в Linux на самом деле является поток, и в нашем сценарии sysbench это имитация проблем планирования потока. Так может ли pidstat игнорировать данные потока?

Запустив man pidstat, вы обнаружите, что в pidstat по умолчанию отображаются метрики для процессов. Однако, когда вы добавляете параметр -t, он также будет отображать метрики для потоков.

Поэтому мы можем остановить предыдущий pidstat в третьем терминале с помощью Ctrl+C, добавить параметр -t и попробовать снова, чтобы посмотреть, что произойдет:

# вывод 1 набора данных каждую секунду (используйте Ctrl+C для остановки)
# параметр `-wt` указывает, что будут выведены метрики переключения контекста для потоков
$ pidstat -wt 1
08:14:05 UID TGID TID cswch/s nvcswch/s Command
...
08:14:05 0 10551 - 6.00 0.00 sysbench
08:14:05 0 - 10551 6.00 0.00 |__sysbench
08:14:05 0 - 10552 18911.00 103740.00 |__sysbench
08:14:05 0 - 10553 18915.00 100955.00 |__sysbench
08:14:05 0 - 10554 18827.00 103954.00 |__sysbench
...

Теперь можно видеть, что хотя количество переключений контекста для процесса sysbench (который является основным потоком) не выглядит очень высоким, количество переключений контекста для его дочерних потоков довольно существенно. Похоже, что виновником чрезмерного количества переключений контекста являются многочисленные потоки sysbench.

Мы выявили основную причину увеличения количества переключений контекста, но заканчивается ли это расследование?

Конечно, нет. Вспомним, что ранее при наблюдении за системными метриками, помимо резкого увеличения частоты переключения контекста, другая метрика также показала существенное изменение. Да, количество прерываний. Количество прерываний также выросло до 10 000, но мы до сих пор не знаем, какой тип прерываний увеличился. Далее нам нужно продолжить наше расследование, чтобы найти источник.

Поскольку мы имеем дело с прерываниями, мы знаем, что они происходят только в режиме ядра. pidstat — это всего лишь инструмент анализа производительности процесса, который не предоставляет никакой подробной информации о прерываниях. Как мы можем определить тип происходящих прерываний?

Путем чтения из файла /proc/interrupts. /proc — это виртуальная файловая система в Linux, используемая для связи между пространством ядра и пространством пользователя. /proc/interrupts является частью этого механизма связи, предоставляя доступное только для чтения представление об использовании прерываний.

В третьем терминале остановим предыдущий pidstat с помощью Ctrl+C, а затем выполним следующую команду, чтобы наблюдать изменения в прерываниях:

# параметр `-d` указывает, что изменения в указанной области будут выделены
$ watch -d cat /proc/interrupts
 CPU0 CPU1
...
RES: 2450431 5279697 Rescheduling interrupts
...

Понаблюдав некоторое время, можно заметить, что наиболее быстро меняющееся прерывание — это прерывание перепланирования (RES). Этот тип прерывания указывает на пробуждение простаивающего CPU для планирования новой задачи для выполнения. В многопроцессорной системе (SMP) планировщик использует этот механизм для распределения задач по разным CPU, обычно называемых межпроцессорными прерываниями (IPI).

Таким образом, увеличение количества прерываний по-прежнему обусловлено проблемой чрезмерного планирования задач, что согласуется с предыдущим анализом количества переключений контекста.

Этот случай демонстрирует преимущества использования нескольких инструментов и сравнения различных метрик. Если бы мы использовали их только в pidstat, мы бы не обнаружили эти серьезные потоки переключения контекста.

Теперь вернемся к первоначальному вопросу: какое количество переключений контекста в секунду считается нормальным?

Ответ зависит от производительности CPU самой системы. Если количество переключений контекста относительно стабильно, то нормальным следует считать от нескольких сотен до менее десяти тысяч. Однако, когда количество переключений контекста превышает десять тысяч или показывает рост на порядок величины, скорее всего, есть проблема с производительностью.

На этом этапе также необходимо более подробно проанализировать тип переключения контекста. Например:

  • Увеличение числа произвольных переключений контекста указывает на то, что процессы ждут ресурсов, возможно, из-за проблем с вводом-выводом или других проблем.
  • Увеличение числа непроизвольных переключений контекста указывает на то, что процессы планируются принудительно, то есть они конкурируют за процессор, что позволяет предположить, что процессор стал узким местом.
  • Увеличение количества прерываний указывает на то, что CPU занят процедурами обработки прерываний, и вам необходимо проанализировать конкретные типы прерываний, изучив файл /proc/interrupts.

На этом все! Спасибо за внимание! Если статья была интересна, подпишитесь на телеграм-канал usr_bin, где будет еще больше полезной информации.