Skip to content

Reduce NodeState memory by 128 B via lazy locks and Interlocked - #4425

Draft
marcschier wants to merge 2 commits into
masterfrom
optimize-nodestate-memory
Draft

Reduce NodeState memory by 128 B via lazy locks and Interlocked#4425
marcschier wants to merge 2 commits into
masterfrom
optimize-nodestate-memory

Conversation

@marcschier

@marcschier marcschier commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Description

Reduce NodeState constructor allocation by 128 B per node on net10.0 x64 by replacing eager lock-object allocation with lock-free primitives and lazy initialization:

  • Removes the dedicated event-monitor counter Lock field in favor of Interlocked/Volatile operations and a clamped decrement, eliminating one heap allocation per node constructor call.
  • Lazily publishes the notifier and browse Lock fields using Interlocked.CompareExchange, preserving the browse → notifier → reference lock ordering.
  • Adds deterministic concurrency tests for excess counter decrements, first-use notifier lock publication, notifier-free fast paths, and serialized browse population.
  • Adds allocation and browse benchmarks for constructor-only, first-use browse, warmed browse, and rendezvoused same-node browse contention.
  • Public API is unchanged. Callback sidecars are deliberately out of scope because replacing the existing public callback fields would be binary-incompatible.

Final net10.0 x64 allocation results:

Scenario master This PR Delta
Construct BaseObjectState 816 B 688 B -128 B
Construct BaseDataVariableState 1,152 B 1,024 B -128 B
First browse of a new node 1,080 B 992 B -88 B
Warm browse 264 B 264 B unchanged
Two rendezvoused browse workers 528 B 528 B unchanged

The matched ShortRun benchmark showed no warm-path regression: warm browse was 69.7 ns on this branch versus 76.4 ns on master. The contended benchmark is scheduler-sensitive, but allocation is identical and the direct warmed path is unchanged after lazy publication.

Related Issues

Checklist

Put an x in the boxes that apply. You can complete these step by step after opening the PR.

  • I have signed the CLA and read the CONTRIBUTING doc.
  • I have added tests that prove my fix is effective or that my feature works and increased code coverage.
  • I have added all necessary documentation.
  • I have verified that my changes do not introduce (new) build or analyzer warnings.
  • I ran all tests locally using the UA.slnx solution against at least .net framework and .net 10, and all passed.
  • I fixed all failing and flaky tests in the CI pipelines and all CodeQL warnings.
  • I have addressed all PR feedback received.

Local validation summary

Validation Result
Opc.Ua.Types.Tests NodeState category, net10.0 642 passed, 0 failed
Opc.Ua.Types.Tests NodeState category, net48 642 passed, 0 failed
Review-focused tests, net10.0 16 passed, 0 failed
Opc.Ua.Server.Tests, net10.0 4,865 passed, 0 failed
UA.slnx Release build with CustomTestTarget=net10.0 succeeded
Opc.Ua.Aot.Tests managed Release build succeeded
BenchmarkDotNet ShortRun, net10.0 x64 completed on branch and master with the same benchmark source

Earlier full Opc.Ua.Types.Tests runs on both TFMs each reached one pre-existing WoT fixture hash failure. The net48 Opc.Ua.Server.Tests run reached a pre-existing certificate-leak teardown failure. Neither failure is in code touched by this PR.

Replace the dedicated event-monitor counter field with Interlocked/Volatile
operations and a clamped decrement. Lazily publish the notifier and browse
Lock fields with CompareExchange, preserving lock ordering. Add concurrency
tests and allocation benchmarks. Public API is unchanged; constructor
allocation reduced by 128 B per node on net10.0 x64.

Relates to #4275

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d2569e2e-7115-4969-bb44-8159e302b450
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Code coverage

Coverage gate passed.

Check Result Threshold
✅ Project line rate 86.79% (240407/276994 lines) >= 70.00%
✅ Project branch rate 76.71% >= 60.00%
✅ Patch coverage 94.83% (55/58 changed lines) >= 60.00% (<= 100 changed lines, advisory)
ℹ️ Baseline delta (advisory) +13.19 pp 73.60% recorded
Uncovered changed lines
  • src/Opc.Ua.Types/State/NodeState.cs: 2643, 2644, 2802

Coverage is above the recorded baseline - consider ratcheting coverage-thresholds.json.

Thresholds live in coverage-thresholds.json. Whole report before exclusions: line 85.87%, branch 75.84%.

@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.75862% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.87%. Comparing base (c4960b5) to head (5341874).
⚠️ Report is 6 commits behind head on master.

Files with missing lines Patch % Lines
src/Opc.Ua.Types/State/NodeState.cs 82.75% 3 Missing and 7 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #4425      +/-   ##
==========================================
+ Coverage   80.70%   80.87%   +0.16%     
==========================================
  Files        1959     1984      +25     
  Lines      272896   276994    +4098     
  Branches    47380    48073     +693     
==========================================
+ Hits       220242   224020    +3778     
- Misses      36173    36437     +264     
- Partials    16481    16537      +56     
Flag Coverage Δ
actions 80.87% <82.75%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/Opc.Ua.Types/State/NodeState.cs 77.68% <82.75%> (-0.04%) ⬇️

... and 127 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d2569e2e-7115-4969-bb44-8159e302b450
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