Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit a1a3dc4

Browse files
committed
Improve perf of metadata-based shared group inclusion.
The call to `RSpec::CallerFilter.first_non_rspec_line` took most of the time. I originally planned to leverage rspec/rspec-support#155 but realized we could avoid calling that entirely by re-using the location from the group’s metadata. I re-ran all the benchmarks and updated them. They look much, much better.
1 parent 580bc76 commit a1a3dc4

9 files changed

+68
-50
lines changed

benchmarks/singleton_example_groups/with_config_hooks.rb

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,19 @@
1010
BenchmarkHelpers.run_benchmarks
1111

1212
__END__
13-
1413
No match -- without singleton group support
15-
614.53533.8%) i/s - 2.520k
14+
575.25029.0%) i/s - 2.484k
1615
No match -- with singleton group support
17-
555.190 (±21.1%) i/s - 2.496k
16+
503.671 (±21.8%) i/s - 2.250k
1817
Example match -- without singleton group support
19-
574.82131.5%) i/s - 2.491k
18+
544.19125.7%) i/s - 2.160k
2019
Example match -- with singleton group support
21-
436.39125.2%) i/s - 1.872k
20+
413.53822.2%) i/s - 1.715k
2221
Group match -- without singleton group support
23-
544.06331.4%) i/s - 2.112k
22+
517.99828.2%) i/s - 2.058k
2423
Group match -- with singleton group support
25-
457.09818.8%) i/s - 1.961k
24+
431.55415.3%) i/s - 1.960k
2625
Both match -- without singleton group support
27-
554.00430.1%) i/s - 2.255k
26+
525.30625.1%) i/s - 2.107k in 5.556760s
2827
Both match -- with singleton group support
29-
452.83419.7%) i/s - 1.935k
28+
440.28816.6%) i/s - 1.848k

benchmarks/singleton_example_groups/with_config_hooks_module_inclusions_and_shared_context_inclusions.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
__END__
1919

2020
No match -- without singleton group support
21-
452.01533.8%) i/s - 1.900k
21+
544.39634.0%) i/s - 2.340k
2222
No match -- with singleton group support
23-
464.520 (±31.0%) i/s - 1.887k
23+
451.635 (±31.0%) i/s - 1.935k
2424
Example match -- without singleton group support
25-
476.96134.6%) i/s - 1.978k in 5.340615s
25+
538.78823.8%) i/s - 2.450k
2626
Example match -- with singleton group support
27-
76.17734.1%) i/s - 266.000
27+
342.99022.4%) i/s - 1.440k
2828
Group match -- without singleton group support
29-
364.55428.3%) i/s - 1.372k
29+
509.96926.7%) i/s - 2.070k
3030
Group match -- with singleton group support
31-
281.76124.1%) i/s - 1.200k
31+
405.28420.5%) i/s - 1.518k
3232
Both match -- without singleton group support
33-
281.52127.4%) i/s - 1.188k
33+
513.34424.0%) i/s - 1.927k
3434
Both match -- with singleton group support
35-
297.886 (±18.1%) i/s - 1.288k
35+
406.111 (±18.5%) i/s - 1.760k

benchmarks/singleton_example_groups/with_module_inclusions.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@
1111
__END__
1212

1313
No match -- without singleton group support
14-
519.88033.9%) i/s - 2.162k
14+
555.49827.0%) i/s - 2.496k
1515
No match -- with singleton group support
16-
481.33428.5%) i/s - 2.028k
16+
529.82623.0%) i/s - 2.397k in 5.402305s
1717
Example match -- without singleton group support
18-
491.348 (±29.9%) i/s - 2.068k
18+
541.845 (±29.0%) i/s - 2.208k
1919
Example match -- with singleton group support
20-
407.25722.3%) i/s - 1.782k
20+
465.44020.4%) i/s - 2.091k
2121
Group match -- without singleton group support
22-
483.40336.4%) i/s - 1.815k
22+
530.97624.1%) i/s - 2.303k
2323
Group match -- with singleton group support
24-
424.93229.4%) i/s - 1.804k
24+
505.29118.8%) i/s - 2.226k
2525
Both match -- without singleton group support
26-
397.83131.9%) i/s - 1.720k
26+
542.16828.4%) i/s - 2.067k in 5.414905s
2727
Both match -- with singleton group support
28-
424.23325.5%) i/s - 1.720k
28+
503.22627.2%) i/s - 1.880k in 5.621210s

benchmarks/singleton_example_groups/with_no_config_hooks_or_inclusions.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
__END__
66

77
No match -- without singleton group support
8-
504.86531.9%) i/s - 2.128k
8+
565.19828.8%) i/s - 2.438k
99
No match -- with singleton group support
10-
463.11526.6%) i/s - 1.998k
10+
539.78118.9%) i/s - 2.496k
1111
Example match -- without singleton group support
12-
472.82531.9%) i/s - 1.938k
12+
539.28728.2%) i/s - 2.450k in 5.555471s
1313
Example match -- with singleton group support
14-
436.53933.9%) i/s - 1.840k
14+
511.57628.1%) i/s - 2.058k
1515
Group match -- without singleton group support
16-
460.64333.4%) i/s - 1.892k
16+
535.29823.2%) i/s - 2.352k
1717
Group match -- with singleton group support
18-
430.33923.2%) i/s - 1.911k
18+
539.45419.1%) i/s - 2.350k
1919
Both match -- without singleton group support
20-
406.71226.6%) i/s - 1.848k
20+
550.93232.1%) i/s - 2.145k in 5.930432s
2121
Both match -- with singleton group support
22-
470.29926.4%) i/s - 1.890k
22+
540.18319.6%) i/s - 2.300k

benchmarks/singleton_example_groups/with_shared_context_inclusions.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@
1111
__END__
1212

1313
No match -- without singleton group support
14-
503.70033.2%) i/s - 2.184k
14+
563.30429.6%) i/s - 2.385k
1515
No match -- with singleton group support
16-
471.01826.8%) i/s - 2.009k
16+
538.73822.3%) i/s - 2.209k
1717
Example match -- without singleton group support
18-
467.85934.8%) i/s - 2.021k in 5.600106s
18+
546.60525.6%) i/s - 2.450k
1919
Example match -- with singleton group support
20-
84.13834.5%) i/s - 296.000 in 5.515586s
20+
421.11123.5%) i/s - 1.845k
2121
Group match -- without singleton group support
22-
384.144 (±27.9%) i/s - 1.560k
22+
536.267 (±27.4%) i/s - 2.050k
2323
Group match -- with singleton group support
24-
349.30127.5%) i/s - 1.288k
24+
508.64417.7%) i/s - 2.268k
2525
Both match -- without singleton group support
26-
388.10025.8%) i/s - 1.702k
26+
538.04727.7%) i/s - 2.067k in 5.431649s
2727
Both match -- with singleton group support
28-
339.31020.3%) i/s - 1.504k
28+
505.38826.7%) i/s - 1.880k in 5.578614s

lib/rspec/core/configuration.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,8 +1158,12 @@ def configure_group_with(group, module_list, application_method)
11581158
# Used internally to extend the singleton class of a single example's
11591159
# example group instance with modules using `include` and/or `extend`.
11601160
def configure_example(example)
1161-
@include_modules.items_for(example.metadata).each do |mod|
1162-
safe_include(mod, example.example_group_instance.singleton_class)
1161+
# We replace the metadata so that SharedExampleGroupModule#included
1162+
# has access to the example's metadata[:location].
1163+
example.example_group_instance.singleton_class.with_replaced_metadata(example.metadata) do
1164+
@include_modules.items_for(example.metadata).each do |mod|
1165+
safe_include(mod, example.example_group_instance.singleton_class)
1166+
end
11631167
end
11641168
end
11651169

lib/rspec/core/example_group.rb

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,21 @@ def self.idempotently_define_singleton_method(name, &definition)
4545
# The [Metadata](Metadata) object associated with this group.
4646
# @see Metadata
4747
def self.metadata
48-
@metadata if defined?(@metadata)
48+
@metadata ||= nil
49+
end
50+
51+
# Temporarily replace the provided metadata.
52+
# Intended primarily to allow an example group's singleton class
53+
# to return the metadata of the example that it exists for. This
54+
# is necessary for shared example group inclusion to work properly
55+
# with singleton example groups.
56+
# @private
57+
def self.with_replaced_metadata(meta)
58+
orig_metadata = metadata
59+
@metadata = meta
60+
yield
61+
ensure
62+
@metadata = orig_metadata
4963
end
5064

5165
# @private
@@ -333,7 +347,7 @@ def self.find_and_eval_shared(label, name, inclusion_location, *args, &customiza
333347
raise ArgumentError, "Could not find shared #{label} #{name.inspect}"
334348
end
335349

336-
SharedExampleGroupInclusionStackFrame.with_frame(name, inclusion_location) do
350+
SharedExampleGroupInclusionStackFrame.with_frame(name, Metadata.relative_path(inclusion_location)) do
337351
module_exec(*args, &shared_block)
338352
module_exec(&customization_block) if customization_block
339353
end

lib/rspec/core/shared_example_group.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ def inspect
2020
# Our definition evaluates the shared group block in the context of the
2121
# including example group.
2222
def included(klass)
23-
SharedExampleGroupInclusionStackFrame.with_frame(@description, RSpec::CallerFilter.first_non_rspec_line) do
23+
inclusion_line = klass.metadata[:location]
24+
SharedExampleGroupInclusionStackFrame.with_frame(@description, inclusion_line) do
2425
klass.class_exec(&@definition)
2526
end
2627
end

spec/rspec/core/metadata_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def metadata_for(*args)
189189

190190
expect(meta[:shared_group_inclusion_backtrace]).to match [ an_object_having_attributes(
191191
:shared_group_name => "some shared behavior",
192-
:inclusion_location => a_string_including("#{__FILE__}:#{line}")
192+
:inclusion_location => a_string_including("#{Metadata.relative_path __FILE__}:#{line}")
193193
) ]
194194
end
195195
end
@@ -213,7 +213,7 @@ def metadata_for(*args)
213213

214214
expect(meta[:shared_group_inclusion_backtrace]).to match [ an_object_having_attributes(
215215
:shared_group_name => "some shared behavior",
216-
:inclusion_location => a_string_including("#{__FILE__}:#{line}")
216+
:inclusion_location => a_string_including("#{Metadata.relative_path __FILE__}:#{line}")
217217
) ]
218218
end
219219
end
@@ -239,11 +239,11 @@ def metadata_for(*args)
239239
expect(meta[:shared_group_inclusion_backtrace]).to match [
240240
an_object_having_attributes(
241241
:shared_group_name => "inner",
242-
:inclusion_location => a_string_including("#{__FILE__}:#{inner_line}")
242+
:inclusion_location => a_string_including("#{Metadata.relative_path __FILE__}:#{inner_line}")
243243
),
244244
an_object_having_attributes(
245245
:shared_group_name => "outer",
246-
:inclusion_location => a_string_including("#{__FILE__}:#{outer_line}")
246+
:inclusion_location => a_string_including("#{Metadata.relative_path __FILE__}:#{outer_line}")
247247
),
248248
]
249249
end

0 commit comments

Comments
 (0)