プロセスの実行時間などを知りたいですか? Linux の time コマンドは時間統計を返し、プログラムで使用されているリソースについての優れた洞察を提供します。
時間には多くの親戚がいる
多くの Linux ディストリビューションと、さまざまな Unix 系オペレーティング システムが存在します。これらにはそれぞれデフォルトのコマンド シェルがあります。最新の Linux ディストリビューションで最も一般的なデフォルト シェルは bash シェルです。ただし、Z シェル (zsh) や Korn シェル (ksh) など、他にもたくさんあります。
これらのシェルにはすべて、 組み込み コマンドまたは 予約語 として独自の time コマンドが組み込まれています。ターミナル ウィンドウに時間を入力すると、シェルは、Linux ディストリビューションの一部として提供される GNU 時刻バイナリを使用する代わりに、内部コマンドを実行します。
GNU バージョンの time を使用したいのは、より多くの オプション があり、より柔軟であるためです。
何時に実行されますか?
type コマンドを使用して、どのバージョンが実行されるかを確認できます。 type は、シェルが内部ルーチンを使用して命令自体を処理するか、または GNU バイナリに渡すかを示します。ターミナル ウィンドウで、「 type 」 、「スペース」、「 time」 という単語を入力して Enter キーを押します。
時間を入力してください
bash シェルでは time が予約語であることがわかります。これは、Bash がデフォルトで内部時間ルーチンを使用することを意味します。
時間を入力してください
Z シェル (zsh) では、時間は予約語であるため、内部シェル ルーチンがデフォルトで使用されます。
時間を入力してください
Korn シェルでは時間はキーワードです。 GNU time コマンドの代わりに内部ルーチンが使用されます。
GNU time コマンドの実行
Linux システム上のシェルに内部時刻ルーチンがある場合、GNU 時刻バイナリを使用したい場合は明示的に指定する必要があります。次のいずれかを行う必要があります。
- /usr/bin/time など、バイナリへの完全なパスを指定します。 where time コマンドを実行して、このパスを見つけます。
-
command timeを使用します。 -
\timeのようなバックスラッシュを使用します。
which time
コマンドを使用すると、バイナリへのパスが得られます。
/usr/bin/time
をコマンドとして使用して GNU バイナリを起動することで、これをテストできます。それはうまくいきます。
time
コマンドから、それが動作するためのコマンド ライン パラメーターが提供されていないことを示す応答が返されます。
command time
を入力することも機能し、
time
から同じ使用法情報を取得します。
command
コマンドは、次のコマンドを無視するようにシェルに指示し、コマンドがシェルの外で処理されるようにします。
コマンド名の前に
\
文字を使用することは、コマンド名の前に
command
を使用することと同じです。
GNU
time
バイナリを使用していることを確認する最も簡単な方法は、バックスラッシュ オプションを使用することです。
時間
\時間
time
time のシェルバージョンを呼び出します。
\time
time
バイナリを使用します。
time コマンドの使用
いくつかのプログラムの時間を計ってみましょう。ここでは、
loop1
と
loop2
という 2 つのプログラムを使用しています。これらはloop1.cとloop2.cから作成されました。これらは、ある種のコーディングの非効率性の影響を実証すること以外には何も役に立ちません。
これはloop1.cです。 2 つのネストされたループ内では文字列の長さが必要です。長さは、2 つのネストされたループの外側で事前に取得されます。
#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
これにより 2 セットの結果が得られましたが、それらは非常に醜い形式になっています。これについては後で何とかすることができますが、結果からいくつかの情報を抜粋してみましょう。
プログラムを実行するときは 2 つの実行モードがあり、それらの間で切り替えられます。これらはユーザー モードとカーネル モードと呼ばれます。
簡単に言うと、ユーザー モードのプロセスは、ハードウェアに直接アクセスしたり、独自の割り当て以外のメモリを参照したりすることはできません。このようなリソースにアクセスするには、プロセスはカーネルにリクエストを行う必要があります。カーネルがリクエストを承認すると、プロセスは要件が満たされるまでカーネル モードの実行に入ります。その後、プロセスはユーザー モードの実行に戻ります。
loop1
の結果から、
loop1
ユーザー モードで 0.09 秒を費やしたことがわかります。カーネル モードで費やした時間がゼロであるか、切り捨てられた後でカーネル モードでの時間が登録するには低すぎる値です。合計経過時間は 0.1 秒でした。
loop1
、合計経過時間全体で平均 89% の CPU 時間が与えられました。
非効率的な
loop2
プログラムの実行には 3 倍の時間がかかりました。合計経過時間は 0.3 秒です。ユーザーモードでの処理時間は0.29秒です。カーネル モードには何も登録されていません。
loop2
は、実行中に平均 96% の CPU 時間が与えられました。
出力のフォーマット
フォーマット文字列を使用して、
time
からの出力をカスタマイズできます。書式文字列には、テキストと書式指定子を含めることができます。形式指定子のリストは、
time
の
マニュアル ページにあります
。それぞれの形式指定子は 1 つの情報を表します。
文字列が出力されると、形式指定子はそれが表す実際の値に置き換えられます。たとえば、CPU の割合を表す形式指定子は文字
P
です。形式指定子が単なる通常の文字ではない
time
を示すには、
%P
のようにパーセント記号を追加します。例で使用してみましょう。
-f
(フォーマット文字列) オプションは、後に続くものがフォーマット文字列であることを
time
通知するために使用されます。
フォーマット文字列は、「Program:」という文字とプログラムの名前 (およびプログラムに渡すコマンド ライン パラメーター) を出力します。
%C
形式指定子は、「時間を計測するコマンドの名前とコマンドライン引数」を表します。
\n
により、出力は次の行に移動します。
形式指定子は多数あり、大文字と小文字が区別されるため、自分でこれを行う場合は、形式指定子が正しく入力されていることを確認してください。
次に、文字 “Total time: ” の後に、プログラムの今回の実行の合計経過時間の値 (%E で表されます) を出力します。
\n を使用して別の改行を指定します。次に、「User Mode (s)」という文字の後に、%U で示されるユーザー モードで費やされた CPU 時間の値が表示されます。
\n を使用して別の改行を指定します。今回はカーネル時間の値を準備します。 「Kernel Mode (s) 」という文字と、その後にカーネル モードで費やされた CPU 時間の形式指定子 (%S) が出力されます。
最後に、文字 “\nCPU: ” を出力して、このデータ値の改行とタイトルを指定します。 %P 形式指定子は、時間指定されたプロセスによって使用される CPU 時間の平均パーセンテージを示します。
フォーマット文字列全体は引用符で囲まれます。値の配置にこだわる場合は、出力にタブを配置するために \t 文字をいくつか含めることもできます。
\time -f "プログラム: %C\n合計時間: %E\nユーザー モード (秒) %U\nカーネル モード (秒) %S\nCPU: %P" ./loop1
出力をファイルに送信する
実行したテストのタイミングを記録するには、出力をファイルに送信できます。これを行うには、-o (出力) オプションを使用します。プログラムからの出力は引き続きターミナル ウィンドウに表示されます。ファイルにリダイレクトされるのは、時刻からの出力のみです。
次のようにテストを再実行し、出力を test_results.txt ファイルに保存できます。
\time -o test_results.txt -f "プログラム: %C\n合計時間: %E\nユーザー モード (s) %U\nカーネル モード (s) %S\nCPU: %P" ./loop1
猫のテスト結果.txt
ループ 1 プログラムの出力がターミナル ウィンドウに表示され、時間ごとの結果が test_results.txt ファイルに保存されます。
次の結果セットを同じファイルにキャプチャする場合は、次のように -a (追加) オプションを使用する必要があります。
\time -o test_results.txt -a -f "プログラム: %C\n合計時間: %E\nユーザー モード (秒) %U\nカーネル モード (秒) %S\nCPU: %P" ./loop2
猫のテスト結果.txt
%C 書式指定子を使用して、書式文字列からの出力にプログラムの名前を含めた理由が明らかになるはずです。
そして時間切れです
おそらく、プログラマーや開発者がコードを微調整するために最もよく使用される time コマンドは、プログラムを起動するたびに内部で何が起こっているのかをもう少し詳しく知りたい人にも役立ちます。





