Skip to content

Conversation

@RicoSuter
Copy link
Contributor

@RicoSuter RicoSuter commented Dec 3, 2025

Proposed changes

Some performance optimizations, reducing memory allocations by ~23% while maintaining full API compatibility and thread-safety.

Related Issues

Types of changes

What types of changes does your code introduce?

  • Bugfix (non-breaking change which fixes an issue)
  • Enhancement (non-breaking change which adds functionality)
  • Test enhancement (non-breaking change to increase test coverage)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected, requires version increase of Nuget packages)
  • Documentation Update (if none of the other choices apply)

Checklist

Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.

  • I have read the CONTRIBUTING doc.
  • I have signed the CLA.
  • I ran tests locally with my changes, all passed.
  • I fixed all failing tests in the CI pipelines.
  • I fixed all introduced issues with CodeQL and LGTM.
  • I have added tests that prove my fix is effective or that my feature works and increased code coverage.
  • I have added necessary documentation (if appropriate).
  • Any dependent changes have been merged and published in downstream modules.

Further comments

1. LoggerFactory Singleton Pattern

File: Stack/Opc.Ua.Core/Types/Utils/LoggerUtils.cs:95-99

Introduced singleton pattern for TraceLoggerTelemetry to eliminate repeated allocations:

private static readonly TraceLoggerTelemetry s_sharedTelemetry = new();

static Utils()
{
    TelemetryExtensions.InternalOnly__TelemetryHook = () => s_sharedTelemetry;
}

Impact: Primary source of 23% allocation reduction
Safety: Thread-safe, no API changes

2. Additional Optimizations

The upstream library also includes:

  • ConcurrentDictionary for lock-free reads in Subscription.cs
  • Enhanced EventSource/ETW telemetry
  • Queue handling improvements
  • MonitoredItem optimizations

All changes maintain backward compatibility.

Benchmark results

Master branch (baseline):

===========================================================================================================================================
Client Benchmark - 1 minute - [2025-12-03 11:22:29.342]

Total received changes:          1194276
Total published changes:         1000000
Process memory:                  555.02 MB (289.25 MB in .NET heap)
Avg allocations over last 60s:   97.03 MB/s

Metric                               Avg        P50        P90        P95        P99      P99.9        Max        Min     StdDev      Count
-------------------------------------------------------------------------------------------------------------------------------------------
Received (changes/s)            19917.67   19902.19   21523.12   22004.03   23617.96   23617.96   23617.96   15474.36    1398.62          -
Processing latency (ms)             4.78       2.37      14.25      20.25      29.60      39.71      73.16       0.00       6.52    1194276
End-to-end latency (ms)            82.79      71.80     146.49     165.29     270.05     387.09     427.97       0.90      51.32    1194276
===========================================================================================================================================
Server Benchmark - 1 minute - [2025-12-03 11:22:29.764]

Total received changes:          1006334
Total published changes:         1192400
Process memory:                  718.87 MB (448.94 MB in .NET heap)
Avg allocations over last 60s:   505.28 MB/s

Metric                               Avg        P50        P90        P95        P99      P99.9        Max        Min     StdDev      Count
-------------------------------------------------------------------------------------------------------------------------------------------
Received (changes/s)            16737.91   16894.72   17389.25   17503.45   17549.66   17549.66   17549.66   13848.97     690.37          -
Processing latency (ms)             0.00       0.00       0.00       0.01       0.01       0.07     244.58       0.00       0.25    1006334
End-to-end latency (ms)           332.08     332.24     546.72     591.58     713.86     802.54     941.21       0.77     167.16    1006334

This PR (optimizations):

===========================================================================================================================================
Client Benchmark - 1 minute - [2025-12-03 11:08:41.825]

Total received changes:          1194087
Total published changes:         1007994
Process memory:                  545.32 MB (290.39 MB in .NET heap)
Avg allocations over last 60s:   74.04 MB/s

Metric                               Avg        P50        P90        P95        P99      P99.9        Max        Min     StdDev      Count
-------------------------------------------------------------------------------------------------------------------------------------------
Received (changes/s)            19903.96   19906.61   21330.26   21587.95   21664.65   21664.65   21664.65   16468.73    1118.32          -
Processing latency (ms)             5.78       2.71      18.04      25.35      35.88      44.56     142.66       0.01       8.35    1194087
End-to-end latency (ms)            76.47      67.54     137.84     154.21     191.12     283.48     314.49       1.19      44.27    1194087
===========================================================================================================================================
Server Benchmark - 1 minute - [2025-12-03 11:08:43.428]

Total received changes:          1000896
Total published changes:         1193530
Process memory:                  737.14 MB (423.26 MB in .NET heap)
Avg allocations over last 60s:   474.08 MB/s

Metric                               Avg        P50        P90        P95        P99      P99.9        Max        Min     StdDev      Count
-------------------------------------------------------------------------------------------------------------------------------------------
Received (changes/s)            16662.03   16716.28   17198.44   17389.35   17589.10   17589.10   17589.10   14610.73     573.32          -
Processing latency (ms)             0.00       0.00       0.00       0.01       0.01       0.08      23.24       0.00       0.05    1000896
End-to-end latency (ms)           302.90     300.90     504.83     544.12     665.81     736.51     760.37       0.21     153.72    1000896

Client => from 97 mb/s to 74 mb/s, 5ms lower latency on avg
Server => from 505 mb/s to 474 mb/s, 30ms lower latency on avg

@CLAassistant
Copy link

CLAassistant commented Dec 3, 2025

CLA assistant check
All committers have signed the CLA.

@RicoSuter RicoSuter changed the title Performance/reduce allocations logger performance: Reduce allocations (logger factory reuse, check enabled) Dec 3, 2025
@RicoSuter
Copy link
Contributor Author

Test Project Status Results
Opc.Ua.Types.Tests ✅ PASSED 288 tests passed
Opc.Ua.Security.Certificates.Tests ✅ PASSED 144 tests passed
Opc.Ua.Encoders.Fuzz.Tests ✅ PASSED 150 tests passed
Opc.Ua.Configuration.Tests ✅ PASSED All tests passed
Opc.Ua.PubSub.Tests ✅ PASSED All tests passed
Opc.Ua.Core.Tests ✅ PASSED All tests passed
Opc.Ua.Server.Tests ✅ PASSED All tests passed
Opc.Ua.Gds.Tests ✅ PASSED All tests passed
Opc.Ua.Client.Tests ✅ PASSED Failed: 0, Passed: 1001, Skipped: 163
Opc.Ua.Client.ComplexTypes.Tests ✅ PASSED Failed: 0, Passed: 3574, Skipped: 0

@codecov
Copy link

codecov bot commented Dec 3, 2025

Codecov Report

❌ Patch coverage is 11.11111% with 64 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.95%. Comparing base (d25caff) to head (f89a12f).
⚠️ Report is 26 commits behind head on master.

Files with missing lines Patch % Lines
...raries/Opc.Ua.Client/Subscription/MonitoredItem.cs 15.78% 14 Missing and 2 partials ⚠️
...ies/Opc.Ua.Server/Server/OpcUaServerEventSource.cs 0.00% 13 Missing and 2 partials ⚠️
.../Opc.Ua.Server/Subscription/SubscriptionManager.cs 0.00% 10 Missing and 3 partials ⚠️
Libraries/Opc.Ua.Client/OpcUaClientEventSource.cs 0.00% 5 Missing and 3 partials ⚠️
...braries/Opc.Ua.Client/Subscription/Subscription.cs 27.27% 6 Missing and 2 partials ⚠️
...nitoredItem/QueueHandler/DataChangeQueueHandler.cs 0.00% 1 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3387      +/-   ##
==========================================
+ Coverage   51.86%   59.95%   +8.08%     
==========================================
  Files         370      374       +4     
  Lines       78618    78304     -314     
  Branches    13650    13620      -30     
==========================================
+ Hits        40779    46947    +6168     
+ Misses      33705    27026    -6679     
- Partials     4134     4331     +197     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

@marcschier
Copy link
Collaborator

Thanks @RicoSuter - this is great, one more thing off my plate :-)

@RicoSuter
Copy link
Contributor Author

RicoSuter commented Dec 3, 2025

@marcschier i think the changes here are really low-risk, no? Reusing the factory instead of creating needs to be checked but seems also safe for me... will dig deeper into more complex improvements when i have time.

@RicoSuter
Copy link
Contributor Author

@marcschier my personal goal is still to achieve 1.2 mio changes in both directions and on server side <100ms average :-) not even sure whether this is possible with OPC UA :-D

@marcschier
Copy link
Collaborator

@RicoSuter, one of the changes we need for that to happen is to reduce GC pressure for monitored item notification and DataValue, Variant, and node id allocations on the subscribe/publish paths client side, we have some benchmarks and the improvements are worth it although it will break apis. Goal is before April next year.

@marcschier
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@RicoSuter
Copy link
Contributor Author

@marcschier do you expect that I add unit tests for the changed LoCs?

@marcschier marcschier merged commit 0e8273e into OPCFoundation:master Dec 4, 2025
83 of 84 checks passed
@marcschier
Copy link
Collaborator

@RicoSuter - No, most of it was for legacy pieces, and the one you fixed is actively tested already... Sorry took longer to merge the queue is quite full right now...

@RicoSuter
Copy link
Contributor Author

RicoSuter commented Dec 7, 2025

@marcschier I've run benchmarks again and updated the PR:

Client receive processing looks good now (even a bit faster), server side still degraded (4-8%) but this is less a problem because most clients do not write that much.

Comparison grid here:
RicoSuter/Namotion.Interceptor#104

Thanks for merging my PR.

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.

Possible memory allocation regression in v1.5.378.10-preview

4 participants