本文章是由機器翻譯。

Windows 事件追蹤

Windows 7 的核心檢測事件,第 2 部分

Dr。Insung ParkAlex Bendetov

我們兩個部分文件系列的第二個組件的歡迎後:核心 Windows 7] 中的記錄事件。 第一個本文中,我們看到事件追蹤的 Windows (ETW) 技術和核心 OS 檢測的高階概觀。 我們也會討論工具支援,以取得和使用作業系統的事件。 在這第二個部分,我們繼續提供更多有關在核心作業系統的各種子元件的事件詳細資料。 我們也會說明如何可以結合不同的系統事件,產生完整的圖片,我們示範使用一組 Windows PowerShell 指令碼的系統行為。

磁碟]、 [檔案]、 [檔案詳細資料] 及 [驅動程式的事件

程式的觀點作業,例如開啟、 讀取或寫入檔案會是存取磁碟上的內容的方式。 因為要最佳化,例如快取和 prefetching,不是所有的檔案 IO 要求導致立即磁碟存取。 此外,檔案內容可能會分散磁碟,和特定的磁碟裝置支援鏡像和等量,等等。 將這類的情況下從檔案讀取一個區塊的資料轉譯成多個存取一或多個磁碟。 檔案和磁碟存取帳戶檔案 IO 開始]、 [檔案 IO 完成]、 [磁碟存取開始]、 [磁碟存取結束,事件分割 IO、 驅動程式的活動和檔案 (唯一的索引鍵的名稱) 對應。

來自使用者應用程式存取檔案和對應的回到使用者應用程式要求完成的要求會經過多個元件的堆疊。 在 Windows IO 系統,IO 作業會追蹤所呼叫的 IO 要求封包 (IRP) 的實體。 它進入 [IO 管理員時,使用者啟動的 IO 作業會轉換成的 IRP]。 如的 IRP 周遊的元件鏈結,每個元件會執行處理要求的必要工作,更新 [IRP 並必要元件,接下來會處理要求時將其傳遞上。 當符合的 IO 要求的所有需求 (在單純的情況下要求的檔案區塊從一個磁碟擷取),註冊的完成常式會呼叫來執行在的資料的任何額外的處理,並要求的資料傳回給使用者應用程式。

在核心 IO 系統中較高的層級,檔案 IO 事件會記錄所發行的應用程式的作業。 檔案 IO 事件包含下列類型:建立、 讀取、 寫入、 清除、 重新命名、 刪除關閉清理]、 [設定資訊]、 [查詢資訊]、 [目錄的列舉] 及 [目錄變更通知。 作業例如建立、 讀取、 寫入、 清除、 重新命名和刪除簡單,以及它們包含資料的項目,例如檔案索引鍵、 IO 要求封包 (IRP) 指標、 區塊的大小和位移到檔案,視。 設定資訊和查詢資訊事件表示檔案屬性已設定,或查詢。 最後一個控點以檔案關閉時,會記錄在清理] 事件。 在關閉的事件指定檔案物件會被釋放。 目錄列舉或目錄變更通知送出到已註冊的接聽程式分別時,會記錄目錄列舉和目錄變更通知事件。 檔案 IO 的事件 ETW 中新增要求作業時。 興趣檔案 IO 作業的持續時間與完成的那些可以啟用透過 IRP 指標原始的檔案 IO 事件可以相互關聯的檔案 IO 完成事件。 檔案 IO 完成事件記錄 IRP 指標,並傳回狀態。

磁碟的事件 IO,堆疊中較低層級,並包含磁碟存取特定的資訊。 讀取和寫入作業產生磁碟讀取和寫入事件,包含磁碟編號,傳輸的大小的位元組位移正在存取的地址、 IRP 指標,和存取的回應時間。 清除事件記錄磁碟清除作業。 不像檔案 IO 事件會記錄在作業開頭,磁碟 IO 的事件在 IO 完成時間。 使用者可以收集額外的磁碟 IO 初始化事件的所有磁碟 IO 事件 (ReadInit WriteInit,FlushInit 事件)。 稍早提到不是所有的檔案 IO 事件如果執行個體要求的內容已使用快取中或者緩衝寫入磁碟的作業有相符的磁碟 IO 事件。 分割 IO 事件指出 IO 要求已被分成多個磁碟 IO 要求因為基礎鏡像的磁碟硬體。 沒有這類硬體的使用者不會看到分割 IO 事件,即使它們啟用它們。 它將原始的父代 IRP 對應到多個子系 IRP。

磁碟 IO 檔案 IO,分割 IO 事件包含開啟的檔案建立唯一的檔案索引鍵。 這個檔案機碼可用來追蹤 IO 系統中相關的 IO 作業。 但是,檔案操作實際的檔案名稱無法使用。 中任何檔案或磁碟 IO 事件 如果要解決的檔案名稱,需要檔案詳細資料的事件。 所有開啟的檔案會列舉來記錄他們的檔案索引鍵和名稱。 在一個的模擬的狀態機器檔案物件追蹤的檔案索引鍵,來記錄檔案 IO 要求和實際的磁碟的存取,然後名稱會更新物件中檔案詳細資料事件發生時。 在歷程記錄因為原因而磁碟 IO 與檔案詳細資料的事件中的檔案索引鍵被命名 FileObject。 大部分的檔案 IO 事件同時包含檔案物件和檔案的金鑰。

驅動程式的事件指出驅動程式的視裝置類型,可能或不可能會重疊與磁碟 IO 活動的活動。 使用者熟悉的 Windows 驅動程式模型 (WDM) 感興趣的可能驅動程式的事件。 驅動程式檢測新增驅動程式 IO 函式呼叫和完成常式的事件。 驅動程式的事件包含檔案的金鑰、 IRP 指標,以及例行地址 (主要和次要函式與完成常式),視個別的事件類型的驅動程式資料。

IO 事件通常會導致非常大量的事件可能需要增加核心工作階段的數字及/或緩衝區的大小 (-logman nb 選項)。 IO 事件還有用於分析檔案的使用方式、 磁碟存取模式和驅動程式的活動。 然而,之 IO] 事件的磁碟 IO 的事件的處理序和執行緒 ID 值不是有效的。 若要相互關聯正確原始的執行緒,因此程序,這些活動,一個需要考慮追蹤內容切換事件。

網路事件

網路活動發生時,會記錄網路事件。 從核心的工作階段的網路事件會發出 TCP/IP 及 UDP/IP 層級。 TCP/IP 事件會記錄時,會發生以下動作:傳送、 接收、 中斷連線,重新傳輸,重新連線,複製,及失敗。 它們都包含 [封包大小、 來源及目的地 IP 位址和連接埠,以外的失敗事件,因為這樣的資訊是使用]。 而且,起始處理的傳送類型的事件識別碼和目標處理序 ID 因為通常這些網路作業不下執行原始/接收處理序內容,都包含接收類型的事件。 這表示一個的程序,但無法執行緒可以屬性網路事件。 UDP/IP 事件是傳送或接收事件包括上面所列的資料項目。 最後,每個作業的型別 (傳送,接收等等) 會對應到一組的事件:一個 IPV4 通訊協定和其他的 IPV6。 在 Windows Vista 中新增的 IPV6 通訊協定的事件。

登錄事件

大部分的登錄作業會使用 ETW,檢測,這些事件可以屬性化處理程序和執行緒,透過事件標頭中的處理序和執行緒識別碼。 登錄的事件內容並不包含完整的登錄機碼名稱。 其中包括唯一的索引是鍵而,記錄為金鑰控制區塊 (KCB),每個開啟的登錄機碼。 核心的工作階段結尾取消的事件,將這些機碼對應到完整的登錄名稱。 如果要解決登錄一個需要使用類似的技巧使用的檔案名稱解析這些在其中對應事件的名稱用來更新狀態機器中的登錄物件。 登錄事件已用於分析存取模式,並識別重複存取最佳化。 登錄的事件內容包含傳回此項作業可以用來監視登錄作業失敗,並疑難排解可能的應用程式的狀態。

圖 1 取得式 ETW PID-清單指令碼,列印的處理程序資料表

<####################
 # Get-ETW-PID-List
 # \@brief Takes in an XML stream and prints the list of process names
 # with PIDs that were detected in the incoming stream.
 ####################>
function Get-ETW-PID-List([Switch] $print) {
    begin {
        $pidlist = new-object System.Collections.Hashtable
        $procid = 0
        $procname = ""
    }

    process {
        $xmldata = $_
        
        # For each Process event, grab process id and binary name 
        # and add to the list. 
        foreach ($e in $xmldata.Events.Event) {
            if ($e.RenderingInfo.EventName.InnerText -eq "Process") {
                foreach ($d in $e.EventData.Data) {
                    # Grab process id.
                    if ($d.Name -eq "ProcessId") {
                       $procid = $d.InnerText
                    # Grab the process name.
                    } elseif ($d.Name -eq "ImageFileName") {
                        $procname = $d.InnerText
                    }
                }
                if (!$pidlist.Contains($procid)) {
                    $pidlist.add($procid, $procname) | Out-Null
                }
            }
        }
    }

    end {
        remove-variable xmldata

        if ($print) {
            "{0,-29}| PID" -f "Binary Name"
            "-------------------------------------"
            foreach ($item in $pidlist.Keys) {
                "{0,-30}({1})" -f $pidlist.$item,$item
            }
        } else {
            return $pidlist
        }
    }
}

圖 2 取得式 ETW PID-清單指令碼的輸出

PS C:\tests> $xmldata | Get-ETW-PID-List -print
Binary Name                  | PID
-------------------------------------
dwm.exe                       (2776)
powershell.exe                (2384)
svchost.exe                   (708)
notepad.exe                   (4052)
iexplore.exe                  (4284)
...
iexplore.exe                  (4072)
svchost.exe                   (3832)
smss.exe                      (244)
System                        (4)
spoolsv.exe                   (1436)
Idle                          (0)

範例為基礎的設定檔事件

範例中的設定檔事件設定檔事件 (hereafter) 可讓 CPU 要花點時間追蹤。 設定檔事件可用來計算的 CPU 使用率一個良好的近似值。 啟用設定檔事件時, Windows 核心開啟的程式碼剖析插斷,會導致記錄從每個處理器 (預設值為 1000年的時間秒,每個處理器上) 以固定速率的設定檔事件。 請注意在某些電腦上的低電源模式,設定檔事件可能已關閉暫時。 設定檔的事件內容是由目前的處理器及指令指標暫存器的值上執行,一次的程式碼剖析的插斷執行緒的執行緒識別碼所組成。 在 Windows 7,設定檔的事件內容也會包含識別執行內容 (執行緒/DPC/ISR) 所需的旗標。

圖 3 取得-ETW-PID-資訊指令碼列印處理程序詳細資料

<####################
 # Get-ETW-PID-Info 
 # \@brief Retrieves various information about a particular process id
 ####################>
function Get-ETW-PID-Info([Int] $p, [switch] $i, [switch] $t) {
    begin {
        $threadlist = New-Object System.Collections.ArrayList
        $imagelist = New-Object System.Collections.ArrayList
        $procname = ""
    }

    process {

        $xmldata = $_
        
        $sievedxml = $($xmldata | Get-ETW-PID-Events $p).$p

        foreach ($e in $sievedxml.Events.Event) {
            if ($e.RenderingInfo.EventName.InnerText -eq "Process") {
                foreach ($d in $e.EventData.Data) {
                    # Grab the process binary name 
                    if ($d.Name -eq "ImageFileName") {
                        $procname = $d.InnerText
                    }
                }
            }
            if ($e.RenderingInfo.EventName.InnerText -eq "Image") {
                foreach ($d in $e.EventData.Data) {
                    # Grab the loaded image name and add it to the list
                    if ($d.Name -eq "FileName") {
                        if (!$imagelist.contains($d.InnerText)) {
                            $imagelist.add($d.InnerText) | Out-Null
                        }
                    }
                }
            }
            if ($e.RenderingInfo.EventName.InnerText -eq "Thread") {
                foreach ($d in $e.EventData.Data) {
                    # Grab thread id and add it to the list
                    if ($d.Name -eq "TThreadId") {
                        $tid = $d.InnerText
                        if (!$threadlist.contains($tid)) {
                            $threadlist.add($tid) | Out-Null
                        }
                    }
                }
            }
        }
    }

    end {
        "Process Name: $procname"
        if ($t) {
            "Thread List: ($($threadlist.Count))"
            $threadlist | Sort -descending
        } else {
            "Thread Count: $($threadlist.Count)"
        }
        if ($i) {
            "Image List ($($imagelist.Count)):"
            $imagelist | Sort
        } else {
            "Images: $($imagelist.Count)"
        }
    }
}

CPU 使用率可以被模擬與設定檔的事件的是與非閒置執行緒的執行緒識別碼的設定檔事件的百分比。 每個處理序的 CPU 使用通訊群組還需要個別的處理程序追蹤設定檔的事件內容中的執行緒識別碼的多一個步驟。 如果狀態機器就如這兩個部分發行項的一系列的第 1 部份所述的程序和執行緒事件,,則直接產生每個處理序 CPU 使用量報告。 您也可追蹤至載入的模組,透過影像載入事件的 CPU 使用率。 比較指令指標位址的範圍已載入的模組中的結果較二進位的影像,因此每個模組的 CPU 使用量的設定檔的指令指標的位置。 如果使用二進位的符號,一個就可以從使用 DbgHelp 程式庫的指令指標,取得函式名稱。 啟用設定檔事件呼叫的堆疊,使用一個甚至可以推算函式如何叫用。 當指令指標指向經常使用的程式庫函式時,這會是很有幫助的。

就緒執行緒事件

有幾個原因為何系統會從執行中的執行緒切換。 最常見的原因是它需要等候其他執行緒完成相關的工作,才能繼續進行。 在執行介面中遭到封鎖從等候設定,例如事件、 號誌、 計時器和物件時執行的執行緒為這類相依。 Windows OS 排程器 (也稱為發送器) 會追蹤的執行緒變成另一個執行緒、 一個的 DPC 或計時器解除封鎖。 元件和執行緒之間的相依性不容易看到,在開發期間預測。 無法事先預期的延遲發生時它會比較難追蹤它問題的根本原因。

準備就緒的執行緒 (或發送器) 事件已新增到協助診斷問題。 當一個執行緒會解除封鎖 (或 readied) 置於發送器就緒佇列,就緒的執行緒事件記錄,其內容包含 readied 執行緒的執行緒識別碼。 下列的就緒執行緒事件鏈結,由一個可以追蹤執行相依性的鏈結它 unfolds。 內容切換事件呈現的上方,表示當 readied 的執行緒實際上已排程執行。 呼叫堆疊啟用就緒的執行緒事件可能會導致將負責解除封鎖,等候中執行緒的程式碼中的點。 就緒執行緒事件新中可以使用 Windows 7。

系統呼叫事件

系統呼叫事件代表項目至] 和 [Windows 核心作業系統的系統呼叫的結束。 系統呼叫是 Windows 核心中,將介面所組成的 API。 此檢測已新增至監視使用者模式應用程式和核心模式元件所做的系統呼叫。 有兩種類型的系統呼叫的事件。 在系統呼叫輸入事件表示系統呼叫的引動過程,並記錄常式對應到叫用的系統服務的位址。 在系統呼叫結束事件指出從系統的呼叫的結束,而且其裝載包含從 API 呼叫傳回的值。 系統呼叫事件用於統計分析系統呼叫活動和延遲,但像某些 IO] 及 [記憶體] 事件,它們會記錄沒有目前處理序和執行緒識別碼資訊標頭中。 若要建立系統處理程序與執行緒的呼叫活動的相互關聯,其中一個必須收集在同一時間的內容切換事件及,期間狀態機器模擬,追蹤目前的執行緒執行於事件中使用之 CPU ID CPU 系統呼叫事件,所述的標頭中部份的這兩個部分發行項的一系列的 1。

進階本機程序呼叫的事件

本機程序呼叫 (LPC) 已經的有效本機 Inter-Process 通訊 (IPC) 機制在 Windows 平台上年。 Windows Vista 提供更有效率且安全的方法,稱為進階本機程序呼叫 (ALPC) 的 IPC 需要。 ALPC 也作為傳輸機制的本機遠端程序呼叫 (RPC)。 ALPC 元件檢測與 ETW,發出傳送、 接收、 等候新的回覆,等候新郵件] 及 [Unwait 事件。

系統組態事件

當核心工作階段結束時,ETW 會記錄說明事件會在其收集的電腦的系統設定的數個事件。 在許多的效能分析案例中瞭解基礎的硬體和軟體組態有助於大幅尤其是的電腦的事件會加以分析是不同的電腦所收集事件的位置,了解的系統行為。 這些系統設定的事件提供 CPU、 圖形卡、 網路卡、 PnP 裝置、 IDE 裝置、 實體和邏輯磁碟的組態和服務的資訊。 系統設定的事件內容有所不同裝置,或設定,它說明了但通常包含描述字串和索引鍵的規格。

圖 4 取得-ETW-PID-資訊的指令碼輸出

PS C:\tests> $xml | Get-ETW-PID-Info 4052 -i
Process Name: notepad.exe
Thread Count: 2
Image List (31):
\Device\HarddiskVolume2\Windows\System32\advapi32.dll
\Device\HarddiskVolume2\Windows\System32\dwmapi.dll
\Device\HarddiskVolume2\Windows\System32\gdi32.dll
\Device\HarddiskVolume2\Windows\System32\imm32.dll
\Device\HarddiskVolume2\Windows\System32\kernel32.dll
\Device\HarddiskVolume2\Windows\System32\KernelBase.dll
...
\Device\HarddiskVolume2\Windows\System32\version.dll
\Device\HarddiskVolume2\Windows\System32\winspool.drv

圖 5 取得-ETW-頂端-VMops 指令碼,來列印最上層 n 的程序叫用大部分的 VM 作業

<####################
 # Get-ETW-Top-VMops
 # \@brief Gets the top $num processes ranked by the number of virtual 
   memory events
 ####################>
function Get-ETW-Top-VMops ([Int] $num) {
    begin {
        $hold = @{}
    }

    process {

        $xmldata = $_

        # Get a list of the PIDs
        $list = $xmldata | Get-ETW-PID-List
       
        # Iterate through each PID
        $eventxml = $xmldata | Get-ETW-PID-Events $list.Keys

        foreach ($pd in $list.Keys) {

            $vmops = 0

            # Count the number of VM events
            foreach ($e in $eventxml.$pd.Events.Event) {
                [String] $type = $e.RenderingInfo.EventName.InnerText
                [String] $opcode = $e.RenderingInfo.Opcode

                if ($type -eq "PageFault") {
                    if ($opcode -eq "VirtualAlloc" –or 
                      $opcode -eq "VirtualFree") {
                        $ vmops++
                    }
                }
            }
            $hold.$pd = $vmops
        }
    }

    end {
        "{0,-20}|{1,-7}| VM Event Count" -f "Binar"," PID"
        "--------------------------------------------------------"
        
        $j = 0
        foreach ($e in ($hold.GetEnumerator() | Sort Value  -Descending)) {
            if ($j -lt $num) {
                $key = $e.Key
                "{0,-20} ({1,-6} {2}" -f $list.$key,"$($e.Key))",$e.Value
            } else {
                return
            }
            $j++
        }
    }
}

簡單的核心 OS 事件分析範例

這的一節,我們會呈現示範幾個基本帳戶處理技術,在某些引入先前作業系統事件上的簡單指令碼。 我們將使用 Windows Powershell 指令碼,為了簡單起見,但是可以為基礎的演算法採用在應用程式更有效率的處理中。 一旦 tracerpt 工具所建立的 XML 傾印,Windows Powershell 使用下列命令中的物件作為一個可以匯入事件:

>$ xmldata = System.Xml.XmlDocument 新物件
>$ xmldata.Load (< XML 傾印檔案 >)

圖 1 中第一個 Windows Powershell 指令碼只會列印掃描程序的事件記錄檔中的所有處理序。 它會更新雜湊資料表使用處理序識別碼和名稱組,並會列印出資料表結尾,如果指定 –print] 選項。 將預設的情況下,傳遞沿著組的陣列至管道,其他的指令碼才能使用它的輸出。 請注意我們略過傳統的引數]、 [註解] 和 [錯誤檢查,以簡化範例指令碼的處理。 我們也假設程序和執行緒識別碼並非回收在這個的指令碼在核心工作階段期間,但執行事實上取得回收。 其他的程式碼所需的正確處理。

這個的指令碼的輸出如果 XML 傾印會包含處理的事件是的圖 2 所示。 下一個指令碼的目標是建立一個基本狀態電腦,給定一個處理程序] 識別碼的若要列印的執行緒數目和載入的影像,在該處理程序中的清單。 如果有 –i] 或 [–t 選項,指令碼會列印載入影像的名稱以及在中的影像的執行緒計數而不是處理程序的執行緒識別碼。 圖 3 顯示指令碼取得-ETW-PID-資訊寫入此功能。 此指令碼呼叫另一個呼叫指令碼取得-ETW-PID 的事件 (也就我們不會顯示以下),挑選只之事件相關為指定的處理序 ID。

我們從的圖 2,尋找 [記事本] 處理程序取得-ETW-PID-資訊指令碼從得到下列輸出。 圖 4 列出 notepad.exe 所載入的所有模組。

最後,我們要列印一個資料表的頂端的 n 程序,與大多數的虛擬記憶體作業。 在這個呼叫 Get-ETW-上-VMops,圖 5 所示的指令碼執行取得-ETW-PID-清單來建構程序識別碼的清單。 然後我們依每個處理程序識別碼過濾器事件,並計算 VM 事件。 上次,我們排序,並列印頂端的 n 個處理程序的資料表。

從 [與前 10 處理程序大部分的虛擬記憶體作業與此指令碼輸出已列在的圖 6。 請注意 logman.exe 的兩個執行個體顯示在資料表,一個用於開始,一個用於停止核心工作階段。

圖 6 取得-ETW-頂端-VMops 輸出

PS C:\tests> $xml | Get-ETW-Top-Vmops 10
Binary              | PID   | VM Event Count
--------------------------------------------------------
svchost.exe          (536)   486
iexplore.exe         (3184)  333
svchost.exe          (1508)  206
logman.exe           (2836)  98
svchost.exe          (892)   37
sidebar.exe          (3836)  37
logman.exe           (1192)  19
svchost.exe          (2052)  18
audiodg.exe          (7048)  18
services.exe         (480)   13

增強您的 [工具] 功能

Windows 7 功能數百個從各種元件的事件提供者。 兩個部分文件系列中我們有呈現的核心 OS ETW 事件可以在 Windows 7 和我們已經使用多年,分析技巧。 個別事件表示某些活動的核心 OS,但是如果結合透過即時線上分析方法,可以被用來產生有意義的報告,提供到模式] 和 [資源使用狀況] 中的異常狀況的見解。 此外,我們知道很多情況下,以有效率且小心檢查這些事件的子集會導致很好的結果,研究的特定欄位中。 ETW 與檢測的應用程式可以受益更進一步精確的相互關聯應用程式和作業系統的活動 ;對於執行個體應用程式發出表示在開頭和重要的應用程式活動的結尾的事件,如果在同一時間收集的核心作業系統事件就會包含正確作業系統資源的使用資訊屬性化的活動。 管理及效能工具開發人員可以利用各種不同的分析技術,以增強其工具] 功能的輪流有助於 IT 工作人員的核心系統事件。 應用程式開發人員可以更診斷應用程式的問題,如果這種分析會併入他們的環境。 我們希望我們兩個部分文件系列會導致升級音效工程練習,更大的軟體品質更好的使用者經驗。

Dr。 Insung Park 開發管理人員對於診斷平台小組與 Windows 檢測。 他已發行十幾論文效能分析、 要求追蹤、 檢測的技術和程式設計方法和支援。 他的電子郵件地址為 insungp@microsoft.com

Alex Bendetov 為 Windows 檢測和診斷平台小組的開發組長。 他對事件追蹤的 Windows 和效能計數器的技術。 他可以達到在 alexbe@microsoft.com