Processes · Time

times#

Report CPU time consumed by this process and its terminated children.

times asks the kernel how many seconds of user-mode and kernel-mode CPU have been charged to the current process, and — separately — to children that have already been reaped. The return is four floating- point seconds: user, system, child-user, child-system. It answers “how much CPU have I burned?”, not “how much wall-clock time has passed?” — for that, see time.

Synopsis#

my ($user, $system, $cuser, $csystem) = times;
my $user_only                         = times;    # scalar context

What you get back#

In list context, four values:

  • $user — CPU time spent in user-mode code of this process.

  • $system — CPU time spent in the kernel on behalf of this process.

  • $cuser — user-mode CPU time of terminated child processes.

  • $csystem — kernel-mode CPU time of terminated child processes.

All four are seconds as double-precision floats; resolution is microsecond on Linux (sourced from getrusage).

In scalar context, times returns just $user.

times takes no arguments and cannot fail in a way visible to the caller.

Children’s times — the “terminated” rule#

$cuser and $csystem aggregate CPU only from children that have been reaped — i.e. a wait or waitpid has successfully collected their exit status, or they were autoreaped because $SIG{CHLD} was set to 'IGNORE'. A child that is still running, or has exited but not yet been reaped (a zombie), contributes nothing.

This matters when measuring a pipeline that spawns workers:

my $pid = fork;
if ($pid == 0) { do_work(); exit }
# (busy child runs here)
my ($u0, $s0, $cu0, $cs0) = times;     # $cu0, $cs0 still 0
waitpid($pid, 0);
my ($u1, $s1, $cu1, $cs1) = times;     # now $cu1, $cs1 reflect child

Until the waitpid returns, the child’s CPU does not appear in the parent’s times.

Examples#

Measure CPU cost of a block of work, excluding wall-clock sleeps or I/O waits:

my ($u0, $s0) = times;
compute_heavy();
my ($u1, $s1) = times;
printf "compute used %.3f s user + %.3f s system\n",
       $u1 - $u0, $s1 - $s0;

Compare CPU time to wall-clock time — a low ratio means the process was mostly waiting rather than computing:

use Time::HiRes qw(time);
my $t0 = time;
my ($u0, $s0) = times;
do_mixed_io_and_compute();
my $wall = time - $t0;
my ($u1, $s1) = times;
printf "cpu/wall = %.2f\n", ($u1 - $u0 + $s1 - $s0) / $wall;

Attribute a parallel workload to its children. Reap every child before reading times:

my @pids = map { my $p = fork; $p == 0 ? (worker($_), exit) : $p } 1..4;
waitpid($_, 0) for @pids;
my (undef, undef, $cu, $cs) = times;
printf "workers used %.2f s user + %.2f s system\n", $cu, $cs;

Scalar context when only the user time matters — e.g. a quick self-profiling print:

printf STDERR "[%.2f] reached checkpoint\n", scalar times;

Edge cases#

  • No arguments, no prototype to worry about. times is a zero-argument built-in; times() and times parse identically. It is not the transliteration operator — that is tr/// (alias y///), which is a separate token.

  • Scalar vs list context is load-bearing. Writing my $t = times; binds $user to $t, discarding the other three values silently. Use my ($u,$s,$cu,$cs) = times; when you want them all.

  • Unreaped children don’t count. See the “terminated” rule above. Reading times before wait gives $cuser == $csystem == 0 even when the child is visibly burning CPU in top.

  • Threads do count. On Linux, kernel-threaded work in the current process shows up in $user / $system just like single-threaded work. Threads in a separate process don’t, until that process exits and is reaped.

  • Clock is monotonic-within-process, not wall-clock. times never goes backwards across a single process’s lifetime, but successive times calls are not directly comparable between parent and child — each getrusage accounting is local.

  • Resolution. Linux reports microsecond-resolution ticks via getrusage, so short measurements (sub-millisecond) are noisy but not zero. For high-precision wall-clock timing, use Time::HiRes::time, not times.

  • Overflow. Values are floats; they can in principle lose sub-microsecond precision after very long runs (years of CPU), but this is not a concern for normal programs.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • time — wall-clock seconds since the epoch; use it when you want elapsed real time, not CPU time

  • Time::HiRes::time — high-resolution wall-clock time, the usual partner for CPU accounting

  • POSIX::times — POSIX wrapper returning an additional real-time “clock ticks since boot” value; use it when you need the elapsed field the built-in omits

  • wait — reap a child so its CPU starts counting in $cuser / $csystem

  • waitpid — reap a specific child for the same reason, without blocking on unrelated ones

  • fork — the operation whose cost shows up in the child columns once the child is reaped