Here is how libcpucycles decides which cycle counter to use. The
underlying principles are as follows:

* Failure is not allowed. Using a low-resolution timer such as
  `gettimeofday()` to estimate cycle counts is not desirable but is better
  than providing no information.

* A counter that does well on some CPUs and OSes can do badly on others.
  The counter selection in libcpucycles is based not just on rules set
  at compile time but also on measurements of how well the counters
  perform when the program first calls `cpucycles()`.

* A critical application of cycle counting is collecting cycle counts
  for multiple options to see which option is faster.
  It is the caller's responsibility,
  given cycle counts for many runs of whichever function is being benchmarked,
  to compute robust statistics
  such as [stabilized quartiles](https://cr.yp.to/papers.html#rsrst),
  so as to filter out occasional cycle-count jumps
  caused by migration to another core
  (if the benchmark is not pinned to a single core)
  or by interrupts from other OS activity,
  not to mention intrinsic variations in the function's run time.
  libcpucycles does not reject an otherwise attractive counter
  merely because of occasional jumps.

* Cycle-counting overhead is not desirable, but does not directly affect
  comparisons of multiple options measured using the same cycle counter,
  so it is less important than consistent major errors such as treating
  2^32 + x cycles as x cycles. (Performance experts seeing a function
  that takes billions of cycles usually focus on smaller subroutines,
  but libcpucycles should not break larger measurements.) This is why
  libcpucycles does not provide direct access to 32-bit cycle counters:
  it provides wrappers that combine the counters with gettimeofday() to
  produce 64 bits, even though this incurs some extra overhead.

* The noise introduced by typical off-core clocks, such as multiplying a
  24MHz clock by 86 to estimate cycles on a 2.064GHz CPU core, comes in
  small part from low resolution but much more from changes in CPU
  frequency: e.g., a 10000-cycle computation might be measured as 20000
  cycles when the CPU enters a power-saving mode. When libcpucycles has
  access to what is believed to be an on-core cycle counter, it uses
  that even when its measurements show some noise. (Choosing an on-core
  cycle counter does not magically eliminate the change in the relative
  speed of the CPU and DRAM; the usual advice to warm up the CPU and set
  constant frequencies if possible still applies.)

When `cpucycles()` is first called, libcpucycles tries running each
cycle counter that has been compiled into the library. For example, for
64-bit ARM CPUs, libcpucycles will try `arm64-pmc`, `arm64-vct`,
`default-gettimeofday`, `default-mach`, `default-monotonic`, and
`default-perfevent`, minus any of those that failed to compile.

Cycle counters that fail at run time with SIGILL (or SIGFPE or SIGBUS or
SIGSEGV or SIGABRT) are eliminated from the list. For example, `arm64-pmc` will
fail with SIGILL if the kernel does not allow user access to
`PMCCNTR_EL0`. Beware that libcpucycles does not catch SIGILL after its
initial tests: if the kernel initially allows user access to
`PMCCNTR_EL0` but later turns it off then `arm64-pmc` will crash.

Independently of these counters, libcpucycles uses various OS mechanisms
to obtain an _estimate_ of the CPU frequency. This estimate is also
available to the caller as `cpucycles_persecond()`.

The methods that libcpucycles uses to ask the OS for an estimated CPU
frequency fail on some OS-CPU combinations, in which case libcpucycles
falls back to a `cpucyclespersecond` environment variable, or, if that
variable does not exist, an estimate of 2399987654 cycles per second.
(This estimate is in a realistic range of CPU speeds, and is close to
multiples of 24MHz, 25MHz, and 19.2MHz, which are common crystal
frequencies.) The sysadmin can create `/etc/cpucyclespersecond` to
override all of the OS mechanisms.

For counters that do not ask for scaling, the estimated CPU frequency is
shown in `cpucycles-info` as a double-check on the counter results. For
counters that ask for scaling, libcpucycles uses the estimated CPU
frequency to compute the scaling, so this is not a double-check. If a
counter asks for scaling and the estimated CPU frequency does not seem
close to a multiple of the counter frequency (possibly with a small
power-of-2 denominator) then libcpucycles will throw the counter away,
except in the case of fixed-resolution OS counters such as
`gettimeofday` and `CLOCK_MONOTONIC`.

libcpucycles computes a precision estimate for each counter (times any
applicable scaling) as follows. Call the counter 1000 times. Check that
the counter has never decreased, and has increased at least once. (A
counter where the decrease/increase checks fail is retried 10 times, so
10000 calls overall, and removed if it fails all 10 times.) The
precision estimate is then the smallest nonzero difference between
adjacent counter results, plus a penalty explained below.

Finally, libcpucycles selects the counter where the precision estimate
is the smallest number of cycles. Note that an inaccurate estimate of
CPU frequency can influence the choice between a scaled counter and an
unscaled counter.

The penalty is as follows:

* 0 for counters clearly documented as hardware cycle counters (RDPMC,
  PMCCNTR, RDCYCLE, RDTICK).

* 300 for fixed-frequency counters and for counters that need to be
  extended from 32 bits.

* 100 for other counters (such as various off-core clocks and
  `default-perfevent`).

* An extra 10 for each working counter earlier in the libcpucycles list
  of counters.

For example, a hardware CPU cycle counter that is early in the list and
that does not need to be extended from 32 bits will be selected even if
it actually has, e.g., a resolution of 8 cycles and 50 cycles of
overhead. As another example, `tsc` and `tscasm` are generally within 1
or 2 cycles in the smallest nonzero difference between adjacent counter
results, so `tsc` will be be selected ahead of `tscasm` because it is
earlier in the list.

libcpucycles does _not_ carry out its counter selection (typically tens
of milliseconds, sometimes even more) as a static initializer; callers
are presumed to not want to incur the cost of initialization unless and
until they are actually using `cpucycles()`. A multithreaded caller thus
has to place locks around any possibly-first call to `cpucycles()`, or
create its own static initializer (an `__attribute__((constructor))`
function) with an initial `cpucycles()` call so that all subsequent
`cpucycles()` calls are thread-safe.
