Sleeping between 1e-2 and 1e-6s

  • Thread starter Stefan Rusterholz
  • Start date
S

Stefan Rusterholz

I noticed that ruby uses a different way to sleep with values >1e-6s.
I added my observations below. My question is now: what is the suggested
way to sleep e.g. 0.001s?
10000.times { sleep(0.0000001) }? Cant' really be it, no? :)

The results:
$ ruby sleeper.rb
100x sleeping 0.01000000s: 0.01003044s per sleep, runtime: 1.00304s
100x sleeping 0.00100000s: 0.01006163s per sleep, runtime: 1.00616s
100x sleeping 0.00010000s: 0.01007538s per sleep, runtime: 1.00754s
100x sleeping 0.00001000s: 0.01011209s per sleep, runtime: 1.01121s
100x sleeping 0.00000100s: 0.01008325s per sleep, runtime: 1.00832s
100x sleeping 0.00000010s: 0.00001131s per sleep, runtime: 0.00113s
100x sleeping 0.00000001s: 0.00000986s per sleep, runtime: 0.00099s

The sleeper.rb file:
#!/usr/bin/ruby

def bench(n=1, &b)
start = Time.now
n.to_i.times(&b)
Time.now-start
end

[0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001].each {
|s|
r = bench(100) { sleep(s) }
printf "100x sleeping %.8fs: %.8fs per sleep, runtime: %.5fs\n", s,
r/100, r
}

Regards
Stefan
 
B

Brian Candler

I noticed that ruby uses a different way to sleep with values >1e-6s.
I added my observations below. My question is now: what is the suggested
way to sleep e.g. 0.001s?
10000.times { sleep(0.0000001) }? Cant' really be it, no? :)

You've hit the granularity of the thread scheduler. On my machine, running
your test code, it appears to be 4ms:

$ ruby sleep.rb
100x sleeping 0.01000000s: 0.01210674s per sleep, runtime: 1.21067s
100x sleeping 0.00100000s: 0.00407440s per sleep, runtime: 0.40744s
100x sleeping 0.00010000s: 0.00411841s per sleep, runtime: 0.41184s
100x sleeping 0.00001000s: 0.00411971s per sleep, runtime: 0.41197s
100x sleeping 0.00000100s: 0.00000858s per sleep, runtime: 0.00086s
100x sleeping 0.00000010s: 0.00000852s per sleep, runtime: 0.00085s
100x sleeping 0.00000001s: 0.00000852s per sleep, runtime: 0.00085s

Ruby is not a precision real-time environment - and neither are Unix or
Windows for that matter.

If you really need such a short pause, you could use ruby-inline and call
nanosleep() or usleep() or select() C functions, depending on what's
available on your platform. You'll block the entire Ruby interpreter for
that period of time, i.e. Ruby won't be able to do work in another thread at
the same time, but at least the CPU will be available to other processes on
your machine, unlike a spinloop as you propose above.

But you should think carefully about what you're doing. For example, if you
were trying to do

loop do
send_packet
precision_sleep(0.001)
end

then you will certainly send less than 1000 packets per second, and the
actual rate you send at will be variable. It may be better to send packets
at an *average* rate of 1000 packets per second, even if they go in bursts
of 10 or 12 packets.

Brian.
 
S

Stefan Rusterholz

Brian said:
Ruby is not a precision real-time environment - and neither are Unix or
Windows for that matter.

Certainly not. But even with Ruby microsecond sleep should be possible.
If you really need such a short pause, you could use ruby-inline and
call nanosleep() or usleep() or select() C functions

That would interrupt all threads. But it could still be an option for
sleeps < 0.01s. I.e. sleep everything > 0.01s with thread_wait_for and
switch to usleep for smaller values. Of course it would be nice to
somehow get the granularity of the scheduler and switch at that.
loop do
send_packet
precision_sleep(0.001)
end

then you will certainly send less than 1000 packets per second

The situation is indeed similar to the above. I'm also well aware of
that problem. It's not really an issue, though as I don't sleep the
interval but the time left in the interval (measured from an absolute
start, not the last time the event happened).

After digging in the code I also understand what happens in that gap.
timeval.tv_usec is a long representing microseconds. Those values are
rounded down to 0, so I assume it effectively doesn't sleep.

Regards
Stefan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,113
Latest member
Vinay KumarNevatia
Top