【譯】A unit of profiling makes the allocations go away

2023-10-23 09:00:22

  在 Visual Studio 17.8 Preview 2 中,我們更新了單元測試分析,允許你在效能分析器中使用任何可用的工具——而不僅僅是儀表工具。有了這個更改,可以很容易地快速分析孤立的小工作單元,進行更改,然後重新度量和驗證更改的影響。假設您有良好的測試覆蓋率,這是利用現有資產來幫助優化應用程式效能的好方法。

誰動了我的乳酪?

  在這個新版本中,我們更新了單元測試分析體驗。以前,當在單元測試上下文選單中選擇 profile 時,它在 Instrumentation 工具下執行,並且您在執行結束時得到報告。

  現在,當您選擇一個 profile 時,Performance Profiler 啟動頁面將出現,您可以選擇任何可用的工具。

  這讓您可以使用 .NET Object Allocation 工具來分析單元測試,以檢視所有的分配以及它們來自哪裡。這是減少不必要的分配並驗證更改的好方法。

讓我們減少一些分配吧!

  現在我們可以使用任何工具了,讓我們花5分鐘看看我們是否可以從效能分析器中減少一些分配。首先,我有一個名為「VerifySimpleCallTree」的單元測試,我們使用它來驗證我們的分析器是否正確地構建了一個呼叫樹。在測試資源管理器中,我右鍵單擊測試並選擇「Profile」,得到 Performance Profiler,選擇 .NET Object Allocation 工具,然後點選「Start」。從這裡開始我的測試執行,一旦完成,我就會得到正常的分配報告,我可以用它來深入研究分配,看看我可以削減什麼來減輕 GC 的負擔。

  當我瀏覽這些型別時,我注意到分配了一堆 Enumerators 。雖然這不是直接錯誤,但它確實看起來很奇怪。通過回溯,我可以看到這是來自我們的 JmcConfigurationService,並且檢視程式碼,可以肯定列舉元是從 Any() 擴充套件方法建立的。

this.patternsLock.EnterReadLock();
try
{
    if (this.unknownModulePatterns.Any(t => t.IsMatch(moduleString)))
    {
        return JmcState.UnknownCode;
    }
    else if (this.systemModulePatterns.Any(t => t.IsMatch(moduleString)))
    {
        return JmcState.SystemCode;
    }
    else
    {
        return IsStringJmc(moduleString, this.excModulePatterns, this.incModulePatterns) ? JmcState.UserCode : JmcState.LibraryCode;
    }
}
finally
{
    this.patternsLock.ExitReadLock();
}

  通過使用靜態區域性函數快速重寫,我們可以刪除列舉數並減少分配。

this.patternsLock.EnterReadLock();
try
{
    if (CheckMatch(this.unknownModulePatterns, moduleString))
    {
        return JmcState.UnknownCode;
    }
    else if (CheckMatch(this.systemModulePatterns, moduleString))
    {
        return JmcState.SystemCode;
    }
    else
    {
        return IsStringJmc(moduleString, this.excModulePatterns, this.incModulePatterns) ? JmcState.UserCode : JmcState.LibraryCode;
    }
}
finally
{
    this.patternsLock.ExitReadLock();
}

static bool CheckMatch(List patterns, string moduleStr)
{
    foreach (var pattern in patterns)
    {
        if (pattern.IsMatch(moduleStr))
        {
            return true;
        }
    }

    return false;
}

  在單元測試上重新執行分析器,我可以驗證並得出結結論:實際上,我已經刪除了這些不必要的分配,並幫助減少了 GC 的負擔。

  雖然這個小調整不會讓我的應用神奇地快20%,但隨著時間的推移慢慢減少不必要的分配是逐步提高應用效能的好方法。有了新的單元測試分析,就可以很容易地處理現有的測試資產,然後驗證更改是否產生了預期的影響。

讓我們知道你的想法!

  使用單元測試進行獨立效能分析的能力令人敬畏。通過隔離特定的程式碼區域,很容易獲得良好的前後跟蹤,以比較和檢視效能優化的影響。我們熱切歡迎任何聰明的想法,看法,或有價值的見解,我們洗耳恭聽!不要隱瞞,請隨時與我們分享吧。

 

原文連結:https://devblogs.microsoft.com/visualstudio/a-unit-of-profiling-makes-the-allocations-go-away/