/* ======================================================================== * Copyright (c) 2005-2025 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.Collections.Generic; using BenchmarkDotNet.Attributes; using Opc.Ua.Bindings; using Opc.Ua.Tests; namespace Opc.Ua.Core.Encoders.Tests { /// /// Common code for encoder/decoder benchmarks. /// public class EncoderBenchmarks { public const int StreamBufferSize = 4096; public const int DataValueCount = 10; public EncoderBenchmarks() { m_nodeId = new NodeId((uint)UnsecureRandom.Shared.Next(50000)); var list = new List(); for (int i = 0; i < DataValueCount; i++) { list.Add(UnsecureRandom.Shared.Next()); } m_list = list.ToArrayOf(); var values = new List(); var now = new DateTime(2024, 03, 01, 06, 05, 59, DateTimeKind.Utc); now += TimeSpan.FromTicks(456789); for (int i = 0; i < DataValueCount; i++) { values.Add( new DataValue( new Variant((UnsecureRandom.Shared.NextDouble() - 0.5) * 1000.0), UnsecureRandom.Shared.NextDouble() > 0.1 ? StatusCodes.Good : StatusCodes.BadDataLost, now, now)); } m_values = values.ToArrayOf(); } [Params(64, 1024)] public int PayLoadSize { get; set; } = 64; protected void TestEncoding(IEncoder encoder) { DateTime now = DateTime.UtcNow; int payLoadSize = PayLoadSize; encoder.WriteInt32("PayloadSize", payLoadSize); while (payLoadSize-- > 0) { encoder.WriteBoolean("Boolean", true); encoder.WriteByte("Byte", 123); encoder.WriteUInt16("UInt16", 1234); encoder.WriteUInt32("UInt32", 123456); encoder.WriteUInt64("UInt64", 1234566890); encoder.WriteSByte("Int8", -123); encoder.WriteInt16("Int16", -1234); encoder.WriteInt32("Int32", -123456); encoder.WriteInt64("Int64", -1234566890); encoder.WriteFloat("Float", 123.456f); encoder.WriteDouble("Double", 123456.789); encoder.WriteDateTime("DateTime", now); encoder.WriteString("String", "The quick brown fox jumps over the lazy dog."); encoder.WriteNodeId("NodeId", m_nodeId); encoder.WriteNodeId("ExpandedNodeId", m_nodeId); encoder.WriteInt32Array("Array", m_list); encoder.WriteDataValueArray("DataValues", m_values); } } protected void TestDecoding(IDecoder decoder) { int payLoadSize = decoder.ReadInt32("PayloadSize"); while (payLoadSize-- > 0) { _ = decoder.ReadBoolean("Boolean"); _ = decoder.ReadByte("Byte"); _ = decoder.ReadUInt16("UInt16"); _ = decoder.ReadUInt32("UInt32"); _ = decoder.ReadUInt64("UInt64"); _ = decoder.ReadSByte("Int8"); _ = decoder.ReadInt16("Int16"); _ = decoder.ReadInt32("Int32"); _ = decoder.ReadInt64("Int64"); _ = decoder.ReadFloat("Float"); _ = decoder.ReadDouble("Double"); _ = decoder.ReadDateTime("DateTime"); _ = decoder.ReadString("String"); _ = decoder.ReadNodeId("NodeId"); _ = decoder.ReadNodeId("ExpandedNodeId"); _ = decoder.ReadInt32Array("Array"); _ = decoder.ReadDataValueArray("DataValues"); } } public virtual void OneTimeSetUp() { // for validating benchmark tests m_telemetry = NUnitTelemetryContext.Create(); m_context = ServiceMessageContext.Create(m_telemetry); m_bufferManager = new BufferManager( nameof(BinaryEncoder), StreamBufferSize, m_telemetry); } public virtual void OneTimeTearDown() { m_context = null!; m_telemetry = null!; m_bufferManager = null!; } /// /// Set up some variables for benchmarks. /// public virtual void GlobalSetup() { // for validating benchmark tests m_telemetry = NUnitTelemetryContext.Create(); m_context = ServiceMessageContext.Create(m_telemetry); m_bufferManager = new BufferManager( nameof(BinaryEncoder), StreamBufferSize, m_telemetry); } /// /// Tear down benchmark variables. /// public virtual void GlobalCleanup() { m_context = null!; m_telemetry = null!; m_bufferManager = null!; } protected NodeId m_nodeId = new(1234); protected ArrayOf m_list; protected ArrayOf m_values; protected ITelemetryContext m_telemetry = null!; protected IServiceMessageContext m_context = null!; protected BufferManager m_bufferManager = null!; } #if NET6_0_OR_GREATER /// /// Helper class to test ArraySegmentStream without Span support. /// public class ArraySegmentStreamNoSpan : ArraySegmentStream { public ArraySegmentStreamNoSpan(BufferManager bufferManager) : base(bufferManager) { } public ArraySegmentStreamNoSpan(BufferCollection buffers) : base(buffers) { } public override int Read(Span buffer) { return ReadMemoryStream(buffer); } public override void Write(ReadOnlySpan buffer) { WriteMemoryStream(buffer); } } #endif }