Accuracy of sleep()




I didn’t expect sleep(seconds) to be super accurate, but I must admit I was surprised over how inaccurate it is. See a benchmark below. Relative error of 10% for sleep times under 0.01 seconds is quite a lot, and may cause potential issues in, e.g., real-time control loops.

using Plots
function testsleep()
    sleeptimes = logspace(-3,1,50)
    actual_sleeptimes = map(sleeptimes) do st
        @elapsed sleep(st)
    sleeptimes, actual_sleeptimes
sleeptimes, actual_sleeptimes = testsleep()
diff = actual_sleeptimes-sleeptimes
plot(sleeptimes, [diff diff./sleeptimes], xlabel="Sleeptimes", ylabel=["Absolute difference" "Relative difference"],
    xscale=:log10, yscale=[:linear :log10], ylims=[(0,1e-2) :auto], layout=2, legend=false)


One can potentially model the time difference and compensate for it. For sleeptimes close to the lower limit of 1e-3s, preliminary testing indicates that one can reduce the relative error about one order of magnitude with a simple polynomial model:

A = log.(sleeptimes).^(0:2)'    # Regressor matrix
x = A\log.(actual_sleeptimes)   # Polynomial coeffs
e = log.(actual_sleeptimes) - A*x

predicted_time(t)       = exp((log(t).^(0:2)')*x)
predicted_difference(t) = predicted_time(t)-t

plot(sleeptimes, [actual_sleeptimes predicted_time.(sleeptimes)], lab=["Actual", "Predicted"], xlabel="Sleeptime", yscale=:log10, xscale=:log10)
plot(sleeptimes, [abs.(diff-predicted_difference.(sleeptimes)) abs.(diff-predicted_difference.(sleeptimes))./sleeptimes],
        xlabel="Sleeptimes", ylabel=["Absolute prediction error" "Relative prediction error"],
        xscale=:log10, yscale=[:linear :log10], ylims=[(0,1e-2) :auto],
        layout=2, legend=false)

# Estimated parameters stat. significant?
σ²  = var(e)       # Prediction error variance
Σ   = σ²*inv(A'A)  # Parameter covariance
p05 = abs.(x)./sqrt.(diag(Σ)) .> 1.96  # Significant?

5-element BitArray{1}:


Does anyone have experience with this before and have suggestions on a more accurate strategy. I’ll see how reproducible the results are on a different system tomorrow and try to improve upon my quick and dirty high-order polynomial model.



Thanks for the link!
usleep(usecs) = ccall(:usleep, Cint, (Cuint,), usecs)
seems way more accurate.


Sleep also frees the main thread to do other asynchronous stuff, while I think calling usleep using ccall might be “blocking” so there is that to consider too.


I found this very good article about how Linux keeps time

By a Wall Street programmer, so she/he should know about latency!
I guess the HPET stuff is a bit specific to the Intel architecture though. Anyone care to comment about other architectures?