Фатмавати Ахмад Заенури/Shutterstock.com
Хотите знать, как долго выполняется процесс и многое другое? Команда Linux time
возвращает статистику времени, предоставляя вам отличную информацию о ресурсах, используемых вашими программами.
время имеет много родственников
Существует много дистрибутивов Linux и различных Unix-подобных операционных систем. У каждого из них есть командная оболочка по умолчанию. Наиболее распространенная оболочка по умолчанию в современных дистрибутивах Linux – это оболочка bash. Но есть много других, таких как оболочка Z (zsh) и оболочка Korn (ksh).
Все эти оболочки содержат собственную команду time
, либо как встроенную команду, либо как зарезервированное слово. Когда вы набираете time
в окне терминала, оболочка выполнит свою внутреннюю команду вместо использования двоичного файла GNU time
, который предоставляется как часть вашего дистрибутива Linux.
Мы хотим использовать версию time
для GNU, потому что она имеет больше опций и более гибка.
Во сколько побежит?
Вы можете проверить, какая версия будет работать, используя команду type
. type
сообщит вам, будет ли оболочка обрабатывать вашу инструкцию самостоятельно со своими внутренними процедурами или передавать ее в двоичный файл GNU.
в окне терминала введите слово type
, пробел, а затем слово time
и нажмите Enter.
время ввода
Мы можем видеть, что в оболочке bash time
является зарезервированным словом. Это означает, что Bash по умолчанию будет использовать свои внутренние процедуры time
.
время ввода
В оболочке Z (zsh) time
является зарезервированным словом, поэтому процедуры внутренней оболочки будут использоваться по умолчанию.
время ввода
В оболочке Korn time
является ключевым словом. Внутренняя процедура будет использоваться вместо команды GNU time
.
Запуск команды времени GNU
Если оболочка в вашей системе Linux имеет внутреннюю подпрограмму time
, вам нужно быть явным, если вы хотите использовать двоичный файл GNU time
. Вы должны либо:
-
Укажите полный путь к двоичному файлу, например,
/usr/bin/time
. Запустите командуwhich time
, чтобы найти этот путь. -
Используйте
время команды
. -
Используйте обратную косую черту, например,
\ time
.
Команда which time
дает нам путь к двоичному файлу.
Мы можем проверить это, используя /usr/bin/time
в качестве команды для запуска двоичного файла GNU. Это работает. Мы получаем ответ от команды time
о том, что мы не предоставили никаких параметров командной строки для работы с ним.
Ввод command time
также работает, и мы получаем ту же информацию об использовании из time
. Команда command
указывает оболочке игнорировать следующую команду, чтобы она обрабатывалась вне оболочки.
Использование символа \
перед именем команды аналогично использованию command
перед именем команды.
Самый простой способ убедиться, что вы используете двоичный файл GNU time
, – это использовать обратную косую черту.
время
\ время
time
вызывает версию времени shell . \ time
использует time
двоичный файл .
Использование команды времени
Давайте время некоторые программы. Мы используем две программы, которые называются loop1
и loop2
. Они были созданы из loop1.c и loop2.c. Они не делают ничего полезного, кроме демонстрации последствий одного типа неэффективности кодирования.
Это loop1.c. Длина строки требуется в двух вложенных циклах. Длина получается заранее, за пределами двух вложенных циклов.
#include "stdio.h" #include "string.h" #include "stdlib.h" int main (int argc, char * argv []) { int i, j, len, count = 0; char szString [] = "как-то-как-то-надо-как-то-как-то-надо-как-то?" // получаем длину строки один раз, вне циклов len = strlen (szString); для (j = 0; j <500000; j ++) { для (i = 0; iЭто loop2.c. Длина строки получается раз за разом для каждого цикла внешнего цикла. Эта неэффективность должна проявиться во времени.
#include "stdio.h" #include "string.h" #include "stdlib.час" int main (int argc, char * argv []) { int i, j, count = 0; char szString [] = "как-то-как-то-надо-как-то-как-то-надо-как-то?" для (j = 0; j <500000; j ++) { // получая длину строки каждые // время запуска цикла for (i = 0; iДавайте запустим программу
loop1
и используемtime
для измерения ее производительности.\ time ./loop1
![]()
Теперь давайте сделаем то же самое для
loop2
.\ time ./loop2
![]()
Это дало нам два набора результатов, но они в действительно ужасном формате. Мы можем сделать что-нибудь об этом позже, но давайте выберем немного информации из результатов.
Когда программы работают, есть два режима выполнения, между которыми они переключаются. Они называются пользовательский режим и режим ядра .
Вкратце, процесс в пользовательском режиме не может напрямую обращаться к аппаратной или эталонной памяти вне своего собственного выделения. Чтобы получить доступ к таким ресурсам, процесс должен делать запросы к ядру. Если ядро подтверждает запрос, процесс переходит в режим ядра до тех пор, пока требование не будет выполнено. Затем процесс переключается обратно на выполнение в пользовательском режиме.
Результаты для
loop1
говорят нам, чтоloop1
провел 0,09 секунды в пользовательском режиме. Он либо провел нулевое время в режиме ядра, либо время в режиме ядра слишком мало, чтобы его можно было зарегистрировать после его округления в меньшую сторону. Общее прошедшее время составило 0,1 секунды.loop1
награждается в среднем 89% процессорного времени в течение всего времени, прошедшего с начала.Неэффективная программа
loop2
выполнялась в три раза дольше. Общее прошедшее время составляет 0,3 секунды. Продолжительность обработки в пользовательском режиме составляет 0,29 секунды. Ничто не регистрируется в режиме ядра.loop2
награждается в среднем 96% процессорного времени за время его работы.Форматирование вывода
Вы можете настроить вывод из
time
, используя строку формата. Строка формата может содержать текст и спецификаторы формата. Список спецификаторов формата можно найти на странице руководства дляtime
. Каждый из спецификаторов формата представляет собой часть информации.Когда строка печатается, спецификаторы формата заменяются фактическими значениями, которые они представляют. Например, спецификатором формата для процента процессора является буква
P
. Чтобы указатьtime
, что спецификатор формата - это не просто обычная буква, добавьте к нему знак процента, например% P
. Давайте использовать это в качестве примера.Опция
-f
(строка формата) используется, чтобы сообщитьtime
, что ниже следует строка формата.Наша строка формата будет печатать символы «Program:» и название программы (и любые параметры командной строки, которые вы передаете программе). Спецификатор формата
% C
обозначает «Имя и аргументы командной строки синхронизируемой команды».\ n
заставляет вывод перемещаться на следующую строку.Существует множество спецификаторов форматов, и они чувствительны к регистру, поэтому убедитесь, что вы вводите их правильно, когда делаете это для себя.
Далее мы собираемся напечатать символы «Общее время:», а затем значение общего прошедшего времени для этого запуска программы (представленного как
% E
).Мы используем
\ n
, чтобы задать еще одну новую строку. Затем мы напечатаем символы «Пользовательский режим (ы)», а затем значение времени ЦП, проведенного в пользовательском режиме, обозначенное% U
.Мы используем
\ n
, чтобы задать еще одну новую строку. На этот раз мы готовимся к значению времени ядра. Мы печатаем символы «Kernel Mode (s)», за которыми следует спецификатор формата для процессорного времени, проведенного в режиме ядра, который равен% S
.Наконец, мы собираемся напечатать символы «
\ n
CPU:», чтобы дать нам новую строку и заголовок для этого значения данных. Спецификатор формата% P
даст средний процент процессорного времени, использованного синхронизированным процессом.Вся строка формата заключена в кавычки. Мы могли бы включить некоторые символы
\ t
для размещения вкладок в выводе, если бы мы были суетливы относительно выравнивания значений.\ time -f "Программа:% C \ nОбщее время:% E \ nИспользуемые режимы (ы)% U \ nКоннельные режимы (ы)% S \ nCPU:% P" ./loop1
![]()
Отправка вывода в файл
Чтобы вести учет времени проведенных вами тестов, вы можете отправить вывод из
time
в файл. Для этого используйте параметр-o
(output). Вывод вашей программы все равно будет отображаться в окне терминала.Это только вывод изtime
, который перенаправляется в файл.Мы можем перезапустить тест и сохранить вывод в файл
test_results.txt
следующим образом:\ time -o test_results.txt -f "Программа:% C \ nОбщее время:% E \ nИспользуемые режимы (ы)% U \ nКоннельные режимы (ы)% S \ nCPU:% P" ./loop1cat test_results.txt
![]()
Выходные данные программы
loop1
отображаются в окне терминала, а результатыtime
отправляются в файлtest_results.txt
.Если вы хотите захватить следующий набор результатов в том же файле, вы должны использовать параметр
-a
(append) следующим образом:\ time -o test_results.txt -a -f "Программа:% C \ nОбщее время:% E \ nПользовательский режим (ы)% U \ nКернелевые режимы (ы)% S \ nCPU:% P" ./loop2cat test_results.txt
![]()
Теперь должно быть понятно, почему мы использовали спецификатор формата
% C
, чтобы включить имя программы в вывод из строки формата.И у нас нет времени
Вероятно, наиболее полезная для программистов и разработчиков для тонкой настройки их кода, команда
time
также полезна для любого, кто хочет узнать немного больше о том, что происходит под капотом каждый раз, когда вы запускаете программу.