概述
Windows 7 包含了 Windows Vista 及更低 Windows 版本中提供的檢測平台 ,用以公開應用程序的診斷信息。有許多機制用於公開檢測和控制信息,包括:
• Windows 事件跟蹤 (ETW)
• Windows 性能計數器
• Windows Management Instrumentation (WMI)
• 事件日志
分析應 用程序性能和使用檢測信息是現實中故障診斷應用程序的關鍵任務。 Windows 檢測機制和 Windows Performance Toolkit 為精簡診斷和分析體驗提供了必要的工具。
目標
在本動手實驗室中,您將學會如何:
• 使用 Windows 性能計數器公 開應用程序的檢測信息
• 使用 Windows Performance Toolkit 分析應用程序 性能
系統要求
要完成本實驗,您必須擁有以下軟件:
• Microsoft Visual Studio 2008
• Windows 7
• Windows 7 SDK
• Microsoft Windows Performance Toolkit
注意 : 本實驗中使用的技術不代表我們推薦使用此開發實踐。在現實中,應該使用獨立的提升流程 (或安裝程序)為您的應用程序注冊性能計數器。此外,可以考慮使用多實例性能計數器允 許多個實例在一台機器上共存(即終端服務,多會話)。使用其他方法將不利於多用戶場景 中的用戶體驗,比如快速用戶切換或終端服務。
練習 1 :使用性能計 數器進行檢測
在本練習中,您將使用 Windows 性能計數器檢測現有應用程序。該應用程序可以將文件 從源目錄復制到目標目錄,並在 UI 上顯示復制進度;但是,要在編程中或者從遠程機器使 用進度信息,必須將檢測信息導出到操作系統。
要完成本練習,您必須作為管理員啟動 Visual Studio ,或者確保應用程序啟動時以權 限提升方式(例如,在應用程序的主執行文件上右鍵單擊,選擇“以管理員身份運行 ”)運行。這是性能計數器注冊的要求。
任務 1 – 添加一個類來公開性 能計數器
要公開應用程序的檢測信息,您需要創建一個類,用於公開指示文件復制操 作進度的 Windows 性能計數器。
1. 打開位於 %TrainingKitInstallfolder% \InstrumentationAndPerformance\Ex1-PerfCounters\Begin 文件夾下的啟動解決方案 Begin.sln ,選擇要使用的語言( C# 或 VB )。
2. 右鍵單擊 Solution Explorer 中的 FileCopier 項目,並選擇 Add New Item 。然後選擇 Class 模板 (C#) 或 Module 模 板 (Visual Basic) ,並將其命名為 FileCopyPerformanceCounters 。
3. (僅適用 於 C# 用戶)使用靜態類,使之只需要一個實例。
C#
public static class FileCopyPerformanceCounters
{
}
4. 在文件開頭添加 命名空間指令,用於 System.Diagnostics 命名空間。
C#
using System.Diagnostics;
Visual Basic
Imports System.Diagnostics
5. 添加一個名為 Initialize 的新公開方法。在該方法 中,您將初始化 PerformanceCounterCategory 和 PerformanceCounter 對象,它們都是向 操作系統公開性能計數器所需的對象。要實現這一點,添加以下代碼(用粗體顯示)。
C#
public static void Initialize()
{
}
Visual Basic
Public Sub Initialize()
End Sub
6. 新建一個 CounterCreationDataCollection 類實例。
C#
public static void Initialize()
{
CounterCreationDataCollection counters = new CounterCreationDataCollection ();
}
Visual Basic
Public Sub Initialize()
Dim counters As New CounterCreationDataCollection()
End Sub
7. 新建一個 CounterCreationData 類實例並初始化:
a. 使用 “ Total Files Copied ”作為計數器名稱。
b. 選擇一個用作計數器輔 助字符串的描述字符串。
c. 使用 PerformanceCounterType.NumberOfItems32 作為 計數器類型。
要實現這一點,添加以下代碼(用粗體顯示)。
C#
public static void Initialize()
{
CounterCreationDataCollection counters = new CounterCreationDataCollection ();
CounterCreationData counter = new CounterCreationData(
"Total Files Copied",
"Total number of files copied by the application.",
PerformanceCounterType.NumberOfItems32);
}
Visual Basic
Public Sub Initialize()
Dim counters As New CounterCreationDataCollection()
Dim counter As New CounterCreationData("Total Files Copied", _
"Total number of files copied by the application.", _
PerformanceCounterType.NumberOfItems32)
End Sub
8. 使用 CounterCreationDataCollection 對象的 Add 方法將上一步中創建的計數器數 據添加到之前創建的集合中。
C#
public static void Initialize ()
{
...
CounterCreationData counter = new CounterCreationData(
"Total Files Copied",
"Total number of files copied by the application.",
PerformanceCounterType.NumberOfItems32);
counters.Add(counter);
}
Visual Basic
Public Sub Initialize()
...
Dim counter As New CounterCreationData("Total Files Copied", _
"Total number of files copied by the application.", _
PerformanceCounterType.NumberOfItems32)
counters.Add(counter)
End Sub
9. 創建另一個 CounterCreationData 類實例並初始化:
a. 使用“ % Files Copied ”作為計數器名稱。
b. 其余參數應 該與用來初始化上一個 CounterCreationData 對象的參數相同。
同時,將它添加到 CounterCreationDataCollection 對象。
C#
public static void Initialize()
{
...
counters.Add(counter);
counter = new CounterCreationData(
"% Files Copied",
"Percent of files copied in the current operation.",
PerformanceCounterType.NumberOfItems32);
counters.Add(counter);
}
Visual Basic
Public Sub Initialize()
...
counters.Add(counter)
counter = New CounterCreationData("% Files Copied", _
"Percent of files copied in the current operation.", _
PerformanceCounterType.NumberOfItems32)
counters.Add(counter)
End Sub
10. 使用 PerformanceCounterCategory 類的 Exists 和 Delete 靜態方法檢查 FileCopier 性能計數器類別是否存在。如果存在,將其刪除,並在下一步中 重新創建。
C#
public static void Initialize()
{
...
counter = new CounterCreationData(
"% Files Copied",
"Percent of files copied in the current operation.",
PerformanceCounterType.NumberOfItems32);
counters.Add(counter);
if (PerformanceCounterCategory.Exists("FileCopier"))
PerformanceCounterCategory.Delete("FileCopier");
}
Visual Basic
Public Sub Initialize()
....
counter = New CounterCreationData("% Files Copied", _
"Percent of files copied in the current operation.", _
PerformanceCounterType.NumberOfItems32)
counters.Add(counter)
If PerformanceCounterCategory.Exists("FileCopier") Then PerformanceCounterCategory.Delete("FileCopier")
End Sub
11. 調用 PerformanceCounterCategory 類的 Create 靜態方法:
a. 使用 “ FileCopier ”作為類別名稱。
b. 選擇一個作為類別輔助字符串的描 述字符串,使用 PerformanceCounterCategoryType.SingleInstance 作為類別。
c. 使用 CounterCreationDataCollection 實例作為最後一個參數。
C#
public static void Initialize()
{
...
if (PerformanceCounterCategory.Exists("FileCopier"))
PerformanceCounterCategory.Delete("FileCopier");
PerformanceCounterCategory.Create(
"FileCopier",
"Instrumentation of the FileCopier application.",
PerformanceCounterCategoryType.SingleInstance,
counters);
}
Visual Basic
Public Sub Initialize()
...
If PerformanceCounterCategory.Exists("FileCopier") Then PerformanceCounterCategory.Delete("FileCopier")
PerformanceCounterCategory.Create("FileCopier", _
"Instrumentation of the FileCopier application.", _
PerformanceCounterCategoryType.SingleInstance, _
counters)
End Sub
12. 將 PerformanceCounter 類型的兩個私有靜態數據成員添加到類 (C#) 或模塊 (Visual Basic) ,稱為 totalFilesCounter 和 percentDoneCounter 。
C#
public static class FileCopyPerformanceCounters
{
private static PerformanceCounter totalFilesCounter;
private static PerformanceCounter percentDoneCounter;
...
}
Visual Basic
Module FileCopyPerformanceCounters
Private totalFilesCounter As PerformanceCounter
Private percentDoneCounter As PerformanceCounter
...
End Module
13. 在 Initialize 方法中,使用 PerformanceCounter 類的新實例初始化計數器,傳遞“ FileCopier ”作為類別名稱,使用相關計數器名稱(“ Total Files Copied ”或“ % Files Copied ”)作為計數器名稱,使用 false 作為最後一個 參數。
C#
public static void Initialize()
{
...
PerformanceCounterCategory.Create(
"FileCopier",
"Instrumentation of the FileCopier application.",
PerformanceCounterCategoryType.SingleInstance,
counters);
totalFilesCounter = new PerformanceCounter(
"FileCopier", "Total Files Copied", false);
percentDoneCounter = new PerformanceCounter(
"FileCopier", "% Files Copied", false);
}
Visual Basic
Public Sub Initialize()
...
PerformanceCounterCategory.Create("FileCopier", _
"Instrumentation of the FileCopier application.", _
PerformanceCounterCategoryType.SingleInstance, _
counters)
totalFilesCounter = New PerformanceCounter( _
"FileCopier", "Total Files Copied", False)
percentDoneCounter = New PerformanceCounter( _
"FileCopier", "% Files Copied", False)
End Sub
14. 在 MainForm.cs (C#) 或 MainForm.vb (Visual Basic) 中 ,找到構造函數,並向 FileCopyPerformanceCounters.Initialize 添加一個調用:
C#
public MainForm()
{
InitializeComponent ();
FileCopyPerformanceCounters.Initialize();
}
Visual Basic
Public Sub New()
Me.InitializeComponent()
FileCopyPerformanceCounters.Initialize()
End Sub
15. 按 F5 鍵 啟動該應用程序。確保沒有拋出任何異常。這一般說明計數器已經成功注冊。如果存在異常 ,則在調試之前應確保 Visual Studio 實例是使用管理員權限啟動的(或者使用管理員權限 啟動了應用程序)。
圖 1
運行 File Copier 應用程序
16. 關閉應用程序。
任務 2 – 公開診斷信息
在本任務中,您將使用上一個步驟中創建的框架,公開從源目錄復制到 目標目錄時有關應用程序進度的診斷信息。
1. 在 FileCopyPerformanceCounters 類 (C#) 或模塊 (Visual Basic) 中,添加兩個方法,名為 UpdateTotalFiles 和 UpdatePercentDone ,它們接收一個整數參數。
在每個方法的正文中,將相關 PerformanceCounter 實例( totalFilesCounter 或 percentDoneCounter )的 RawValue 屬性設置為方法參數指定的值。要實現這一點,添加以下代碼(用粗體顯示):
C#
public static class FileCopyPerformanceCounters
{
...
public static void UpdateTotalFiles(int totalFiles)
{
totalFilesCounter.RawValue = totalFiles;
}
public static void UpdatePercentDone(int percentDone)
{
percentDoneCounter.RawValue = percentDone;
}
}
Visual Basic
Module FileCopyPerformanceCounters
...
Public Sub UpdateTotalFiles(ByVal totalFiles As Integer)
totalFilesCounter.RawValue = totalFiles
End Sub
Public Sub UpdatePercentDone(ByVal percentDone As Integer)
percentDoneCounter.RawValue = percentDone
End Sub
End Module
2. 更新復制的文件的數量。要實現這一點,打開 MainForm.cs 文件 (C#) 或 MainForm.vb (Visual Basic) 。然後按照以下步驟操作:
a. (對於 C# 用戶)找到 BtnCopy_Click 方法並導航到注冊 work 實例 DoWork 方法的代碼。
b. (對於 Visual Basic 用戶)找到 worker_DoWork Sub 。
c. 在復制文件的循環中,插入對 FileCopyPerformanceCounters.UpdateTotalFiles 方法的調用,使用當前復制的文件數作為 參數。
C#
private void BtnCopy_Click(object sender, EventArgs args)
{
...
this.worker.DoWork += (o, e) =>
{
string[] files = Directory.GetFiles(source);
for (int i = 0; i < files.Length; ++i)
{
Thread.Sleep(1000);
File.Copy(files[i], Path.Combine(dest, Path.GetFileName(files[i])));
this.worker.ReportProgress((int)((100.0f * i) / files.Length));
FileCopyPerformanceCounters.UpdateTotalFiles(i);
}
};
...
}
Visual Basic
Private Sub worker_DoWork() Handles worker.DoWork
Dim files = Directory.GetFiles(Me.txtSourceDirectory.Text)
For i = 0 To files.Length - 1
Thread.Sleep(1000)
File.Copy(files(i), Path.Combine (Me.txtDestinationDirectory.Text, Path.GetFileName(files(i))))
Me.worker.ReportProgress(CInt(Fix((100.0F * i) / files.Length)))
FileCopyPerformanceCounters.UpdateTotalFiles(i)
Next i
End Sub
3. 更新復制的文件的百分比。要實現這一點,按照以下步驟操作:
a. (對於 C# 用戶)在 BtnCopy_Click 方法中,導航到注冊 worker 實例 ProgressChanged 方法的代碼 。
b. (對於 Visual Basic 用戶)找到 worker_ProgressChanged Sub 。
c. 插入對 FileCopyPerformanceCounters.UpdatePercentDone 方法的調用,並將其傳遞到 ProgressChangedEventArgs 參數的 ProgressPercentage 屬性。
C#
private void BtnCopy_Click(object sender, EventArgs args)
{
...
this.worker.WorkerReportsProgress = true;
this.worker.ProgressChanged += (o, e) =>
{
this.BeginInvoke((MethodInvoker)delegate
{
progressBar.Value = e.ProgressPercentage;
FileCopyPerformanceCounters.UpdatePercentDone (e.ProgressPercentage);
});
};
...
}
Visual Basic
Private Sub worker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles worker.ProgressChanged
progressBar.Value = CInt(e.ProgressPercentage)
FileCopyPerformanceCounters.UpdatePercentDone(e.ProgressPercentage)
End Sub
4. 按 F5 鍵啟動應用程序並使用源文本框和目標文本框旁邊的“浏 覽”按鈕選擇源目錄和目標目錄。
注意 :確保源目錄中有一些文件,並使用空的目標目錄。
5. 啟動性能監視器( )。可以在“開始”菜單的搜索框中鍵入 perfmon 來啟動。
6. 在左導航 面板中,選擇 Monitoring Tools 節點下的 Performance Monitor 。
圖 2
打開性能監視器
7. 單擊綠色 按鈕打開 Add Counters 對話框。
8. 在 Available counters 部分的 FileCopier 類別下,找到 % FilesCopied 和 Total Files Copied 計數器。選擇它們並單擊 Add 。
圖 3
添加性能計數器
9. 右鍵單擊 % Procesor Time 計數器並選擇 Hide Selected Counters 。
10. 回到 File Copier 應用程序,單擊 Copy 按鈕並檢查性 能計數器的值是否隨著復制操作的進度上升。
圖 4
復制文件
圖 5
復制文件後的性能計數器
在本練習中,您通過公開 Windows 性能計 數器並從 Windows 性能監視器使用它們,向現有應用程序添加了檢測功能。完整的練習解決 方案位於 %TrainingKitInstallfolder%\
InstrumentationAndPerformance\Ex1- PerfCounters\End 文件夾,根據語言不同有不同的版本。
練習 2 : 性能分析
在本練習中,您將分析在上一個練習中開發的應用程序的性能,分析它的 CPU 和 I/O 利用率。您將使用 Windows Performance Toolkit 執行分析,無需修改應用程 序代碼或使用第三方分析程序。
要完成該練習,系統中必須安裝有 Microsoft Windows Performance Toolkit 。注意,在 32 位系統中,應該安裝 32 位版本的 Windows Performance Toolkit ;在 64 位系統上,應該安裝 64 位的 Windows Performance Toolkit 版本。
任務 1 – 檢測應用程序
您將使用 Windows Performance Toolkit 命令行工具 (xperf.exe) 和 “ BASE ” 集合配置文件檢 測應用程序。
1. 啟動練習 1 中的完整應用程序。
注意 :如果您沒有完成練 習,可以使用 %TrainingKitInstallfolder%\InstrumentationAndPerformance\Ex1- PerfCounters\End 文件夾中提供的完整解決方案,選擇要使用的語言( C# 或 VB )。 .
2. 選擇文件復制操作的源目錄和目標目錄。
3. 使用管理員權限打開命令行(在“開始”菜單搜索框中鍵入“ Command Prompt ”,然後右鍵單擊第一個結果並選擇“以管理員身份運行 ”)。
4. 導航到 Windows Performance Toolkit 的安裝目錄(如果將工具包 安裝到默認的安裝目錄,則可以使用命令 cd C:\Program Files\Microsoft Windows Performance Toolkit )。
5. 運行以下命令打開基本的檢測配置文件。
命令
xperf -on BASE
6. 單擊應用程序中的 Copy 按鈕啟動復制操作。
7. 完成復制操作時,回到命令提示符並運行以下命令,在 result.etl 文件中生成收集到的檢 測數據。
命令
xperf -d result.etl
8. 運行以下命令打開 Windows Performance Toolkit UI 。
命令
xperf result.etl
9. 從左邊的列表 中,選擇“ Disk Utilization by Process ”和“ CPU Sampling by Process ”。
圖 6
分析檢測數據
10. 在每個圖右上方出現的組合框中,僅選擇 FileCopier.exe 進度。
注意:需要從 Task Manager 的 Processes 部分獲取 FileCopier 進度 id 。要打開任務管理器,右鍵單擊任務欄,然後選擇 Start Task Manager 。
圖 7
兩個圖都只選擇 FileCopier 進度
11. 檢查 CPU 利用率和磁盤利用率,確 定磁盤或 CPU 是否是該應用程序的瓶頸。
12. 選擇磁盤利用率的一個區域並右鍵單 擊,然後選擇 Summary Table 並檢查進程執行的各種磁盤訪問。
13. 選擇磁盤利用 率圖的一個區域並右鍵單擊,然後選擇 Detail Graph 並檢查應用程序復制文件時磁盤頭的 活動。
14. 完成後,回到命令提示符,並運行以下命令刪除檢測文件。
命令
del result.etl
在本練習中,您在沒有修改源代碼的情況下,使用 Windows Performance Toolkit 分析了應用程序的性能特征。
小結
在本實驗中,您使 用 Windows 性能計數器公開了檢測信息,以便在編程中使用或者遠程查看。此外,您還在未 修改源代碼的情況下,使用 Windows Performance Toolkit 在外部分析了應用程序的性能。