简体   繁体   中英

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

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM