summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2022-08-01 14:24:12 -0700
committerAaron Patterson <aaron.patterson@gmail.com>2022-08-02 09:04:04 -0700
commite4e054e3ce409f1c1d04bf7cd75aa9238e205d52 (patch)
tree30bb1aa941ec81549a0ed448af24aa94f129dd7f
parentda00243dfe745cba3b176112fe8245c23e6f1635 (diff)
Speed up setting the backref match object
This patch speeds up setting the backref match object by avoiding some memcopies. Take the following code for example: ```ruby "hello world" =~ /hello/ p $~ ``` When the RE matches the string, we have to set the Match object in the backref global. So we would allocate a match object[^1] and use `rb_reg_region_copy`[^2] to make a deep copy of the stack allocated `re_registers` struct[^3] in to the newly created Ruby object. This could possibly trigger GC[^4], and would allocate new memory. This patch makes a shallow copy of the `re_registers` struct on to the Match object allowing the match object to manage the `re_registers` pointer and also avoiding some calls to `xmalloc` and some manual memcopy. Benchmark looks like this: ```ruby require "benchmark/ips" def test_re thing thing =~ /hello/ end Benchmark.ips do |x| x.report("re hit") do test_re "hello world" end x.report("re miss") do test_re "world" end end ``` Before this patch: ``` $ ruby -v test.rb ruby 3.2.0dev (2022-07-27T22:29:00Z master 4ad69899b7) [arm64-darwin21] Ignoring bcrypt-3.1.16 because its extensions are not built. Try: gem pristine bcrypt --version 3.1.16 Warming up -------------------------------------- re hit 345.401k i/100ms re miss 673.584k i/100ms Calculating ------------------------------------- re hit 3.452M (± 0.5%) i/s - 17.270M in 5.002535s re miss 6.736M (± 0.4%) i/s - 34.353M in 5.099593s ``` After this patch: ``` $ ./ruby -v test.rb ruby 3.2.0dev (2022-08-01T21:24:12Z less-memcpy 0ff2a56606) [arm64-darwin21] Warming up -------------------------------------- re hit 419.578k i/100ms re miss 673.251k i/100ms Calculating ------------------------------------- re hit 4.201M (± 0.7%) i/s - 21.398M in 5.093593s re miss 6.716M (± 0.4%) i/s - 33.663M in 5.012756s ``` Matches get faster and misses maintain the same speed [^1]: https://github.com/ruby/ruby/blob/24204d54ab730791bfbd0cd66b8e12f0bd62ca5d/re.c#L1737 [^2]: https://github.com/ruby/ruby/blob/24204d54ab730791bfbd0cd66b8e12f0bd62ca5d/re.c#L1738 [^3]: https://github.com/ruby/ruby/blob/24204d54ab730791bfbd0cd66b8e12f0bd62ca5d/re.c#L1686 [^4]: https://github.com/ruby/ruby/blob/24204d54ab730791bfbd0cd66b8e12f0bd62ca5d/re.c#L981
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/6206
-rw-r--r--re.c4
1 files changed, 1 insertions, 3 deletions
diff --git a/re.c b/re.c
index 7642dc3651..a633d1bb7b 100644
--- a/re.c
+++ b/re.c
@@ -1735,9 +1735,7 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
}
match = match_alloc(rb_cMatch);
- int copy_err = rb_reg_region_copy(RMATCH_REGS(match), regs);
- onig_region_free(regs, 0);
- if (copy_err) rb_memerror();
+ memcpy(RMATCH_REGS(match), regs, sizeof(struct re_registers));
if (set_backref_str) {
RMATCH(match)->str = rb_str_new4(str);