diff --git a/Fuzzing/Encoders/Fuzz.Tests/Opc.Ua.Encoders.Fuzz.Tests.csproj b/Fuzzing/Encoders/Fuzz.Tests/Opc.Ua.Encoders.Fuzz.Tests.csproj
index c442d0e38..01a220e07 100644
--- a/Fuzzing/Encoders/Fuzz.Tests/Opc.Ua.Encoders.Fuzz.Tests.csproj
+++ b/Fuzzing/Encoders/Fuzz.Tests/Opc.Ua.Encoders.Fuzz.Tests.csproj
@@ -31,7 +31,8 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
diff --git a/Stack/Opc.Ua.Core/Stack/Bindings/BufferManager.cs b/Stack/Opc.Ua.Core/Stack/Bindings/BufferManager.cs
index 730b2b708..2f79d6849 100644
--- a/Stack/Opc.Ua.Core/Stack/Bindings/BufferManager.cs
+++ b/Stack/Opc.Ua.Core/Stack/Bindings/BufferManager.cs
@@ -405,7 +405,7 @@ class Allocation
private readonly object m_lock = new object();
private int m_allocated;
private int m_id;
- private SortedDictionary m_allocations = new SortedDictionary();
+ private Dictionary m_allocations = new Dictionary();
#else
private const byte kCookieLength = 1;
#endif
diff --git a/Tests/Common/Main.cs b/Tests/Common/Main.cs
index 533666dba..da1588d60 100644
--- a/Tests/Common/Main.cs
+++ b/Tests/Common/Main.cs
@@ -28,19 +28,66 @@
* ======================================================================*/
using System;
+using System.Linq;
+using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Jobs;
+using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
+using BenchmarkDotNet.Validators;
+using Opc.Ua;
-static class Program
+[assembly: Config(typeof(BenchmarksDefaultConfig))]
+
+class BenchmarksDefaultConfig : ManualConfig
{
- // Main Method
- public static void Main(String[] args)
+ public BenchmarksDefaultConfig()
{
- IConfig config = ManualConfig.Create(DefaultConfig.Instance)
- // need this option because of reference to nunit.framework
- .WithOptions(ConfigOptions.DisableOptimizationsValidator)
- ;
- BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
+ if (Program.CmdLineUsed)
+ {
+ var defaults = DefaultConfig.Instance;
+ foreach (var exporter in defaults.GetExporters())
+ {
+ AddExporter(exporter);
+ }
+ foreach (var logger in defaults.GetLoggers())
+ {
+ AddLogger(logger);
+ }
+ foreach (var analyser in defaults.GetAnalysers())
+ {
+ AddAnalyser(analyser);
+ }
+ foreach (var validator in defaults.GetValidators())
+ {
+ AddValidator(validator);
+ }
+ WithOptions(ConfigOptions.DisableOptimizationsValidator);
+ }
+ else
+ {
+ AddJob(Job.Dry);
+ AddLogger(ConsoleLogger.Default);
+ AddValidator(JitOptimizationsValidator.DontFailOnError);
+ }
}
-}
+ static class Program
+ {
+ ///
+ /// Whether command line was used to start.
+ ///
+ public static bool CmdLineUsed = false;
+
+ // Main Method
+ public static void Main(string[] args)
+ {
+ IConfig config = ManualConfig.Create(DefaultConfig.Instance)
+ // need this option because of reference to nunit.framework
+ .WithOptions(ConfigOptions.DisableOptimizationsValidator)
+ ;
+ CmdLineUsed = true;
+ BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
+ }
+ }
+}
diff --git a/Tests/Opc.Ua.Client.ComplexTypes.Tests/Opc.Ua.Client.ComplexTypes.Tests.csproj b/Tests/Opc.Ua.Client.ComplexTypes.Tests/Opc.Ua.Client.ComplexTypes.Tests.csproj
index 1672657e9..7f8a1356a 100644
--- a/Tests/Opc.Ua.Client.ComplexTypes.Tests/Opc.Ua.Client.ComplexTypes.Tests.csproj
+++ b/Tests/Opc.Ua.Client.ComplexTypes.Tests/Opc.Ua.Client.ComplexTypes.Tests.csproj
@@ -11,6 +11,8 @@
+
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/Tests/Opc.Ua.Client.Tests/ContinuationPointInBatchTest.cs b/Tests/Opc.Ua.Client.Tests/ContinuationPointInBatchTest.cs
index 1a485928b..aae4cc354 100644
--- a/Tests/Opc.Ua.Client.Tests/ContinuationPointInBatchTest.cs
+++ b/Tests/Opc.Ua.Client.Tests/ContinuationPointInBatchTest.cs
@@ -824,7 +824,7 @@ public void ParallelManagedBrowseWithManyContinuationPoints(ManagedBrowseTestDat
}
}
-#endregion Tests
+ #endregion Tests
#region async tests
diff --git a/Tests/Opc.Ua.Client.Tests/Opc.Ua.Client.Tests.csproj b/Tests/Opc.Ua.Client.Tests/Opc.Ua.Client.Tests.csproj
index f43c0d631..3f76f3f12 100644
--- a/Tests/Opc.Ua.Client.Tests/Opc.Ua.Client.Tests.csproj
+++ b/Tests/Opc.Ua.Client.Tests/Opc.Ua.Client.Tests.csproj
@@ -25,6 +25,8 @@
+
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/Tests/Opc.Ua.Configuration.Tests/Opc.Ua.Configuration.Tests.csproj b/Tests/Opc.Ua.Configuration.Tests/Opc.Ua.Configuration.Tests.csproj
index 0c90649cc..396b672ee 100644
--- a/Tests/Opc.Ua.Configuration.Tests/Opc.Ua.Configuration.Tests.csproj
+++ b/Tests/Opc.Ua.Configuration.Tests/Opc.Ua.Configuration.Tests.csproj
@@ -33,7 +33,8 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
diff --git a/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj b/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj
index ea041e192..225147ab2 100644
--- a/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj
+++ b/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj
@@ -13,6 +13,8 @@
+
+
diff --git a/Tests/Opc.Ua.Core.Tests/Types/Utils/DictionaryKeyBenchmark.cs b/Tests/Opc.Ua.Core.Tests/Types/Utils/DictionaryKeyBenchmark.cs
new file mode 100644
index 000000000..30bdf9e5f
--- /dev/null
+++ b/Tests/Opc.Ua.Core.Tests/Types/Utils/DictionaryKeyBenchmark.cs
@@ -0,0 +1,601 @@
+/* ========================================================================
+ * Copyright (c) 2005-2024 The OPC Foundation, Inc. All rights reserved.
+ *
+ * OPC Foundation MIT License 1.00
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The complete license agreement can be found here:
+ * http://opcfoundation.org/License/MIT/1.00/
+ * ======================================================================*/
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using BenchmarkDotNet.Attributes;
+using NUnit.Framework;
+using Assert = NUnit.Framework.Legacy.ClassicAssert;
+
+
+using BenchmarkDotNet.Order;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Collections.ObjectModel;
+using Opc.Ua;
+using Opc.Ua.Test;
+using System.Collections.Concurrent;
+using BenchmarkDotNet.Configs;
+#if NET8_0_OR_GREATER
+using System.Collections.Frozen;
+#endif
+
+namespace Opc.Ua.Core.Tests.Types.UtilsTests
+{
+ ///
+ /// Performance tests for uint key dictionaries.
+ ///
+ [TestFixture, Category("Dictionary")]
+ [SetCulture("en-us"), SetUICulture("en-us")]
+ [Parallelizable]
+ [MemoryDiagnoser]
+ [Orderer(SummaryOrderPolicy.FastestToSlowest)]
+ [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
+ [BenchmarkCategory("uint")]
+ [CategoriesColumn]
+ public class DictionaryUIntKeyBenchmark : DictionaryKeyBenchmark
+ {
+ }
+
+ ///
+ /// Performance tests for NodeId key dictionaries.
+ ///
+ [TestFixture, Category("Dictionary")]
+ [SetCulture("en-us"), SetUICulture("en-us")]
+ [Parallelizable]
+ [MemoryDiagnoser]
+ [Orderer(SummaryOrderPolicy.FastestToSlowest)]
+ [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
+ [BenchmarkCategory(nameof(NodeId))]
+ [CategoriesColumn]
+ public class DictionaryNodeIdKeyBenchmark : DictionaryKeyBenchmark
+ {
+ [Params(IdType.Numeric, IdType.String, IdType.Guid, IdType.Opaque, IdType.Opaque + 1)]
+ public IdType NodeIdType { get; set; } = (uint)IdType.Numeric;
+
+ private NodeIdDictionary m_nodeIdDictionary = null;
+
+ ///
+ /// Tests performance and memory usage of ImmutableDictionary.
+ ///
+ [Test]
+ [BenchmarkCategory("TryGet")]
+ [Benchmark()]
+ public void TestNodeIdDictionary()
+ {
+ foreach (NodeId key in m_lookup)
+ {
+ _ = m_nodeIdDictionary.TryGetValue(key, out _);
+ }
+ }
+
+ protected override NodeId GetRandomKey(Random random, DataGenerator generator)
+ {
+ IdType nodeIdType = NodeIdType;
+ if (NodeIdType > IdType.Opaque)
+ {
+ nodeIdType = (IdType)random.Next((int)IdType.Numeric, (int)IdType.Opaque);
+ }
+
+ switch (nodeIdType)
+ {
+ case IdType.String:
+ return new NodeId(generator.GetRandomString(), (ushort)random.Next(0, 10));
+ case IdType.Guid:
+ return new NodeId(Guid.NewGuid(), (ushort)random.Next(0, 10));
+ case IdType.Opaque:
+ return new NodeId(generator.GetRandomByteString(), (ushort)random.Next(0, 10));
+ default:
+ case IdType.Numeric:
+ return new NodeId((uint)random.Next(0, 10 * NumElements), (ushort)random.Next(0, 10));
+ }
+ }
+
+ ///
+ /// Overridden to initialize the NodeIdDictionary.
+ ///
+ protected override void Initialize()
+ {
+ base.Initialize();
+ m_nodeIdDictionary = new NodeIdDictionary();
+ foreach (var entry in m_regularDictionary)
+ {
+ m_nodeIdDictionary.Add(entry.Key, entry.Value);
+ }
+ }
+ }
+
+ ///
+ /// Performance tests for T key dictionaries. Abstract to exclude from tests.
+ ///
+ public abstract class DictionaryKeyBenchmark
+ {
+ // [Params(16, 128, 1024)]
+ public int NumElements { get; set; } = 1024;
+
+ // Create a Dictionary and a SortedDictionary
+ protected T[] m_lookup = null;
+ protected Dictionary m_regularDictionary = null;
+ protected NamespaceTable m_namespaceTable = new NamespaceTable(new List { Namespaces.OpcUa, "urn:myserver", "http://opcfoundation.org/bar", "http://opcfoundation.org/foo" });
+
+ // test dictionaries
+ private ImmutableDictionary m_immutableDictionary = null;
+ private ConcurrentDictionary m_concurrentDictionary = null;
+ private SortedDictionary m_sortedDictionary = null;
+ private ReadOnlyDictionary m_readonlyDictionary = null;
+#if NET8_0_OR_GREATER
+ private FrozenDictionary m_frozenDictionary = null;
+#endif
+
+ // worker dictionaries for add/remove
+ private Dictionary m_regularWorker = null;
+ private ConcurrentDictionary m_concurrentWorker = null;
+ private SortedDictionary m_sortedWorker = null;
+
+ // synchronization
+ private object m_lock;
+
+ #region Test Setup
+ [OneTimeSetUp]
+ public void OneTimeSetUp()
+ {
+ Initialize();
+ }
+
+ [OneTimeTearDown]
+ public void OneTimeTearDown()
+ {
+ }
+ #endregion
+
+ #region Benchmark Setup
+ ///
+ /// Set up some variables for benchmarks.
+ ///
+ [GlobalSetup]
+ public void GlobalSetup()
+ {
+ Initialize();
+ }
+
+ ///
+ /// Tear down benchmark variables.
+ ///
+ [GlobalCleanup]
+ public void GlobalCleanup()
+ {
+ }
+ #endregion
+
+ #region TryGetValue
+ ///
+ /// Tests performance and memory usage of ImmutableDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Immutable")]
+ [BenchmarkCategory("TryGet")]
+ public void TestImmutableDictionary()
+ {
+ foreach (T key in m_lookup)
+ {
+ _ = m_immutableDictionary.TryGetValue(key, out _);
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of SortedDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Concurrent")]
+ [BenchmarkCategory("TryGet")]
+ public void TestConcurrentDictionary()
+ {
+ foreach (T key in m_lookup)
+ {
+ _ = m_concurrentDictionary.TryGetValue(key, out _);
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of SortedDictionary.
+ ///
+ [Test]
+ [Benchmark]
+ [BenchmarkCategory("TryGet")]
+ public void TestSortedDictionary()
+ {
+ foreach (T key in m_lookup)
+ {
+ _ = m_sortedDictionary.TryGetValue(key, out _);
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of ReadonlyDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Readonly")]
+ [BenchmarkCategory("TryGet")]
+ public void TestReadonlyDictionary()
+ {
+ foreach (T key in m_lookup)
+ {
+ _ = m_readonlyDictionary.TryGetValue(key, out _);
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of Dictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Regular", Baseline = true)]
+ [BenchmarkCategory("TryGet")]
+ public void TestRegularDictionary()
+ {
+ foreach (T key in m_lookup)
+ {
+ _ = m_regularDictionary.TryGetValue(key, out _);
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of FrozenDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Frozen")]
+ [BenchmarkCategory("TryGet")]
+ public void TestFrozenDictionary()
+ {
+#if NET8_0_OR_GREATER
+ foreach (T key in m_lookup)
+ {
+ _ = m_frozenDictionary.TryGetValue(key, out _);
+ }
+#else
+ TestRegularDictionary();
+#endif
+ }
+ #endregion
+
+ #region RemoveValue
+ [IterationSetup(Target = nameof(TryRemoveConcurrentDictionary))]
+ public void PrepareTryRemoveConcurrentDictionary()
+ {
+ m_concurrentWorker = new ConcurrentDictionary(m_regularDictionary);
+ }
+
+ [Test]
+ [Benchmark(Description = "Concurrent")]
+ [BenchmarkCategory("Remove")]
+ public void TryRemoveConcurrentDictionary()
+ {
+ foreach (T key in m_lookup)
+ {
+ _ = m_concurrentWorker.TryRemove(key, out _);
+ }
+ }
+
+ [IterationSetup(Target = nameof(TryRemoveSortedDictionary))]
+ public void PrepareTryRemoveSortedDictionary()
+ {
+ m_sortedWorker = new SortedDictionary(m_regularDictionary);
+ }
+
+ [Test]
+ [Benchmark]
+ [BenchmarkCategory("Remove")]
+ public void TryRemoveSortedDictionary()
+ {
+ foreach (T key in m_lookup)
+ {
+ lock (m_lock)
+ {
+ _ = m_sortedWorker.Remove(key);
+ }
+ }
+ }
+
+ [IterationSetup(Target = nameof(TryRemoveRegularDictionary))]
+ public void PrepareTryRemoveDictionary()
+ {
+ m_regularWorker = new Dictionary(m_regularDictionary);
+ }
+
+ ///
+ /// Tests performance and memory usage of Dictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Regular", Baseline = true)]
+ [BenchmarkCategory("Remove")]
+ public void TryRemoveRegularDictionary()
+ {
+ foreach (T key in m_lookup)
+ {
+ lock (m_lock)
+ {
+ _ = m_regularWorker.Remove(key);
+ }
+ }
+ }
+ #endregion
+
+ #region Iterate
+ ///
+ /// Tests performance and memory usage of ImmutableDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Immutable")]
+ [BenchmarkCategory("Iterate")]
+ public void IterateImmutableDictionary()
+ {
+ foreach (var keyPair in m_immutableDictionary)
+ {
+ _ = keyPair.Key;
+ _ = keyPair.Value;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of SortedDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Concurrent")]
+ [BenchmarkCategory("Iterate")]
+ public void IterateConcurrentDictionary()
+ {
+ foreach (var keyPair in m_concurrentDictionary)
+ {
+ _ = keyPair.Key;
+ _ = keyPair.Value;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of SortedDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "ConcurrentToArray")]
+ [BenchmarkCategory("Iterate")]
+ public void IterateToArrayConcurrentDictionary()
+ {
+ foreach (var keyPair in m_concurrentDictionary.ToArray())
+ {
+ _ = keyPair.Key;
+ _ = keyPair.Value;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of SortedDictionary.
+ ///
+ [Test]
+ [Benchmark]
+ [BenchmarkCategory("Iterate")]
+ public void IterateSortedDictionary()
+ {
+ foreach (var keyPair in m_sortedDictionary)
+ {
+ _ = keyPair.Key;
+ _ = keyPair.Value;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of ReadonlyDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Readonly")]
+ [BenchmarkCategory("Iterate")]
+ public void IterateReadonlyDictionary()
+ {
+ foreach (var keyPair in m_readonlyDictionary)
+ {
+ _ = keyPair.Key;
+ _ = keyPair.Value;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of Dictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Regular", Baseline = true)]
+ [BenchmarkCategory("Iterate")]
+ public void IterateRegularDictionary()
+ {
+ foreach (var keyPair in m_regularDictionary)
+ {
+ _ = keyPair.Key;
+ _ = keyPair.Value;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of FrozenDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Frozen")]
+ [BenchmarkCategory("Iterate")]
+ public void IterateFrozenDictionary()
+ {
+#if NET8_0_OR_GREATER
+ foreach (var keyPair in m_frozenDictionary)
+ {
+ _ = keyPair.Key;
+ _ = keyPair.Value;
+ }
+#else
+ IterateRegularDictionary();
+#endif
+ }
+ #endregion
+
+ #region Count
+ public const int CountRepeats = 1000;
+ ///
+ /// Tests performance and memory usage of ImmutableDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Immutable")]
+ [BenchmarkCategory("Count")]
+ public void CountImmutableDictionary()
+ {
+ for (int i = 0; i < CountRepeats; i++)
+ {
+ _ = m_immutableDictionary.Count;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of ConcurrentDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Concurrent")]
+ [BenchmarkCategory("Count")]
+ public void CountConcurrentDictionary()
+ {
+ for (int i = 0; i < CountRepeats; i++)
+ {
+ _ = m_concurrentDictionary.Count;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of SortedDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Sorted")]
+ [BenchmarkCategory("Count")]
+ public void CountSortedDictionary()
+ {
+ for (int i = 0; i < CountRepeats; i++)
+ {
+ _ = m_sortedDictionary.Count;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of ReadonlyDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Readonly")]
+ [BenchmarkCategory("Count")]
+ public void CountReadonlyDictionary()
+ {
+ for (int i = 0; i < CountRepeats; i++)
+ {
+ _ = m_readonlyDictionary.Count;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of Dictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Regular", Baseline = true)]
+ [BenchmarkCategory("Count")]
+ public void CountRegularDictionary()
+ {
+ for (int i = 0; i < CountRepeats; i++)
+ {
+ _ = m_regularDictionary.Count;
+ }
+ }
+
+ ///
+ /// Tests performance and memory usage of FrozenDictionary.
+ ///
+ [Test]
+ [Benchmark(Description = "Frozen")]
+ [BenchmarkCategory("Count")]
+ public void CountFrozenDictionary()
+ {
+#if NET8_0_OR_GREATER
+ for (int i = 0; i < CountRepeats; i++)
+ {
+ _ = m_frozenDictionary.Count;
+ }
+#endif
+ }
+ #endregion
+
+ #region Helper Methods
+ protected virtual T GetRandomKey(Random random, DataGenerator generator)
+ {
+ if (typeof(T) == typeof(uint))
+ {
+ return (T)(object)Convert.ToUInt32(random.Next(0, 10 * NumElements)); // Random uint key
+ }
+ else if (typeof(T) == typeof(NodeId))
+ {
+ return (T)(object)new NodeId((uint)random.Next(0, 10 * NumElements), (ushort)random.Next(0, 10));
+ }
+ else if (typeof(T) == typeof(ExpandedNodeId))
+ {
+ return (T)(object)new ExpandedNodeId((uint)random.Next(0, 10 * NumElements), m_namespaceTable.GetString((uint)random.Next(0, m_namespaceTable.Count - 1)));
+ }
+ else
+ {
+ throw new NotSupportedException("Unsupported key type");
+ }
+ }
+
+ ///
+ /// Initializes a new instance.
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA5394:Do not use insecure randomness", Justification = "Not used for crypto.")]
+ protected virtual void Initialize()
+ {
+ var random = new Random(0x62541);
+ var randomSource = new RandomSource(0x62541);
+ var generator = new DataGenerator(randomSource);
+
+ // Populate dictionaries with random data
+ m_regularDictionary = new Dictionary(NumElements);
+ m_lookup = new T[NumElements];
+ for (int i = 0; i < NumElements; i++)
+ {
+ m_lookup[i] = GetRandomKey(random, generator);
+ m_regularDictionary[m_lookup[i]] = generator.GetRandomDataValue();
+ }
+
+ // initialize other dicts
+ m_sortedDictionary = new SortedDictionary(m_regularDictionary);
+ m_readonlyDictionary = new ReadOnlyDictionary(m_regularDictionary);
+ m_concurrentDictionary = new ConcurrentDictionary(m_regularDictionary);
+ m_immutableDictionary = m_regularDictionary.ToImmutableDictionary();
+#if NET8_0_OR_GREATER
+ m_frozenDictionary = m_regularDictionary.ToFrozenDictionary();
+#endif
+ m_lock = new object();
+ }
+ #endregion
+ }
+}
diff --git a/Tests/Opc.Ua.Core.Tests/Types/Utils/HiResClock.cs b/Tests/Opc.Ua.Core.Tests/Types/Utils/HiResClock.cs
index 342be1fc1..3aa8c8da7 100644
--- a/Tests/Opc.Ua.Core.Tests/Types/Utils/HiResClock.cs
+++ b/Tests/Opc.Ua.Core.Tests/Types/Utils/HiResClock.cs
@@ -153,7 +153,8 @@ public void HiResUtcNowTickCount(bool disabled)
long lastTickCount = HiResClock.UtcNow.Ticks;
long firstTickCount = lastTickCount;
int counts = 0;
- while (stopWatch.ElapsedMilliseconds <= HiResClockTestDuration)
+ long elapsedMilliseconds = stopWatch.ElapsedMilliseconds;
+ while (elapsedMilliseconds <= HiResClockTestDuration)
{
long tickCount;
do
@@ -164,6 +165,7 @@ public void HiResUtcNowTickCount(bool disabled)
Assert.LessOrEqual(lastTickCount, tickCount);
lastTickCount = tickCount;
counts++;
+ elapsedMilliseconds = stopWatch.ElapsedMilliseconds;
}
if (!disabled)
{
@@ -171,7 +173,7 @@ public void HiResUtcNowTickCount(bool disabled)
}
stopWatch.Stop();
long elapsed = (lastTickCount - firstTickCount) / TimeSpan.TicksPerMillisecond;
- TestContext.Out.WriteLine("HiResClock counts: {0} resolution: {1}µs", counts, stopWatch.ElapsedMilliseconds * 1000 / counts);
+ TestContext.Out.WriteLine("HiResClock counts: {0} resolution: {1}µs", counts, (elapsedMilliseconds * 1000.0 / counts));
// test accuracy of counter vs. stop watch
try
{
diff --git a/Tests/Opc.Ua.Gds.Tests/Opc.Ua.Gds.Tests.csproj b/Tests/Opc.Ua.Gds.Tests/Opc.Ua.Gds.Tests.csproj
index e3fb13096..42851197b 100644
--- a/Tests/Opc.Ua.Gds.Tests/Opc.Ua.Gds.Tests.csproj
+++ b/Tests/Opc.Ua.Gds.Tests/Opc.Ua.Gds.Tests.csproj
@@ -26,6 +26,8 @@
+
+
diff --git a/Tests/Opc.Ua.PubSub.Tests/Opc.Ua.PubSub.Tests.csproj b/Tests/Opc.Ua.PubSub.Tests/Opc.Ua.PubSub.Tests.csproj
index e94dd8810..671cdf912 100644
--- a/Tests/Opc.Ua.PubSub.Tests/Opc.Ua.PubSub.Tests.csproj
+++ b/Tests/Opc.Ua.PubSub.Tests/Opc.Ua.PubSub.Tests.csproj
@@ -33,7 +33,8 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
diff --git a/Tests/Opc.Ua.Security.Certificates.Tests/Opc.Ua.Security.Certificates.Tests.csproj b/Tests/Opc.Ua.Security.Certificates.Tests/Opc.Ua.Security.Certificates.Tests.csproj
index 74deacf33..081cbca26 100644
--- a/Tests/Opc.Ua.Security.Certificates.Tests/Opc.Ua.Security.Certificates.Tests.csproj
+++ b/Tests/Opc.Ua.Security.Certificates.Tests/Opc.Ua.Security.Certificates.Tests.csproj
@@ -35,7 +35,8 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
diff --git a/Tests/Opc.Ua.Server.Tests/Opc.Ua.Server.Tests.csproj b/Tests/Opc.Ua.Server.Tests/Opc.Ua.Server.Tests.csproj
index 6d535bd75..7a7d89c09 100644
--- a/Tests/Opc.Ua.Server.Tests/Opc.Ua.Server.Tests.csproj
+++ b/Tests/Opc.Ua.Server.Tests/Opc.Ua.Server.Tests.csproj
@@ -33,7 +33,8 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+