Высокая средняя загрузка ЦП; как найти первопричину?

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

Они принимают ввод со своего стандартного ввода в виде потока байтов. Когда этот stdin приходит из обычного файла, байты поступают оттуда, когда это канал, это данные, которые обычно отправляются другим процессом, когда это какой-то файл устройства, который может поступать на физические устройства, подключенные к компьютеру. Например, когда это символьное устройство tty, это данные, отправляемые по некоторой последовательной линии, как правило, терминалом. Терминал — это устройство, которое преобразует события клавиатуры в последовательности байтов.

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

Здесь, если вы собираетесь выдавать такое приглашение и ожидаете событие нажатия клавиши , вы, вероятно, захотите, чтобы ваше приложение (ваш скрипт )был только интерактивным. Либо ожидайте, что стандартный ввод будет терминалом, либо примите ввод с терминала независимо от того, на чем открыт стандартный ввод.

Теперь, как показано выше, все приложения видят потоки байтов, это терминал (или эмулятор терминала )и роль дисциплины линии устройства tty для преобразования нажатой клавиши в последовательности байтов. Несколько примеров:

  • когда вы нажимаете клавишу a , терминалы ASCII отправляют 0x61 байт,
  • когда вы нажимаете клавишу £ , терминалы UTF -8 отправляют два байта 0xc2 и 0xa3.
  • Когда вы нажимаете клавишу Enter , терминалы ASCII отправляют байт 0x0d, который tty line дисциплинирует в системах на основе ASCII -, таких как Linux, обычно преобразуется в 0x0a
  • Когда вы нажимаете только Ctrl , терминалы ничего не отправляют, но если вы нажимаете его с C ,терминалы отправляют байт 0x03, который перехватывается дисциплиной линии tty для отправки сигнала SIGINT задаче переднего плана
  • Когда вы нажимаете Влево , терминалы обычно отправляют последовательность байтов, (варьируется в зависимости от терминала, приложения могут запрашивать базу данных terminfo для ее перевода ), первый из которых 0x1b. Например, в зависимости от режима, в котором он находится, xtermв системах на основе ASCII -отправит либо 0x1b 0x4f 0x44, либо 0x1b 0x5b 0x44(<ESC>[Aили<ESC>OA).

Итак, вот вопросы, которые я бы задал:

  1. Вы все еще хотите запрашивать пользователя, если стандартный ввод не является терминалом
  2. Если ответ на 1 положительный, то вы хотите отправить запрос пользователю на терминале или через stdin/stdout?
  3. Если ответ на 1 отрицательный, вы все еще хотите ждать 5 секунд между каждой итерацией?
  4. Если ответ на 2 — через терминал , должен ли сценарий прерваться, если он не может обнаружить управляющий терминал, или вернуться в нетерминальный режим -?
  5. Вы хотите учитывать только клавиши, нажатые после того, как вы выдали подсказку. IOW, если пользователь случайно введет ключ до того, как будет выдано приглашение.
  6. На что вы готовы пойти, чтобы убедиться, что вы читаете только байты, выданные для одного нажатия клавиши?

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

#! /bin/sh -

# ":" being a special builtin, POSIX requires it to exit if a
# redirection fails, which makes this a way to easily check if a
# controlling terminal is present and readable:
:</dev/tty

# if using bash however not in POSIX conformance mode, you'll need to
# change it to something like:
exec 3< /dev/tty 3<&- || exit

read_key_with_timeout() (
  timeout=$1 prompt=$2
  saved_tty_settings=$(stty -g) || exit

  # if we're killed, restore the tty settings, the convoluted part about
  # killing the subshell process is to work around a problem in shells
  # like bash that ignore a SIGINT if the current command being run handles
  # it.
  for sig in INT TERM QUIT; do
    trap '
      stty "$saved_tty_settings"
      trap - '"$sig"'
      pid=$(exec sh -c '\''echo "$PPID"'\'')
      kill -s '"$sig"' "$pid"

      # fall back if kill failed above
      exit 2' "$sig"
  done

  # drain the tty's buffer
  stty -icanon min 0 time 0; cat > /dev/null

  printf '%s\n' "$prompt"

  # use the tty line discipline features to say the next read()
  # should wait at most the given number of deciseconds (limited to 255)
  stty time "$((timeout * 10))" -echo

  # do one read and count the bytes returned
  count=$(dd 2> /dev/null count=1 | wc -c)

  # If the user pressed a key like the £ or Home ones described above
  # it's likely all the corresponding bytes will have been read by dd
  # above, but not guaranteed, so we may want to drain the tty buffer
  # again to make sure we don't leave part of the sequence sent by a
  # key press to be read by the next thing that reads from the tty device
  # thereafter. Here allowing the terminal to send bytes as slow as 10
  # per second. Doing so however, we may end up reading the bytes sent
  # upon subsequent key presses though.
  stty time 1; cat > /dev/null

  stty "$saved_tty_settings"

  # return whether at least one byte was read:
  [ "$(($count))" -gt 0 ]

) <> /dev/tty >&0 2>&0

until
  echo "Hello World"
  sleep 1
  echo "Done greeting the world"
  read_key_with_timeout 5 "Press any key to stop"
do
  continue
done
1
19.03.2019, 03:50
1 ответ

Меня интересует то же самое, и я проверяю Мунина , чтобы помочь ответить на этот вопрос.

Когда что-то вызывает высокую среднюю нагрузку:

  • это не всегда очевидно и
  • у вас не всегда есть время расследовать, когда это происходит

Munin записывает определенные данные о вашей системе, поэтому при скачках средней нагрузки вы можете вернуться и исследовать (, например. сравнить с файлами журнала ).

См.http://munin-monitoring.org/

В этой записи в блоге есть несколько подходов, включая Munin

0
07.05.2020, 01:06

Теги

Похожие вопросы