Printing running time in nanos, with commas

Previously the queue performance tests printed nano/micro/milli/second
running times. Now we print just the nanos but using
fstrconv.ItoaComma(...) for readability. This makes the output
significantly more succinct.
Recording read/write failures

Every time a queue prevents a read or a write operation that failure is
recorded in a readFail or writeFail field. This allows us to measure
which end of the queue is outpacing the other. This feature is primarily
to give insight into the construction of benchmarks which should
exercise scenarios where the producer or the consumer is faster.

It's worth noting that keeping all of the queues aligned for common
features like this is very awkward. Some mitigation of this should be
investigated, code generation or struct delegation.
Duplicated fields moved into paddedCounters struct

Each of the queues have the same first 8 fields. These fields perform
the basic task of managing the read/write indices and caches, plus
tracking read/write failures.

These fields have been moved into a common struct called paddedCounters.
This makes it easier to make certain kinds of changes which alter these
8 fields (which in practice is common).
PointerQ's CommitRead/Write() take no arguments

Previously the caller needed to indicate how many pointers had been
committed. Now we store the size of the last buffer inside the queue
itself and use this when committing reads and writes. This reduces some
flexibility as it was previously possible for the client code to use
only some of a buffer and commit only the part they had used. It seems
unlikely this flexibility was very useful in practice, and made client
code significantly more complex.

During this change the min(...) and powerOfTwo(...) utility methods were
moved out of the spscq/ package and into the flib/fmath/ package.
ReadMany Added