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

namespace Benchmark.TracingBenchmarks;

/// <summary>APM 埋点开销基准。同一份被测代码,只切换跟踪器档位</summary>
/// <remarks>
/// 回答两个问题:NewLife 原生埋点(星尘侧)相对"不用 APM"增加多少;再加上 OpenTelemetry 后增加多少。
/// 所有档位共用同一个被测方法体,保证可比性。
/// </remarks>
[MemoryDiagnoser]
[SimpleJob(launchCount: 1, warmupCount: 3, iterationCount: 10)]
public class OtelBenchmark
{
    /// <summary>跟踪器档位</summary>
    public enum TracerKind
    {
        /// <summary>无 APM。tracer 为 null,埋点调用被 ?. 短路</summary>
        None,

        /// <summary>NewLife 原生:DefaultTracer 本地聚合(StarTracer 的每片段路径与之相同)</summary>
        Star,

        /// <summary>OpenTelemetry,但没有任何监听者</summary>
        OtelNoListener,

        /// <summary>OpenTelemetry,存在活动监听者</summary>
        OtelListener,

        /// <summary>OpenTelemetry 输出 + NewLife 原生双写</summary>
        Dual,
    }

    /// <summary>跟踪器档位</summary>
    [ParamsAllValues]
    public TracerKind Kind { get; set; }

    private ITracer? _tracer;
    private ActivityListener? _listener;

    private readonly Object _tag = new { Id = 123, Name = "订单", Amount = 99.5, Time = DateTime.Now };
    private readonly Exception _error = new InvalidOperationException("模拟业务异常");

    /// <summary>初始化。只监听指定源名,使"无监听者"档位保持真实短路</summary>
    [GlobalSetup]
    public void Setup()
    {
        _listener = new ActivityListener
        {
            ShouldListenTo = s => s.Name == "Bench.Otel.Listener" || s.Name == "Bench.Otel.Dual",
            Sample = (ref ActivityCreationOptions<ActivityContext> o) => ActivitySamplingResult.AllDataAndRecorded,
        };
        ActivitySource.AddActivityListener(_listener);

        switch (Kind)
        {
            case TracerKind.None:
                _tracer = null;
                break;
            case TracerKind.Star:
                _tracer = new DefaultTracer();
                break;
            case TracerKind.OtelNoListener:
                _tracer = new OpenTelemetryTracer { SourceName = "Bench.Otel.NoListener" };
                break;
            case TracerKind.OtelListener:
                _tracer = new OpenTelemetryTracer { SourceName = "Bench.Otel.Listener" };
                break;
            case TracerKind.Dual:
                _tracer = new OpenTelemetryTracer { SourceName = "Bench.Otel.Dual", Inner = new DefaultTracer() };
                break;
        }
    }

    /// <summary>清理</summary>
    [GlobalCleanup]
    public void Cleanup()
    {
        _listener?.Dispose();
        _listener = null;
    }

    /// <summary>空埋点。真实代码中最常见的形态</summary>
    [Benchmark]
    public void EmptySpan()
    {
        using var span = _tracer?.NewSpan("bench.op");
    }

    /// <summary>带数据标签的埋点</summary>
    [Benchmark]
    public void TaggedSpan()
    {
        using var span = _tracer?.NewSpan("bench.op", _tag);
    }

    /// <summary>嵌套两层埋点</summary>
    [Benchmark]
    public void NestedSpans()
    {
        using var outer = _tracer?.NewSpan("bench.outer");
        using var inner = _tracer?.NewSpan("bench.inner", _tag);
    }

    /// <summary>异常埋点</summary>
    [Benchmark]
    public void ErrorSpan()
    {
        using var span = _tracer?.NewSpan("bench.op", _tag);
        span?.SetError(_error, _tag);
    }
}

/// <summary>星尘侧周期成本基准。聚合数据每采样周期被取走一次</summary>
[MemoryDiagnoser]
[SimpleJob(launchCount: 1, warmupCount: 3, iterationCount: 10)]
public class OtelPeriodicBenchmark
{
    private DefaultTracer _tracer = null!;

    /// <summary>每个周期内累计的埋点条数</summary>
    [Params(100, 1000)]
    public Int32 Count { get; set; }

    /// <summary>初始化</summary>
    [GlobalSetup]
    public void Setup() => _tracer = new DefaultTracer();

    /// <summary>填充埋点数据。不计入被测路径</summary>
    [IterationSetup]
    public void Fill()
    {
        for (var i = 0; i < Count; i++)
        {
            using var span = _tracer.NewSpan("bench.op" + (i % 8));
        }
    }

    /// <summary>取走并重置聚合数据</summary>
    /// <returns></returns>
    [Benchmark]
    public ISpanBuilder[] TakeAll() => _tracer.TakeAll();
}