Skip to content

perf: SortedMap.exists and forall walk a map with a reference type through the interface - #47

Open
xperiandri wants to merge 1 commit into
feat/sorted-mapfrom
perf/sorted-map
Open

xperiandri wants to merge 1 commit into
feat/sorted-mapfrom
perf/sorted-map

Conversation

@xperiandri

Copy link
Copy Markdown
Collaborator

Proposed Changes

Builds on #37. SortedMap.exists and SortedMap.forall walk a map through IEnumerable<KeyValuePair<K, V>> when the key or the value is a reference type, and through the struct enumerator of ImmutableSortedDictionary<K, V> when both are value types. In the code that all reference types share, each call of a member of a generic struct needs a lookup of the exact type at run time, and the struct enumerator of ImmutableSortedDictionary<K, V> is made of such calls. No public signature changes.

strings a string next to an integer integers
a walk through the interface against the struct enumerator, 100 to 100 000 bindings 0.56 to 0.62 of the time (16 against 29 ns per binding) 1.3 to 1.6
exists and forall of the library against a copy of the old loop, 100 to 100 000 bindings, two runs 0.55 to 0.84 (the largest map is the noisiest cell) 0.60 to 0.69 in either place 0.90 to 1.13, the same time

Ratios are the time relative to the code before; below 1 is faster. The cost of the interface is the boxed enumerator, 56 bytes per call, which the comment of the functions already counted. The base build read 0.90 to 1.10 against the same copy of the old loop, which is the check of the script.

The other collections were measured for the same pattern too; only SortedSet and SortedMap gain (the method, and the tables of every collection and cell, are in the fifth comment of #45: #45 (comment)).

The contracts run on integers, so the commit adds tests with strings and with a string next to an integer: the results of Map, and the stop at the first match and at the first failure.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

A performance change that keeps every result and every signature.

Checklist

  • Build and tests pass locally (the whole test project: 9 922 test runs on net8.0 and net10.0)
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation: the comment above exists and forall carries the measured numbers, as the other comments of the module do

🤖 Generated with Claude Code

…e through the interface

The code that all reference types share needs a lookup of the exact type at run time for each call of a member of a
generic struct, and the struct enumerator of `ImmutableSortedDictionary<K, V>` is made of such calls. A walk through
`IEnumerable<KeyValuePair<K, V>>` took 0.56 to 0.62 times as long for strings of 100 to 100 000 bindings (16 against 29 ns
for a binding) and 1.3 to 1.6 times as long for integers, so `typeof` of the key and of the value picks the enumerator: the
struct one when both are value types, the interface when either is a reference type.

Compiled into the library and measured against a copy of the old loop in the same process, `exists` and `forall` took
0.55 to 0.84 times as long for string keys and values (the largest map is the noisiest cell), 0.60 to 0.69 for a string
next to an integer in either place, and the same time for integer keys and values (0.90 to 1.13). The cost is the boxed
enumerator, 56 bytes per call, which the comment of the functions already counted.

The contracts run on integers, so strings, and a string next to an integer, get tests of their own: the results of `Map`,
and the stop at the first match and at the first failure.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant