I need to perform a task every 10ms. I've been using
kernel.sleep(0.01), but sleep seems to be slow and erratic at sub-second
resolutions. Here's a test I ran along with the results:
So I'm wondering if there's a way to get a steady 10ms delay. Another
option would be to set up an alarm or scheduled callback or something
every 10ms. Is this possible.
I need to perform a task every 10ms. I've been using
kernel.sleep(0.01), but sleep seems to be slow and erratic at sub-second
resolutions. Here's a test I ran along with the results:
irb(main):001:0> 0.upto(25) do
irb(main):002:1* puts Time.now.usec/1000
irb(main):003:1> STDOUT.flush
irb(main):004:1> sleep 0.01
irb(main):005:1> end
105
132
143
162
191
It's unlikely to get 10ms intervals reliably even in C, so getting it
in ruby is very unlikely.
The reason it's hard to get it even in C is (as man setitimer says):
"Time values smaller than the resolution of the system clock are
rounded up to this resolution (typically 10 milliseconds)."
Even taking the system clock resolution out of the equation, if the GC
kicks in, it will definitely cause a delay greater than 10ms. Add in
the rest of the delays caused by ruby's runtime, and it's a loosing
game.
If you require running a loop at 10ms intervals, you're probably going
to have to dip down into C.
- Evan Phoenix
···
On Apr 26, 12:57 pm, Earle Clubb <ecl...@valcom.com> wrote:
I need to perform a task every 10ms. I've been using
kernel.sleep(0.01), but sleep seems to be slow and erratic at sub-second
resolutions. Here's a test I ran along with the results:
So I'm wondering if there's a way to get a steady 10ms delay. Another
option would be to set up an alarm or scheduled callback or something
every 10ms. Is this possible.
I ran your code as a script and it worked fine on Windows XP.
I did not try irb.
Harry
···
On 4/27/07, Earle Clubb <eclubb@valcom.com> wrote:
I need to perform a task every 10ms. I've been using
kernel.sleep(0.01), but sleep seems to be slow and erratic at sub-second
resolutions. Here's a test I ran along with the results:
irb(main):001:0> 0.upto(25) do
irb(main):002:1* puts Time.now.usec/1000
irb(main):003:1> STDOUT.flush
irb(main):004:1> sleep 0.01
irb(main):005:1> end
So I'm wondering if there's a way to get a steady 10ms delay. Another
option would be to set up an alarm or scheduled callback or something
every 10ms. Is this possible.
I believe part of the problem is that you are not correcting for the
time that ruby spends in the loop. In [ruby-talk:42003] Dave Thomas
proposed this solution:
def every(period)
base = last = Time.now.to_f
count = 0
loop do
now = Time.now.to_f
actual_secs = now - base
expected_secs = period * count
correction = expected_secs - actual_secs
correction = -period if correction < -period
select(nil, nil, nil, period + correction)
now = Time.now
last = now.to_f
count += 1
yield(now)
end
end
Which I've tested using this code:
n = 0
every(0.01) do
puts Time.now.usec / 1000
n += 1
break if n == 25
end
> I need to perform a task every 10ms. I've been using
> kernel.sleep(0.01), but sleep seems to be slow and erratic at sub-second
> resolutions. Here's a test I ran along with the results:
It's unlikely to get 10ms intervals reliably even in C, so getting it
in ruby is very unlikely.
The reason it's hard to get it even in C is (as man setitimer says):
"Time values smaller than the resolution of the system clock are
rounded up to this resolution (typically 10 milliseconds)."
I've been reading about this a bit lately and as far as I understand it,
windows has a 15ms "tick" (this might be different for different windows
versions)
The linux tick is by default 10ms. You can change linux to 1ms though
(1000HZ), by changing a kernel setting:
CONFIG_HZ_1000=y
I use 1000 HZ and my output is:
123
133
143
153
163
173
183
193
203
213
223
233
n = 0
every(0.01) do
puts Time.now.usec / 1000
n += 1
break if n == 25
end
I do have to say that, given what this code does and the time in which
it runs, saying that ruby just cannot run fast is silly. I am very glad
to have seen this thread!
I need to perform a task every 10ms. I've been using
kernel.sleep(0.01), but sleep seems to be slow and erratic at sub-second
resolutions. Here's a test I ran along with the results:
It's an older 32 bit dual processor AMD box. That was with Ruby 1.8.5. OS is Linux Redhat Enterprise, but the Ruby was compiled locally.
I consistently get precise timings off of it, just like that. I do not, however, on another box -- a newer 64 bit dual core AMD, also running Linux. On that box a wait of 0.01 seems to fairly consistently wait about 0.012.
I think that is about as precise as one is going to make the timings, with Ruby, in any case, though.
Kirk Haines
···
On Fri, 27 Apr 2007, Joel VanderWerf wrote:
khaines@enigo.com wrote:
...
Try select()
----
irb(main):005:0> 0.upto(25) do
irb(main):006:1* select(nil,nil,nil,0.01)
irb(main):007:1> puts Time.now.usec/1000
irb(main):008:1> end
138
148
158
168
178
188
198
...
What kind of system are you on? It doesn't work so well for me.
On Apr 26, 2:06 pm, khai...@enigo.com wrote:
> On Fri, 27 Apr 2007, Earle Clubb wrote:
> > I need to perform a task every 10ms. I've been using
> > kernel.sleep(0.01), but sleep seems to be slow and erratic at sub-second
> > resolutions. Here's a test I ran along with the results:
[snip]
> Try select()
[snip]
It depends on what you mean by fast. For some applications I write, ten
milliseconds is a long time, and a hundred milliseconds is an eternity.
We do use ruby where appropriate, but not for latency-sensitive
applications.
Paul
···
On Tue, May 08, 2007 at 07:12:12AM +0900, Lloyd Linklater wrote:
I do have to say that, given what this code does and the time in which
it runs, saying that ruby just cannot run fast is silly. I am very
glad to have seen this thread!
Have you all tried this outside of irb?
Just run the actual script itself + profiler to find out where the slowdown is occurring.
Try it with sleep and select versions. This might show some different points.. maybe not.
···
On Apr 27, 2007, at 9:58 AM, Lionel Bouton wrote:
Joel VanderWerf wrote the following on 27.04.2007 00:04 :
khaines@enigo.com wrote:
...
Try select()
----
irb(main):005:0> 0.upto(25) do
irb(main):006:1* select(nil,nil,nil,0.01)
irb(main):007:1> puts Time.now.usec/1000
irb(main):008:1> end
138
148
158
168
178
188
198
...
What kind of system are you on? It doesn't work so well for me.
I'm wondering too, I see a nearly constant 2ms delay added to the 10ms
sleep with select on both an Athlon64 X2 3800+ and an Athlon XP 2400+.
I consistently get precise timings off of it, just like that. I do not,
however, on another box -- a newer 64 bit dual core AMD, also running
Linux. On that box a wait of 0.01 seems to fairly consistently wait
about
0.012.
I think that is about as precise as one is going to make the timings,
with
Ruby, in any case, though.
Kirk Haines
So I've done some more testing and I found something interesting:
Code:
#!/usr/bin/ruby -w
require 'enumerator'
a =
15.times do
sleep 0.008000499999999999
# sleep 0.0080004999999999999
a << Time.now.usec / 1000.0
end
a.each_cons(2) {|x,y| puts y-x}
Now if use the second sleep expression instead of the first, I get the
following results:
11.978
12.016
11.963
12.073
11.939
12.06
12.235
11.696
12.0
12.047
11.956
12.004
11.996
12.0
Can anyone explain why the delay jumps from ~8ms to ~12ms? I think this
may be the root of my problem.
ruby is interpreted langue and becouse of some restrictions on select and
interpereter you can't get exact delays, the bigger delay is more acurate
it's but if you need that sort of precision consder including c code.
···
On Tuesday 08 May 2007 13:15, Paul Brannan wrote:
On Tue, May 08, 2007 at 07:12:12AM +0900, Lloyd Linklater wrote:
> I do have to say that, given what this code does and the time in which
> it runs, saying that ruby just cannot run fast is silly. I am very
> glad to have seen this thread!
It depends on what you mean by fast. For some applications I write, ten
milliseconds is a long time, and a hundred milliseconds is an eternity.
We do use ruby where appropriate, but not for latency-sensitive
applications.
Paul
--
Marcin Raczkowski
---
Friends teach what you should know
Enemies Teach what you have to know