国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

AOT漫談: 如何獲取C#程序的CPU利用率

開發(fā) 前端
如果你的AOT使用默認的 WindowsThreadPool,那想獲取 cpu利用率基本上是無力回天,當然有達人知道的話可以告知下,如果切到默認的.NET線程池還是有的一拼,即使沒有 pdb 符號也可以根據_minThreads和_maxThreads的內容反向搜索。

一、背景

1. 講故事

上篇聊到了如何對AOT程序進行輕量級的APM監(jiān)控,有朋友問我如何獲取AOT程序的CPU利用率,本來我覺得這是一個挺簡單的問題,但一研究不是這么一回事,這篇我們簡單的聊一聊。

二、如何獲取CPU利用率

1. 認識cpuUtilization字段

熟悉.NET底層的朋友應該知道,.NET線程池中有一個cpuUtilization字段就記錄了當前機器的CPU利用率,所以接下來的思路就是如何把這個字段給挖出來,在挖這個字段之前也要知道 .NET6 為界限出現(xiàn)過兩個線程池。

1)win32threadpool.cpp

這是 .NET6 之前一直使用的 .NET線程池,它是由 clr 的 1)win32threadpool.cpp 實現(xiàn)的,參考代碼如下:

SVAL_IMPL(LONG,ThreadpoolMgr,cpuUtilization);
PortableThreadPool.cs

為了更好的跨平臺以及高層統(tǒng)一, .NET團隊用C#對原來的線程池進行了重構,所以這個字段自然也落到了C#中,參考如下:

internal sealed class PortableThreadPool
{
    private int _cpuUtilization;
}
WindowsThreadPool.cs

我原以為線程池已經被這兩種實現(xiàn)平分天下,看來我還是年輕了,不知道什么時候又塞入了一種線程池實現(xiàn) WindowsThreadPool.cs,無語了,它是簡單的 WindowsThreadPool 的 C#封裝,舍去了很多原來的方法實現(xiàn),比如:

internal static class WindowsThreadPool
{
    public static bool SetMinThreads(int workerThreads, int completionPortThreads)
    {
        return false;
    }
    public static bool SetMaxThreads(int workerThreads, int completionPortThreads)
    {
        return false;
    }

    internal static void NotifyThreadUnblocked()
    {
    }

    internal unsafe static void RequestWorkerThread()
    {
        //todo...
        //提交到 windows線程池
        Interop.Kernel32.SubmitThreadpoolWork(s_work);
    }
}

而這個也是 Windows 版的AOT默認實現(xiàn),因為 Windows線程池是由操作系統(tǒng)實現(xiàn),沒有源碼公開,觀察了reactos的開源實現(xiàn),也未找到類似的cpuUtilization字段,這就比較尷尬了,常見的應對措施如下:

  1. 因為dump或者program中沒有現(xiàn)成字段,只能在程序中使用代碼獲取。
  2. 修改windows上的 aot 默認線程池。

2. 如果修改AOT的默認線程池

在微軟的官方文檔:https://learn.microsoft.com/zh-cn/dotnet/core/runtime-config/threading 上就記錄了Windows線程池的一些概況以及如何切換線程池的方法,截圖如下:

圖片圖片

這里選擇 MSBuild 的方式來配置。

<Project Sdk="Microsoft.NET.Sdk">

 <PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>net8.0</TargetFramework>
  <ImplicitUsings>enable</ImplicitUsings>
  <Nullable>enable</Nullable>
  <PublishAot>true</PublishAot>
  <UseWindowsThreadPool>false</UseWindowsThreadPool>
  <InvariantGlobalization>true</InvariantGlobalization>
 </PropertyGroup>
</Project>

接下來寫一段簡單的C#代碼,故意讓一個線程死循環(huán)。

internal class Program
    {
        static void Main(string[] args)
        {
            Task.Run(() =>
            {
                Test();
            }).Wait();
        }

        static void Test()
        {
            var flag = true;
            while (true)
            {
                flag = !flag;
            }
        }
    }

這里要注意的一點是發(fā)布成AOT的程序不能以普通的帶有元數(shù)據的C#程序來套。畢竟前者沒有元數(shù)據了,那怎么辦呢?這就考驗你對AOT依賴樹的理解,熟悉AOT的朋友都知道,依賴樹的構建最終是以有向圖的方式存儲在 _dependencyGraph 字段中,每個節(jié)點由基類 NodeFactory 承載,參考代碼如下:

public abstract class Compilation : ICompilation
{
    protected readonly DependencyAnalyzerBase<NodeFactory> _dependencyGraph;
}

public abstract partial class NodeFactory
{
    public virtual void AttachToDependencyGraph(DependencyAnalyzerBase<NodeFactory> graph)
    {
        ReadyToRunHeader = new ReadyToRunHeaderNode();

        graph.AddRoot(ReadyToRunHeader, "ReadyToRunHeader is always generated");
        graph.AddRoot(new ModulesSectionNode(), "ModulesSection is always generated");

        graph.AddRoot(GCStaticsRegion, "GC StaticsRegion is always generated");
        graph.AddRoot(ThreadStaticsRegion, "ThreadStaticsRegion is always generated");
        graph.AddRoot(EagerCctorTable, "EagerCctorTable is always generated");
        graph.AddRoot(TypeManagerIndirection, "TypeManagerIndirection is always generated");
        graph.AddRoot(FrozenSegmentRegion, "FrozenSegmentRegion is always generated");
        graph.AddRoot(InterfaceDispatchCellSection, "Interface dispatch cell section is always generated");
        graph.AddRoot(ModuleInitializerList, "Module initializer list is always generated");

        if (_inlinedThreadStatics.IsComputed())
        {
            graph.AddRoot(_inlinedThreadStatiscNode, "Inlined threadstatics are used if present");
            graph.AddRoot(TlsRoot, "Inlined threadstatics are used if present");
        }

        ReadyToRunHeader.Add(ReadyToRunSectionType.GCStaticRegion, GCStaticsRegion);
        ReadyToRunHeader.Add(ReadyToRunSectionType.ThreadStaticRegion, ThreadStaticsRegion);
        ReadyToRunHeader.Add(ReadyToRunSectionType.EagerCctor, EagerCctorTable);
        ReadyToRunHeader.Add(ReadyToRunSectionType.TypeManagerIndirection, TypeManagerIndirection);
        ReadyToRunHeader.Add(ReadyToRunSectionType.FrozenObjectRegion, FrozenSegmentRegion);
        ReadyToRunHeader.Add(ReadyToRunSectionType.ModuleInitializerList, ModuleInitializerList);

        var commonFixupsTableNode = new ExternalReferencesTableNode("CommonFixupsTable", this);
        InteropStubManager.AddToReadyToRunHeader(ReadyToRunHeader, this, commonFixupsTableNode);
        MetadataManager.AddToReadyToRunHeader(ReadyToRunHeader, this, commonFixupsTableNode);
        MetadataManager.AttachToDependencyGraph(graph);
        ReadyToRunHeader.Add(MetadataManager.BlobIdToReadyToRunSection(ReflectionMapBlob.CommonFixupsTable), commonFixupsTableNode);
    }
}

結合上面的代碼,我們的 PortableThreadPool 靜態(tài)類會記錄到根區(qū)域的 GCStaticsRegion 中,有了這些知識,接下來就是開挖了。

3. 使用 windbg 開挖

用 windbg 啟動生成好的 aot程序,接下來用 Example_21_8!S_P_CoreLib_System_Threading_PortableThreadPool::__GCSTATICS 找到類中的靜態(tài)字段。

0:007> dp Example_21_8!S_P_CoreLib_System_Threading_PortableThreadPool::__GCSTATICS L1
00007ff6`e4b7c5d0  000002a5`a4000468
0:007> dp 000002a5`a4000468+0x8 L1
000002a5`a4000470  000002a5`a6809ca0
0:007> dd 000002a5`a6809ca0+0x50 L1
000002a5`a6809cf0  0000000a
0:007> ? a
Evaluate expression: 10 = 00000000`0000000a

從上面的卦中可以清晰的看到,當前的CPU=10%。這里稍微解釋下 000002a5a4000468+0x8 是用來跳過vtable從而取到類實例,后面的 000002a5a6809ca0+0x50 是用來獲取 PortableThreadPool._cpuUtilization 字段的,布局參考如下:

0:012> !dumpobj /d 27bc100b288
Name:        System.Threading.PortableThreadPool
MethodTable: 00007ffc6c1aa6f8
EEClass:     00007ffc6c186b38
Tracked Type: false
Size:        512(0x200) bytes
File:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.8\System.Private.CoreLib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffc6c031188  4000d42       50         System.Int32  1 instance                10 _cpuUtilization
00007ffc6c0548b0  4000d43       5c         System.Int16  1 instance               12 _minThreads
00007ffc6c0548b0  4000d44       5e         System.Int16  1 instance            32767 _maxThreads

三、總結

總的來說如果你的AOT使用默認的 WindowsThreadPool,那想獲取 cpu利用率基本上是無力回天,當然有達人知道的話可以告知下,如果切到默認的.NET線程池還是有的一拼,即使沒有 pdb 符號也可以根據_minThreads和_maxThreads的內容反向搜索。

責任編輯:武曉燕 來源: 一線碼農聊技術
相關推薦

2024-10-11 14:42:59

2017-08-25 15:56:54

Linuxproc文件系統(tǒng)CPU利用率

2023-04-04 09:22:50

LinuxCPU命令

2024-10-24 11:08:00

C#AOT泛型

2010-03-11 16:49:55

Linux CPU利用

2024-06-26 09:29:53

2011-03-17 15:16:38

2013-01-04 10:44:31

IBMdW

2019-03-05 15:53:40

Linux服務器CPU

2019-08-28 06:58:06

Linux監(jiān)控腳本Shell

2012-10-11 10:21:33

數(shù)據中心CPU利用率服務器效率

2025-09-15 08:34:01

2010-03-15 15:01:37

2019-01-23 10:21:32

吞吐量響應時間CPU

2011-03-17 13:54:42

查詢參數(shù)SQL語句利用率

2021-02-03 09:26:49

數(shù)據中心基礎設施能源

2025-11-03 02:45:00

2015-09-07 11:54:25

云計算數(shù)據中心資源利用

2013-03-19 12:23:25

SDN網絡利用率網絡系統(tǒng)架構

2011-04-12 09:07:47

磁盤空間利用率虛擬化的隱藏成本
點贊
收藏

51CTO技術棧公眾號

91精品综合久久久久久| 高清av不卡| 成人羞羞视频在线看网址| 另类天堂视频在线观看| 久久久999精品免费| 欧美高清无遮挡| 欧美一区2区视频在线观看| 无限国产资源| 亚洲午夜极品| 国产福利视频一区| 136国产福利精品导航网址应用| 欧美性生活久久| 三级在线播放| 亚洲成年人网站在线观看| 国产又黄又猛又粗| 久久久国产午夜精品| 青青草原网站在线观看| 日韩国产在线观看一区| 国内精品久久国产| 亚洲黄色影院| 欧美激情第六页| 国产福利91精品| 欧美精品久久久| 亚洲一区二区动漫| 日韩欧美三级一区二区| 久久99高清| 欧美日韩999| 依依综合在线| 亚洲欧美福利视频| 日韩欧美视频在线播放| 无码人妻精品一区二区蜜桃网站| 中文字幕一区二区三| 久久免费电影| 国产精品对白刺激| 成人免费黄色在线| 麻豆传媒视频在线观看| 69视频在线免费观看| 国产一区91精品张津瑜| av动漫在线观看| 日韩欧美精品网站| 免费福利视频一区二区三区| 国产精品专区一| 久久国产人妖系列| 欧美日韩日日摸| 日韩欧乱色一区二区三区在线 | 国产人久久人人人人爽| 久久亚洲私人国产精品va| 欧美尤物巨大精品爽| 国产精品综合视频| 国产激情视频在线看| 中文字幕免费在线不卡| 欧美日韩精品一区二区三区 | 亚洲人永久免费| 一区二区日韩免费看| 国产鲁鲁视频在线观看免费| 欧美亚洲一区二区在线| 精品国产日韩欧美| 男女免费网站| 国产精品成人品| 亚洲第一精品在线| 9.1国产丝袜在线观看 | 一二三四社区在线视频6| 欧美大片在线免费观看| 欧美午夜一区| 别急慢慢来1978如如2| 色悠久久久久综合欧美99| 在线成人动漫av| 黄动漫在线免费观看| www.日韩.com| 欧美日韩免费观看一区=区三区| 日日橹狠狠爱欧美超碰| 日韩免费电影一区| 日韩av影院| 日韩小视频在线播放| 欧美大胆一级视频| 99成人在线| 国产剧情在线| 精品亚洲欧美日韩| 亚洲一区在线观看免费| 国产精品三p一区二区| 欧美黄网在线观看| 国产一区二区三区三区在线观看| 亚洲精品一二| 亚洲制服国产| 日韩最新中文字幕| 这里只有精品在线观看| 久久精品国产久精国产| 国产桃色电影在线播放| 日本一区网站| 亚洲成人久久一区| 九九视频精品免费| 色婷婷成人网| 成人拍拍拍在线观看| 国产成人97精品免费看片| 亚洲九九爱视频| 日韩在线看片| 91在线直播| 欧美日韩一级在线| 精品国产一区二区三区久久| 欧美国产精品劲爆| 亚洲一区二区三区| av中文资源在线资源免费观看| 青草全福视在线| 欧美一区二区视频97| 欧美性猛交xxxx乱大交| 国产精品一二三在| 国产探花在线精品| av在线免费网址| 欧美精品aaaa| 久久精品综合一区| 欧美精品www在线观看| 欧美在线视频全部完| 97se亚洲国产综合自在线| 国产精品久久久久一区二区三区厕所| 黄色一级片在线观看| 青青草成人免费在线视频| 91色在线观看| 岛国av在线播放| 久草.com| 免费在线a视频| 欧美精选在线播放| 久久久久九九视频| 国产精品最新自拍| 亲子伦视频一区二区三区| 国产三区视频在线观看| 日本欧洲一区| 午夜精品久久久内射近拍高清| 成人动漫视频在线观看完整版| 久久99精品久久久久久琪琪| 日韩欧美国产小视频| 久久久国产精品不卡| 一区精品在线播放| 国产二区精品| 日本不卡视频| 亚洲自拍欧美另类| 亚洲综合成人网| 激情亚洲成人| 婷婷六月天丁香| 综合国产在线视频| 91免费观看视频| 在线日韩一区| 国产黄在线看| 91九色在线观看视频| 亚洲欧洲国产一区| 五月天一区二区| 日韩视频免费在线| 久精品国产欧美| 免费人成黄页在线观看忧物| 欧美a在线观看| 成人aaaa免费全部观看| 精品一二三四区| 五月激激激综合网色播| 2023欧美最顶级a∨艳星| 国产精品久久久av| 久久精品国产一区二区三区| 中文字幕一区二区三| 欧洲福利电影| 蜜桃视频在线观看免费视频| 久久久精品在线视频| 日韩在线第一区| 久久艳片www.17c.com| 亚洲一区二区三区视频在线播放| 国产精品乱看| 在线观看中文字幕的网站| 色综合久久久久无码专区| 国产成人自拍视频在线观看| 精品国产依人香蕉在线精品| 国产一区二区三区免费播放| 亚洲国产高清一区| 亚洲一区二区av| 日韩av官网| 蜜臀av性久久久久蜜臀av麻豆| 区一区二日本| 欧美大片在线播放| 免费yellow网站| 伊人网在线播放| 日韩情涩欧美日韩视频| 日韩高清不卡一区二区| 国产精品无圣光一区二区| 久久er99热精品一区二区三区| heyzo亚洲| 欧美高清你懂的| 成人免费毛片片v| 伊人精品在线观看| 久久久黄色av| 日韩精品欧美在线| 全部孕妇毛片丰满孕妇孕| 成年人在线视频| 成人h动漫精品一区二区器材| 日本不卡一二三区黄网| 欧美视频在线免费看| 2024亚洲男人天堂| 欧美 日韩 国产一区| 亚洲成人人体| 国产精品久久777777毛茸茸| 国产精品久久久久久亚洲伦| 日韩av有码在线| 午夜精品一区二区三区在线观看| 写真福利理论片在线播放| 欧美日韩国产传媒|