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

309

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

Я знаю, что я мог бы написать perl или python script, чтобы это сделать, но есть ли способ сделать это в оболочке? (что бывает bash)

Показать ещё 1 комментарий
Теги:

9 ответов

377
Лучший ответ

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

$ help time

time: time [-p] PIPELINE
    Execute PIPELINE and print a summary of the real time, user CPU time,
    and system CPU time spent executing PIPELINE when it terminates.
    The return status is the return status of PIPELINE.  The `-p' option
    prints the timing summary in a slightly different format.  This uses
    the value of the TIMEFORMAT variable as the output format.

Пример:

$ time sleep 2
real    0m2.009s
user    0m0.000s
sys     0m0.004s
  • 0
    Как это используется в такой команде, как time -pi=x; while read line; do x=x; done < /path/to/file.txt ? Он сразу возвращает 0.00, если я не помещаю ничего перед циклом while ... что дает?
  • 0
    это плохая «временная» версия, встроенная в bash. где находится внешняя команда времени?
Показать ещё 4 комментария
86

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

Примечание редактора: Чтобы убедиться, что вы вызываете внешнюю утилиту time, а не ключевое слово оболочки time, вызовите ее как /usr/bin/time.
time является POSIX-обязательной утилитой, но единственным вариантом, который требуется для поддержки, является -p.
Конкретные платформы реализуют конкретные нестандартные расширения: -v работает с утилитой GNU 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

  • 1
    Вы случайно не знаете, из какого пакета Debian это будет? не устанавливается по умолчанию
  • 1
    Я ссылался на твой пост Роберт. Если вы не имеете в виду, что предложенная вами команда не является встроенной в bash?
Показать ещё 8 комментариев
61
#!/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 при запуске. Эта переменная имеет некоторые специальные свойства. Смотрите справочную страницу: D
  • 0
    Я попробовал оба выше и метод в комментарии. В первом я получаю ошибку «Недопустимая переменная», а во втором я получаю «Неопознанная переменная»
14

Для линейного дельта-измерения попробуйте gnonom.

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

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

Изображение 3896

  • 1
    Отличный совет, но только для ясности: это полезно для построчной синхронизации, но издержки, связанные с такими мелкими моментами, значительно увеличивают общую синхронизацию.
  • 2
    Отличная утилита .. Спасибо, что поделились
Показать ещё 1 комментарий
13

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

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

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
11

Если вы собираетесь использовать время позже для вычисления, узнайте, как использовать параметр -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 или любым вашим любимым синтаксисом. Мне нравится эта техника.

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

Если вам нужна только точность во второй, вы можете использовать встроенную переменную $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
2

Вы можете использовать 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
}
  • 0
    Вы разместили два идентичных фрагмента кода. Должно быть, вы хотели иметь что-то другое.
  • 3
    @StasBekman не соответствует действительности, сначала используется ( & ) (новый контекст, subshell ), а другие с { & } (та же оболочка, тот же контекст)
Показать ещё 1 комментарий
1

Способ

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

вывод →

real    0m0.014s
user    0m0.010s
sys     0m0.002s
  • 0
    Нет необходимости использовать -lphtread или -o . Просто нужно использовать команду time , которую принятый ответ объясняет лучше.
  • 7
    Это был пример. То есть у моего execute.c есть потоки, поэтому мне нужен -lpthread, и для простоты идентификации это -o per.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню