What is the resolution of std.time.Timer and is it good enough?

Let me preface this with, I haven’t researched this in enough depth, but maybe we can do this research together.

So the two questions are:

  • what are the resolutions for std.time.Timer depending on platforms?
  • are these resolutions good enough?
    (for example to be used as accurate measurements for benchmarks)

From this video:

it seems that:

  • window’s query performance counter is bad?
    it botches a high precision measurement into a low precision value
  • zig uses queryPerformanceCounter on windows src/std/time.zig
  • using rdtscp directly gives access to greater precision,
    can we write a zig library that makes use of that?
  • would that allow us to get more accurate timings, or do I misunderstand something?
  • If so are there similar instructions for different architectures?
  • Ideally someone from the community does the process from the video
    to see whether the zig code results in throwing away a lot of precision on windows
  • what is the precision on other operating systems?
  • Can we develop some benchmarks for timing itself and how accurate it is?
1 Like

After seeing this topic, I couldn’t help settings this up :wink:

The code just queries the timer but basically does nothing else. Sample output:

zig build bench-noop --release=fast && ./zig-out/bin/bench-noop
noop!, n=10, avg: 16, std: 8
noop!, n=100, avg: 12, std: 1
noop!, n=1000, avg: 14, std: 4
noop!, n=10000, avg: 15, std: 10
noop!, n=100000, avg: 14, std: 6
noop!, n=1000000, avg: 13, std: 25

I originally stumbled across this while looking at an issue on zbench. I’m not 100% sure how meaningful that is, but the results vary quite drastically if you run this multiple times (at least on my Linux machine). Also, standard deviations tend to outnumber the average at higher N, which is …not a good sign.

1 Like

Two functions that returns the CPU ticks for aarch64 and x86_64 architectures:

fn aarch64_ticks() u64 {
    return asm volatile(
        "mrs %[ret], CNTVCT_EL0"
        : [ret] "=r" (-> u64)

fn x86_64_ticks() u64 {
    return asm volatile(
        \\ rdtsc
        \\ shl $32, %%rdx
        \\ or %%rdx, %%rax
        : [ret] "={rax}" (-> u64)
        : "rdx"

besides, I think @nyc has some more code around this topic on GitHub - jnordwick/tempus: fast, minimal clocks, TSC, dates, and timestamps for zig