Skip to content

Avoid a set per combineWith and cache TransitionFunctionImpl's hash - #334

Merged
swissiety merged 1 commit into
developfrom
perf/transition-function-combine
Sep 23, 2026
Merged

swissiety merged 1 commit into
developfrom
perf/transition-function-combine

Conversation

@swissiety

Copy link
Copy Markdown
Member

Follow-up to #281, picking up the allocation concern from its review.

What changes

  • combineWith built a LinkedHashSet of both functions' state change statements on every call, only to discard it in the common case where the union is a single statement. It now checks whether the other function already has all of this function's statements (typically both have the same single one) and, if so, returns a function of the other's kind with the merged sequences. Only a genuinely new combination builds an ImmutableSet, which CombinedTransitionFunctionImpl takes over without copying (ImmutableSet.copyOf on an ImmutableSet is a no-op).
  • hashCode() hashed the whole sequence multimap on every call, while weights are hashed repeatedly as keys of the automata's maps. The functions are immutable, so the hash is computed once and cached (the same racy-single-check idiom as String.hashCode). With compressed oops the extra int fits in the existing padding of a plain TransitionFunctionImpl; only the rare combined instance grows by 8 bytes.

Behaviour is unchanged: the result has the same set of state change statements as before, getStateChangeStatement() returns the same statement, and combining stays commutative and idempotent. TransitionFunctionImplTest gains an assertion for the shortcut direction and for hash equality of the commutative results.

Testing (-DtestSetup=Soot)

  • All idealPDS test classes pass except IteratorHasNextTest test1/test2/test4, which fail identically on develop.
  • FileMustBeClosedTest (49 tests): 71.1 s on this branch vs 73.7 s on develop, one run each, so within noise. No regression, but no claimed speed-up either.

🤖 Generated with Claude Code

Follow-up to #281. combineWith built a LinkedHashSet of both functions'
state change statements on every call, only to throw it away again in
the common case where the union is a single statement. It now checks
whether the other function already has all of this function's
statements (typically both have the same single one) and, if so,
returns a function of the other's kind with the merged sequences; only
a genuinely new combination builds an ImmutableSet, which
CombinedTransitionFunctionImpl then takes over without copying. The
result's statements, and the one getStateChangeStatement() returns,
are the same as before.

hashCode() hashed the whole sequence multimap on every call, while the
weights are hashed over and over as keys of the automata's maps. The
functions are immutable, so the hash is now computed once and cached.
With compressed oops the extra int fits in the padding of a plain
TransitionFunctionImpl.
@swissiety
swissiety enabled auto-merge September 23, 2026 14:55
@swissiety
swissiety merged commit ff8457f into develop Sep 23, 2026
8 checks passed
@swissiety
swissiety deleted the perf/transition-function-combine branch September 23, 2026 15:00
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