今年5月份的时候研究分布式追踪的问题知道了的拦截方式比较零散, 恰好8月份的时候看到这篇文章,这个文章总结的比较完整。存档了好久,趁今天有空翻译给你们。原文地址,校验:张蘅水linux
.NET是一个托管运行时,这意味着它提供了“管理”您的程序的高级功能,从简介到公共语言运行时(CLR)(2007年编写):git
运行时具备许多功能,所以按以下方式对它们进行分类颇有用:github
您能够看到,“Debugging/Profiling”虽然不是基本或辅助功能,但因为“ 须要建立完整的编程环境 ” ,它仍然会进入列表。golang
这篇文章的其他部分将看什么 监测,可观测性和内省功能核心CLR提供,为何他们是有用的,如何提供他们。编程
为了便于浏览,帖子分为3个主要部分(最后有一些“额外阅读材料”):windows
首先,咱们将查看CLR提供的诊断信息,传统上这些信息是经过“Windows事件跟踪”(ETW)提供的。api
CLR提供的各类事件涉及:安全
例如,这是触发AppDomain Load事件的地方,这是Exception Thrown事件,这里是GC Allocation Tick事件。服务器
若是你想看到来自你的.NET程序的ETW事件,我建议使用优秀的PerfView工具,从这些PerfView教程开始,或者这个优秀的演讲PerfView:终极.NET性能工具。PerfView被普遍承认,由于它提供了宝贵的信息,例如Microsoft工程师常常将其用于性能调查。数据结构
可是,若是从名称中不清楚,ETW事件仅在Windows上可用,这并不适合新的.NET“跨平台”世界。您能够在Linux上使用PerfView进行性能跟踪(经过LTTng),但这只是cmd-line集合工具,称为“PerfCollect”,分析和丰富的UI(包括flamegraphs)目前仅适用于Windows。
可是若是你想分析.NET Performance Linux,还有其余一些方法:
上面的第二个连接讨论了在.NET Core中正在使用的新“EventPipe”基础架构(以及EventSources和EventListeners,你能发现一个主题!),你能够看到它在跨平台性能监控设计中的目标。在高层次上,它将为CLR提供一个单独的位置来推进与诊断和性能相关的“事件”。而后,这些“事件”将被路由到一个或多个记录器,例如,可能包括ETW,LTTng和BPF,精确记录器由CLR运行的OS /平台肯定。.NET Cross-Plat性能和事件设计中还有更多背景信息能够解释不一样日志记录技术的优缺点。
“事件管道”中正在进行的全部工做都在“性能监控”项目和相关的“EventPipe”问题中进行跟踪。
最后,还有一个性能分析控制器的(Performance Profiling Controller )将来计划,其目标以下:
控制器负责以简单和跨平台的方式控制性能分析基础结构和.NET性能诊断组件生成的性能数据。
咱们的想法是经过从“事件管道”中提取全部相关数据,经过HTTP服务器公开如下功能:
REST API
- Pri 1:简单分析:为运行时间配置X个时间并返回跟踪。
- Pri 1:高级分析:开始跟踪(以及配置)
- Pri 1:高级分析:中止跟踪(对此调用的响应将是跟踪自己)
- Pri 2:获取与全部EventCounters或指定EventCounter相关的统计信息。
可浏览的HTML页面
- Pri 1:流程中全部托管代码堆栈的文本表示。
- 提供当前正在运行的用做简单诊断报告的快照概述。
- Pri 2:显示EventCounters的当前状态(可能具备历史记录)。
* 提供现有计数器及其值的概述。
* 开放性问题:我不相信存在必要的公共API来枚举EventCounters。
我很高兴看到“性能分析控制器(Performance Profiling Controller)”(PPC?)的位置,我认为将这种内置到CLR中确实很是有价值,这是其余运行时的内容。
CLR提供的另外一个强大功能是Profiling API,它(大部分)被第三方工具用于在很是低级别挂钩到运行时。您能够在此概述中找到有关API的更多信息,但在较高级别,它容许您链接在如下状况下触发的回调:
来自BOTR页面的图像分析API - 概述
此外还有其余很是强大的功能。首先,您能够设置每次执行.NET方法时调用的挂钩,不管是在运行时仍是用户代码中。这些回调被称为“进入/离开”钩子,而且有一个很好的示例显示如何使用它们,但为了使它们工做,您须要了解不一样操做系统和CPU架构的“调用约定”,这并不老是容易的。另外,做为警告,Profiling API是一个只能经过C / C ++代码访问的COM组件,你不能在C#/ F#/ VB.NET中使用它!
其次,Profiler可以经过SetILFunctionBody()API在JIT 以前重写任何.NET方法的IL代码。这个API功能很是强大,构成了许多.NET APM工具的基础,您能够在我以前的文章中了解更多关于如何使用它的方法。如何模拟密封类和静态方法以及随附的代码。
事实证实,运行时必须执行各类疯狂的技巧才能使Profiling API正常工做,只需查看进入此PR的内容容许从新链接(有关'ReJIT'的详细信息,请参阅ReJIT:A How-To指南)。
全部Profiling API接口和回调的整体定义可在\vm\inc\corprof.idl中找到(请参阅接口说明语言)。但它分为2个逻辑部分,一个是Profiler - >'Execution Engine'(EE)接口,称为ICorProfilerInfo
:
// Declaration of class that implements the ICorProfilerInfo* interfaces, which allow the // Profiler to communicate with the EE. This allows the Profiler DLL to get // access to private EE data structures and other things that should never be exported // outside of the EE.
这在如下文件中实现:
另外一个主要部分是EE - > Profiler回调,它们在ICorProfilerCallback
界面下组合在一块儿:
// This module implements wrappers around calling the profiler's // ICorProfilerCallaback* interfaces. When code in the EE needs to call the // profiler, it goes through EEToProfInterfaceImpl to do so.
这些回调在如下文件中实现:
最后,值得指出的是,Profiler API可能没法在.NET Core运行的全部操做系统和CPU-arch上运行,例如Linux上的ELT调用存根问题,有关详细信息,请参阅CoreCLR Profiler API的状态。
除此以外,“分析”和“调试”确实有一些重叠,所以从CLR调试与CLR分析中了解.NET运行时上下文中不一样的API提供了什么是有帮助的。
调试意味着不一样的事情不一样的人,好比我问在Twitter上“ 什么是你调试的.NET程序的途径 ”,并获得了普遍的不一样反应,虽然反应两组含有一个很好的工具清单和技术,因此他们值得一试,谢谢#LazyWeb!
但也许这句话最好总结一下Debugging到底是什么😊
CLR提供了与调试相关的很是普遍的功能,但为何须要提供这些服务,优秀的帖子为何托管调试与本机调试不一样?提供了3个理由:
因此给一个体面的经验,CLR 具备提供更高级别的调试API称ICorDebug
,这将在下面从“经常使用的调试方案”的图像中显示的BOTR:
此外,还有很好的描述了不一样部分如何在管理断点如何工做中相互做用?,虽然描述左和右是上图中的相反!
Here’s an overview of the pipeline of components: 1) End-user 2) Debugger (such as Visual Studio or MDbg). 3) CLR Debugging Services (which we call "The Right Side"). This is the implementation of ICorDebug (in mscordbi.dll). ---- process boundary between Debugger and Debuggee ---- 4) CLR. This is mscorwks.dll. This contains the in-process portion of the debugging services (which we call "The Left Side") which communicates directly with the RS in stage #3. 5) Debuggee's code (such as end users C# program)
可是如何实现全部这些以及从CLR Debugging简要介绍的不一样组件是什么:
全部.Net调试支持都在咱们称之为“The Dac”的dll之上实现。此文件(一般命名
mscordacwks.dll
)是咱们的公共调试API(ICorDebug
)以及两个私有调试API 的构建块:SOS-Dac API和IXCLR。在一个完美的世界中,每一个人都会使用
ICorDebug
咱们的公共调试API。可是,像您这样的工具开发人员所需的绝大多数功能都缺少ICorDebug
。这是咱们正在修复的问题,但这些改进将进入CLR v.next,而不是旧版本的CLR。实际上,ICorDebug
API仅在CLR v4中添加了对故障转储调试的支持。任何调试CLR v2崩溃转储的人根本没法使用ICorDebug
!
(有关其余文章,请参阅SOS和ICorDebug)
该ICorDebug
API其实是分红多个接口,也有在他们的70!我不会在这里列出全部内容,可是我将展现它们所属的类别,有关更多信息,请参阅ICorDebug的分区,其中包含此列表,由于它更详细。
另外须要注意的是,与Profiling APIs同样,调试API的支持级别因操做系统和CPU架构而异。例如,截至2018年8月,“没有针对Linux ARM进行托管调试和诊断的解决方案”。有关“Linux”支持的更多信息,请参阅这篇很棒的文章,在Linux上使用LLDB调试.NET Core,并从Microsoft 检出诊断存储库,其目标是更容易在Linux上调试.NET程序。
最后,若是你想看看ICorDebug
API在C#中的样子,看一下CLRMD库中包含的包装器,包括全部可用的回调(CLRMD将在后面的文章中进行更深刻的介绍)。
“数据访问组件(Data Access Component)”(DAC)在BOTR页面中有详细讨论,但实际上它提供了对CLR数据结构的“进程外”访问,所以能够从另外一个进程读取其内部详细信息。这容许调试器(via ICorDebug
)或'Son of Strike'(SOS)扩展进入CLR的运行实例或内存转储,并找到以下内容:
除此以外,若是您想要解释全部奇怪的名称和一点'.NET历史课',请参阅此Stack Overflow答案。
SOS命令的完整列表很是使人印象深入,而且在WinDBG旁边使用它可让您很是低级地了解程序和CLR中发生的状况。要了解它是如何实现的,让咱们看一下这个!HeapStat
命令,该命令能够为您提供.NET GC正在使用的不一样堆大小的摘要:
(来自SOS的图片:即将发布的版本有一些新命令 - HeapStat)
这是代码流,显示了SOS和DAC如何协同工做:
!HeapStat
命令(连接)!HeapStat
处理'Workstation GC' 的命令中的代码(连接)GCHeapUsageStats(..)
功能,重负荷(连接)DacpGcHeapDetails
包含指向GC堆中主数据的指针的数据结构,例如段,卡表和各代(连接)GetGCHeapStaticData
填充DacpGcHeapDetails
结构的DAC函数(连接)DacpHeapSegmentData
包含GC堆的单个“段”的详细信息的数据结构(连接)GetHeapSegmentData(..)
填充DacpHeapSegmentData
结构的DAC(连接)因为Microsoft发布了调试API,它容许第三方使用ICorDebug
接口,这里列出了我遇到的一些内容:
咱们要看的最后一个区域是“内存转储”,能够从实时系统中捕获并离线分析。.NET运行时一直很好地支持在Windows上建立“内存转储”,如今.NET Core是“跨平台”,也能够在其余操做系统上使用相同的工具。
“内存转储”的一个问题是,获取SOS和DAC文件的正确匹配版本可能会很是棘手。幸运的是,Microsoft刚刚发布了如下dotnet symbol
CLI工具:
能够下载任何给定核心转储,minidump或任何支持平台的文件格式(如ELF,MachO,Windows DLL,PDB和便携式PDB)的调试所需的全部文件(给出coreclr模块的符号,模块,SOS和DAC)。
最后,若是你花费任什么时候间分析'内存转储',你真的应该看看微软几年前发布的优秀的CLR MD库。我以前已经写过你能够用它作什么,但简而言之,它容许你经过一个直观的C#API与内存转储交互,其中的类能够访问ClrHeap,GC Roots,CLR Threads,Stack Frames和更多。实际上,除了实现工做所需的时间以外,CLR MD还能够实现大多数(若是不是所有)SOS命令。
ClrMD托管库是CLR仅内部调试API的包装器。虽然这些仅内部API对于诊断很是有用,但咱们不支持它们做为公开的,有文档的版本,由于它们很是难以使用而且与CLR的其余实现细节紧密耦合。ClrMD经过围绕这些低级调试API提供易于使用的托管包装来解决此问题。
经过在官方支持的库中提供这些API,Microsoft使开发人员可以在CLRMD之上构建各类工具,这是一个很好的结果!
总而言之,.NET Runtime提供了普遍的诊断,调试和分析功能,能够深刻了解CLR内部的状况。