Получить время выполнения программы в оболочке


407

Я хочу выполнить что-то в оболочке Linux в нескольких различных условиях и иметь возможность выводить время выполнения каждого выполнения.

Я знаю, что мог бы написать Perl или Python-скрипт, который бы делал это, но есть ли способ сделать это в оболочке? (что случилось с Bash)



возможно ли получить Ticksподобный случай windows?
Свободная прогулка

Ответы:


534

Используйте встроенное timeключевое слово:

время помощи

время: время [-p] ТРУБОПРОВОД
    Выполнить PIPELINE и распечатать сводку реального времени, пользовательского времени процессора,
    и системное процессорное время, потраченное на выполнение PIPELINE, когда он завершается.
    Статус возврата - это статус возврата ТРУБОПРОВОДА. Параметр `-p '
    печатает временную сводку в несколько ином формате. Это использует
    значение переменной TIMEFORMAT в качестве выходного формата.

Пример:

$ time sleep 2
реальный 0m2.009s
пользователь 0m0.000s
sys 0m0.004s

1
Как это используется в команде, как time -p i=x; while read line; do x=x; done < /path/to/file.txt? Он сразу возвращает 0.00, если я не помещаю ничего перед циклом while. Что дает?
Натли

это плохая «временная» версия, встроенная в bash. где находится внешняя команда времени?
Znik

6
@Znik, попробуйте / usr / bin / time
Марк Райкок

10
@natli: В то timeвремя как можно рассчитать весь конвейер как есть (благодаря тому, что он является ключевым словом Bash ), вам нужно использовать групповую команду ( { ...; ...; }) для time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
синхронизации

2
Чтобы увидеть все версии времени, которые вы установили в своей системе, вы можете использоватьtype -a time
spinup

120

Вы можете получить гораздо более подробную информацию, чем встроенная в bash time(которую упоминает Роберт Гэмбл), используя time (1) . Обычно это так /usr/bin/time.

Примечание редактора: чтобы убедиться, что вы вызываете внешнюю утилиту, time а не time ключевое слово вашей оболочки , используйте ее как /usr/bin/time.
timeявляется утилитой под мандатом POSIX , но единственная опция, которую требуется поддерживать, это -p.
Конкретные платформы реализуют конкретные, нестандартные расширения: -vработает с GNU «s timeутилитами, как показано ниже (вопрос помечен); реализация BSD / macOS использует -lдля получения аналогичных результатов - см man 1 time.

Пример подробного вывода:


$ /usr/bin/time -v sleep 1
       Command being timed: "sleep 1"
       User time (seconds): 0.00
       System time (seconds): 0.00
       Percent of CPU this job got: 1%
       Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.05
       Average shared text size (kbytes): 0
       Average unshared data size (kbytes): 0
       Average stack size (kbytes): 0
       Average total size (kbytes): 0
       Maximum resident set size (kbytes): 0
       Average resident set size (kbytes): 0
       Major (requiring I/O) page faults: 0
       Minor (reclaiming a frame) page faults: 210
       Voluntary context switches: 2
       Involuntary context switches: 1
       Swaps: 0
       File system inputs: 0
       File system outputs: 0
       Socket messages sent: 0
       Socket messages received: 0
       Signals delivered: 0
       Page size (bytes): 4096
       Exit status: 0


2
Вы случайно не знаете, из какого пакета Debian это будет? кажется, не устанавливается по умолчанию
ʞɔıu

1
Я ссылался на твой пост Роберт. Если вы не имеете в виду, что предложенная вами команда не является встроенной в bash?
grepsedawk

24
Удивительно, но он устанавливается из пакета под названием «время».
Пол Томблин

2
Выходные данные из / usr / bin / time выглядят так: «0.00user 0.00system 0: 02.00 истек 0% CPU (0avgtext + 0avgdata 0maxresident) k 0inputs + 0outputs (0major + 172minor) pagefaults 0swaps»
Пол Томблин

4
@Nick: "sudo apt-get время установки".
Роберт Гэмбл

79
#!/bin/bash
START=$(date +%s)
# do something
# start your script work here
ls -R /etc > /tmp/x
rm -f /tmp/x
# your logic ends here
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"

14
Есть намного более простой способ. Bash вычисляет автоматически специальную переменную $ SECONDS, после чего пересчет на основе внешней команды даты не требуется. Переменная $ SECONDS сохраняет количество секунд, в течение которых запускается bash-скрипт. Эта переменная имеет какое-то специальное свойство. Смотрите
справочную

Я попробовал оба выше и метод в комментарии. В первом я получаю ошибку «
Недопустимая

45

Для построчного измерения дельты попробуйте gnomon .

Утилита командной строки, немного похожая на команду moreutils, для добавления метки времени к стандартному выводу другой команды. Полезно для длительных процессов, где вы хотите получить исторический отчет о том, что занимает так много времени.

Вы также можете использовать опции --highи / или --medium, чтобы указать порог длины в секундах, в течение которого гномон будет выделять метку времени красным или желтым цветом. И вы можете сделать еще несколько вещей.

пример


3
Отличный совет, но только для ясности: это полезно для построчной синхронизации , но накладные расходы на такую ​​мелкую синхронизацию значительно увеличивают общую синхронизацию.
mklement0

2
Отличная утилита .. Спасибо за то, что поделились
Kishan B

19

Если вы хотите большей точности, используйте %Nс date(и используйте bcдля сравнения, потому что $(())только обрабатывает целые числа).

Вот как это сделать:

start=$(date +%s.%N)
# do some stuff here
dur=$(echo "$(date +%s.%N) - $start" | bc)

printf "Execution time: %.6f seconds" $dur

Пример:

start=$(date +%s.%N); \
  sleep 0.1s; \
  dur=$(echo "$(date +%s.%N) - $start" | bc); \
  printf "Execution time: %.6f seconds\n" $dur

Результат:

Execution time: 0.104623 seconds

15

Если вы собираетесь использовать время позже для вычисления, узнайте, как использовать -fопцию /usr/bin/timeдля вывода кода, который экономит время. Вот некоторый код, который я недавно использовал, чтобы получить и отсортировать время выполнения целого ряда студенческих программ:

fmt="run { date = '$(date)', user = '$who', test = '$test', host = '$(hostname)', times = { user = %U, system = %S, elapsed = %e } }"
/usr/bin/time -f "$fmt" -o $timefile command args...

Позже я объединил все $timefileфайлы и направил вывод в интерпретатор Lua . Вы можете сделать то же самое с Python или Bash или любой другой ваш любимый синтаксис. Я люблю эту технику.


Примечание: полный путь /usr/bin/timeнеобходим, потому что, хотя which timeвы скажете иначе, если вы просто запустите time, он запустит версию вашей оболочки, timeкоторая не принимает никаких аргументов.
Кевин Дайс


13

Если вам нужна только точность с точностью до секунды, вы можете использовать встроенную $SECONDSпеременную, которая подсчитывает количество секунд, в течение которых работает оболочка.

while true; do
    start=$SECONDS
    some_long_running_command
    duration=$(( SECONDS - start ))
    echo "This run took $duration seconds"
    if some_condition; then break; fi
done

10

Вы можете использовать timeи subshell () :

time (
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
)

Или в той же оболочке {}:

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}

Вы разместили два идентичных фрагмента кода. Должно быть, вы хотели иметь что-то другое.
Стасон

3
@StasBekman не соответствует действительности, сначала используется (& )(новый контекст, subshell ), а другие - с {& }(та же оболочка, тот же контекст)
Эдуардо Куомо

Ага! Я очень внимательно смотрел на них и не видел разницы. Спасибо за разъяснение, что {} vs ().
Стасон

2

Путь

$ > g++ -lpthread perform.c -o per
$ > time ./per

вывод >>

real    0m0.014s
user    0m0.010s
sys     0m0.002s

Не нужно использовать -lphtreadили -oтеги. Просто нужно использовать timeкоманду, которую принятый ответ объясняет лучше.
Деннис

7
Это был пример. То есть у моего execute.c есть потоки, поэтому мне нужен -lpthread, и для простоты идентификации это -o per.
Робел Шарма

0

Один, возможно, простой метод (который может не отвечать потребностям разных пользователей) - это использование оболочки PROMPT.it - ​​простое решение, которое может быть полезно в некоторых случаях. Вы можете использовать функцию подсказок bash, как в примере ниже:

экспорт PS1 = '[\ t \ u @ \ h] \ $' 

Приведенная выше команда приведет к изменению приглашения оболочки на:

[ЧЧ: ММ: имя пользователя SS @ имя хоста] $ 

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

примечания:
1) имейте в виду, что если вы подождали какое-то время, прежде чем вводить следующую команду, то это время необходимо учитывать, т. е. время, отображаемое в приглашении оболочки, является меткой времени, когда отображалось приглашение оболочки, а не при вводе команды. некоторые пользователи нажимают клавишу Enter, чтобы получить новое приглашение с новой отметкой времени, прежде чем они будут готовы к следующей команде.
2) Существуют другие доступные опции и модификаторы, которые можно использовать для изменения приглашения bash, обратитесь к (man bash) для более подробной информации.


Не точка, в которой выполняется программа, а продолжительность выполнения программы.
Гено Чен,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.