Поиск по сайту:

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


Хотите узнать, как долго выполняется процесс, и многое другое? Команда Linux time возвращает статистику времени, предоставляя вам интересные сведения о ресурсах, используемых вашими программами.

время имеет много родственников

Существует множество дистрибутивов Linux и различных Unix-подобных операционных систем. Каждый из них имеет командную оболочку по умолчанию. Наиболее распространенной оболочкой по умолчанию в современных дистрибутивах Linux является оболочка bash. Но есть и много других, таких как оболочка Z (zsh) и оболочка Korn (ksh).

Все эти оболочки включают собственную команду time либо как встроенную команду, либо как зарезервированное слово. Когда вы вводите time в окне терминала, оболочка выполнит свою внутреннюю команду вместо использования двоичного файла GNU time, который предоставляется как часть вашего дистрибутива Linux.

Мы хотим использовать версию time GNU, потому что она имеет больше возможностей и более гибкая.

В какое время будет работать?

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

в окне терминала введите слово type, пробел, а затем слово time и нажмите Enter.

type time

Мы видим, что в оболочке bash time является зарезервированным словом. Это означает, что Bash будет использовать свои внутренние подпрограммы time по умолчанию.

type time

В оболочке Z (zsh) time является зарезервированным словом, поэтому по умолчанию будут использоваться внутренние подпрограммы оболочки.

type time

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

Запуск команды времени GNU

Если оболочка в вашей системе Linux имеет внутреннюю подпрограмму time, вам необходимо явно указать, хотите ли вы использовать двоичный файл GNU time. Вы должны либо:

  • Укажите полный путь к двоичному файлу, например  /usr/bin/time. Запустите команду what time, чтобы найти этот путь.
  • Используйте командное время.
  • Используйте обратную косую черту, например \time.

Команда what time дает нам путь к двоичному файлу.

Мы можем проверить это, используя /usr/bin/time в качестве команды для запуска двоичного файла GNU. Это работает. Мы получаем ответ от команды time, сообщающий нам, что мы не предоставили никаких параметров командной строки для ее работы.

Ввод command time также работает, и мы получаем ту же информацию об использовании из time. Команда command указывает оболочке игнорировать следующую команду, чтобы она обрабатывалась вне оболочки.

Использование символа \ перед именем команды равносильно использованию command перед именем команды.

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

time
\time

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[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek";

 // get length of string once, outside of loops
 len = strlen( szString );  

 for (j=0; j<500000; j++) {

 for (i=0; i < len; i++ ) {

  if (szString[i] == '-')
    count++;
   }
 }

 printf("Counted %d hyphens\n", count);

 exit (0);

} // end of main

Это loop2.c. Длина строки получается раз за разом для каждого цикла внешнего цикла. Эта неэффективность должна проявляться в таймингах.

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main (int argc, char* argv[])
{
 int i, j, count=0;
 char szString[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek";

 for (j=0; j<500000; j++) {

 // getting length of string every
 // time the loops trigger
 for (i=0; i < strlen(szString); i++ ) {

   if (szString[i] == '-')
    count++;
   }
 }

 printf("Counted %d hyphens\n", count);

 exit (0);

} // end of main

Давайте запустим программу 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, чтобы добавить еще одну новую строку. Затем мы напечатаем символы «User Mode (s)», за которыми следует значение времени ЦП, затраченного в пользовательском режиме, обозначенное %U.

Мы используем \n, чтобы добавить еще одну новую строку. На этот раз мы готовимся к значению времени ядра. Мы печатаем символы «Kernel Mode (s)», за которыми следует спецификатор формата для времени ЦП, затрачиваемого в режиме ядра, который равен %S.

Наконец, мы напечатаем символы «\nCPU:», чтобы дать нам новую строку и заголовок для этого значения данных. Спецификатор формата %P указывает средний процент процессорного времени, используемого синхронизируемым процессом.

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

\time -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1

Отправка вывода в файл

Чтобы вести учет времени проведенных вами тестов, вы можете отправить выходные данные из time в файл. Для этого используйте параметр -o (вывод). Вывод вашей программы по-прежнему будет отображаться в окне терминала. В файл перенаправляется только вывод из time.

Мы можем повторно запустить тест и сохранить результат в файл test_results.txt следующим образом:

\time -o test_results.txt -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1
cat test_results.txt

Выходные данные программы loop1 отображаются в окне терминала, а результаты time передаются в файл test_results.txt.

Если вы хотите записать следующий набор результатов в тот же файл, вы должны использовать параметр -a (добавить) следующим образом:

\time -o test_results.txt -a -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop2
cat test_results.txt

Теперь должно быть понятно, почему мы использовали спецификатор формата %C для включения имени программы в вывод из строки формата.

И мы вне времени

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

RELATED: Best Linux Laptops for Developers and Enthusiasts