解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
4.78 KiB
X
using System.Buffers;
using BenchmarkDotNet.Attributes;
using NewLife;
using NewLife.Data;
using NewLife.Messaging;

namespace Benchmark.StreamingBenchmarks;

/// <summary>消息帧层基准:自解析定界 / 头先行绑定 / 整帧切出 / 头部包与整帧构建</summary>
/// <remarks>
/// 命令:dotnet run --project Benchmark/Benchmark.csproj -c Release -- --filter "*MessageFrameBenchmark*"
/// SRMP 帧:4 字节头(&lt;64k)或 8 字节扩展头;负载长度覆盖三档。
/// </remarks>
[MemoryDiagnoser]
[SimpleJob(warmupCount: 2, iterationCount: 10)]
public class MessageFrameBenchmark
{
    private static readonly SrmpCodec _codec = new();

    private Byte[] _frame = null!;
    private ReadOnlySequence<Byte> _seq;
    private ReadOnlySequence<Byte> _seqSplit;
    private Pipe _pipe = null!;
    private DefaultMessage _message = null!;
    private WebSocketCodec _wsCodec = null!;
    private Byte[] _wsFrame = null!;
    private ReadOnlySequence<Byte> _wsSeq;
    private ArrayPacket _view;

    /// <summary>负载大小(字节)</summary>
    [Params(64, 4096, 65536)]
    public Int32 Size { get; set; }

    [GlobalSetup]
    public void Setup()
    {
        // SRMP 帧:头部 + 负载
        var headerSize = Size < 0xFFFF ? 4 : 8;
        _frame = new Byte[headerSize + Size];
        _frame[0] = 0x01;
        _frame[1] = 0x66;
        if (headerSize == 4)
        {
            _frame[2] = (Byte)(Size & 0xFF);
            _frame[3] = (Byte)(Size >> 8);
        }
        else
        {
            _frame[2] = 0xFF;
            _frame[3] = 0xFF;
            _frame[4] = (Byte)(Size & 0xFF);
            _frame[5] = (Byte)((Size >> 8) & 0xFF);
            _frame[6] = (Byte)((Size >> 16) & 0xFF);
            _frame[7] = (Byte)((Size >> 24) & 0xFF);
        }
        Random.Shared.NextBytes(_frame.AsSpan(headerSize));

        _seq = new ArrayPacket(_frame).AsReadOnlySequence();

        // 跨段序列:头部最后一个字节与负载分离(头跨段最坏情形)
        IPacket chain = new ArrayPacket(_frame[..(headerSize - 1)]);
        chain.Append(new ArrayPacket(_frame[(headerSize - 1)..]));
        _seqSplit = chain.AsReadOnlySequence();

        _view = new ArrayPacket(_frame);

        _pipe = new Pipe();
        _message = new DefaultMessage();
        _message.SetBody(_view);

        // WebSocket 帧(无掩码,服务端方向)
        _wsCodec = new WebSocketCodec { IsServer = true };
        var wsHead = _wsCodec.BuildHeader(new WsMessage { Type = WebSocketMessageType.Binary }, Size);
        var headBytes = wsHead.ToArray();
        wsHead.TryDispose();

        _wsFrame = new Byte[headBytes.Length + Size];
        headBytes.CopyTo(_wsFrame, 0);
        _wsSeq = new ArrayPacket(_wsFrame).AsReadOnlySequence();
    }

    [GlobalCleanup]
    public void Cleanup() => _pipe.Dispose();

    /// <summary>SRMP 自解析定界:单段序列</summary>
    [Benchmark]
    public ParseResult? TryParse_SingleSegment() => _codec.TryParse(_seq);

    /// <summary>SRMP 自解析定界:头部跨段(最坏情形)</summary>
    [Benchmark]
    public ParseResult? TryParse_SplitSegment() => _codec.TryParse(_seqSplit);

    /// <summary>头先行绑定:头部到齐即绑定限长 Body(不切负载)</summary>
    [Benchmark]
    public Boolean HeaderFirstBind()
    {
        _pipe.Writer.Append(new ArrayPacket(_frame));

        var rs = _codec.TryParse(_pipe.Reader.Buffer);
        var ok = rs != null;
        if (rs != null)
        {
            _pipe.Reader.AdvanceTo(rs.Value.HeaderSize, rs.Value.HeaderSize);
            _message.BindBody(_pipe.Reader.Limit(rs.Value.BodyLength));
        }

        _pipe.Reader.AdvanceTo(_pipe.Reader.Buffer.Length);

        return ok;
    }

    /// <summary>整帧切出:等帧齐后 TakeFrame(拥有句柄)</summary>
    [Benchmark]
    public Boolean WholeFrameTake()
    {
        _pipe.Writer.Append(new ArrayPacket(_frame));

        var frame = _pipe.Reader.TakeFrame(_frame.Length);
        var ok = frame.Total > 0;
        frame.TryDispose();

        return ok;
    }

    /// <summary>头部包构建:BuildHeader(流式发送头部)</summary>
    [Benchmark]
    public Int32 BuildHeader()
    {
        var pk = _codec.BuildHeader(_message, Size);
        var total = pk.Total;
        pk.TryDispose();

        return total;
    }

    /// <summary>整帧构建:Build(头 + 负载链;构建转移体所有权,每轮重新注入负载)</summary>
    [Benchmark]
    public Int32 Build()
    {
        _message.SetBody(new ArrayPacket(_frame));

        var pk = _codec.Build(_message);
        var total = pk!.Total;
        pk.TryDispose();

        return total;
    }

    /// <summary>WS 帧自解析定界</summary>
    [Benchmark]
    public ParseResult? WebSocketTryParse() => _wsCodec.TryParse(_wsSeq);
}