概述

安装

  创建一个控制台应用程序,安装 BenchmarkDotNet NuGet 包.支持:

  • 项目: 具有PackageReferences的经典和现代的项目
  • 运行时: .NET Framework (4.6+), .NET Core (2.0+), Mono, CoreRT
  • 操作系统: Windows, Linux, MacOS
  • 开发语言: C#, F#, VB

设计一个基准测试

  创建一个控制台应用程序,编写一个用于测试类和方法,并给方法打上 Benchmark特性。在以下示例中,我们比较了MD5和SHA256加密哈希函数:

    using System; using System.Security.Cryptography; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; namespace MyBenchmarks { public class Md5VsSha256 { private const int N = 10000; private readonly byte[] data; private readonly SHA256 sha256 = SHA256.Create(); private readonly MD5 md5 = MD5.Create(); public Md5VsSha256() { data = new byte[N]; new Random(42).NextBytes(data); } [Benchmark] public byte[] Sha256() => sha256.ComputeHash(data); [Benchmark] public byte[] Md5() => md5.ComputeHash(data); } public class Program { public static void Main(string[] args) { var summary = BenchmarkRunner.Run(typeof(Program).Assembly); } } }

   BenchmarkRunner.Run<Md5VsSha256>(),这个调用运行你的基准测试并将结果打印到控制台。

  值得注意是,在做基准测试前,请讲程序配置成 Release模式。否则,结果将不符合实际。如果忘记更改配置,BenchmarkDotNet将打印警告。

基准测试结果

    BenchmarkDotNet=v0.11.3, OS=Windows 10.0.17134.472 (1803/April2018Update/Redstone4) Intel Core i7-2630QM CPU 2.00GHz (Sandy Bridge), 1 CPU, 8 logical and 4 physical cores Frequency=1948699 Hz, Resolution=513.1629 ns, Timer=TSC .NET Core SDK=2.1.502 [Host] : .NET Core 2.1.6 (CoreCLR 4.6.27019.06, CoreFX 4.6.27019.05), 64bit RyuJIT DefaultJob : .NET Core 2.1.6 (CoreCLR 4.6.27019.06, CoreFX 4.6.27019.05), 64bit RyuJIT | Method | Mean | Error | StdDev | |------- |----------:|----------:|----------:| | Sha256 | 100.90 us | 0.5070 us | 0.4494 us | | Md5 | 37.66 us | 0.1290 us | 0.1207 us |

Jobs

  你可以一次性测试多个环境。例如,你可以对比.NET Framework, .NET Core, Mono and CoreRT性能测试。只需在类声明之前添加 ClrJobMonoJobCoreJobCoreRtJob属性(它需要.NETCore项目,已安装corecrl和Mono):

    [ClrJob, MonoJob, CoreJob, CoreRtJob] public class Md5VsSha256

  结果示例:

    BenchmarkDotNet=v0.11.0, OS=Windows 10.0.16299.309 (1709/FallCreatorsUpdate/Redstone3) Intel Xeon CPU E5-1650 v4 3.60GHz, 1 CPU, 12 logical and 6 physical cores Frequency=3507504 Hz, Resolution=285.1030 ns, Timer=TSC .NET Core SDK=2.1.300-preview1-008174 [Host] : .NET Core 2.1.0-preview1-26216-03 (CoreCLR 4.6.26216.04, CoreFX 4.6.26216.02), 64bit RyuJIT Job-YRHGTP : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0 Core : .NET Core 2.1.0-preview1-26216-03 (CoreCLR 4.6.26216.04, CoreFX 4.6.26216.02), 64bit RyuJIT CoreRT : .NET CoreRT 1.0.26414.01, 64bit AOT Mono : Mono 5.10.0 (Visual Studio), 64bit | Method | Runtime | Mean | Error | StdDev | |------- |-------- |-----------:|----------:|----------:| | Sha256 | Clr | 75.780 us | 1.0445 us | 0.9771 us | | Sha256 | Core | 41.134 us | 0.2185 us | 0.1937 us | | Sha256 | CoreRT | 40.895 us | 0.0804 us | 0.0628 us | | Sha256 | Mono | 141.377 us | 0.5598 us | 0.5236 us | | | | | | | | Md5 | Clr | 18.575 us | 0.0727 us | 0.0644 us | | Md5 | Core | 17.562 us | 0.0436 us | 0.0408 us | | Md5 | CoreRT | 17.447 us | 0.0293 us | 0.0244 us | | Md5 | Mono | 34.500 us | 0.1553 us | 0.1452 us |

  这里有很多内置的jobs可供使用。例如,你可以对比加 LegacyJitX86vs LegacyJitX64vs RyuJitX64

    [LegacyJitX86Job, LegacyJitX64Job, RyuJitX64Job]

  或者你可以定义你自己的jobs:

    [Config(typeof(Config))] public class Md5VsSha256 { private class Config : ManualConfig { public Config() { Add(new Job(EnvMode.LegacyJitX86, EnvMode.Clr, RunMode.Dry) { Env = { Runtime = Runtime.Clr }, Run = { LaunchCount = 3, WarmupCount = 5, TargetCount = 10 }, Accuracy = { MaxStdErrRelative = 0.01 } })); } }

  更多阅读 Jobs, Configs

列字段

  你可以给概览表增加自定义字段:

    [MinColumn, MaxColumn] public class Md5VsSha256

Method | Median | StdDev | Min | Max ---|------|------|------|------|--- Sha256 | 131.3200 us | 4.6744 us | 129.8216 us | 147.7630 us Md5 | 26.2847 us| 0.4424 us | 25.8442 us | 27.4258 us

  当然,您可以根据完整的基准摘要定义自己的列。

  更多阅读 Columns

报表

  你可以将基准测试结果导出成多种形式:

    [MarkdownExporter, AsciiDocExporter, HtmlExporter, CsvExporter, RPlotExporter] public class Md5VsSha256

  如果你安装了R, RPlotExporter 可以生成很多漂亮的图:

  更多阅读 Exporters

基线

  为了放大研究,你需要标记基准测试方法为 基线

    public class Sleeps { [Benchmark] public void Time50() => Thread.Sleep(50); [Benchmark(Baseline = true)] public void Time100() => Thread.Sleep(100); [Benchmark] public void Time150() => Thread.Sleep(150); }

  因此,您将在摘要表中有其他列: Method | Median | StdDev | Ratio ---|------|------|------|------ Time100 | 100.2640 ms | 0.1238 ms | 1.00 Time150 | 150.2093 ms| 0.1034 ms | 1.50 Time50 | 50.2509 ms| 0.1153 ms | 0.50

  更多阅读 Baselines

参数

  可以通过Params属性标记类中的一个或多个字段或属性。在该属性中,可以指定一组值。然后,您将得到每个params值组合的结果。

    public class IntroParams { [Params(100, 200)] public int A { get; set; } [Params(10, 20)] public int B { get; set; } [Benchmark] public void Benchmark() { Thread.Sleep(A + B + 5); } }

Method | Median | StdDev | A | B ---|------|------|------|------ |------ Benchmark | 115.3325 ms | 0.0242 ms | 100 | 10 Benchmark | 125.3282 ms | 0.0245 ms | 100 | 20 Benchmark | 215.3024 ms | 0.0375 ms | 200 | 10 Benchmark | 225.2710 ms | 0.0434 ms | 200 | 20

  更多阅读

开发语言

  你也可以基于F#或者VB来编写基准测试. 例如:

    type StringKeyComparison () = let mutable arr : string [] = [||] let dict1 = ConcurrentDictionary<_,_>() let dict2 = ConcurrentDictionary<_,_>(StringComparer.Ordinal) [<Params (100, 500, 1000, 2000)>] member val public DictSize = 0 with get, set [<GlobalSetup>] member self.GlobalSetupData() = dict1.Clear(); dict2.Clear() arr <- getStrings self.DictSize arr |> Array.iter (fun x -> dict1.[x] <- true ; dict2.[x] <- true) [<Benchmark>] member self.StandardLookup () = lookup arr dict1 [<Benchmark>] member self.OrdinalLookup () = lookup arr dict2
    Public Class Sample <Params(1, 2)> Public Property A As Integer <Params(3, 4)> Public Property B As Integer <Benchmark> Public Function Benchmark() As Integer return A + B End Function End Class

诊断

  可以把这诊断器附加到您的基准测试,并获得一些有用的信息。

  当前正诊断器: - GC和内存分配( MemoryDiagnoser),它是跨平台、内置的,默认情况下不再启用。 - JIT内联事件( InliningDiagnoser)。您可以在一个单独的软件包中找到这个诊断程序,其中包含用于Windows的诊断程序( BenchmarkDotNet.Diagnostics.Windows): image

  下面是 MemoryDiagnoser的输出示例,请注意右侧的额外列( Gen 0Allocated):

Method | Mean | StdDev | ==Gen 0== | ==Allocated== ---|------|------|------|------ |------ Iterative | 31.0739 ns | 0.1091 ns | _ | 0 B LINQ | 83.0435 ns | 1.0103 ns | 0.0069 | 32 B

  更多阅读 Diagnosers

BenchmarkRunner

  运行基准测试有几种方法:可以使用现有类、基于internet上的代码或基于源代码运行基准测试:

    var summary = BenchmarkRunner.Run<MyBenchmarkClass>(); var summary = BenchmarkRunner.Run(typeof(MyBenchmarkClass)); string url = "<E.g. direct link to a gist>"; var summary = BenchmarkRunner.RunUrl(url); string benchmarkSource = "public class MyBenchmarkClass { ..."; var summary = BenchmarkRunner.RunSource(benchmarkSource);

  更多阅读 如何运行

版权声明: 本文为智客工坊「楠木大叔」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

results matching ""

    No results matching ""