nauful / LibUA

Open-source OPC UA client and server library
Apache License 2.0
262 stars 94 forks source link

Change MemoryBuffer to use ArrayPool #150

Closed bjornfe closed 9 months ago

bjornfe commented 9 months ago

Fixes #151

Switched to using ArrayPool in MemoryBuffer to increase performance and to reduce Allocation Pressure.

Here are some diagnostics before and after the switch: Client Code: ClientCode

Client allocation rate without ArrayPool: ClientWithoutArrayPool

Server allocation rate without ArrayPool ServerWithoutArrayPool

Throughput without ArrayPool ClientThroughputWithoutArrayPool

Client allocation rate with ArrayPool: ClientWithArrayPool

Server allocation rate with ArrayPool: ServerWithArrayPool

Throughput with ArrayPool: ClientThroughputWithArrayPool

nauful commented 9 months ago

On the server side, change the sample to not print every Info message:

private class DemoLogger : ILogger
{
    public bool HasLevel(LogLevel Level)
    {
        return true;
    }

    public void LevelSet(LogLevel Mask)
    {
    }

    public void Log(LogLevel Level, string Str)
    {
        if (Level > LogLevel.Info)
        {
            Console.WriteLine("[{0}] {1}", Level.ToString(), Str);
        }
    }
}

On the client side, try this test code:

var lastPrint = Environment.TickCount64;
int readCount = 0;
ReadValueId[] readTargets = [
    new ReadValueId(new NodeId(2, 1), NodeAttribute.Value, null, new QualifiedName(0, null)),
    new ReadValueId(new NodeId(2, 2), NodeAttribute.Value, null, new QualifiedName(0, null)),
    new ReadValueId(new NodeId(2, 3), NodeAttribute.Value, null, new QualifiedName(0, null)),
];

while (true)
{
    for (int pass = 0; pass < 100; pass++)
    {
        var readRes = client.Read(readTargets, out DataValue[] dvs);
        if (readRes == StatusCode.Good)
        {
            ++readCount;
        }
    }

    var curTicks = Environment.TickCount64;
    if (curTicks > lastPrint + 1000)
    {
        double reads = 1000.0 * readCount / (curTicks - lastPrint);
        Console.WriteLine(reads);
        readCount = 0;
        lastPrint = curTicks;
    }
}

Performance is a lot better: image

nauful commented 9 months ago

Message encryption is now the limiting factor. With no security, most of the time taken is now spent in chunking/sending.

Client change for testing (don't use this in production!):

var messageSecurityMode = MessageSecurityMode.None;
var securityPolicy = SecurityPolicy.None;

image