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

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? :slight_smile:

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

On Tue, Jun 05, 2007 at 12:57:30AM +0900, Stefan R. wrote:

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? :slight_smile:

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.

Brian C. wrote:

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