Ruby/Rspec Performance Monitor - ruby

So I'm working on Rspec problems, and this is the last one I have left. For whatever reason, it's been much harder than all of the others. The three Rspec tests that are in question are as folows:
it "runs a block N times" do
n = 0
measure(4) do
n += 1
end
n.should == 4
end
it "returns the average time, not the total time, when running multiple times" do
run_times = [8,6,5,7]
fake_time = #eleven_am
Time.stub(:now) { fake_time }
average_time = measure(4) do
fake_time += run_times.pop
end
average_time.should == 6.5
end
it "returns the average time when running a random number of times for random lengths of time" do
fake_time = #eleven_am
Time.stub(:now) { fake_time }
number_of_times = rand(10) + 2
average_time = measure(number_of_times) do
delay = rand(10)
fake_time += delay
end
average_time.should == (fake_time - #eleven_am).to_f/number_of_times
end
And my code is as follows:
require 'time'
def measure(pass = 0)
start_time = Time.now
if pass == 0
yield
else
pass.times {|current| result = yield(current)}
end
Time.now - start_time
end
(The if/else is present, as an earlier test requires that the code takes one second to execute a program that sleeps for 1 second. In that case, pass would be 0, so the program would jump straight to the yield.)
Full Rspec here
Now, the code DOES pass the 'it "runs a block N times" do' test, but I feel that the way I have it set up prevents the other two tests from being able to pass. (At the same time, a simple yield won't allow it to pass, because it will get an error from trying to + 1 to nil)
I'm not looking for a copy/paste answer, but moreso whether or not I'm on the right track (Or if my pass.times should be reworked.)
If you have any examples that may be able to lead me in the right direction, I'd be more than happy to see them!

You say you "feel" it won't let the other tests pass, do you know this? I just ran it, and here's the results:
Performance Monitor
takes about 0 seconds to run an empty block
takes exactly 0 seconds to run an empty block (with stubs)
takes about 1 second to run a block that sleeps for 1 second
takes exactly 1 second to run a block that sleeps for 1 second (with stubs)
runs a block N times
returns the average time, not the total time, when running multiple times (FAILED - 1)
So the last spec fails. Looks like it's just returning the wrong value, it doesn't look at whether there were multiple passes. So updating that:
require 'time'
def measure(pass = 0)
start_time = Time.now
if pass == 0
yield
else
pass.times {|current| result = yield(current)}
end
(Time.now - start_time) / (pass == 0 ? 1 : pass)
end
Now running the specs shows me:
(in /Users/nick/learn_ruby)
Performance Monitor
takes about 0 seconds to run an empty block
takes exactly 0 seconds to run an empty block (with stubs)
takes about 1 second to run a block that sleeps for 1 second
takes exactly 1 second to run a block that sleeps for 1 second (with stubs)
runs a block N times
returns the average time, not the total time, when running multiple times
returns the average time when running a random number of times for random lengths of time
Finished in 1.01 seconds
7 examples, 0 failures
Great part about testing first is you can just find out if what you are doing is wrong, and then fix it.

def measure(pass = 1)
start_time = Time.now
pass.times {yield}
(Time.now - start_time) / (pass)
end
for any future passerbys, this could be written more efficiently like so, using a default value of 1 for pass

Related

How to correct Ruby countdown timer?

import time
def countdown(time_sec):
while time_sec:
mins, secs = divmod(time_sec, 60)
timeformat = "{:02d}:{:02d}".format(mins, secs)
print(timeformat, end='\r')
time.sleep(1)
time_sec -= 1
print("Time ended.")
This Python codes you see above work smootly and count down from given time_sec.
This codes also clean screen every second. I would like to write codes which are
work exactly same in Ruby.
#timer.rb(Ruby codes) here
def countdown time_sec
while time_sec
mins, secs = time_sec.divmod(60)[0], time_sec.divmod(60)[1]
timeformat = "%02d:%02d" % [mins, secs]
puts "#{timeformat}\r"
sleep(1)
time_sec -= 1
end
puts "Time is ended."
end
This Ruby codes you see above work in wrong way. Firstly seconds are printed one after the other. But I would like to update single line like above Python codes do. Secondly when this Ruby codes is run and countdown reached 00:00, It keeps counting down from -01:59. How can I correct this code?
You are using puts, which adds a line ending and messes up the\r.
Futhermore, the Python code runs until time_sec is zero, which evaluates as false and causes the loop to stop. In Ruby zero does not evaluate as
false.
def countdown(time_sec)
time_sec.downto(0) do |t|
print "%02d:%02d\r" % t.divmod(60)
sleep 1
end
end

How to call a method every X seconds in Rails? [duplicate]

For example, if I want to make a timer, how do I make a delay in the loop so it counts in seconds and do not just loop through it in a millisecond?
The 'comment' above is your answer, given the very simple direct question you have asked:
1.upto(5) do |n|
puts n
sleep 1 # second
end
It may be that you want to run a method periodically, without blocking the rest of your code. In this case, you want to use a Thread (and possibly create a mutex to ensure that two pieces of code are not attempting to modify the same data structure at the same time):
require 'thread'
items = []
one_at_a_time = Mutex.new
# Show the values every 5 seconds
Thread.new do
loop do
one_at_a_time.synchronize do
puts "Items are now: #{items.inspect}"
sleep 5
end
end
end
1000.times do
one_at_a_time.synchronize do
new_items = fetch_items_from_web
a.concat( new_items )
end
end
Somehow, many people think that putting a sleep method with a constant time interval as its argument will work. However, note that no method takes zero time. If you put sleep(1) within a loop, the cycle will surely be more than 1 second as long as you have some other content in the loop. What is worse, it does not always take the same time processing each iteration of a loop. Each cycle will take more than 1 second, with the error being random. As the loop keeps running, this error will contaminate and grow always toward positive. Especially if you want a timer, where the cycle is important, you do not want to do that.
The correct way to loop with constant specified time interval is to do it like this:
loop do
t = Time.now
#... content of the loop
sleep(t + 1 - Time.now)
end

ping function every x amount seconds

How would I do a specific task every x amount of seconds in ruby? I've tried using Time.now.to_i for epoch then once a Time.now_i hits that task second it executes, but I have not successfuly done this, can someone show me a small example on how to execute a function every x amount of seconds?
Attempt:
def interval(timeout,function,*data)
now = Time.now.to_i
tasktime = Time.now.to_i + timeout
taskfunction = function
taskdata = data
end
I stopped the code there because I do not know how/what to do next in ruby, so what it should do for example if someone can generate a code that can do something like this example,
def say(word)
puts word
end
If you set a interval for the function would be say, the data would be the "word" then it would execute that function every x amount of seconds
If you simply sleep for a constant amount of time as suggested in other answers, the error will contaminate as it keeps running, and will not be accurate. In fact, each iteration would take longer than the given interval.
The answer shown below adjusts the lag each time per iteration.
module Kernel
def tick_every sec, &pr
Thread.new do loop do
pr.call
t = Time.now.to_f
frac = t.modulo(sec.to_f)
sleep(sec - frac)
end end
end
end
thread = tick_every(2) do
puts "foo"
end
...
some_other_tasks
...
thread.kill
You can use Kernel#sleep method for the same.
Here is the post
Ruby sleep or delay less than a second?
Tell Ruby Program to Wait some amount of time
This method would puts the word every 2 seconds endless, synchronously (means other ruby code has to wait until this execution is finished (..endless..:)).
def say(word)
while true do
t = Time.now.to_f
puts word
frac = t.modulo(2.to_f)
sleep(2 - frac)
end
end

What does fake_time += 60 in rspec mean?

I'm going through an rspec tutorial on using "Time." Can someone explain what the following code means?
it "takes exactly 1 second to run a block that sleeps for 1 second (with stubs)" do
fake_time = #eleven_am
Time.stub(:now) { fake_time }
elapsed_time = measure do
fake_time += 60 # adds one minute to fake_time
end
elapsed_time.should == 60
end
I get it's suppose to take 60 seconds, but technically I'm just adding 60 seconds to the time variable fake_time, which should be instantaneous. Why does it take 60 seconds?
And here's the code for the measure function, which I wrote. It's suppose to measure how long it takes to run a block of code.
def measure
m1 = Time.now
num.times { yield }
m2 = Time.now
m2 - m1
end
This test is using basic stubbing. It doesn't make the method take extra time - it simply modifies the 'stubbed' value that would be returned by Time.now. This is useful for testing to ensure that after a certain amount of time 'would have elapsed', the expected values will be returned.

A Simple Ruby Script Freezes My Machine

CONSTANT = 1000000000000000000
array = (1..CONSTANT).to_a
start = Time.now
array.each do |i|
if 1000 < i < CONSTANT * 9 / 10
elsif i > CONSTANT * 9 / 10
else
end
end
finish = Time.now
puts "Running time: #{finish - start} seconds"
I wrote the above script in an attempt to figure out how much time saving could be achieved by re-ordering the control branches. The script froze my machine immediately after being run, which couldn't be terminated via CTL + C.
Could someone please point out what happened there?
You're iterating over a huge number.
Lets say your CPU can iterate one array item per nanosecond (which is good!), that means it'll take 1e9 seconds to iterate over the array. That's 31 years!
Your constant is far, far too large.
You are creating a huge array which you don't even need. That is forcing your machine to start paging (it would take up 5% of the 64-bit address space and your machine certainly doesn't have that much RAM). Your code is not making it to the loop (the condition in the if statement isn't valid ruby).
CONSTANT = 1000
# start with something small, then increase by 10
# 10000000 works for me.
start = Time.now
CONSTANT.times do |i|
if 1000 < i && CONSTANT * 9 / 10
elsif i > CONSTANT * 9 / 10
else
end
end
finish = Time.now
puts "Running time: #{finish - start} seconds"
What happened is that you tried to create a rather large array:
CONSTANT = 1000000000000000000
array = (1..CONSTANT).to_a
And your machine got upset with you. You might have better luck using the Range on its own without the to_a call.

Resources