Doug Hoyte

NAME

Timer::CPU - Precise user-space timer using the CPU clock

SYNOPSIS

    use Timer::CPU;

    my $elapsed_ticks = Timer::CPU::measure(sub {
      ## Do stuff
    });

DESCRIPTION

For most timer operations, Time::HiRes is great. Since it provides microsecond resolution in real "wall-clock" time it is very useful for determining how long an operation actually takes in seconds.

However, on most CPUs it is possible to take much higher resolution measurements. These measurements aren't in absolute units like seconds but instead in "cycles" or "ticks". These measurements relate to wall-clock time via an unspecified conversion ratio and can therefore only be used for relative comparisons between code on the same machine (and are subject to other constraints described below).

The resolution of this module is extremely high. For example, it can detect the difference between a sub that returns nothing, one that returns a number, and one that returns an empty string. It can detect whether an if branch is taken or not, and even the difference between eq comparing strings that match and strings that differ by only the last character.

USAGE

This module provides one function: Timer::CPU::measure. Its first argument should be a callback code-ref. This is the code to be benchmarked. It is always called in void context. The return value is a number that corresponds to how many CPU cycles were spent executing your callback.

The following other arguments can be passed in as keyword arguments: warm_ups, iterations, and method. For example:

    say Timer::CPU::measure(sub { },
                            warm_ups => 10,
                            iterations => 50000,
                            method => 'median');

measure will first invoke your provided callback warm_ups times (default is 2) and throw away the timing results. It will then invoke your callback iterations times (default is 1000), recording the number of ticks elapsed for each invocation. Finally, it will return a summary of the results according to the method parameter which should be one of min, max, mean, or median. The default method is min.

CAVEATS

There are many caveats to this timing technique, but there are caveats to all timing techniques.

It can be difficult to measure perl code by ticks elapsed because, compared to C, perl code typically does a lot "under the hood".

On x86 and x86-64, this module uses the rdtsc ("ReaD Time-Stamp Counter") instruction. On SPARC it accesses the %tick register which is a 64-bit counter incremented every cycle. Various other CPUs might work (see cycle.h) although they haven't been tested. An architecture that is noticeably missing is ARM.

As mentioned above, the real "wall-clock" time duration of a tick isn't necessarily known. You may be able to figure out the clock frequency with Sys::Info::Device::CPU, but (on x86/x86-64) you should first verify your CPU is modernish and has a constant time-stamp counter (look for "constant_tsc" in /proc/cpuinfo if you are on linux).

If your kernel context-switches out your process your timing data will be corrupted. While performing benchmarks you should consider running in single-user mode or, if you have multiple CPUs/cores, pegging your process to a particular CPU (with something like Sys::CpuAffinity).

Many CPUs have the ability to dynamically scale their clock speed in order to save power. If the CPU your process is running on changes clock speed during your measurements your data will be corrupted. You should consider fixing your CPU to a constant clock speed while running benchmarks.

If the machine is hibernated or suspended, data will be corrupted also.

On some architectures, operating systems can disable access to the time-stamp counter (ie by setting a bit in the CR4 register on x86). This is uncommon but is sometimes done in virtualised environments to protect against harvesting information from timing side-channels.

SEE ALSO

Timer-CPU github repo

Time::HiRes

Time-Stamp Counter

String::Compare::ConstantTime

AUTHOR

Doug Hoyte, <doug@hcsw.org>

The tick collection routines are copied from the file cycle.h in the FFTW 3 project. They are written by Matteo Frigo and contributors (see source code) and are distributed under the MIT license.

COPYRIGHT & LICENSE

Copyright 2013-2014 Doug Hoyte.

This module is licensed under the same terms as perl itself.