分节阅读 6(1 / 1)

黑客技术大宝库 佚名 5052 字 4个月前

将介绍第二种情况并在下一节中介绍第三种情况。

换言之,nt在核心态花费时间的第二个原因是由于中断调用使用户程序不能继续运行。中断调用是用户应用程序发出io请求所造成的。在接下来的几张幻灯片中我们将会看到一些技术细节,似乎只有nt设备驱动程序的编写者会对这些内容感兴趣,促使我们深入到这一层次细节的原因是nt计算中断调用时间的方式,通过性能监视器中两个分开的计数器——一个用于统计中断调用时间的计数器和另一个称为dpc时间百分比的计数器——可以显示中断调用时间。那么,dpc是什么呢?为了理解这两个计数器,首先我们需要理解dpc。首先让我们来看一看当一个中断调用产生时将会发生什么。当中断调用产生时,正在运行的线程将被依次中断。一段nt系统代码将会被运行,以便找到拥有这个中断源的驱动程序,并调用该驱动程序,该驱动程序完成需要由它完成的工作后,释放中断并返回到正在执行的线程。仅作为一个侧面,由于中断产生时是与上下文无关的,在通用操作系统及处理中断调用方面,nt被认为是完美快捷的。nt并不切换到某些特殊的中断处理线程。它仅仅保存当前运行线程的状态,并调用驱动程序来完成工作,之后中断被释放,被中断的线程重新回到运行状态。由于中断调用可能来源于许多不同的中断源,必须使用一种机制来实现中断的优先提交,这也正是使用两个不同的计数器——中断调用时间和dpc时间——来监视中断的原因。nt使用32个相关优先级来实现中断的优先提交和服务。它是一个你永远不会在用户程序中看到的内部编号,同样,你也永远不会在性能监视器中看到它。它被称为中断请求优先级或irql。

当一个驱动程序被加载时,它告诉nt自己的中断源和irql。请考虑一下。换言之,中断拥有一个相关的优先权。因此,当一个中断产生时,nt必须查看该中断源的irql。如果它的值高于现在正在运行的程序所处的优先级,那么该中断将得到服务。如果它的值低于或等于现在正在运行的程序所处的优先级,对该中断的处理将被延迟到高优先级中断源完成工作之后。当一个中断产生时,什么将被阻挡?什么工作将不能在驱动程序处理中断的过程中发生呢?答案是:其它具有相同或较低优先级的中断以及所有线程的执行。换言之,因为中断调用总是中断进程活动而无论其具有何等的进程或线程优先级,因此系统中所有的进程活动都将被挂起。为了使具有高优先级的驱动程序所占用的时间达到最少,nt提供了这样一种方法:驱动程序好像是在说,我做了应当在这个中断优先级下进行的工作,但是我还有更多工作要做。现在我将释放中断,但请在稍后再次调用我,以便使我能够完成在高优先级下未能做完的工作。这种操作被称为延迟分配调用(dpc)。延迟分配调用是驱动程序请求nt稍后再次调用它的一种方法。系统中存在一个用于记录驱动程序回调请求的系统队列或列表。何时进行回调呢?当没有更高优先级的中断调用需要提交时。请看最后一张幻灯并注意dpc(延迟分配调用)落入优先级谱系中的什么位置?他们落入优先级2,该优先级低于硬件设备中断但高于常规线程执行。

一种简单的方法是把中断调用看作两个阶段:第一个阶段处于中断级别,第二个阶段处于dpc级别。在性能监视器中,dpc和中断调用时间这两个计数器就在你的面前,因为他们就在处理器的缺省cpu时间计数器当中,这就是我们解释中断提交过程细节的原因,由此,你可以更清楚地理解中断调用时间和dpc时间所代表的内容。中断调用时间反映了中断过程的第一阶段。dpc时间反映了中断过程的第二阶段。现在,让我们做一个演示并观察性能监视器中的中断活动。

启动性能监视器。让我们通过单击添加按钮向显示区域中添加中断调用时间和dpc时间。显示区域中出现了我们刚刚描述的计数器。单击添加。单击关闭。由于性能监视器的缺省刻度范围是0到100,这里只显示了一些相当小的数字。我将通过单击鼠标右键打开属性对话框,并切换到图表选项卡,将垂直显示的最大值由100减至10以便易于读取数值。让我们来做一下,现在,我们正通过dpc活动观察中断。红线代表dpc时间,绿线代表中断调用时间。如果我们快速地来回移动鼠标,象我正在做的这样,注意到绿线出现一些突然的跃升了吗?它是由移动鼠标产生的中断形成的。现在,dpc时间好像在每秒有规律地发生,这肯定是某些io操作的结果。如果见到这种有连续dpc操作不断发生的系统,我们应返回到前面的内容。我们的下一步工作是找出谁正在执行io操作。你还记得完成这个工作的工具吗?正是文件监视器。文件监视器将告诉我们哪个进程产生了稍后将导致dpc的io操作。在观察中断调用时间活动时需要记住的重点是它不会占用任何线程或进程,这将引出我们这一节的快速问答。

如果系统看上去很慢,但在任务管理器中却并未看到有进程正在运行,正在发生什么呢?一定是中断调用。使用性能监视器查看每秒的中断数和每秒的dpc数或中断调用时间百分比和dpc时间百分比。再次强调,中断调用中消耗的时间并不占用线程,因此,没有进程处于运行状态。请观察中断调用时间。

我说过我们将回过头来标识由nt创建并运行于系统中的每个进程,为什么这很重要呢?因为如果某些上下文正在运行且不是由你所运行的,那么它一定是nt的一部分——某些系统进程。因此,能够标识出所有的系统进程是在windows 2000和windows nt 4.0系统中进行故障诊断或性能分析的另一个重要组成。

现在,我们用来观察系统进程树的工具是在前面曾将介绍过的tlist/t。同样,tlist/t将显示进程间的层次结构。因此,使用该工具,我们可以对进程来源以及进程在树中所处位置进行快速浏览。作为对那一节的回顾,我将返回命令行方式,执行tlist/t,并在回顾幻灯时参考这些内容。请观察tlist/t的输出,系统中的头两个进程正是我们将要描述的——它们的进程id是0和8。0号进程是空闲进程。在多处理器系统中,这个不运行实际程序的进程将为每个cpu分配一个线程。换言之,每个cpu的空闲时间将被分别计算。顺便提一下,这也是检查你系统中第二、三、四、五个cpu使用效率的一种快速简洁的方法。通过分别观察每个cpu的空闲时间,可以确定在你的多处理器服务器或工作站中负载分布的均匀程度。空闲进程并不显示为运行。请记住,在quick slice及任务管理器中,空闲进程看起来在被运行,这是因为当时钟间隔时间激发时,没有线程正在运行,因而时钟间隔被cpu的空闲线程所占用。因此使其看起来像是在运行,但实际上,系统正处于空闲状态。

第二个进程——8号进程(在nt 4.0中的进程id为2),是一类称为核心态系统线程的特殊类型线程家族。这个被称作系统的系统进程,包含了两个版本nt系统中操作系统和一些需要使其自身部分运行于实际线程的设备的子例程实例。换言之,它们需要与其它一些系统活动并发执行。一些例子可以帮助理解这个概念。

操作系统中几个需要在后台运行的部分——例如交换程序——会运行一个系统线程。当nt认为一个在一段时间内未运行的进程变为空闲时,若其它进程请求物理内存,它将把该进程的内存空间标记为被清除。那么,由谁来完成将该进程交换出内存的工作呢?正是交换程序。交换程序是与其它在系统中运行的线程同时运行着的一个线程。文件服务器是创建系统线程的一个驱动程序。这是一个有趣的例证,在负荷较重的文件服务器上,作为客户端io活动的结果而表现为运行状态的进程却由于该文件服务器本身不是一个进程而不表现为一个服务器进程。要知道,是驱动程序创建和使用系统线程以提供伺服并为远程网络io请求服务。因此,这是一个非常重要的监视点,在此,负荷较重的文件服务器将使系统线程得以继续,而因为系统线程主要在被称作系统的进程中予以披露,故我们需要一些方法来深入而密切地关注系统进程,从而找出到底是什么线程正在运行着。基于我们已经讲到的内容,如果告诉你系统进程正在运行着,那你又能知道些什么呢?基本来说,你什么也知道不了。你只知道nt中的某一片段(或许是一个驱动程序)正在运行,但你并不知道它具体是哪一个片段。

这就将我们带到了下一个演示中:理解系统进程中的哪个线程正在运行,进而知道nt中的哪个驱动程序或片段创建了该线程。而这却是一个凌乱的处理过程,因为,它需要使用3个工具:性能监视器、进程浏览器和nt 4.0资源工具包中一个被称为pstat的工具,该工具并不只存在于windows 2000资源工具包中,它也是platform sdk(亦即平台软件开发工具包)的组成部分,且与msdn(microsoft开发网络)及其后续版本一并发布。它也是本次讲座演示文件的组成部分。

我们首先要做的是使用性能监视器找出运行于系统进程中的线程。接着,我们将使用pviewer来赋予它们那些我们所感兴趣的线程并找到线程的内存起始地址,内存起始地址是一个代表该系统线程从系统沙箱中何处开始运行的数字。最后,我们将使用pstat,该工具提供了一个关于系统沙箱的内存映射并就线程运行于哪个驱动程序中进行定位,换言之,线程所运行的代码片段是属于哪个驱动程序的。因此,该过程多少有些复杂,它毕竟使用了3个工具,但还是让我们进行这个演示来看一看它是如何工作的。

首先,我们将回到性能监视器。让我们从一个新图表开始。事实上,由于我们已改变了图表设置,我们将启动一个新的性能监视器实例。我将单击加号,并向图表中添加系统进程中线程的cpu时间。我转到线程对象,选中处理器时间百分比,向下滚动到被称作系统的进程,单击第一个线程——线程0,拖曳鼠标,向下滚动直到将所有系统进程中的线程全部被选中,然后,单击添加。现在,我并没能如愿,因为,在windows 2000中仍有另一个进程,该进程中也包含着一些系统线程,它就是csr访问——一个windows子系统进程。该进程是包含部分windows系统的nt片段。在nt 4.0中,所有的系统线程均存在于系统进程中。在windows 2000中,某些系统线程存在于csr访问进程中,而另一些则存在于被称为系统的进程中。我们单击添加,接着,单击关闭。

我现在查看30多个零散系统线程的执行情况。让我们快速移动鼠标,可以看到有东西曾运行过。我是如何在这个由30多个零散计数器组成的列表中找到线程随机内存排列的呢?我将再次打开加亮开关,单击高亮度按钮,向下滚动屏幕直到随鼠标移动而移动的计数器也被以白色加亮。在显示区域中部有一个绿色凸起。就在那儿,你们看到了吗?是从绿色变成白色的那个。当我移动鼠标时,在csr访问中的6号线程看上去正在运行。第二步是使用pviewer,该工具存在于支持工具包中,依次单击开始/程序/ windows 2000支持工具/工具进程浏览器。选中csr访问,向下滚动并选中6号线程,我们现在所寻找的信息是线程的起始地址,它位于pviewer显示区域的底部。该地址是线程开始执行的起点。它以十六进制显示,0x在十六进制中代表a000-9cbf。好的,我们有了一个内存地址。接下来做什么呢?第三步——运行pstat,该工具存在于我们的演示中并在执行着的pstat尾部。因此,请忽略掉出自线程的所有细节。在pstat显示区域的最后部分是系统沙箱的内存映射。它列出了每个驱动程序的名字以及在系统内存中的地址。如果我让它到达末端并从后向前看,我将寻找在线程运行地址处启动的驱动程序。不幸的是,pstat并不显示驱动程序的结束地址,而只提供起始地址。因此,需要密切关注我们所查看的特定地址编号究竟落在了哪个驱动程序上。我们目前所举的例子非常简单,因为这里只有一个驱动程序在a00处被调用。如果你查看整个列表,其它任何事件均编有以f、8或b打头的号码。因此,我立刻就能判断出该线程设备肯定是驱动程序win32k.sys中的一个代码片段。它是win32图形和窗口操作系统的一个组件。这就有点儿意思了。当你移动鼠标时,你会期望窗口操作系统中的某一片段能够运行以指示出你正在哪个窗口上移动着鼠标。虽然这只是一个人为例证,但它毕竟演示了使用上述3个工具(性能监视器、pviewer和pstat)以深入探究系统进程或csr访问并找出创建线程的驱动程序的技巧。这是一个非常重要的技巧,因为,