私の理解では、time
はシステムコールに費やされた合計時間を記録します。次に、time
とstrace -fc
によって報告されるsys時間の累積合計が同じになると予想します。しかし、それらは大きく異なります(13.5対0.005)。何が起こっている?
# time php index.php >/dev/null
real 0m16.292s
user 0m2.728s
sys 0m13.548s
# strace -fc php index.php >/dev/null
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
83.72 0.000365 0 54845 munmap
10.09 0.000044 0 36705 mmap
6.19 0.000027 0 18249 madvise
0.00 0.000000 0 289 read
0.00 0.000000 0 119 write
0.00 0.000000 0 118 3 open
0.00 0.000000 0 118 close
0.00 0.000000 0 23 stat
[ cut 0 duration syscalls for brevity ]
100.00 0.000436 110951 82 total
(これらのテストを約50回再実行しましたが、どちらも一貫した結果が得られます)
プロセスは、システムコールを実行せずに任意の時間を費やすことができます。
たとえば、_while :; do :; done
_を実行するシェルは、システムコールを実行せず、sys
CPU時間を費やさず、user
CPU時間のみを費やす無限の時間を費やします。
_strace -c
_は、システムコールごとにsys
CPU時間をカウントしようとします。 nanosleep(1000000000)
は、CPU時間は0ミリ秒近くかかりますが、実時間は1秒です。
_$ bash -c 'time strace -fc sleep 1'
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
[...]
0.00 0.000000 0 1 nanosleep
[...]
100.00 0.000000 33 3 total
real 0m1.006s
user 0m0.001s
sys 0m0.003s
_
Sys時間をstraceによって報告された時間と比較する方が理にかなっていますが、プロセスに割り当てられたすべてのsysCPU時間がこれらのsyscallに費やされているわけではないことに注意してください。たとえば、mmapされたデータにアクセスすると、プロセスはシステムコールを実行せずに多くのシステム時間を費やす可能性があります。
ここで、これらの多数のmmaps()
呼び出しは、メモリを割り当てることである可能性があります。それらはいくつかのマッピングを更新するだけなので、瞬時に実行されます。しかし、それらに初めて書き込むときは、実際のメモリでそれらの書き込みをバックアップするためにシステム時間が必要になる場所です。
または、共有ライブラリのようなオブジェクトファイルをマップすることもできます(数がopen()s
の数からそれほど遠くないため、これも可能性があります)。繰り返しになりますが、mmap()
は高速ですが、後でメモリを読み取ることは、ページフォールトと、ディスクからデータを読み取る実際の時間も意味します。これは、システムコールには含まれません。
より基本的には、以前のバージョンの質問のように_time strace -f your-application
_を実行すると、time
はコマンドとstrace
の両方の時間を計測します。
strace
は多くのオーバーヘッドを追加します。 stracedアプリケーションのシステムコールごとにいくつかのシステムコールを実行します。
やってる
_strace -fc time your-application
_
の代わりに
_time strace -fc your-application
_
より良い一致を与える可能性が高くなります。
しかし、私が見つけたのは、プロセスが子を待機するために行うwait*()
システムコールの場合、strace
はそれらのwait*()
システムコールによって報告された時間をシステム時間としてカウントするということです。これは、子プロセス(少なくとも待機中のプロセス)の時間が数回カウントされることを意味します。 time
は子プロセスでcmd
を実行し、それを待機するため、これは_strace -f time cmd
_で重要です。
_$ strace -c time head -c 100M /dev/urandom > /dev/null
0.00user 0.76system 0:00.76elapsed 99%CPU (0avgtext+0avgdata 1796maxresident)k
0inputs+0outputs (0major+83minor)pagefaults 0swaps
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.762288 762288 1 wait4
0.00 0.000000 0 1 read
0.00 0.000000 0 112 write
0.00 0.000000 0 2 open
0.00 0.000000 0 2 close
0.00 0.000000 0 2 fstat
0.00 0.000000 0 6 mmap
0.00 0.000000 0 4 mprotect
0.00 0.000000 0 1 munmap
0.00 0.000000 0 1 brk
0.00 0.000000 0 4 rt_sigaction
0.00 0.000000 0 3 3 access
0.00 0.000000 0 1 clone
0.00 0.000000 0 1 execve
0.00 0.000000 0 1 Arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00 0.762288 142 3 total
_
time
とstrace
は同じシステム時間(wait4()
システムコールによって返される)を報告しますが、_-f
_を使用します:
_$ strace -fc time head -c 100M /dev/urandom > /dev/null
strace: Process 2298 attached
0.01user 1.33system 0:01.91elapsed 69%CPU (0avgtext+0avgdata 1920maxresident)k
0inputs+0outputs (0major+84minor)pagefaults 0swaps
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
54.60 1.331335 1331335 1 wait4
39.43 0.961497 75 12804 read
5.94 0.144825 6 25711 write
0.01 0.000148 11 13 6 open
0.00 0.000104 8 13 mmap
0.00 0.000094 19 5 3 execve
0.00 0.000063 8 8 mprotect
0.00 0.000050 6 9 close
0.00 0.000041 7 6 6 access
0.00 0.000037 5 7 fstat
0.00 0.000031 16 2 munmap
0.00 0.000030 8 4 brk
0.00 0.000007 4 2 Arch_prctl
0.00 0.000006 6 1 1 ioctl
0.00 0.000000 0 4 rt_sigaction
0.00 0.000000 0 1 clone
------ ----------- ----------- --------- --------- ----------------
100.00 2.438268 38591 16 total
_
1.33 istime
が行う1つのwait4()
システムコールによって報告される時間。これは、head
(time
の子)のsys時間を報告します。
ただし、strace
は、その上にhead
孫のすべてのシステムコールのシステム時間を取得しようとします。これは、2回カウントされることを意味します(正確ではありません)。孫のそのストレーシングは、以前の0.76ではなく1.33を取得するため、ストレースされたプロセスに起因するオーバーヘッドが発生します。 strace、time、headを同じプロセッサで強制的に実行すると(_taskset 1
_を使用)、これは大幅に削減されます。