What could be causing ruby NoMethodError backtrace to be so slow? - ruby

I have a pretty large ruby (non-rails) application that I'm developing. It's reasonably fast considering how large and complex it is (go ruby!), but sometimes I fat finger a method name and get the NoMethodError.
And usually when this happens, the application hangs for like 20 to 30 seconds to just print out the backtrace.
Specifically, if I do something like this:
puts "about to crash!"
Array.new().inspekt # NoMethodError here
I see the "about to crash!" right away, and then 20s or so nothing seems to happen before I finally get the NoMethodError and backtrace.
At first I thought it might be the "did you mean" gem, so I turned that off with --disable-did_you_mean on the command line, and that turned off the "did you mean" suggestions, but nothing sped up the backtrace.
What's interesting is that this is only for NoMethodError.
If I cause some other exception, such as:
puts "about to crash!"
a = 3/0
Then I see the backtrace immediately.
And to make things even weirder, if I interrupt the process right after the "about to crash!" (such as with a ctrl-c on unix) then I immediately get the NoMethodError and it's backtrace. So it has the information - but ruby is stuck on trying to clean something up perhaps, something that only gets cleaned up on NoMethodError?
Info: ruby 2.7.0
OS: CentOS Linux release 7.5.1804
UPDATE - to responses so far:
Everyone seems to be concerned about the backtrace and profiling the ruby code.
Except the slowdown is NOT happening there. There are NO LINES OF RUBY CODE that are executed during the slowdown. All of the lines prior to this, "in the backtrace" are already executed and in a matter of a second or so. Then the system hangs, between the puts and the NoMethodError. There is no ruby code in between to profile, so any profiler that is looking at code written in my ruby script isn't going to help. The slowdown is something internal to ruby and is not in my code, unless I'm terribly confused about what's happening.
To be very clear:
Line 10042: puts "HERE" # Happens at ~1s
Line 10043: Array.new().inspekt # Happens at ~20-30s
There is no code between those lines to profile. The 20-30s is not happening in any code before line 10042 executes, so profiling that will not help.
I do have other Fibers that are paused. But there is no code here that yields to them. Is it possible that there's some strange built-in yield code that attempts to run other (paused) fibers when an exception is hit? I can't think of a reason you'd ever want this behavior, and many reasons why it would be catastrophic, but I can't think of anything else that would cause this problem (that is also killable with a ctrl-c!)

I would try to debug the full backtrace in there to see what is actually happening
begin
puts "about to crash!"
Array.new().inspekt
rescue => e
puts e.backtrace
raise # raise anyway
end
In my case I get 20 lines of backtrace with ruby 2.6.3 and irb, if that doesn't really tell you anything interesting I would then do the tedious work of measuring each runtime by modifying each file of the backtrace and printing the times at each step, debugging yay!

Related

See the current line being executed of a ruby script

I have a ruby script, apparently correct, that sometimes stops working (probably on some calls to Postgresql through the pg gem). The problem is that it freezes but doesn't produce any error, so I can't see the line number and I always have to isolate the line by using puts "ok1", puts "ok2", etc. and see where the script stops.
Is there any better way to see the current line being executed (without changing the script)? And maybe the current stack?
You could investigate ruby-debug a project that has been rewritten several times for several different versions of ruby, should allow you to step through your code line by line. I personally prefer printf debugging in a lot of cases though. Also, if I had to take an absolutely random guess at your problem, I might investigate whether or not you're running into a race condition and/or deadlock in your DB.

app is not stopping at "gets" - is my online interpreter forcing a timeout?

While starting an assignment (Towers of Hanoi), I leave my code in a very basic state while I ponder the logic of how to continue.
while arr3.count < 6
puts "Move ring FROM which tower?"
from = gets.chomp
puts "Move ring TO which tower?"
to = gets.chomp
end
Before I can start building the rest of the app, however, gets seems to fall through without any input from me, and the second puts displays on the screen. This continues looping every, say, 30 seconds or so. Should I assume this is a feature of online interpreters (like codeacademy labs)?
Now I'm distracted from continuing the assignment and have to find a better place to do my code.
I'm installing Aptana (based on some advice on this forum) to see if I can get a better environment to do my assignments. Or do most people use a text editor then run their .rb file through the windows console window?
Thx

Ruby process is at 100% after script ends, profiling, solution?

UPDATE: Problem located in my related question - Nokogiri performance problem
I am having a serious problem with my program. After program reaches it's last statement, Aptana studio shows the program is still running even after the last line was evaluated. Ruby process (after the last line of the script) is still running with 100% CPU usage, it ends after several seconds (15-30 maybe). I am trying to at atleast see where the problem is but after a long time I am still at the beginning. So the question is, what could cause this problem and how can I at least see where the problem is, what are my options? Some additional information:
Aptana debbug mode: After the last line, this will show in the Debug window:
<terminated, exit value: 0>path/to/ruby
But Ruby process is still running and using 100% CPU
I was trying to use gdb to profile Ruby process itself, but ended up with nothing using method described here: Profilig using gdb. I am using debian squeeze 64-bit and i tried both versions of script (8,12 > 16,24). When I tried to get some stack info I just get this:
Program received signal SIGSEGV, Segmentation fault.
0x00007f20539a80b8 in ?? () from /lib/libc.so.6
/home/giron/programovani/gdb_init.sh:1: Error in sourced command file:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(backtrace) will be abandoned.
When the function is done executing, GDB will silently stop.
After I quit gdb, following output shows up in Aptana console (But this is maybe absolutely useless, probably gdb did this, I don't know):
/home/giron/Aptana Studio 3 Workspace/RedisXmlConcept/bin/main.rb: [BUG] Segmentation fault
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
-- control frame ----------
c:0001 p:0000 s:0002 b:0002 l:000f68 d:000f68 TOP
---------------------------
-- C level backtrace information -------------------------------------------
/home/giron/.rvm/rubies/ruby-1.9.2-p290/lib/libruby.so.1.9(rb_vm_bugreport+0x5f)[0x7f205488216f]
/home/giron/.rvm/rubies/ruby-1.9.2-p290/lib/libruby.so.1.9(+0x63274) [0x7f205476a274]
/home/giron/.rvm/rubies/ruby-1.9.2-p290/lib/libruby.so.1.9(rb_bug+0xb3) [0x7f205476a413]
/home/giron/.rvm/rubies/ruby-1.9.2-p290/lib/libruby.so.1.9(+0x10c215) [0x7f2054813215]
/lib/libpthread.so.0(+0xeff0) [0x7f20544f9ff0]
/lib/libc.so.6(+0xe40b8) [0x7f20539a80b8]
/lib/libgcc_s.so.1(_Unwind_Backtrace+0x49) [0x7f2050d5b599]
/lib/libc.so.6(backtrace+0x4e) [0x7f20539a81ae]
/home/giron/.rvm/rubies/ruby-1.9.2-p290/bin/ruby(_start+0) [0x400890]
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html
Just to be sure that I have described problem well, last line of code (before this, Nokogiri parsing and work with Redis database is done):
puts "End"
End is printed out and after this Ruby process will consume 100% CPU for several seconds
This question is related to my previous one here: Nokogiri performance problem where are some more code snippets but since I am focusing on the different approach here (profiling Ruby), I have created new question.
Thank you in advance for any tips, I am pretty much clueless right now.
I was trying to use gdb to profile Ruby process itself
Don't do that. Calling backtrace may not be safe in the context you are executing in, and (apparently) causes your program to SIGSEGV.
Instead, just attach gdb to the Ruby process, and execute thread apply all where command. Update your question with the output, and you may get a better answer.

Ruby Threads Die?

I've been playing around with threads but I keep running into a problem where the treads seem to just die or stop.
Whats going on here? And how do I get round it?
I've included the code, but didn't paste it here as I think this problem is more fundamental to ruby.
source code
thanks.
Edit
Ruby 1.8, MacOS (snow leopard)
It looks like you're forgetting to add your new Thread objects to your threads object.
3.times do |t|
threads << Thread.new { word_list.process }
end
Your threads.each {|t| t.join} is working on an empty array, and so is ignoring the threads you did create. Make the change and it should wait.
Edit: I meant to << onto the array, not set it equal.
If you've got threads randomly "going away", make sure you've set Thread.abort_on_exception to true. That'll stop the interpreter if an uncaught exception reaches the top-level in a background thread (via SystemExit, so don't rescue Exception or they'll get swallowed), and can be immensely useful in tracking down random bugs.

how to produce delay in ruby

How to produce delay in ruby?
I used sleep statement but it didn't give me what I want.
puts "amit"
sleep(10)
puts "scj"
I want it to first print amit, then a delay of 10 seconds, then print scj.
But in above case what happens is it will pause for 10 seconds and then it will print amit and scj together. I don't want that.
I hope you got what I want to say.
I can't reproduce this. From a console, this does exactly what you'd expect:
puts "amit"
sleep 10
puts "scj"
(Ruby 1.8.6 on Linux)
Can you provide a similar short but complete example which doesn't do what you want - or explain your context more?
If you're writing a web application, then the browser may well only see any data once the whole response has been written - that would explain what you're seeing. If that's the case, you'll need a different approach which would allow the initial response to be written first, and then make the browser make another request. The delay could be at the server or the client, depending no the scenario.
Call $stdout.flush before the call to sleep. The output is probably buffered (although usually output is only line-buffered so puts, which produces a newline, should work without flushing, but apparently that's not true for your terminal).

Resources