Issue #7051 has been updated by sam.saffron (Sam Saffron).


Apologies it has taken me so long to respond here. 

> I concur with ko1's objection to having the bindings available. It would introduce *massive* performance overhead and kill many optimizations we implementers do currently or hope to do in the future.

I never really intended for this to be something that is on always, just a best-effort, optional thing. (if tracing is enabled you avoid optimisations, if not, you provide a best effort stack to the caller). Same goes for classes, if you can not provide them, do not, its a best effort API for diagnostics. 

My point here is that the current API is very limiting. It comes with no option to provide granularity of data collected in the backtrace. 

Let me illustrate some issues: 

1. There is no way to peel off a portion of the backtrace. 

Often when profiling rails I would like a backtrace that is limited to the frames in my application. To achieve this I would to something like the following: 

# before entering my code
current_depth = caller_locations.length 
# Problem, allocating a bunch of strings for filenames etc, I do not need
# This is very common as Rails starts off with a VERY deep frame after a ton of Rack stuff etc. 


# in my code 
partial_trace = caller_locations(0-current_depth) # Problem, negative depth is not supported - so I am forced to grab a full trace and discard my stuff 

Ideally the API should allow you to opt-in to information and pass that through to vm_backtrace_to_ary and vm_backtrace_frame_ary etc. It should also allow for negative params. 

A better API would be: 

current_depth = caller_locations(0,-1, BacktraceInfo::None)

app_frames = caller_locations(0,-current_depth, BacktraceInfo::Label) # if I only happen to want labels  

These changes make it much more efficient to gather stack traces at the correct granularity. 

Then you set BacktraceInfo::Default to be Label & Path & LineNo, which allow you to add the fancy *best effort* Klass & Bindings 

Overall this makes it much faster to profile stuff that has deep stack traces, you can cut down on allocations a lot. 

--- 

As to my exception stuff. 

def boom
  raise "boom"
end

begin
  boom
rescue => e
  p e.backtrace
end

# ["t.rb:2:in `boom'", "t.rb:6:in `<main>'"]

Shouldn't the backtrace be stored in RubyVM::Backtrace::Location objects and then optionally grabbed using backtrace_locations or backtrace depending on how you feel? 

I would go as far as saying you should allow for a user flag 

Exception.backtrace_location_info = BacktraceInfo::Label 
# and possibly
Exception.disable_backtraces = true

That allows you to gather less information in exceptions causing exceptions to be much faster.

----

As to naming 

backtrace_locations is ok, though I personally prefer Stacktrace and Stackframe , #stacktrace 


----------------------------------------
Feature #7051: Extend caller_locations API to include klass and bindings. Allow caller_locations as a method hanging off Thread. 
https://bugs.ruby-lang.org/issues/7051#change-33142

Author: sam.saffron (Sam Saffron)
Status: Open
Priority: Normal
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: 2.0.0


The new caller_locations api allows one to get label, base_label, path, lineno, absolute_path. 

I feel this API should be extended some what and cleaned up a bit. 

1. I think there should be complete parity with caller and backtrace APIs. 

As it stands caller_locations is a fine replacement for `caller`, however the same code responsible for `caller` is also responsible for Thread#backtrace. As it stands there is no equivalent Thread#backtrace_locations API that allows one to grab OO backtraces for a thread. 

For sampling profilers a common technique is to spin a thread that grabs stack traces from a profiled thread. 

I played around with some of this here: https://github.com/SamSaffron/stacktrace/blob/master/test/test_stacktrace.rb 

2. I think there should be a way to get the class the method belongs to where possible. 

At the moment you need to use something like ruby2ruby to determine the class of a frame in a backtrace. Getting the class is actually very important for auto-instrumentation techniques. A general approach is to grab stack traces, determine locations that seemed to be called a lot, and then instrument them. Trouble is, without a class it is very hard to pick a point to instrument. 

I got this working with my stacktrace gem so I think it is feasible.

3. Ability to grab bindings up the call chain

For some advanced diagnostic techniques it is very handy to grab bindings up the chain, that way you can print out local vars in a calling method and so on. It would be handy if this api exposed bindings. 

4. Naming and longer term deprecation of caller 

The name caller_locations to me feels a bit unnatural, as an API it is superior in all ways to the current caller, yet is far harder to type or remember. I am not really sure what it should be named but caller feels a bit wrong. Also it feels very tied to MRI returning RubyVM:::Backtrace::Location , Location seems to me in the wrong namespace. Is JRuby and Rubinius going to be expected to add this namespace? Is this going to be spec? 

Has any though been given to longer term deprecation of 'caller'. 

5. What about exceptions? 

Exception has no equivalent of caller_locations, for exceptions it makes much more sense to cut down on allocations and store a thinner stack trace object, in particular for the massively deep stacks frameworks like rails have. Then materialize the strings if needed on iteration through Exception#backtrace

    


-- 
http://bugs.ruby-lang.org/