Linux / コマンド / time - コマンド実行時間の測定

timeはコマンドやパイプラインが実行されるのにかかった時間やCPU使用時間を測定します。Bashのtime予約語ではシェル組み込みコマンド・関数・パイプラインまで測定でき、外部GNU /usr/bin/timeではメモリや入出力など詳細なリソース使用量を提供できます。

単純な速度確認にはBash timeが便利で、最大メモリやページフォルトなどOSレベルの統計が必要な場合は外部timeを明示的に実行するのがよいでしょう。

timeコマンドとは?

Bashではtimeが通常の実行ファイルより先に構文として認識される予約語です。予約語であるため、1つの外部プログラムだけでなくパイプライン全体、シェル関数や組み込みコマンドも自然に測定できます。

多くのLinuxシステムには別途GNU Timeの実行ファイルもインストールされています。同じ名前ですがオプションや出力情報が異なるので、次のコマンドで現在の環境を確認してください。

type -a time
command -V time
ls -l /usr/bin/time

Bash time基本構文

time [-p] コマンド [引数 ...]
time [-p] コマンド1 | コマンド2

測定するコマンドの前にtimeを付けます。

time sleep 1
time find /usr -type f >/dev/null

コマンドが終了すると、通常 real、user、sys の3つの値が表示されます。

real、user、sys の意味

項目 意味
real 開始から終了までの実際に経過した時間です。ディスク・ネットワーク待ちや他のプロセスのために待った時間も含まれます。
user プロセスがユーザーモードで CPU を使用した累積時間です。
sys プロセスのためにカーネルモードで使用した累積 CPU 時間です。

複数のコアや複数のプロセスを並列で使用すると、user + sys が real より大きくなることがあります。逆に入出力待ちが長いと real は大きいが CPU 時間は少ない場合があります。時間が表示されたことは処理成功の証明ではありません。参照権限などのエラーを確認し、同じ入力と正常終了の条件を揃えて比較してください。

パイプライン全体の測定

Bash の予約語 time は、続くパイプライン全体が終了するまで測定します。

time find /var/log -type f -print0 | xargs -0 wc -l >/dev/null

パイプラインの最初のコマンドだけを個別に測定したい場合は、グループを明確に構成するか、外部ツールを使用する際に測定範囲に注意する必要があります。測定したい作業の開始点と終了点を最初に決めることが重要です。

複数のコマンドを1つの作業として測定する

以下は、使用する Makefile とビルドスクリプトが準備されたプロジェクトでの例です。make clean の削除対象を確認し、/srv/app は実際の作業ディレクトリに置き換えます。最初の例は clean に成功した場合だけ次へ進み、次の例は移動に失敗したらサブシェルを終了します。job.sh も自分で用意した実行可能な作業スクリプトに置き換えてください。

コマンドリストを中括弧やサブシェルでまとめると、全体の時間を測定できます。

time {
  make clean &&
  make -j4
}
time (
  cd /srv/app || exit 1
  ./build.sh
)

中括弧グループは現在のシェルで実行され、丸括弧グループはサブシェルで実行されます。作業中にディレクトリや変数が変わる場合は、この違いを考慮してください。

移植可能な出力形式 -p

time -p sleep 1

-p は POSIX 形式の real、user、sys の出力を使用します。複数のシステムで結果を単純に解析する必要がある場合に便利ですが、ロケールや精度まで含めた自動化の要件は別途検討する必要があります。Bash の POSIX モードでは、次の単語がハイフンで始まる場合に time を予約語として認識しないため、同じ書き方でも外部 time が必要になることがあります。対象シェルと実装を確認してください。

TIMEFORMAT で Bash 出力を変更する

Bash の予約語の出力は TIMEFORMAT 変数で調整できます。

TIMEFORMAT='elapsed=%3R s user=%3U s sys=%3S s'
time sleep 1
形式 意味
%R 経過時間
%U ユーザーモードCPU時間
%S システムモードCPU時間
%P CPU使用率をパーセンテージで表示
%% リテラルパーセント記号

TIMEFORMATは現在のシェルに影響します。一時的に適用する場合は、既存の値を保持するか、サブシェル内で設定してください。

(
  TIMEFORMAT='elapsed=%R s'
  time ./job.sh
)

外部GNU timeの使用

外部コマンドのオプションを確実に使用するには、フルパスを指定してください。

/usr/bin/time ./job.sh
/usr/bin/time -v ./job.sh

-vは、最大常駐メモリ、ページフォルト、ファイルシステム入出力、コンテキストスイッチなど、システムが提供する詳細な情報を出力します。実際に提供される項目と値は、オペレーティングシステムによって異なる場合があります。

GNU timeのよく使われるオプション

オプション 説明
-p POSIX形式で時間を出力します。
-v 利用可能なリソース統計を詳しく出力します。
-f 形式 フォーマット指定子で出力内容を構成します。
-o ファイル 測定結果を指定したファイルに書き込みます。
-a -oファイルを上書きせずに末尾に追加します。

必要な形式で時間とメモリを出力する

/usr/bin/time -f 'elapsed=%e max_rss=%MKB' ./job.sh

%eは経過時間、%Mは最大常駐メモリサイズを示します。GNU Time のマニュアルは %M をキロバイト単位の最大常駐メモリと説明しています。仮想メモリサイズやホスト全体の使用量ではありません。項目のサポートは現在のオペレーティングシステムでも確認してください。

測定結果をファイルに保存

/usr/bin/time -v -o time-report.txt ./job.sh
/usr/bin/time -v -a -o time-report.txt ./job.sh

-oを使用すると、測定対象コマンドの標準エラーと時間レポートを分離でき、自動化に便利です。

time出力が標準エラーに出る理由

時間情報は基本的に標準エラーに出力されます。測定対象コマンドの標準出力がパイプやファイルに送られても、時間結果が混ざらないようにするための動作です。

time ./job.sh >job-output.txt

このコマンドは作業の標準出力のみをファイルに保存し、時間情報はターミナルに表示します。Bash予約語の時間情報だけを別にリダイレクトするには、グループ全体の標準エラーを扱う必要がありますが、そうすると作業自体の標準エラーも一緒に入り得ます。

{ time ./job.sh >job-output.txt; } 2>time-and-errors.txt

時間レポートだけを分離するには、外部GNU Timeの-oの方がより明確です。

正確な比較のための注意点

  • 最初の実行とその後の実行は、ファイルシステムキャッシュ、実行時コンパイル(JIT、Just-In-Time compilation)、接続の再利用によって異なる場合があります。
  • バックグラウンド負荷、CPU周波数の調整、仮想マシン資源の競合を制御します。
  • 非常に短い命令は、測定自体のオーバーヘッドが結果に大きな影響を与えます。
  • 複数回繰り返して中央値や分布を比較します。
  • 出力先がターミナルかファイルかによって、実行時間は異なる場合があります。
  • 速度差が実際の作業結果やエラー率を変えないかも確認します。

Bash timeと/usr/bin/timeの比較

区分 Bash time GNU /usr/bin/time
種類 Bashの予約語 外部実行ファイル
パイプライン 全体のパイプラインを直接測定するのは簡単です。 基本的に指定したプログラムを実行します。
シェル関数・組み込みコマンド 直接測定することができます。 別のシェルを経由しないと直接実行するのは難しいです。
詳細なリソース情報 基本時間統計が中心です。 -vはメモリや入出力などの統計を提供します。
出力のカスタマイズ TIMEFORMAT -f, -o, -a

よくある質問

realよりuser時間の方が大きくなることはありますか?

可能です。複数のプロセスやCPUコアで使用したCPU時間が累積すると、実際の経過時間よりもユーザーCPU時間が大きくなることがあります。

time -vが動作しません。

Bashの予約語が先に解釈されるためかもしれません。GNU Timeがインストールされている場合は/usr/bin/time -v コマンドのようにフルパスを使用してください。

timeはコマンドの終了状態を変更しますか?

一般的に、測定対象のコマンドやパイプラインの終了状態を返します。パイプラインでは、Bashのpipefail設定によって結果が異なる場合があります。

参考資料