Skip to content

Commit 2baf04d

Browse files
committed
⚡ Faster SequenceSet#normalize when frozen
Calling `SequenceSet#normalize` on a frozen set can be more than 4x faster, by simply re-parsing `@string` and scanning its elements, rather than fully generating a new string and comparing it with `@string`. ``` normal reparse and check: 20449.2 i/s generate and compare: 20267.2 i/s - 1.01x slower v0.5.12: 3090.2 i/s - 6.62x slower frozen and normal generate and compare: 19328485.2 i/s reparse and check: 17455122.3 i/s - 1.11x slower v0.5.12: 3730.0 i/s - 5181.95x slower unsorted reparse and check: 16936.2 i/s generate and compare: 16872.9 i/s - 1.00x slower v0.5.12: 2583.6 i/s - 6.56x slower abnormal generate and compare: 17610.8 i/s reparse and check: 16596.1 i/s - 1.06x slower v0.5.12: 2560.3 i/s - 6.88x slower frozen unsorted reparse and check: 10089.5 i/s v0.5.12: 2333.7 i/s - 4.32x slower generate and compare: 2093.1 i/s - 4.82x slower frozen abnormal reparse and check: 10392.1 i/s v0.5.12: 2354.5 i/s - 4.41x slower generate and compare: 2124.3 i/s - 4.89x slower ``` Please note that these results do vary based on benchmark settings, e.g: size of the sequence set.
1 parent 74156fd commit 2baf04d

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

benchmarks/sequence_set-normalize.yml

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ prelude: |
4242
end
4343
end
4444
45-
def init_unsorted_sets(...)
45+
def make_unsorted_sets(...)
4646
init_sets(...)
4747
.each do |seqset|
4848
entries = shuffle_entries(seqset)
@@ -51,6 +51,10 @@ prelude: |
5151
seqset.append entry
5252
end
5353
end
54+
end
55+
56+
def init_unsorted_sets(...)
57+
make_unsorted_sets(...)
5458
.tap do maybe_profile("seqset-normalize-unsorted") end
5559
end
5660
@@ -68,14 +72,30 @@ prelude: |
6872
.join(",")
6973
end
7074
71-
def init_abnormal_sets(...)
75+
def make_abnormal_sets(...)
7276
init_sets(...)
7377
.each do |seqset|
7478
seqset.string = abnormal_form(seqset)
7579
end
80+
end
81+
82+
def init_abnormal_sets(...)
83+
make_abnormal_sets(...)
7684
.tap do maybe_profile("seqset-normalize-abnormal") end
7785
end
7886
87+
def init_frozen_unsorted_sets(...)
88+
make_unsorted_sets(...)
89+
.map(&:freeze)
90+
.tap do maybe_profile("seqset-normalize-frozen-unsorted") end
91+
end
92+
93+
def init_frozen_abnormal_sets(...)
94+
make_abnormal_sets(...)
95+
.map(&:freeze)
96+
.tap do maybe_profile("seqset-normalize-frozen-abnormal") end
97+
end
98+
7999
# warmup (esp. for JIT)
80100
WARMUP_RUNS.times do
81101
init_sets(count: 20, set_size: 100, max: 120).each do |set|
@@ -96,6 +116,12 @@ benchmark:
96116
- name: "abnormal"
97117
prelude: $sets = init_abnormal_sets
98118
script: $sets.sample.normalize
119+
- name: "frozen unsorted"
120+
prelude: $sets = init_frozen_unsorted_sets
121+
script: $sets.sample.normalize
122+
- name: "frozen abnormal"
123+
prelude: $sets = init_frozen_abnormal_sets
124+
script: $sets.sample.normalize
99125

100126
contexts:
101127
# n.b: can't use anything newer as the baseline: it's over 500x faster!

lib/net/imap/sequence_set.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1707,7 +1707,7 @@ def xor!(other)
17071707
#
17081708
# Related: #normalize!, #normalized_string
17091709
def normalize
1710-
return self if frozen? && (@string.nil? || @string == normalized_string)
1710+
return self if frozen? && (@string.nil? || normal_string?(@string))
17111711
remain_frozen dup.normalize!
17121712
end
17131713

@@ -1907,6 +1907,8 @@ def each_parsed_entry(str)
19071907
str&.split(",", -1) do |entry| yield parse_string_entry(entry) end
19081908
end
19091909

1910+
def normal_string?(str) normalized_entries? each_parsed_entry str end
1911+
19101912
def normalized_entries?(entries)
19111913
max = nil
19121914
entries.each do |first, last|

0 commit comments

Comments
 (0)