windows内核开发学习笔记四十六:事件追踪(ETW)

        Windows提供了统一的跟踪和记录事件的机制,称为ETW(Event Tracing For Windows)。用户模式应用程序和内核模式驱动程序都可以使用ETW来记录事件。ETW是直接由内核支持的事件记录机制。在它的框架结构中,共有三种组件:

  • 控制器(Control):负责启动、停止或配置事件记录会话。
  • 提供者(Provider):负责向ETW注册自己的事件类,并接受控制器的命令,以便启动或者停止它们所负责的事件类的记录过程。
  • 消费者(Consumer):负责有针对性地读取它们想要的事件数据,选择一个或多个记录会话。它们既可以实时地接收ETW缓冲区中的数据,也可以接收日志文件中的事件数据。

        事件追踪能力对于诊断系统的性能问题尤为重要,因而windows内置了一个内核日志的记录器(Kernel logger)作为ETW提供者,专门用于记录内核和核心驱动程序的事件。此内核日志记录器由WMI(Windows Management Instrumentation,windows管理规范)。设备驱动程序实现的也是内核模块ntoskernel.exe的一部分。WMI驱动程序的名称为“WMIxWDM”,它是在I/O管理器初始化过程中调用WMI组件的初始化函数(WMIInitialize)而创建的。它除了实现内核日志记录器的功能,也管理用户模式ETW事件类型的注册工作。由于它的实现形式是驱动程序,因此,其他内核例程或设备驱动可以通过I/O接口与它通信。在WRK中的WMI驱动程序的代码中,器初始化的例程在base\ntos\wmi\wmi.c文件中的WmipDriverEntry。

        早期的windows版本就提供了事件管理器(event manager)和性能计数器(performance counter)这些设施来报告错误和指示关键的性能数据,但没有提供统一的接口,并不具备良好的扩展能力。后来的windows版本提供了新的事务管理机制进行事件报告和性能分析,即Windows管理规范(WMI)。WMI是工业标准WBEM(Web-Based Enterprise Management)的一个实现,WBEM标准包含了一套针对企业的数据采集和数据管理设施的设计方案,它具有很好的灵活性和可可扩展性。从windows nt4.0(SP4)的版本都支持WMI,在WRK中可以看到内核模式驱动程序WMIxWDM的实现代码,ETW的内核日志记录器实际上也是WMI设施的一部分。

        内核日志记录器是一个事件的提供者,它有一个预定义的GUID,即内核变量SystemTraceControlGuid。内核日志记录器支持多种事件类,它采用标志位(flag)来指示是否记录某一类型的事件。而且,它进一步将这些标志位分成了8个组,每个组使用一个掩码(29位)来描述。下面就是在public\internel\base\inc\ntperf.h中的相关定义:

#define PERF_MASK_INDEX     (0xe000 0000)

#define PERF_MASK_GROUP    (~PERF_MASK_INDEX)

#define PERF_NUM_MASKS       8

typedef struct _PERDINFO_GROUPMASK {

        ULONG Masks[PERF_NUM_MASK];

}PERFINFO_GROUPMASK,*PPERFINFO_GROUPMASK;

        当控制器程序指示内核日志记录器记录某些类型的内核事件时,它们需要构造一个PERFINFO_GROUPMASK对象,将需要记录的标志位置上。PERFINFO_GROUPMASK的Masks数组包含8个ULONG成员,每个ULONG的最高3位(即29~31位)是组的索引(0~7),低的29位(即0~28位)为组内的标志位。内核日志记录器的标志位是由windows系统定义的,并且允许扩展,在2003版本仅仅使用了部分标志位,在WRK的public\internal\base\inc\ntwmi.h的文件的PERF_宏定义。如:PERF_CONTEXT_SWITCH

#define PERF_CONTEXT_SWITCH    0x2000 0004         //Context Switch

这说明处理器线程环境切换的事件标志位是第2个组(组索引为1)的低3位(0x00000004)。

        在windows中,系统的全局组掩码是由全局变量PerfGloabalGroupMask定义的,以环境切换事件为例。当PERF_CONTEXT_SWITCH标志位被置上时,线程切换时就会记录一个CSwitch事件。在base\ntos\ke\i386\ctxswap.asm的SwapContext函数中。在base\ntos\wmi\callout.c的WmiTraceContextSwap函数中可以看到CSwitch事件的记录过程。

        缓存区管理时WMI驱动程序的重要职责之一。WMI驱动程序为环境切换事件定义了一个缓冲区数组(WmipContextSwapProcessBuffer变量),让每个处理器使用它自己的缓存区,从而避免缓冲区冲突。一旦属于某个处理器的当前缓冲区满了(不足以再存放CSwitch事件),则交由WMI刷新该缓冲区,下次记录新的CSwitch事件时重新申请一个新的缓冲区作为当前的缓冲区。WMI为每个记录会话管理缓冲区,它在创建记录会话时根据控制器的指示,创建何理数量的缓冲区,在base\ntos\wmi\traceup.c文件中WmipStartLogger和WmipAllocateTraceBufferPool的函数的代码。

        现在开始讨论内核日志记录器的控制器的消费者,微软提供了一个叫xperf的性能工具,它既是一个控制器,也是一个消费者。Xperf利用I/O接口(NtDeviceIoControlFile函数)与WMI驱动程序进行通信,public\internal\base\inc\wmiumkm.h文件中包含了IOCTL_WMI_次功能码的定义。Windows SDK提供了事件追踪API(位于advapi32.dll模块中),因而用户模式+应用程序可以很方便地操纵和控制WMI驱动程序,Xperf直接在ntdll.dll的ETW接口上工作,并没有使用advapi32.dll中的事件追踪API。

        虽然在WRK中可以看到ETW和WMI的实现代码,但是由于内核日志记录器只提供了有限的事件日志类型,且缺乏成熟的分析工具,因此在2003以前的版本中,ETW和WMI并没有得到很好的使用。从Vista开始,内核日志记录器提供了大量内核事件信息,涉及线程、进程、内存管理、同步机制、文件I/O和磁盘I/O等系统的各个方面,并且在许多关键事件上可以导出响应的调用栈(包括内核栈和用户栈),由于xperf是可以自由下载的软件且功能丰富,在将来的windows系统中,利用和WMI作为性能分析工具,将可以解决很多问题。xperf工具在2003/XP以前的版本受限于内核记录器的能力,只有部分可执行模块可以运行,不能进行安装,不能像在vista以上版本那样捕获很多事件。WMI驱动程序的接口规范以及内核日志记录器支持的事件类型在不同的Windows版本上是一致的,使得xperf可以在xp/200上得以运行,大在vista以后的版本,WMI驱动程序的内核日志记录器的内部实现有响应的调整和变化。

你可能感兴趣的:(系统内核,windows内核,操作系统,操作系统,系统内核,windows内核,驱动开发,C/C++)