[ruby-core:125877] [Ruby Feature#22134] Faster rb_scan_args() for keyword args (optimization)
Issue #22134 has been reported by luke-gru (Luke Gruber). ---------------------------------------- Feature #22134: Faster rb_scan_args() for keyword args (optimization) https://bugs.ruby-lang.org/issues/22134 * Author: luke-gru (Luke Gruber) * Status: Open ---------------------------------------- ## Motivation When using the `rb_scan_args()` API, often we want to find a value for a given keyword argument. In order to do this, we call `rb_scan_args()` like so: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:", &str, &kwargs); // duplicates the kwargs hash in argv if (!NIL_P(kwargs)) rb_get_kwargs(kwargs, &id_example, 0, 1, &example); // mutates the duplicated kwargs hash to retrieve `example:` ``` This duplicates the keyword args hash given in `argv`. It would be nice to be able to grab a direct reference to the keyword hash and to have a variant of `rb_get_kwargs()` that didn't mutate the passed in hash. ## Proposal Add a new valid format character for `rb_scan_args()`: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:^", &str, &kwargs); // access kwargs directly from argv if (!NIL_P(kwargs)) rb_get_kwargs_const(kwargs, &id_example, 0, 1, &example); // don't mutate the passed kwargs hash ``` This '^' character would only be valid after a ":'. I have a [pull request](https://github.com/ruby/ruby/pull/17558) available for anyone that is interested. Thank you! -- https://bugs.ruby-lang.org/
Issue #22134 has been updated by nobu (Nobuyoshi Nakada). What about this alongside `HAVE_RB_SCAN_ARGS_BORROW_KEYWORDS`: ```C #define RB_SCAN_ARGS_BORROW_KEYWORDS "^" ``` It is lengthy but can reduce duplication. ---------------------------------------- Feature #22134: Faster rb_scan_args() for keyword args (optimization) https://bugs.ruby-lang.org/issues/22134#change-117808 * Author: luke-gru (Luke Gruber) * Status: Open ---------------------------------------- ## Motivation When using the `rb_scan_args()` API, often we want to find a value for a given keyword argument. In order to do this, we call `rb_scan_args()` like so: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:", &str, &kwargs); // duplicates the kwargs hash in argv if (!NIL_P(kwargs)) rb_get_kwargs(kwargs, &id_example, 0, 1, &example); // mutates the duplicated kwargs hash to retrieve `example:` ``` This duplicates the keyword args hash given in `argv`. It would be nice to be able to grab a direct reference to the keyword hash and to have a variant of `rb_get_kwargs()` that didn't mutate the passed in hash. ## Proposal Add a new valid format character for `rb_scan_args()`: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:^", &str, &kwargs); // access kwargs directly from argv if (!NIL_P(kwargs)) rb_get_kwargs_const(kwargs, &id_example, 0, 1, &example); // don't mutate the passed kwargs hash ``` This '^' character would only be valid after a ":'. I have a [pull request](https://github.com/ruby/ruby/pull/17558) available for anyone that is interested. Thank you! -- https://bugs.ruby-lang.org/
Issue #22134 has been updated by nobu (Nobuyoshi Nakada). A small correction to my previous comment: `RB_SCAN_ARGS_BORROW_KEYWORDS` itself can be used for feature detection, so a separate `HAVE_RB_SCAN_ARGS_BORROW_KEYWORDS` is unnecessary. Extensions can define it as `""` when absent to share the same format string across Ruby versions. Also, how about naming the non-destructive API `rb_lookup_kwargs` rather than `rb_get_kwargs_const`? We could introduce `rb_extract_kwargs` as a more descriptive name for the existing destructive operation, while retaining `rb_get_kwargs` as a compatibility alias. ---------------------------------------- Feature #22134: Faster rb_scan_args() for keyword args (optimization) https://bugs.ruby-lang.org/issues/22134#change-118840 * Author: luke-gru (Luke Gruber) * Status: Open ---------------------------------------- ## Motivation When using the `rb_scan_args()` API, often we want to find a value for a given keyword argument. In order to do this, we call `rb_scan_args()` like so: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:", &str, &kwargs); // duplicates the kwargs hash in argv if (!NIL_P(kwargs)) rb_get_kwargs(kwargs, &id_example, 0, 1, &example); // mutates the duplicated kwargs hash to retrieve `example:` ``` This duplicates the keyword args hash given in `argv`. It would be nice to be able to grab a direct reference to the keyword hash and to have a variant of `rb_get_kwargs()` that didn't mutate the passed in hash. ## Proposal Add a new valid format character for `rb_scan_args()`: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:^", &str, &kwargs); // access kwargs directly from argv if (!NIL_P(kwargs)) rb_get_kwargs_const(kwargs, &id_example, 0, 1, &example); // don't mutate the passed kwargs hash ``` This '^' character would only be valid after a ":'. I have a [pull request](https://github.com/ruby/ruby/pull/17558) available for anyone that is interested. Thank you! -- https://bugs.ruby-lang.org/
Issue #22134 has been updated by nobu (Nobuyoshi Nakada). Measurements used the same Ruby development build on macOS arm64, with JIT disabled. The following are medians of seven samples, in nanoseconds per call: | Arguments | Existing approach | `rb_lookup_kwargs` | Speedup | |------------------------------------------|------------------:|-------------------:|--------:| | One keyword | 67.4 | 54.3 | 1.24x | | One keyword via a frozen hash splat | 64.3 | 47.6 | 1.35x | | Four keywords | 121.1 | 106.6 | 1.14x | | Sixteen keywords via a frozen hash splat | 286.5 | 253.0 | 1.13x | ---------------------------------------- Feature #22134: Faster rb_scan_args() for keyword args (optimization) https://bugs.ruby-lang.org/issues/22134#change-118841 * Author: luke-gru (Luke Gruber) * Status: Open ---------------------------------------- ## Motivation When using the `rb_scan_args()` API, often we want to find a value for a given keyword argument. In order to do this, we call `rb_scan_args()` like so: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:", &str, &kwargs); // duplicates the kwargs hash in argv if (!NIL_P(kwargs)) rb_get_kwargs(kwargs, &id_example, 0, 1, &example); // mutates the duplicated kwargs hash to retrieve `example:` ``` This duplicates the keyword args hash given in `argv`. It would be nice to be able to grab a direct reference to the keyword hash and to have a variant of `rb_get_kwargs()` that didn't mutate the passed in hash. ## Proposal Add a new valid format character for `rb_scan_args()`: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:^", &str, &kwargs); // access kwargs directly from argv if (!NIL_P(kwargs)) rb_get_kwargs_const(kwargs, &id_example, 0, 1, &example); // don't mutate the passed kwargs hash ``` This '^' character would only be valid after a ":'. I have a [pull request](https://github.com/ruby/ruby/pull/17558) available for anyone that is interested. Thank you! -- https://bugs.ruby-lang.org/
Issue #22134 has been updated by nobu (Nobuyoshi Nakada). The restriction, `rb_lookup_kwargs` (or `rb_get_kwargs_const`) must not be used without `"^"`, should be stated in the document. ---------------------------------------- Feature #22134: Faster rb_scan_args() for keyword args (optimization) https://bugs.ruby-lang.org/issues/22134#change-118890 * Author: luke-gru (Luke Gruber) * Status: Open ---------------------------------------- ## Motivation When using the `rb_scan_args()` API, often we want to find a value for a given keyword argument. In order to do this, we call `rb_scan_args()` like so: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:", &str, &kwargs); // duplicates the kwargs hash in argv if (!NIL_P(kwargs)) rb_get_kwargs(kwargs, &id_example, 0, 1, &example); // mutates the duplicated kwargs hash to retrieve `example:` ``` This duplicates the keyword args hash given in `argv`. It would be nice to be able to grab a direct reference to the keyword hash and to have a variant of `rb_get_kwargs()` that didn't mutate the passed in hash. ## Proposal Add a new valid format character for `rb_scan_args()`: ```c VALUE str; VALUE kwargs; VALUE example; rb_scan_args(argc, argv, "1:^", &str, &kwargs); // access kwargs directly from argv if (!NIL_P(kwargs)) rb_get_kwargs_const(kwargs, &id_example, 0, 1, &example); // don't mutate the passed kwargs hash ``` This '^' character would only be valid after a ":'. I have a [pull request](https://github.com/ruby/ruby/pull/17558) available for anyone that is interested. Thank you! -- https://bugs.ruby-lang.org/
participants (2)
-
luke-gru (Luke Gruber) -
nobu (Nobuyoshi Nakada)