2024年10月16日 星期三

如何在 Visual Studio 2017 對 .NET Core 專案啟用分析器功能

在 Visual Studio 2017 裡面,有個好用的「分析器」功能,可以幫助開發人員寫好程式。他的作法是在背景執行一連串的程式碼分析,透過一組規則集 (RuleSet) 對專案中的程式碼進行剖析與檢查,如果有發現任何問題,就會在「錯誤清單」中呈現資訊、警告或錯誤,並且提供部分規則的自動修復功能。不過,在 Visual Studio 2017 對 .NET Core 專案的支援度並沒有太多文件著墨,我花了好多時間才研究出背後的差異之處。我打算透過本篇文章分享如何在 Visual Studio 2017 啟用與設定 .NET Core 專案的程式碼分析器功能。


基本上,在 Microsoft Docs 上關於 Visual Studio 2017 分析器的文件,所有的「操作步驟」大多都只適用於 .NET Framework 專案類型。到了 .NET Core 之後,雖然分析器的觀念都完全一樣,但是分析器的設定方式已經有點不一樣,這點真的困擾我一些時間。

以下我列出幾個重要的文件入口頁,先建立一些基本觀念再開始使用還是比較好:

早在十多年前,最知名的 FxCop 套件,就是用來分析 .NET Framework 專案原始碼,自動檢測潛在的程式碼問題。爾後被整併到 Visual Studio 之中,變成內建的程式分析器,雖然 FxCop 這個名詞變得少見,但內部還是一直使用這個名字。

直到 .NET Compiler Platform ("Roslyn") 出現之後,這一切都改變了。因為 Roslyn 將 NET 程式語言的編譯器全部開放原始碼,而且公開許多 C#/VB 程式碼剖析的 APIs,所以 Visual Studio 也開始進一步改用 Roslyn 改寫所有分析器。


簡單來說:目前 Visual Studio 2017 的分析器已經全數改用 Roslyn 進行程式碼分析。

在 .NET Framework 專案啟用分析器的步驟

在 Visual Studio 2017 建立任何一個 .NET Framework 專案範本,預設就會啟用內建的分析器。預設選取的規則集為 適用於 Managed 程式碼的 Managed 建議規則規則集 (Managed Recommended Rules rule set for managed code),這些規則的重點在於程式碼中最關鍵的問題,包括潛在的安全性漏洞、應用程式損毀,以及其他重要的邏輯和設計錯誤。

這份 適用於 Managed 程式碼的 Managed 建議規則規則集 文件的翻譯,在 Visual Studio 2017 中操作介面翻譯為 Microsoft 受控建議規則,有一點不太一樣。你可以從「專案屬性」的「程式碼分析」頁籤中看見。規則集檔案的路徑為 C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Team Tools\Static Analysis Tools\Rule Sets\MinimumRecommendedRules.ruleset

這些規則集都是可以調整的,在 Visual Studio 2017 中完整的規則集文件,可以參考 程式碼分析規則集參考 文件。

在 Visual Studio 2017 的 .NET Framework 專案中開啟規則集,有兩種方法:

  1. 方案總管任意專案下,找到 [參考] / [分析器] 按滑鼠右鍵,點擊 [開啟使用中的規則集合]
  2. 方案總管任意專案按滑鼠右鍵,選擇「屬性」,切換到「程式碼分析」頁籤,點擊「開啟」按鈕。

請注意:在 .NET Core 專案中,從 VS2017 的方案總管中,會完全找不到可以開啟程式碼分析器規則集的功能,從專案屬性中也會找不到程式碼分析頁籤,這點是有點不便!

最後提醒:透過 程式碼分析規則編輯器 對規則集檔案所做的修改,在 .NET Core 的專案中,完全無法產生效果!

在 .NET Core 專案啟用分析器的步驟

我之前就是一直被 .NET Framework 專案的分析器設定步驟卡住,怎樣設定都無效,甚至設定到有點怒氣 XD

在 Visual Studio 2017 中對 .NET Core 專案設定分析器的完整設定步驟如下:

  1. 開啟 NuGet 套件管理員
  2. 點擊「瀏覽」頁籤並勾選「包括搶鮮版」
  3. 搜尋 fxcopanalyzers 關鍵字,並安裝 Microsoft.CodeAnalysis.FxCopAnalyzers 套件。

或直接透過套件管理器主控台輸入以下命令:(2018/09/24: 請記得安裝最新 Beta 版本。)

Install-Package Microsoft.CodeAnalysis.FxCopAnalyzers -IncludePrerelease

安裝好必要的分析器套件後,接下來就簡單測試一下。

你先隨便建立一個類別檔,並輸入以下內容,然後 [建置] 專案:

using System;
using System.IO;
...
...
public class NoDisposeMethod
{
    FileStream newFile;

    public NoDisposeMethod()
    {
        newFile = new FileStream(@"c:\temp.txt", FileMode.Open);
    }
}

上述程式碼會引發 CA1001:具有可處置欄位的類型應該是可處置的 警告,你可以從 錯誤清單 中發現這些訊息。

啟用完整解決方案分析

Visual Studio 2017 預設只會分析目前開啟過的檔案,如果要預設分析方案中所有專案的所有程式碼,可以參考以下設定:

  1. 打開選單 [工具] / [選項] / [文字編輯器] / [C#] / [進階]
  2. 勾選【啟用完整解決方案分析】(Enable full solution analysis)
  3. 啟用之後,必須做一次建置動作,分析器才會生效。

如何調整分析器規則集

在 .NET Framework 可以透過建立 *.ruleset 檔案,你可以透過 [新增項目] 精靈,搜尋 [程式碼分析規則集] 項目範本,即可建立一個自訂規則集。在 Visual Studio 2017 中有個 程式碼分析規則編輯器 可用,不過這套編輯器完全不適用於 .NET Core 專案,千萬不要透過這套來編輯規則集內容。

在 .NET Core 專案中,調整規則集的方式,已經整合進 方案總管,你只要從 [專案] / [相依性] / [分析器] 去挑選適合的規則,直接按滑鼠右鍵,就可以切換該條規則的嚴重性。

只要你第一次切換任何一條規則的嚴重性設定,該專案就會自動建立規則集設定檔(*.ruleset),並且全自動設定相容於 .NET Framework 的規則集。意思也就是說,只要你的方案中有 .NET Core 專案的存在,你就應該用 .NET Core 的規則集設定方法,而這些自動產生的規則集設定檔,也同時可以套用到 .NET Framework 專案中!

.NET Core 預設專案範本內建的分析器套件

  • 主控台應用程式 (.NET Core) & 類別庫 (.NET Core)

    • 這兩個專案範本預設沒有內建任何分析器 (Analyzer)。

    • 如果想要安裝額外的分析器,以下介紹的每個分析器套件,只要用 NuGet 安裝好就能直接使用。

    • 只有在 主控台應用程式 (.NET Core) 與 類別庫 (.NET Core) 專案範本中,才看的見 程式碼分析規則集 (Code Analysis Rule Set) 這個「項目範本」(Item Template)。如果你在 ASP.NET Core Web 應用程式的專案中新增項目時,就會搜尋不到這個項目範本,要特別注意!

  • ASP.NET Core Web 應用程式

    • 預設內建 3 個 NuGet 套件 (包含 4 個分析器)
    1. Microsoft.CodeAnalysis.Analyzers
      • 套件說明:提供使用 .NET Compiler Platform (Roslyn) APIs 的相關導引。
      • 專案位址:https://github.com/dotnet/roslyn-analyzers
      • 更多資訊:Microsoft.CodeAnalysis.Analyzers.md
      • Microsoft.CodeAnalysis.Analyzers
      • Microsoft.CodeAnalysis.CSharp.Analyzers
    2. Microsoft.AspNetCore.Mvc.Analyzers
      • 套件說明:專門針對 ASP.NET Core MVC 的 C# 分析器。
      • 專案位址:https://github.com/aspnet/Mvc/tree/master/src/Microsoft.AspNetCore.Mvc.Analyzers
      • Microsoft.AspNetCore.Mvc.Analyzers
    3. Microsoft.EntityFrameworkCore.Analyzers
      • 套件說明:專門針對 Entity Framework Core 提供的 C# 分析器。
      • 專案位址:https://github.com/aspnet/EntityFrameworkCore/tree/release/2.2/src/EFCore.Analyzers
      • Microsoft.EntityFrameworkCore.Analyzers

詳細介紹 Microsoft.CodeAnalysis.FxCopAnalyzers 分析器

這個 Microsoft.CodeAnalysis.FxCopAnalyzers 分析器,原始碼位於 dotnet/roslyn-analyzers 專案。主要的目的在於幫助開發人員更正確的使用 Roslyn 靜態分析的 APIs,我認為一般人不太需要啟用所有的規則集,畢竟不是所有人都需要如此嚴謹的撰寫 C# 程式碼。

要使用 Microsoft.CodeAnalysis.FxCopAnalyzers 可以直接透過 NuGet 安裝 Microsoft.CodeAnalysis.FxCopAnalyzers 即可。

安裝過程除了會安裝 Microsoft.CodeAnalysis.FxCopAnalyzers 之外,也會連同安裝以下 4 個分析器。

  1. Microsoft.CodeQuality.Analyzers
  2. Microsoft.NetFramework.Analyzers
  3. Microsoft.NetCore.Analyzers
  4. Text.Analyzers
    • 套件資訊:Contains analyzers for text included in code, such as comments.

安裝之後,會有以下分析器:

相關連結

 

資料來源:https://blog.miniasp.com/post/2018/09/24/Enabling-Code-Analysis-in-VS2017-for-NET-Core



延伸資料

[iThome第8屆鐵人賽 19]靜態程式碼分析之Assembly品質分析 - Code Analysis(以前的FxCop)

https://blog.alantsai.net/posts/2017/01/devopsseries-codeanalysis

2024年10月2日 星期三

From120s to 0.5s Programming Optimization

程式算法本身的複雜度

CPU的速度和設計架構

CPU的位元帶寬

自己的程式的寫法




將一個照片RGB格式的彩色圖像轉換成黑白照片。

轉換的公式如下:
  Y = 0.299 * R + 0.587 * G + 0.114 * B; 

圖像尺寸640*480*24bit,RGB圖像已經按照RGBRGB順序排列的格式了。


以下是輸入和輸出的定義:

已經完成了第一個最佳化
看得出來最佳化在哪裡嗎?


優化原則: 圖像是一個2D資料,我用一個1維陣列來存儲。 編譯器處理1維陣列的效率高過2維陣列

這大概是能想得出來的最簡單的寫法了,實在看不出有什麼毛病,好了,編譯一下跑一跑吧。

這個代碼分別用VC6.0和GCC編譯,產生2個版本,分別在PC上和embedded system上面跑。

速度多少?說出來嚇死你!


第一次試跑的成績

在PC上,因為有硬體浮點運算處理器,CPU頻率也夠高,計算速度為20秒

embedded system ,沒有以上2個優勢,浮點操作被編譯器分解成了整數運算,運算速度為120秒左右
這只是一副圖像的運算速度!!

上面這個代碼還沒有跑,就已經知道會很慢了,因為這其中有大量 的浮點運算。只要能不用浮點運算,一定能快很多。

那這個公式怎麼能用定點的整數運算替代呢?

可以如何化簡?
我們就先簡化算式D吧!

RGB的取值範圍都是0~255,都是整數,只是這個係數比較麻煩, 不過這個係數可以表示為:
這一下,能快多少呢?

化簡後的成績


PC上的速度2秒

Embedded system
上的速度45秒


這個代碼編譯後,又快了20%
還是太慢!

雖然快了不少,還是太慢了一些,
20秒處理一幅圖像,地球人都不能 接受!

仔細看一下這個式子!

RGB的取值有文章可做,RGB的取值永遠都大於等於0,小於等於
255,我們能不能將D,E,F都預先計算好呢?然後用查表算法計 算呢?
我們使用3個數組分別存放DEF的256種可能的取值,然後。。。


查表數組初始化



突破音障!
這一次的成績把我嚇出一身冷汗,執行時間居然從30秒一下提高到 了2秒!在PC上測試這段代碼,眼皮還沒眨一下,代碼就執行完了。

一下提高15倍,爽不爽?
下一程,幾 秒?

120秒 ->45秒 -> 30秒 -> 2秒
還能再 快嗎?

很多embedded sysytem 的32bitCPU,都至少有2個ALU,能不能讓2個ALU都跑起來?

2個ALU處理的數據不能有數據依賴,也就是說:
某個ALU的輸入條件不能是別的ALU的輸出,這樣
才可以並行
到這裡,似乎已經足夠快了,但是我們反覆實驗,發現,還有辦法再快!

Int D[256],E[256],F[256]; //查表數組 更改為:
Unsigned short D[256],E[256],F[256]; //查表數組

這是因為編譯器處理int類型和處理unsigned short類型的效率不一樣
將函數聲明為inline,這樣編譯器就會將其
嵌入到母函數中,可以減少CPU調用子函 數所產生的開銷
這2個小小的改進帶來的效益!


一次的成績是: 0.5秒

現在,我們已經達到了客戶的要求!

如果加上以下措施,應該還可以更快:

把查表的數據放置在CPU的高速數據CACHE
裡面

把函數calc_lum()用組合語言來寫

同樣的需求,寫法不一樣,速度可以從120秒 變化為0.5秒,說明CPU的潛能是很大的!看你 如何去挖掘。