From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-3.3 required=3.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,MAILING_LIST_MULTI, MIME_HTML_MOSTLY,RCVD_IN_DNSWL_MED,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id AE5ED1F852 for ; Tue, 1 Feb 2022 03:59:59 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 84250120AF0; Tue, 1 Feb 2022 12:59:56 +0900 (JST) Received: from mail-vk1-f181.google.com (mail-vk1-f181.google.com [209.85.221.181]) by neon.ruby-lang.org (Postfix) with ESMTPS id 58008120AEF for ; Tue, 1 Feb 2022 12:59:45 +0900 (JST) Received: by mail-vk1-f181.google.com with SMTP id o15so9659920vki.2 for ; Mon, 31 Jan 2022 19:59:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=xZ+r0AnvLNH/rMyZ5f3R72WfCut6bt2kf1QxC4axYFU=; b=o1lCrMiI41icgd0GpVHUciVd/0KjUh+RSqHU8orDvmhWPRJsvzNuzTZ5Nupf2caQIK QuQhGR2unAdDhzhva1zgqmX2amzIDw76VwyG3x5XkLL9z4ycD3kvt6PM4ZcgxInWdMaV dgi6GBPeQH/J+b6jrj6RZ0j8/NeAQ+GfIthSv8Tl6uJNYQAIM7uPv5wzSFNH/4VfpdwS d8eroNOWvjNSbAVq9g4XXsQja8P8YT7hefbuoSnSUq2N9nx0yvZUomfuOoOtiCGvBivK 0A2ZNwkyNJSz7G7QKrZxhA+FF+xd7Wni9LtnjWYG307n2AYcvYBe29W1vHfEc7TcBDk9 TVXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=xZ+r0AnvLNH/rMyZ5f3R72WfCut6bt2kf1QxC4axYFU=; b=48Jwy1U0L2avqtMuGx7OU++Rb30kcK/cUrj4j2Epq9KIIbhERIXliwjucIexVoKVAq a2PKMj2/qClpgolX1ypi2a1fKPvzPZlgeUCtTN2b9xqz5WdpDkZr5NH/nQLMqVT9v11G RWkMVooenO41RBkJ0Y6yrG+rR9djy/eJz2YJYUWA7aUBSdFKnik4a6tSY8JQvPbJHIQZ TLommotqQ202ahskwwKf+qHg4hVsfSJHxigwEU00XbkQT8DIbDlKK0D6qr6IgmiiP2MO 3roHR3JoVISGR5PEwjEBiTTH1EFWOBrcmxVrSmJ8c1WE6ntsnpxJIWFObfWcE8Fd6sC2 OPVQ== X-Gm-Message-State: AOAM533jjAy0p90hpqKkXycarg8fm/MCsqIEKYorggzTiP4E2mCr75hq qA2tDUWm2NMk5YSSGOcbOxzetRpXVx5MYJT7E5+cPTXS4DU= X-Google-Smtp-Source: ABdhPJxGTo+lELA7RtlAysP+mCEA4ihKdeoo8Ha/+XvMWNkeKXN0KeSvTmJpCjy61gBW7pjkn1uPpK/6mcsbQ0CMdlY= X-Received: by 2002:a1f:a84e:: with SMTP id r75mr9356179vke.21.1643687983200; Mon, 31 Jan 2022 19:59:43 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Gregory Cohen Date: Mon, 31 Jan 2022 22:59:31 -0500 Message-ID: To: Ruby developers X-ML-Name: ruby-core X-Mail-Count: 107407 Subject: [ruby-core:107407] Re: [Ruby master Feature#16663] Add block or filtered forms of Kernel#caller to allow early bail-out X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Reply-To: Ruby developers Content-Type: multipart/mixed; boundary="===============0236332686==" Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" --===============0236332686== Content-Type: multipart/alternative; boundary="0000000000005c3ec705d6eceef3" --0000000000005c3ec705d6eceef3 Content-Type: text/plain; charset="UTF-8" unsubscribe On Mon, Jan 31, 2022 at 8:39 PM jeremyevans0 (Jeremy Evans) < noreply@ruby-lang.org> wrote: > Issue #16663 has been updated by jeremyevans0 (Jeremy Evans). > > > headius (Charles Nutter) wrote in #note-25: > > Is there a way to prohibit the `to_enum` form? I don't think it will be > useful to support since it may vary greatly across implementations > (depending on what the stack looks like and what gets included). > > I don't know of a way to do this. I don't think the method being called > can tell whether it is being run via an enumerator or not. In CRuby, you > could probably override `to_enum`, check if the method being called is a C > method using the same C function, and fail in that case, but that's trivial > to work around be rebinding the Kernel `to_enum` method. > > > It does raise a question for me, though... is your patch eagerly > capturing the stack? I have been trying to figure out how the stack trace > is identical in both the block form and the to_enum form and it seems like > the trace would have to have been captured at the same level, rather than > at the point the enum starts to run. > > It isn't identical. From the tests: > > ```ruby > cllr = caller_locations(1, 2); ary = > Thread.to_enum(:each_caller_location).to_a[2..3] > assert_equal(cllr.map(&:to_s), ary.map(&:to_s)) > ``` > > The `[2..3]` shows there are extra entries in the `to_enum` case. > > ---------------------------------------- > Feature #16663: Add block or filtered forms of Kernel#caller to allow > early bail-out > https://bugs.ruby-lang.org/issues/16663#change-96305 > > * 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/ > > Unsubscribe: > > --0000000000005c3ec705d6eceef3 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
unsubscribe

On Mon, Jan 31, 2022 at 8:39 PM jeremyevans0 = (Jeremy Evans) <noreply@ruby-la= ng.org> wrote:
Issue #16663 has been updated by jeremyevans0 (Jeremy Evans).


headius (Charles Nutter) wrote in #note-25:
> Is there a way to prohibit the `to_enum` form? I don't think it wi= ll be useful to support since it may vary greatly across implementations (d= epending on what the stack looks like and what gets included).

I don't know of a way to do this.=C2=A0 I don't think the method be= ing called can tell whether it is being run via an enumerator or not.=C2=A0= In CRuby, you could probably override `to_enum`, check if the method being= called is a C method using the same C function, and fail in that case, but= that's trivial to work around be rebinding the Kernel `to_enum` method= .

> It does raise a question for me, though... is your patch eagerly captu= ring the stack? I have been trying to figure out how the stack trace is ide= ntical in both the block form and the to_enum form and it seems like the tr= ace would have to have been captured at the same level, rather than at the = point the enum starts to run.

It isn't identical.=C2=A0 From the tests:

```ruby
=C2=A0 =C2=A0 cllr =3D caller_locations(1, 2); ary =3D Thread.to_enum(:each= _caller_location).to_a[2..3]
=C2=A0 =C2=A0 assert_equal(cllr.map(&:to_s), ary.map(&:to_s))
```

The `[2..3]` shows there are extra entries in the `to_enum` case.

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

* 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 u= nable to provide one or both of these.

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

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

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

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

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

```ruby
def find_matching_frame(regex)
=C2=A0 caller(file: regex)
end
```

This API would provide a middle ground between explicitly specifying a maxi= mum 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 al= l Ruby implementations and drastically reducing it where stack traces are e= xpensive.



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

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=3Dunsubscribe= >
<http://lists.ruby-lang.org/cgi-bin/m= ailman/options/ruby-core>
--0000000000005c3ec705d6eceef3-- --===============0236332686== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline --===============0236332686==--