初次接触BenchmarkDotNet

  1. 创建控制台程序:
  2. 引用NuGet包:BenchmarkDotNet,版本:0.13.5
  3. Program.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

namespace MyBenchmarks
{
    [SimpleJob(RuntimeMoniker.Net60)]
    [SimpleJob(RuntimeMoniker.Net70)]
    [MemoryDiagnoser]
    public class TestBooleanArray
    {

        private bool[] oldBooleanArray;
        private bool[] newBooleanArray;
        private List<bool> resultBooleanArray;

        [Params(800)]
        public int N;

        [GlobalSetup]
        public void Setup()
        {
            oldBooleanArray = new bool[N];            
            new BooleanGenerator().NextBoolean(oldBooleanArray);

            newBooleanArray  = new bool[N];
            new BooleanGenerator().NextBoolean(newBooleanArray);

            resultBooleanArray = new List<bool>(N);
            for (int i = 0; i < oldBooleanArray.Length; i++)
            {
                //Debug.WriteLine($"oldBooleanArray[{i}]:{oldBooleanArray[i]},newBooleanArray[{i}]:{newBooleanArray[i]},Result:{oldBooleanArray[i] == newBooleanArray[i]}");
                //oldBooleanArray[i] == newBooleanArray[i];
                resultBooleanArray.Add(false);
            }
        }

        [GlobalCleanup]
        public void Cleanup()
        {
            Console.WriteLine($"Result Count:{resultBooleanArray.Count(t => t == true)}");
        }

        //[Benchmark(BaseLine=true)]
        //public void ComputeMain()
        //{
        //    Compute()

        //    Console.WriteLine(resultBooleanArray.Count(t => t == true));
        //}

        [Benchmark]
        public void Compute()
        {
            //resultBooleanArray = new List<bool>(N);
            for (int i = 0; i < oldBooleanArray.Length; i++)
            {
                //Debug.WriteLine($"oldBooleanArray[{i}]:{oldBooleanArray[i]},newBooleanArray[{i}]:{newBooleanArray[i]},Result:{oldBooleanArray[i] == newBooleanArray[i]}");
                //oldBooleanArray[i] == newBooleanArray[i];
                resultBooleanArray[i] = oldBooleanArray[i] == newBooleanArray[i];
            }
            //Console.WriteLine(resultBooleanArray.Count(t => t == true));
        }

       
        public class BooleanGenerator
        {
            Random rnd;

            public BooleanGenerator()
            {
                rnd = new Random();
            }

            public bool NextBoolean()
            {
                return rnd.Next(0, 2) == 1;
            }

            public void NextBoolean(bool[] buffer)
            {
                for (int i = 0; i < buffer.Length; i++)
                {
                    buffer[i] = rnd.Next(0, 2) == 1;
                }
            }
        }
    }



    public class Program
    {
        public static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<TestBooleanArray>();
            //Console.ReadKey();
        }
    }
}
  1. 实验结果:
// * Summary *

BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1702/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=7.0.100
  [Host]   : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2 [AttachedDebugger]
  .NET 6.0 : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2
  .NET 7.0 : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2


|  Method |      Job |  Runtime |   N |     Mean |     Error |    StdDev |
|-------- |--------- |--------- |---- |---------:|----------:|----------:|
| Compute | .NET 6.0 | .NET 6.0 | 800 | 1.359 us | 0.0272 us | 0.0636 us |
| Compute | .NET 7.0 | .NET 7.0 | 800 | 1.310 us | 0.0267 us | 0.0786 us |
  1. BenchmarkDotNet代码说明:
  • SimpleJob特性:
    指定使用测试环境,使用的环境由枚举类 RuntimeMoniker 指定。测试时,可以在同一个类中设置多个SimpleJob,BenchmarkDotNet会根据SimpleJob根据tight的环境测试。注意:没有安装对应的库,测试时,BenchmarkDotNet对应的测试时都是NA。
//使用的NET6.0的环境
[SimpleJob(RuntimeMoniker.Net60)]
//使用NET7.0的环境
[SimpleJob(RuntimeMoniker.Net70)]
public class TestBooleanArray
{

}
  • Params特性:
    针对属性,赋值参数提供的值。
//BenchmarkDotNet创建类时,N赋值我800
[Params(800)]
public int N;

//BenchmarkDotNet会进行2此测试,分别使用,N=800,N=8000的测试结果。
[Params(800,8000)]
public int N;

针对 [Params(800,8000)] 的测试结果的显示方式:

// * Summary *

BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1702/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=7.0.100
  [Host]   : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2 [AttachedDebugger]
  .NET 6.0 : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2
  .NET 7.0 : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2


|  Method |      Job |  Runtime |    N |      Mean |     Error |    StdDev |    Median |
|-------- |--------- |--------- |----- |----------:|----------:|----------:|----------:|
| Compute | .NET 6.0 | .NET 6.0 |  800 |  1.337 us | 0.0258 us | 0.0681 us |  1.349 us |
| Compute | .NET 7.0 | .NET 7.0 |  800 |  1.300 us | 0.0263 us | 0.0775 us |  1.323 us |
| Compute | .NET 6.0 | .NET 6.0 | 8000 | 14.569 us | 0.5402 us | 1.5928 us | 14.721 us |
| Compute | .NET 7.0 | .NET 7.0 | 8000 | 13.357 us | 0.3407 us | 1.0046 us | 13.713 us |
  • Benchmark特性:
    需要测试的方法上边添加Benchmark特性
[Benchmark]
public void Compute()
{

    for (int i = 0; i < oldBooleanArray.Length; i++)
    {

        resultBooleanArray[i] = oldBooleanArray[i] == newBooleanArray[i];
    }

}
  • GlobalSetup与GlobalCleanup特性
    GlobalSetup特性:类似C#的构造函数,主要针对Benchmark方法中使用的对象进行过初始化。
    GlobalCleanup特性:类似C#的析构函数。主要针对Benchmark方法中使用的对象进行过注销。
  • MemoryDiagnoser特性
    显示测试的方式中,内存的使用情况。一般放在类上边。测试结果中:Allocated字段代表使用的内存的情况:
// * Summary *

BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1702/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=7.0.100
  [Host]   : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2 [AttachedDebugger]
  .NET 6.0 : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2
  .NET 7.0 : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2


|  Method |      Job |  Runtime |    N |      Mean |     Error |    StdDev |    Median | Allocated |
|-------- |--------- |--------- |----- |----------:|----------:|----------:|----------:|----------:|
| Compute | .NET 6.0 | .NET 6.0 |  800 |  1.388 us | 0.0278 us | 0.0464 us |  1.391 us |         - |
| Compute | .NET 7.0 | .NET 7.0 |  800 |  1.367 us | 0.0265 us | 0.0669 us |  1.363 us |         - |
| Compute | .NET 6.0 | .NET 6.0 | 8000 | 14.628 us | 0.5206 us | 1.5351 us | 14.727 us |         - |
| Compute | .NET 7.0 | .NET 7.0 | 8000 | 13.212 us | 0.2900 us | 0.8550 us | 13.440 us |         - |

以下是Net Framework 4.6、Net Framework 4.8环境的运行结果:

// * Summary *

BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1702/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
  [Host]               : .NET Framework 4.8.1 (4.8.9139.0), X86 LegacyJIT [AttachedDebugger]
  .NET Framework 4.6.2 : .NET Framework 4.8.1 (4.8.9139.0), X86 LegacyJIT
  .NET Framework 4.8.1 : .NET Framework 4.8.1 (4.8.9139.0), X86 LegacyJIT


|  Method |                  Job |              Runtime |    N |      Mean |     Error |    StdDev | Allocated |
|-------- |--------------------- |--------------------- |----- |----------:|----------:|----------:|----------:|
| Compute | .NET Framework 4.6.2 | .NET Framework 4.6.2 |  800 |  2.444 us | 0.1732 us | 0.5107 us |         - |
| Compute | .NET Framework 4.8.1 | .NET Framework 4.8.1 |  800 |  2.409 us | 0.1793 us | 0.5288 us |         - |
| Compute | .NET Framework 4.6.2 | .NET Framework 4.6.2 | 8000 | 24.934 us | 1.6724 us | 4.9310 us |         - |
| Compute | .NET Framework 4.8.1 | .NET Framework 4.8.1 | 8000 | 24.677 us | 1.7765 us | 5.2381 us |         - |

以上代码中测试中,没有内存的消耗。修改Compute方法,增加内存的消耗,代码如下:

[Benchmark]
public void Compute()
{
    resultBooleanArray = new List<bool>(N);
    for (int i = 0; i < oldBooleanArray.Length; i++)
    {
        //Debug.WriteLine($"oldBooleanArray[{i}]:{oldBooleanArray[i]},newBooleanArray[{i}]:{newBooleanArray[i]},Result:{oldBooleanArray[i] == newBooleanArray[i]}");
        resultBooleanArray.Add(oldBooleanArray[i] == newBooleanArray[i]);
        //resultBooleanArray[i] = oldBooleanArray[i] == newBooleanArray[i];
    }
    //Console.WriteLine(resultBooleanArray.Count(t => t == true));
}

通过以下测试结果可以看出,当N=800时,执行Compute方法时,内存消耗856 B,当N=8000时,执行Compute方法时,内存消耗8056 B

// * Summary *

BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1702/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=7.0.100
  [Host]   : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2 [AttachedDebugger]
  .NET 6.0 : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2
  .NET 7.0 : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2


|  Method |      Job |  Runtime |    N |      Mean |     Error |    StdDev |    Median |   Gen0 |   Gen1 | Allocated |
|-------- |--------- |--------- |----- |----------:|----------:|----------:|----------:|-------:|-------:|----------:|
| Compute | .NET 6.0 | .NET 6.0 |  800 |  1.982 us | 0.0943 us | 0.2781 us |  2.058 us | 0.1335 |      - |     856 B |
| Compute | .NET 7.0 | .NET 7.0 |  800 |  2.113 us | 0.0884 us | 0.2607 us |  2.154 us | 0.1354 |      - |     856 B |
| Compute | .NET 6.0 | .NET 6.0 | 8000 | 19.785 us | 1.1409 us | 3.3640 us | 20.622 us | 1.2817 | 0.0610 |    8056 B |
| Compute | .NET 7.0 | .NET 7.0 | 8000 | 19.950 us | 0.9851 us | 2.9044 us | 20.818 us | 1.2817 | 0.0610 |    8056 B |
  • 控制台程序执行测试代码:
public class Program
{
    public static void Main(string[] args)
    {
        var summary = BenchmarkRunner.Run<TestBooleanArray>();
    }
}
posted @ 2023-05-29 16:31  Light_Yang  阅读(74)  评论(0编辑  收藏  举报