ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: "jeremyevans0 (Jeremy Evans)" <noreply@ruby-lang.org>
To: ruby-core@ruby-lang.org
Subject: [ruby-core:106613] [Ruby master Feature#16663] Add block or filtered forms of Kernel#caller to allow early bail-out
Date: Fri, 10 Dec 2021 16:08:05 +0000 (UTC)	[thread overview]
Message-ID: <redmine.journal-95282.20211210160800.286@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-16663.20200228222717.286@ruby-lang.org

Issue #16663 has been updated by jeremyevans0 (Jeremy Evans).


matz (Yukihiro Matsumoto) wrote in #note-10:
> `find_caller` is going to find a single entry from call frames. Is it sufficient for OP's demand?

Hopefully @headius can answer that.  I assume that finding the first matching entry would be the most common use of this method.  For cases where you do want to iterate past the first matching entry, you could still get normal iteration in `find_caller` by having the block return nil/false, and use `break` to return a different value.

I'm fine with either `find_caller` or `each_caller`.  Each is implementable in terms of the other.  Which we choose is not of great importance to me, but I think it would be useful to offer some way to support this.

> Besides that, is it worth adding a global Kernel method?

Maybe not.  @nobu mentioned `Thread::Backtrace.find_caller`, which is a possibility.  Alternatively, it could be a singleton method on `Kernel` instead of an instance method (`Kernel.find_caller` without `Kernel#find_caller`), or a singleton method on `Thread`.



----------------------------------------
Feature #16663: Add block or filtered forms of Kernel#caller to allow early bail-out
https://bugs.ruby-lang.org/issues/16663#change-95282

* Author: headius (Charles Nutter)
* Status: Open
* Priority: Normal
----------------------------------------
There are many libraries that use `caller` or `caller_locations` to gather stack information for logging or instrumentation. These methods generate an array of informational stack frames based on the current call stack.

Both methods accept parameters for `level` (skip some number of Ruby frames) and `length` (only return this many frames). However many use cases are unable to provide one or both of these.

Instrumentation uses, for example, may need to skip an unknown number of frames at the top of the trace, such as to dig out of rspec plumbing or active_record internals and report the first line of user code. In such cases, the typical pattern is to simply request *all* frames and then filter out the one that is desired.

This leads to a great deal of wasted work gathering those frames and constructing objects to carry them to the user. On optimizing runtimes like JRuby and TruffleRuby, it can have a tremendous impact on performance, since each frame has a much higher cost than on CRuby.

I propose that we need a new form of `caller` that takes a block for processing each element.

```ruby
def find_matching_frame(regex)
  caller do |frame|
    return frame if frame.file =~ regex
  end
end
```

An alternative API would be to allow passing a query object as a keyword argument, avoiding the block dispatch by performing the match internally:

```ruby
def find_matching_frame(regex)
  caller(file: regex)
end
```

This API would provide a middle ground between explicitly specifying a maximum number of stack frames and asking for all frames. Most common, hot-path uses of `caller` could be replaced by these forms, reducing overhead on all Ruby implementations and drastically reducing it where stack traces are expensive.



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

  parent reply	other threads:[~2021-12-10 16:08 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-28 22:27 [ruby-core:97307] [Ruby master Feature#16663] Add block or filtered forms of Kernel#caller to allow early bail-out headius
2021-10-26 19:29 ` [ruby-core:105817] " jeremyevans0 (Jeremy Evans)
2021-11-09 12:27 ` [ruby-core:105985] " Eregon (Benoit Daloze)
2021-11-09 12:36 ` [ruby-core:105986] " Eregon (Benoit Daloze)
2021-11-09 13:28 ` [ruby-core:105988] " zverok (Victor Shepelev)
2021-11-09 16:32 ` [ruby-core:105990] " Eregon (Benoit Daloze)
2021-11-18  6:57 ` [ruby-core:106122] " matz (Yukihiro Matsumoto)
2021-11-18  9:47 ` [ruby-core:106129] " Eregon (Benoit Daloze)
2021-11-18 18:17 ` [ruby-core:106155] " jeremyevans0 (Jeremy Evans)
2021-11-19 20:18 ` [ruby-core:106180] " Eregon (Benoit Daloze)
2021-12-09  7:49 ` [ruby-core:106575] " matz (Yukihiro Matsumoto)
2021-12-09 20:20 ` [ruby-core:106607] " Dan0042 (Daniel DeLorme)
2021-12-10 16:08 ` jeremyevans0 (Jeremy Evans) [this message]
2021-12-11  9:57 ` [ruby-core:106618] " headius (Charles Nutter)
2021-12-11 18:53 ` [ruby-core:106622] " jeremyevans0 (Jeremy Evans)
2021-12-15 14:56 ` [ruby-core:106691] " headius (Charles Nutter)
2021-12-15 16:28 ` [ruby-core:106696] " Dan0042 (Daniel DeLorme)
2022-01-03 18:16 ` [ruby-core:106954] " jeremyevans0 (Jeremy Evans)
2022-01-04 10:59 ` [ruby-core:106960] " Eregon (Benoit Daloze)
2022-01-11 16:47 ` [ruby-core:107056] " Dan0042 (Daniel DeLorme)
2022-01-11 18:26 ` [ruby-core:107060] " Eregon (Benoit Daloze)
2022-01-14  3:25 ` [ruby-core:107114] " mame (Yusuke Endoh)
2022-01-14 21:43 ` [ruby-core:107133] " jeremyevans0 (Jeremy Evans)
2022-01-18 16:21 ` [ruby-core:107179] " headius (Charles Nutter)
2022-01-19  2:57 ` [ruby-core:107188] " jeremyevans0 (Jeremy Evans)
2022-02-01  0:45 ` [ruby-core:107404] " headius (Charles Nutter)
2022-02-01  1:39 ` [ruby-core:107405] " jeremyevans0 (Jeremy Evans)
2022-02-01  3:59   ` [ruby-core:107407] " Gregory Cohen
2022-02-17  7:56 ` [ruby-core:107616] " matz (Yukihiro Matsumoto)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-95282.20211210160800.286@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).