只有累積,沒有奇蹟

2020年8月12日 星期三

[NETCore] 使用 BenchmarkDotNet 測試程式碼效能

前言
在開發或是 POC 時為了記錄代碼程式執行的時間,都會採用在代碼上加上  stopWatch  紀錄花費時間,使用方式不外乎就是 new Stopwatch、Start、Stop、Reset、ElapsedMilliseconds,以詳細記錄代碼所花費的時間,接下來為了要顯示在 console 上可能還要針對 log 在輸出內容做簡單排版方便記錄,最近發現上述惱人的事情都可以使用  BenchmarkDotNet  套件來幫你完成,不僅可以完成上述提到的事情,還會自動將結果輸出成 report html 檔案,並會記錄執行時的 Runtime 版本與硬體資訊,這篇就針對 benchmarkDotNet 做簡單的介紹與說明若有問題或是有更推薦的工具歡迎提出一起討論或是給予指導。

BenchmarkDotNet 安裝
套件支援下列項目
  • Runtimes: Full .NET Framework (4.6+), .NET Core (2.0+), Mono, CoreRT
  • OS: Windows, Linux, MacOS
  • Languages: C#, F#, VB
Manage Nuget Package 安裝
Step 1 : 在 Visual Studio IDE 按下快捷鍵  Ctrl + Q ,滑鼠指標會移到右上角搜尋框輸入 nuget 按下 enter
Step 2 : 在搜尋框輸入 benchmarkDotNet,點擊 Install
由於此套件要下載的 dll 很多因此等待時間會比較長,接著就是無止境的下一步

Package Manager Console 安裝
不愛 GUI 介面的人可以選擇輸入以下指令進行安裝 
Install-Package BenchmarkDotNet -Version 0.11.4

使用方式
接著參考官網的範例(沒梗)比較 C# 裡 MD5 和 SHA256 兩個方法在新增特定筆數時,哪一個會花費比較少的時間完成(效能)會比較好,也順便練習在 Benchmarkdotnet 套件是如何實作及 Report 內容是如何呈現,新增一個 Console 專案為 BenchmarkDotnet,並在專案中加入下列代碼
using System;
using System.Security.Cryptography;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace benchmarkLab
{
    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<Md5VsSha256>();
            Console.ReadKey();
        }
    }

    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);
    }
}

程式說明
  • Md5VsSha256 類別 : 產生 Md5 與 sha256 方法上加上  Benchmark  attribute
  • Main 類別 : 使用  BenchmarkRunner.Ren<T>  T是你要驗證的 classname
  • 下一步將執行方式改為  Release  ,如果你的Visual Studio 有開啟 Just my code 也會提示你關閉此功能
    按下 Ctrl + F5 執行專案,接著可以觀察到 Benchmark 開始針對 release 資料夾底下 projectName.exe 檔案執行測試,並列出測試環境的 runtime 與 framework 資訊
    測試跑完之後我們直接看結果 
    // * Summary *
    
    BenchmarkDotNet=v0.11.4, OS=Windows 10.0.17763.379 (1809/October2018Update/Redstone5)
    Intel Core i7-8550U CPU 1.80GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
      [Host]     : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.3324.0
      DefaultJob : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.3324.0
    
    
    | Method |      Mean |     Error |    StdDev |
    |------- |----------:|----------:|----------:|
    | Sha256 | 151.71 us | 1.2058 us | 0.9414 us |
    |    Md5 |  30.46 us | 0.6038 us | 0.5930 us |
    
    // * Hints *
    Outliers
      Md5VsSha256.Sha256: Default -> 3 outliers were removed
      Md5VsSha256.Md5: Default    -> 2 outliers were removed, 3 outliers were detected
    
    // * Legends *
      Mean   : Arithmetic mean of all measurements
      Error  : Half of 99.9% confidence interval
      StdDev : Standard deviation of all measurements
      1 us   : 1 Microsecond (0.000001 sec)
    
    // ***** BenchmarkRunner: End *****
    // ** Remained 0 benchmark(s) to run **
    Run time: 00:00:39 (39.09 sec), executed benchmarks: 2
    
    Global total time: 00:00:45 (45.68 sec), executed benchmarks: 2
    // * Artifacts cleanup *
    從報告中可以看出來,執行時間 sha256 為 151.71 us 與 md5 的 30.46 us 較久,1 us : 1 Microsecond (0.000001 sec),因此可以判定在 .Net Framework 環境下 md5 比 sha256 來的快 

    Report
    前面有提到案下執行後,會針對專案 release 資料夾底下 backmarklab.exe 檔案執行測試,測試完畢後除了會 console 出測試結果之外,如果注意 console 內容來可以發現內容有提到結果輸出成 report,輸出路徑在  release\BenchmarkDotNet.Artifacts\results  目錄底下,如下圖所示
    // * Export *
    BenchmarkDotNet.Artifacts\results\benchmarkLab.Md5VsSha256-report.csv
    BenchmarkDotNet.Artifacts\results\benchmarkLab.Md5VsSha256-report-github.md
    BenchmarkDotNet.Artifacts\results\benchmarkLab.Md5VsSha256-report.html
    Repost 提供三種呈現方式,分別是 : csv、html 與 html,都記錄測試時間結果還有環境變數資訊
    HTML 呈現方式
    MD 呈現方式

    設定環境變數 - Job

    剛剛的測試數據證明了在 .NET Framework 下是 Md5 比 sha256 快,但如果今天程式是執行在 .NET Core 環境下是否還是一樣呢 ? 在一開始有提到,benchmarkdotnet 支援 .Net Framework 與 .NET Core 以及 mono,可以執行一次同時確認多個環境變數,舉例來說想同時驗證 .NET Framework、.NET Core 環境,只需要在 attribute 上加上  [clrJob]  與  coreJob  ,如下範例
    [ClrJob, CoreJob]
    public class Md5VsSha256
    可以看到輸出結果多了 clr 部分,但是其結果卻是 NA,這時需要開啟專案 csproj 檔案,調整下列內容
    詳細可以參考官網常見問題 : 傳送門
    <TargetFrameworks>netcoreapp2.2;net461</TargetFrameworks>
    <PlatformTarget>AnyCPU</PlatformTarget>
    
    重新執行一次,可以發現 .NET Framework 與 .NET Core 數據有正常呈現
    加入了在 .NET Core 環境測試,從結果來看 md5 速度上還是優於 sha256,另外在測試時建議將測試環境不要用到的程式關閉,避免影響到測試時的效能,才可以更呈現結果更為準確。

    GitHub Sample Code 傳送門 :  BenchmarkDotNet Lab

    感想
    透過以上簡單的應用可以看出來 Banchmarkdotnet 不僅可以協助測試,還可以將測試數據輸出成報表呈現,只需要在測試的類別上加上 [Benchmark] 即可,並在測試時考慮到 cold start & warm state、手動調整執行次數與執行時 GC 資訊,相關文件與更多的功能都可以在官網看到,想了解更多的朋友去 benchmarkdotnet.org 尋寶吧 ! 
      參考
      benchmarkdotnet
      使用 BenchmarkDotnet 测试代码性能

      Copyright © m@rcus 學習筆記 | Powered by Blogger

      Design by Anders Noren | Blogger Theme by NewBloggerThemes.com