You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Benchmark的Foo1结果行添加内部函数Bar1的额外统计列?

在BenchmarkDotNet中同时展示主方法与内部调用方法的基准统计数据

要在Foo1的结果行中同时展示Bar1的均值、标准差等统计数据,有两种实用方案:

方案一:手动追踪内部方法耗时并输出自定义列

在Foo1中通过计时器记录Bar1的执行时间,在所有测试结束后手动计算统计值,再通过BenchmarkDotNet的自定义列功能输出到结果表格:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.IO;
using BenchmarkDotNet.Attributes;

public class BenchMarkDemo
{
    private readonly Stopwatch _stopwatch = new Stopwatch();
    private List<double> _bar1ExecutionTimes = new List<double>();
    public double Bar1Mean { get; private set; }
    public double Bar1StdDev { get; private set; }

    [Benchmark] 
    public void Foo1() 
    { 
        // 模拟前置业务操作
        var stream = dosomethingElse();
        
        // 记录Bar1执行耗时
        _stopwatch.Restart();
        var output = Bar1(stream);
        _stopwatch.Stop();
        _bar1ExecutionTimes.Add(_stopwatch.Elapsed.TotalMilliseconds);
        
        // 模拟后置业务操作
        /* ... */ 
    }

    public string Bar1(Stream stream) { 
        return streamToString(stream);
    }

    // 所有测试完成后计算Bar1的统计值
    [GlobalCleanup]
    public void CalculateBar1Statistics()
    {
        if (_bar1ExecutionTimes.Count == 0) return;
        
        Bar1Mean = _bar1ExecutionTimes.Average();
        double mean = Bar1Mean;
        double sumOfSquares = _bar1ExecutionTimes.Sum(t => Math.Pow(t - mean, 2));
        Bar1StdDev = Math.Sqrt(sumOfSquares / _bar1ExecutionTimes.Count);
    }

    // 将Bar1的均值作为自定义列输出
    [BenchmarkColumn]
    public double Bar1MeanColumn => Bar1Mean;

    // 将Bar1的标准差作为自定义列输出
    [BenchmarkColumn]
    public double Bar1StdDevColumn => Bar1StdDev;

    // 模拟业务方法
    private Stream dosomethingElse() => new MemoryStream(Encoding.UTF8.GetBytes("sample benchmark data"));
    private string streamToString(Stream stream) 
    {
        stream.Position = 0;
        using var reader = new StreamReader(stream);
        return reader.ReadToEnd();
    }
}

这种方式的优势是能直接在Foo1的结果行中展示Bar1的统计数据,缺点是需要手动实现统计逻辑,精度略低于BenchmarkDotNet原生统计。

方案二:将Bar1标记为独立基准方法

给Bar1添加[Benchmark]属性,让BenchmarkDotNet原生统计它的性能数据,还可以通过[Group]特性将两个方法归为一组,方便对比:

using System.IO;
using System.Text;
using BenchmarkDotNet.Attributes;

public class BenchMarkDemo
{
    [Benchmark, Group("FooBarGroup")] 
    public void Foo1() 
    { 
        var stream = GetTestStream();
        var output = Bar1(stream);
        /* ... */ 
    }

    [Benchmark, Group("FooBarGroup")]
    public string Bar1Benchmark() { 
        // 使用和Foo1中一致的测试输入,确保统计具备对比性
        var stream = GetTestStream();
        return streamToString(stream);
    }

    // 提取公共测试数据构造逻辑,避免输入不一致
    private Stream GetTestStream() => new MemoryStream(Encoding.UTF8.GetBytes("sample benchmark data"));

    public string Bar1(Stream stream) { 
        return streamToString(stream);
    }

    private string streamToString(Stream stream) 
    {
        stream.Position = 0;
        using var reader = new StreamReader(stream);
        return reader.ReadToEnd();
    }
}

这种方式的优势是利用BenchmarkDotNet原生的高精度统计逻辑,无需手动计算;核心注意点是必须保证Bar1基准方法的输入和Foo1中调用时的输入完全一致,否则统计数据没有参考价值。

内容的提问来源于stack exchange,提问作者Vivek MVK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 13:21:16