聊一聊 dotnet-trace 調查 lock鎖競爭

来源:https://www.cnblogs.com/huangxincheng/archive/2023/05/09/17384543.html
-Advertisement-
Play Games

一:背景 1. 講故事 最近在分析一個 linux 上的 dump,最後的誘因是大量的lock鎖誘發的高頻上下文切換,雖然問題告一段落,但我還想知道一點信息,所謂的高頻到底有多高頻?鎖競爭到底是一個怎樣的鎖競爭? 如果瞭解這些信息對我們後續分析此類問題非常有幫助。 要想獲取此類信息,看 dump 肯 ...


一:背景

1. 講故事

最近在分析一個 linux 上的 dump,最後的誘因是大量的lock鎖誘發的高頻上下文切換,雖然問題告一段落,但我還想知道一點信息,所謂的高頻到底有多高頻?鎖競爭到底是一個怎樣的鎖競爭? 如果瞭解這些信息對我們後續分析此類問題非常有幫助。

要想獲取此類信息,看 dump 肯定是沒有用的,只能給程式安裝一個攝像頭,在 Windows 平臺上可以在 perfview 上配一個 Microsoft-Windows-DotNETRuntime:ContentionKeyword 事件輕鬆搞定,截圖如下:

但 PerfView 是和 Windows 深度綁定的,那在 Linux 上怎麼辦呢? 對,有朋友知道用 dotnet-trace。

二:探究 dotnet-trace

1. 如何監控 lock 競爭

dotnet-trace 是 CLR 團隊寫的一個跨平臺的小工具,專門用於獲取 .NET 程式的各種事件,可以理解成 PerfView 的一個子集,這裡安裝就不說了,詳見官方文檔:https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace

查閱文檔之後,只需要在 --clrevents 中配 contention 事件即可,詳情參見文檔:https://learn.microsoft.com/en-us/dotnet/fundamentals/diagnostics/runtime-contention-events

2. 測試案例

為了方便解讀,這裡我故意造一個 鎖護送 現象,參考代碼如下:


    internal class Program
    {
        public static object lockMe = new object();

        static void Main(string[] args)
        {
            long i = 10;

            Parallel.For(0, int.MaxValue, new ParallelOptions() { MaxDegreeOfParallelism = 4 }, (j) =>
            {
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
                lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++; lock (lockMe) i++;
            });
        }
    }

將程式跑起來後,使用 dotnet-trace ps 找到 PID,再用 dotnet-trace 進行跟蹤,這裡持續跟蹤 1分鐘。


[root@localhost ~]# dotnet-trace ps
 3316  dotnet  /usr/share/dotnet/dotnet  dotnet ConsoleApp3.dll  

[root@localhost ~]# dotnet-trace collect -p 3316 --clrevents contention --duration 00:00:01:00

Provider Name                           Keywords            Level               Enabled By
Microsoft-Windows-DotNETRuntime         0x0000000000004000  Informational(4)    --clrevents

Process        : /usr/share/dotnet/dotnet
Output File    : /root/dotnet_20230509_105906.nettrace
Trace Duration : 00:00:01:00
[00:00:01:00]	Recording trace 29.7885  (MB)
Press <Enter> or <Ctrl+C> to exit...148  (MB)
Stopping the trace. This may take several minutes depending on the application being traced.

Trace completed.

[root@localhost ~]# ls

anaconda-ks.cfg  dotnet_20230509_105906.nettrace  Music     Templates
Desktop          Downloads                        Pictures  Videos
Documents        initial-setup-ks.cfg             Public

3. nettrace 文件分析

至於分析 dotnet_20230509_105906.nettrace 的工具就特別多了,dotnet-trace,perf,perfview,visualstudio,不過我個人建議還是使用 prefview,因為它的洞察能力會更好,用 perfview 打開之後點擊 EventStats 觀察統計信息:

從圖中可以看到 1min 的時間內生成了總計將近 200w 的 start 和 stop 事件。

有了統計信息還不行,我還想知道每一次 start 的詳細信息,可以點擊 perfview 中的 Events 面板中的 Microsoft-Windows-DotNETRuntime/Contention/Start 事件,可以看到記錄中每一次爭搶的開始時間。

有些朋友可能要問了,Start 和 Stop 到底代表什麼意思,簡而言之就是爭搶的開始時間和結束時間,時間差就是排隊時間,截圖如下:

從圖中可以看到,某些競爭鎖的時候耗費了 1ms 的時間,同時得到調度的線程也不是串列的,比如 4232 號線程就得到了兩次連續執行。

接下來回答最後一個問題,除了看到每一次lock競爭的詳細信息,能不能看到每一次 lock 時的代碼調用棧呢? 當然是可以的,畢竟 HasStack="True" ThreadID="3,316" ProcessorNumber="0" ContentionFlags="Managed" ClrInstanceID="0" 中的 HasStack="True" 就是告訴當前是有調用棧信息的,在 Time MSec 列點擊右鍵選擇 Open Any Stacks

從圖中的線程棧可以看到,Start 事件是由 Main 方法中的 Parallel.For 誘發的,非常清楚。

三:總結

dotnet-trace 是一個非常強大的跨平臺性能分析工具,構建在 EventPipe 之上,特點就是跨平臺,除了對鎖競爭外,還有其他的各種有趣的事件,有興趣的朋友可以查閱查閱。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Markdown 備忘清單 Markdown 是一種輕量級標記語言,創始人為約翰·格魯伯(John Gruber)。 它允許人們使用易讀易寫的純文本格式編寫文檔,然後轉換成有效的 XHTML(或者HTML)文檔。這種語言吸收了很多在電子郵件中已有的純文本標記的特性。 由於 Markdown 的輕量化 ...
  • Applicationcontext的功能拓展主要來自於不屬於beanfactory的介面,主要包括四個介面 Messagesource :國際化 ResourcePatternResolver :獲取資源 ApplicationEventPublisher:發佈事件 EnvironmentCapa ...
  • Listener監聽器,實現一個顯示線上用戶人數 每博一文案 關於後半身,脾氣越溫,福報越深。 師傅說:惜命最好的方式不是養生,而是管好自己的情緒。 壞毛病都是慣出來的,但好脾氣都是磨出來的,與人生氣,傷的是和氣,與自己生氣,傷的是身體。 佛說:人有五毒心,貪嗔痴慢疑,其中一時的嗔念起,百萬葉障深, ...
  • GMP調度場景 場景1 P擁有G1,M1獲取P後開始運行G1,G1使用 go func 創建G2,為了局部性G2優先加入到P1的本地隊列 場景2 G1運行完成後(函數:goexit),M上運行的goroutine切換為G0,G0負責調度時協程的切換(函數:schedule)。從P的本地隊列取G2,從 ...
  • Legends-Of-Heroes 一個LOL風格的球球大作戰游戲,基於ET7.2,使用狀態同步 Main 基於C#雙端框架[ET7.2],同步到ET主幹詳情請看日誌。(https://github.com/egametang/ET) 註意:已經升級.Net7,請安裝.Net7 SDK. 此游戲為E ...
  • 字元串駐留池(string intern pool)是指,對於某些編程語言,相同的字元串字面值(即具有相同文本內容的字元串)在程式運行時只會被在記憶體中存儲一份,即只保存一個字元串實例。這樣做可以減少記憶體占用,並提高程式執行的效率。 在 Java 中,字元串駐留池是一個存儲字元串的緩存,它存儲在運行時 ...
  • 1、創建WEBAPI 1 using Dapper; 2 using MesErp.Models; 3 using Microsoft.AspNetCore.Mvc; 4 using Microsoft.Extensions.Configuration; 5 using Newtonsoft.Jso ...
  • C#是一種強類型語言,可以捕獲和處理各種異常,從而幫助我們發現程式中出現的錯誤。在程式開發過程中,如果需要找到特定的錯誤情況並處理,這時就需要創建自定義異常。本文將介紹如何在C#中創建和使用自定義異常。 1、什麼是異常? 異常是指在程式執行期間發生的錯誤或異常情況,例如除法中除以0、文件不存在、記憶體 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...