Пространство ядра и пространство пользователя

Несколько недель назад я работал над забавным проектом дверной монитор с Raspberry Pi 3 модель B и сценариями оболочки. Недавно я подключил камеру к Pi и обновил скрипт, чтобы при открытии двери снимался снимок и отправлялся в виде прикрепленного файла к уведомлению по электронной почте.

Одна из проблем, с которой я столкнулся, заключалась в том, что время выполнения скрипта значительно увеличилось с нескольких секунд до 17,58 секунды. Я смог идентифицировать и изолировать время выполнения каждой строки скрипта. Я понял, что выполнение команды raspistill заняло 5,87 секунды. В результате полностью отсутствует возможность сделать снимок человека, открывающего дверь.

как сократить время выполнения распистилля

Простой raspistill, за которым следует тег «- help» на терминале, предоставил дополнительную информацию о командах параметров изображения:

pi@raspberrypi:~ $ raspistill --help 
Runs camera for specific time, and take JPG capture at end if requested  
usage: raspistill [options]  
Image parameter commands 
... 
-t, --timeout : Time (in ms) before takes picture and shuts down (if not specified, set to 5s)

Мне удалось сократить время выполнения raspistill до нескольких миллисекунд, указав время до того, как снимок будет сделан в сценарии, следующим образом:

Как эффективно получить время выполнения скрипта

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

time yourscript.sh   // get execution for a script
time ls              // get execution time of ls command

что дало следующий результат:

Теперь вы можете заметить, что команда time предоставляет реальное, пользовательское и системное время. Понимание пространства пользователей и пространств ядра имеет значение. Одна из этих вещей не похожа на другую. Реальное относится к фактическому истекшему времени; Пользователь и система относятся к процессору, используемому только процессом.

Статистика реального времени, пользовательского и системного времени

  • Реальное - время на настенных часах - время от начала до конца разговора. Это все прошедшее время, включая временные интервалы, используемые другими процессами, и время, которое процесс заблокировал (например, если он ожидает завершения ввода-вывода).
  • Пользователь - время, затрачиваемое ЦП в пользовательском режиме кода (вне ядра) внутри процесса. Это только фактическое время ЦП, использованное для выполнения процесса. Другие процессы и время, которое процесс затрачивает на блокировку, не учитываются в этой цифре.
  • Sys - время, затрачиваемое ядром в процессе. Это означает выполнение процессорного времени, затрачиваемого на системные вызовы внутри ядра, в отличие от кода библиотеки, который все еще выполняется в пользовательском пространстве. Как и «пользователь», это только процессорное время, используемое процессом. См. Ниже краткое описание режима ядра (также известного как «режим супервизора») и механизма системных вызовов.

User+Sys сообщит вам, сколько фактического процессорного времени использовал ваш процесс. Обратите внимание, что это касается всех процессоров, поэтому, если процесс имеет несколько потоков (и этот процесс выполняется на компьютере с более чем одним процессором), он потенциально может превысить время настенных часов, указанное Real (что обычно происходит). Обратите внимание, что в выходных данных эти цифры включают время User и Sys всех дочерних процессов (и их потомков), когда они могли быть собраны, например на wait(2) или waitpid(2), хотя базовые системные вызовы возвращают статистику для процесса и его дочерних элементов отдельно.

Истоки статистики, представленной time (1)

Статистика, сообщаемая time, собирается из различных системных вызовов. "Пользователь" и "Система" происходят от wait (2) или times (2), в зависимости от конкретной системы. "Реальный" рассчитывается на основе времени начала и окончания, полученного в результате gettimeofday (2) вызова. В зависимости от версии системы time также может собирать различные другие статистические данные, такие как количество переключений контекста.

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

Краткое руководство по режиму ядра и режима пользователя

В Unix или любой операционной системе с защищенной памятью режим «ядра» или «супервизора» относится к привилегированному режиму, в котором может работать ЦП. Определенные привилегированные действия, которые могут повлиять на безопасность или стабильность, могут быть выполнены только тогда, когда ЦП работает в этом режиме. режим. Эти действия недоступны для кода приложения.

Примером такого действия может быть манипулирование MMU для получения доступа к адресному пространству другого процесса. Обычно код пользовательского режима не может этого сделать (по уважительной причине), хотя он может запрашивать разделяемую память у ядра, которая может быть прочитана или записана более чем одним процессом. В этом случае разделяемая память явно запрашивается у ядра через безопасный механизм, и оба процесса должны явно подключиться к ней, чтобы использовать ее.

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

По соображениям безопасности вы не можете переключиться в режим ядра и выполнить произвольный код - ловушки управляются через таблицу адресов, в которые нельзя записывать, если ЦП не работает в режиме супервизора. Вы ловите ловушку с явным номером ловушки, и адрес ищется в таблице переходов; ядро имеет конечное число контролируемых точек входа.

Вызовы «system» в библиотеке C (особенно те, которые описаны в разделе 2 страниц руководства) имеют компонент пользовательского режима, который вы фактически вызываете из своей программы C. Незаметно для себя они могут выполнить один или несколько системных вызовов ядра для выполнения определенных служб, таких как ввод-вывод, но при этом у них все еще есть код, работающий в пользовательском режиме.

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

Подробнее о «sys»

Есть вещи, которые ваш код не может делать в пользовательском режиме - например, выделение памяти или доступ к оборудованию (жесткий диск, сеть и т. Д.). Они находятся под наблюдением ядра, и только оно может их делать. Некоторые выполняемые вами операции (например, malloc или_16 _ / _ 17_) будут вызывать эти функции ядра, и это будет считаться системным временем. К сожалению, это не так просто, как «каждый вызов malloc будет засчитываться в« sys »времени».

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

Вызов malloc выполнит некоторую собственную обработку (все еще учитывается во времени 'user'), а затем где-то по пути он может вызвать функцию в ядре (считается в 'sys время). После возврата из вызова ядра еще некоторое время будет в поле «пользователь», а затем malloc вернется к вашему коду. Что касается того, когда происходит переключение, и сколько его тратится в режиме ядра ... вы не можете сказать. Это зависит от реализации библиотеки. Кроме того, другие, казалось бы, невинные функции также могут использовать malloc и тому подобное в фоновом режиме, которые снова будут иметь некоторое время в sys.

Некоторое содержание этой статьи представляет собой комбинацию ответов, изначально опубликованных на S tack Overflow.

Если вам понравилась эта статья, вам также может понравиться Как создать двунаправленное приложение для Интернета вещей / чата с Python »

Пожалуйста, хлопните в ладоши за поддержку!

Ваше здоровье!!!