本文章是由機器翻譯。

執行緒效能

Visual Studio 2010 中的資源爭用並行處理剖析

Maxim Goldin

隨著 commonplace 以往更多核心處理器,軟體開發人員正在建置多執行緒的應用程式,利用額外的處理容量,以達到較佳的效能。您可以使用 [平行執行緒的電源分割成個別工作的整體工作和平行執行這些工作。

執行緒,不過,通常需要與完成一項工作,而且有時候需要同步處理它們的行為,如果演算法或資料的存取要求它到每個通訊。就例如同時寫入存取相同的資料應授互斥的方式,以避免資料損毀的執行緒。

同步處理,通常是透過取得物件的執行緒授與共用或獨占存取敏感的程式碼或資料的共用的同步物件的使用來完成。當不再需要存取時,執行緒 relinquishes 擁有權和其他執行緒可以嘗試取得存取。根據使用的同步處理種同時擁有權的要求可能會允許在此同時存取共用的資源的多個執行緒,或一些執行緒可能會封鎖,直到放開從先前擷取的物件。範例 
include 重要區段 C/C + + 中使用 EnterCriticalSection 和 LeaveCriticalSection 存取常式、 WaitForSingleObject 函式,以 C/C + + 和 lock 陳述式和 C# 中的 [監視器] 類別。

必須小心,進行選擇同步處理機制,因為不適當的同步處理執行緒之間可以降低而增強效能提升的目標的多執行緒處理。因此,是越來越重要,才能偵測到的情況下,執行緒會被封鎖因為要讓沒有進度的鎖定 contentions。

在 Visual Studio 2010 效能工具包括新的程式碼剖析方法 — 資源爭用進行程式碼剖析,可協助您偵測並行執行緒之間的爭用。您可以找到這項功能很好第一個看 wintellect.com/CS/blogs/jrobbins/archive/2009/10/19/vs-2010-beta-2-concurrency-resource-profiling-in-depth-first-look.aspx John Robbins ’ Wintellect 部落格張貼中。

這個本文我逐步解說爭用程式碼剖析的調查,並說明可以使用 Visual Studio 2010 IDE 和命令列工具會收集的資料。我也告訴您如何,您可以分析在 Visual 的 Studio 2010 資料和您看到如何從一個分析檢視移到另一個時進行爭用調查。然後我會修正程式碼和原始的剖析結果,以驗證此修正程式可以降低 contentions 數目的結果的修改過的應用程式進行程式碼剖析的比較。

啟動與問題

做為範例,我使用相同 Hazim Shafi 用於他的部落格張貼的矩陣乘法應用程式 「 效能圖樣 1:用來識別鎖定爭用 」 ( blogs.msdn.com/hshafi/archive/2009/06/19/performance-pattern-1-identifying-lock-contention.aspx )。程式碼範例以 C + +,撰寫,但我討論的概念是 Managed 程式碼也同樣適用。

範例矩陣乘法的應用程式會使用數個執行緒來將兩個矩陣相乘。每一個執行緒取得作業的一部份,並執行下列的程式碼片段:

for (i = myid*PerProcessorChunk; 
     i < (myid+1)*PerProcessorChunk; 
     i++) {
  EnterCriticalSection(&mmlock);
  for (j=0; j<SIZE; j++) {
    for (k=0; k<SIZE; k++) {
      C[i][j] += A[i][k]*B[k][j];
    }
  }
  LeaveCriticalSection(&mmlock);
}

每一個執行緒有自己的識別碼 (myid),並負責計算結果的矩陣 C] 中作為輸入使用矩陣 A 和 B 中的列 (一或多個) 數。關閉程式碼檢查顯示沒有真正模稜兩可寫入共用發生,並將每個執行緒會寫入不同的資料列的 C。還開發人員決定保護重要區段與矩陣該工作分派。因為它讓我很好的機會,以示範新的 Visual Studio 2010 效能工具輕鬆找出多餘的同步處理,感謝此,開發人員。

程式碼剖析的資料收集

假設您有 Visual Studio 專案與稍早所示的程式碼 (雖然並非必要 — 您可以將該程式碼剖析工具附加到已執行任何應用程式),您啟動爭用程式碼剖析,藉由按一下 [分析] 功能表中的 [啟動 [效能精靈]。

圖 1 中顯示精靈的第一頁選擇並行存取,並確定已核取 「 收集資源爭用資料 」 的選項。請注意在任何版本的 Windows 作業系統上的運作方式進行程式碼剖析該資源爭用並行存取。「 視覺化的多執行緒的應用程式行為 」 的選項需要 Windows Vista 或 Windows 7。


圖 1 啟用並行存取資源設定檔

在精靈的第二頁,請確定目前的專案為目標。精靈在最後一張確定已核取 「 啟動在精靈完成後,程式碼剖析 」 選項,然後按一下 [完成]。在程式碼剖析工具下執行時,啟動應用程式。當它結束,程式碼剖析的資料檔案會顯示在 [效能總管] 視窗中 (請參閱 的 圖 2)。


圖 2 的 效能分析結果檔案,在 [效能總管

程式碼剖析的報表自動在 Visual Studio 會開啟,並顯示效能調查結果摘要 的 圖 3 所示的檢視中。


圖 3 的 程式碼剖析的報告的摘要檢視

程式碼剖析的資料分析

並非所有的同步處理會造成的鎖定競爭。如果使用 [鎖定],嘗試取得的鎖定的擁有權並不會封鎖執行緒的執行,並沒有爭用情形發生。在設定檔資源爭用的模式下分析工具收集會造成爭用的同步處理事件的資料,並不會報告成功 (解除封鎖) 資源購。如果您的應用程式並不會造成任何 contentions,將會不收集任何資料。如果您取得資料,表示應用程式已鎖定 contentions。

每個的競爭的程式碼剖析工具報告的執行緒已被封鎖,在競爭發生 (資源和呼叫堆疊) 的地方,當發生 (時間戳記),以及所需的時間 (長度),執行緒已封鎖嘗試取得一個的鎖定輸入一個重要的區段的爭用等候單一物件等等。

當您開啟 [檔案第一次看到 [摘要] 檢視 ( 的 圖 3),3 個主要區域,您可以使用簡短的診斷與:

  1. contentions 圖表顯示 contentions 繪製為應用程式的存留期的秒數。您可以以視覺方式檢查爭用特殊圖文集或選取時間間隔,並將它拉或篩選結果。篩選 re-analyzes 資料及外所選取間隔的資料中移除。
  2. 最 Contended 資源表格列出造成最偵測到的 contentions 的資源。
  3. 最 Contended 執行緒表格列出 contentions 最高數目的執行緒。此資料表會使用一個的準則不在 contentions 長度為 contentions 數目。因此,您可能有很長的時間為單一的爭用封鎖的執行緒,但它 won’t 顯示在 [摘要] 檢視。手動,遇到許多很短 contentions,與封鎖執行緒,只在非常的短時間,每個競爭的執行緒會呈現在 [摘要] 檢視。

如果您看到 [’s 負責 contentions 大部分的資源檢查該資源在更多詳細資料。如果您觀察遭遇大量 contentions 並不預期的執行緒,檢查執行緒的 contentions。

就例如 的 圖 3,您可以看到重要區段 1 會負責在該應用程式的幾乎所有 (99.90%) contentions。let’s 進一步調查該資源。

資源名稱,並在 [摘要] 檢視上的執行緒 ID 是超連結。重要區段 1 傳輸您資源的詳細資料檢視 (請參閱 的 圖 4) 內容設定為特定資源的位置上按一下,關鍵區段 1。


圖 4 的 資源詳細資料檢視

資源詳細資料

資源詳細資料檢視的上半部會顯示以時間為基礎的圖表,每個水平規線所屬執行緒的位置。線條會標示為執行緒根函式,除非您命名您的程式碼中的 Managed 的執行緒 (,就例如藉由使用 C# System.Threading.Thread.Name 屬性)。在此線路上的區塊代表的執行緒,在該資源上的爭用。區塊長度是競爭長度。從不同的行區塊可能重疊在表示數個執行緒同時封鎖上資源的時間。

合計列是特殊的。它 doesn’t 隸屬於任何特定的執行緒,但包含所有 contentions 的 (它是實際投射到一行的爭用區塊) 此資源上的所有執行緒。您可以看到重要區段 1 是很忙,似乎 doesn’t 其合計列上任何空的介面槽。

您可以藉由選取的時間範圍,使用左邊的滑鼠按鈕 (在圖表中您要啟動,然後向右拖曳指標點按滑鼠左鍵) 拉到圖表的特定部份。有兩個連結的圖表右上角部份,縮放重設及縮小。縮放重設會還原原始的圖表檢視。縮小會帶您回到步驟 un-zooming 步驟所圖表您放大的方式相同。

爭用區塊的整體的模式可能會導致您一些關於您的應用程式執行的結論。就例如,您可以看到 contentions 的各種執行緒會大量重疊,在提示在小於最佳的平行處理的時間。很多時間,超過它執行和 ’s 還另一個指示應用程式 ’s 效率的資源上,每個執行緒會被封鎖。

函數詳細資料

資源詳細資料檢視的底端部分是競爭呼叫堆疊 (沒有資料會顯示,直到您選取特定的爭用。當您選取 [區塊對應的堆疊就會出現在下方面板。您可以也停留在圖表上的爭用區塊上方,而不需按一下,及快顯視窗會提供您堆疊和競爭長度。

為您可以請參閱 「 競爭中的呼叫堆疊範例的其中一個應用程式函式被呼叫的 MatMult 列,讓您知道它是爭用的原因。若要判斷哪一個函式的程式碼行是負責在競爭,連按兩下函數名稱,在 [呼叫堆疊] 面板中。會讓您進入 的 [圖 5] 所示 」 [函數詳細資料檢視。


圖 5 的 函式詳細資料檢視

在此檢視中,您會看到圖形的簡報的呼叫 MatMult 的函式,以及內部的它所呼叫的函式。下一節,檢視的清楚顯示 EnterCriticalSection(&mmlock) 負責被封鎖所有時間的執行緒。

當您知道哪一行程式碼的負責 contentions 時,您可能會考慮您的決定實作該方法的同步處理。它是最好的方法,來保護您的程式碼嗎?根本是所需的保護嗎?

在 [範例] 應用程式中使用此程式碼的關鍵區段是不必要,因為執行緒 don’t 共用寫入相同的結果矩陣資料列。Visual Studio 的 [效能] 工具會帶您到點,您可以註解 mmlock,使用大幅加速應用程式。如果只是永遠也容易 !

函數詳細資料檢視的更深入描述,請參閱 「 Visual Studio 分析工具小組部落格,在 blogs.msdn.com/profiler/archive/2010/01/19/vs2010-investigating-a-sample-profiling-report-function-details.aspx

執行緒詳細資料

如我先前所述,摘要檢視會針對您的調查提供很好的起點。藉由查看最 Contended 資源] 及 [最 Contended 執行緒資料表,您可以決定要如何繼續進行。如果您發現其中一個執行緒呈可疑,因為您 didn’t 預期在 contended 執行緒的頂端的清單中,您可能會決定讓執行緒仔細地加以查看。

按一下 [摘要] 檢視上的執行緒 ID 跳至執行緒詳細資料檢視 (請參閱 的 圖 6)。雖然這個檢視看起來類似於資源詳細資料檢視的它有不同的意義,因為它會 contentions 顯示所選往來書信內容中。每個水平規線代表執行緒已在執行緒的存留期期間對付的資源。在這個圖表上 won’t 請參閱爭用區塊重疊的時間,因為這就表示相同的執行緒已在一個以上的資源被封鎖在同一時間。


圖 6 執行緒詳細資料檢視,與選取的爭用封鎖

請注意 WaitForMultipleObjects (這我不此處顯示) 分開處理表示以單一圖表線物件的集合。這是 WaitForMultipleObjects 的因為分析工具會將所有的參數物件視為單一的實體。

(和縮小縮放圖表、 選取特定 contentions 和檢視長度,以毫秒為單位和呼叫堆疊) 的資源詳細資料檢視中,您可以執行任何操作會適用於該執行緒的詳細資料檢視。連按兩下函數名稱,以瀏覽到該函式的函式詳細資料檢視的爭用呼叫堆疊面板中。

在此範例中您可以看到執行緒也需要花費更多的時間,比執行中的執行,前期被封鎖,然後它封鎖部分的多個控點上很長的時間。當最後一個區塊因等待其他執行緒完成,早期 contentions 表示未最佳化的執行緒使用方式造成封鎖的狀態執行的狀態中的多個執行緒。

搜尋下問題

您可能已經注意到,圖表座標軸標籤是超連結。這可讓資源的詳細的檢視和設定所需的內容,檢視每個時間的執行緒之間切換。可以是反覆進行的方法中尋找和解決的問題很有用。比方就說,您可以檢閱資源 R1 封鎖許多執行緒。您可以請從資源詳細資料檢視的執行緒 T1 的詳細檢視,並了解它已被封鎖不只在 R1,但有時候也在 R2 的資源上。您可以再深入探討 R2 的詳細資料,並觀察已封鎖的 R2 的所有執行緒。下一個執行緒可以吸引您的注意檢查封鎖 T2 的所有資源的 T2 的標籤,您可以按一下,以此類推。

程式碼剖析資料的爭用 won’t 提供明確的回答者會保留鎖定,在任何指定時間的問題。但是,給定的同步物件,執行緒和知識的應用程式 ’s 行為之間公平使用,您還可以藉由資源的詳細資料中的資料,以執行緒詳細資料的樞紐分析之後,找出可能的鎖定擁有者 (成功地同步處理鎖定擷取的執行緒) 和備份。

就例如假設資源 R 在時間 t 上看到執行緒封鎖的 T 的執行緒詳細資料檢視中。您可以按一下 R] 標籤上的 [切換至資源詳細資料檢視的 R 和 R 上看到所有已封鎖的執行緒,在應用程式生命週期。在時間 t 您請參閱數目它們 (包括 T) 封鎖上 R。不封鎖 R 在時間 t 的執行緒是可能的鎖定擁有者。

我稍早注意圖表 ’s 合計列是所有的爭用區塊的投射。[合計] 標籤也是一個的超連結,但從資源詳細資料檢視,它會讓您進入 [爭用檢視 (請參閱 的 圖 7) 也就是每個資源爭用呼叫樹狀圖的集合。您啟動適當的資源呼叫樹狀結構的作用中的路徑。此檢視會顯示資源在呼叫樹狀圖中 contentions 和封鎖時間統計資料之每個資源,並為每個節點 (函式)。不同於其他檢視此一就像彙總到資源呼叫樹狀結構的爭用堆疊,其他程式碼剖析的模式中的內容,並讓您統計資料的整個執行的應用程式。


圖 7 的 爭用檢視與套用至關鍵區段 1 的最忙碌路徑

從爭用] 檢視您可以回到的任何資源,使用快顯功能表的 [資源詳細資料] 檢視。指向資源,以滑鼠右鍵按一下滑鼠,然後選取 [顯示爭用資源詳細資料。其他有趣的動作也可在 [內容] 功能表中。為一般的建議瀏覽內容功能表,在程式碼剖析工具檢視 — 可以是很有幫助!

按一下 [合計] 標籤的執行緒詳細資料檢視,以顯示會在所選取執行緒] [處理序檢視 (請參閱 的 圖 8)。在這個檢視中您可以看到在執行緒啟動相對於應用程式開始時間時已終止時, 多久執行,多少它遇到 contentions,和多久封鎖跨所有 contentions 以毫秒為單位,和執行緒 ’s 存留時間的百分比。


圖 8 的 處理程序的檢視

一次,則可能回到任何執行緒的執行緒詳細資料檢視使用 [內容] 功能表,選取 [感興趣的執行緒、 上按一下滑鼠右鍵,然後選取 [顯示執行緒爭用詳細資料。

另一個可能的調查流程是在開啟檔案時,直接顯示處理序檢視、 上其中一個可用的資料行 (比方就說 contentions 數排序執行緒) 的標題,即可排序執行緒、 選取其中一個執行緒,然後切換至執行緒透過內容功能表的爭用詳細資料圖表。

修正問題並比較結果

您應用程式中找到根本原因的鎖定 contentions 之後,您可以標記為註解 mmlock 重要區段,然後重新執行程式碼剖析:

for (i = myid*PerProcessorChunk; 
     i < (myid+1)*PerProcessorChunk; 
     i++) {
  // EnterCriticalSection(&mmlock);
  for (j=0; j<SIZE; j++) {
    for (k=0; k<SIZE; k++) {
      C[i][j] += A[i][k]*B[k][j];
    }
  }
  // LeaveCriticalSection(&mmlock);
}

您預期可減少,contentions 數目和確實分析的修改程式碼報告只有一個的鎖定競爭, 的 [圖 9] 所示。


圖 9 的 固定的程式碼的剖析結果的摘要檢視

我們也可以比較新的和先前的效能結果,在 Visual Studio 中。若要執行此動作在 [效能總管] 中選取這兩個檔案 (選取一個檔案,請按 Shift 或 Ctrl],然後選取另一個]),然後按一下滑鼠右鍵,並選擇比較效能報告。

圖 10 所示比較報表出現。在 [範例] 應用程式中,您可以看到 MatMult 函式從 1,003 放到 [0 的內含爭用的該數字。


圖 10 的 比較報告

替代的資料收集方法

如果您建立效能工作階段的取樣或檢測程式碼剖析時,您可以隨時將轉換它稍後為並行存取模式。快速執行它的一種方法,是使用 [效能總管] 中的程式碼剖析的 [模式] 功能表。只要選取想,在模式和您 ’re OK 了。

您也可以瀏覽您的工作階段屬性設定值。指向您的工作階段,在 [效能總管] 中,按一下滑鼠右鍵以顯示快顯] 功能表,然後選取 [屬性]。屬性頁可讓您控制您的程式碼剖析工作階段模式及其他程式碼剖析的參數 [一般] 索引標籤中。

一旦您的程式碼剖析模式已設定為並行存取 (或該項目的的取樣) 中,您可以是啟動應用程式 (它 ’s 已經在您的目標清單如果您用效能精靈,或是您可以新增它有手動),或您可以附加至 ’s 啟動且正在執行的應用程式。效能總管提供控制項,以執行這些的工作如 的 [圖 11] 所示。


圖 11 設定檔的 [效能總管] 中的控制項

Visual Studio UI 自動化收集程式碼剖析資料的必要步驟的數字。但是,則可能使用可用於自動的執行指令碼的命令列工具來收集程式碼剖析的資料。

若要啟動您的應用程式進行程式碼剖析模式的競爭中開啟 (這會將所有的程式碼剖析工具二進位碼檔案放在您的路徑是 x86 或 x64 的工具),Visual Studio] 命令,然後執行下列一項:

  1. VSPerfCmd.exe /start:CONCURRENCY、 RESOURCEONLY /output: <YourOutputFile>

  2. VSPerfCmd.exe /launch: < 您應用程式 > /args: 引 「 < 您應用程式數 > 」

  3. 執行您的案例

  4. VSPerfCmd.exe / 中斷連結

    • 如果您的應用程式終止時,但它會導致不會讓您可以將它加入您的指令碼,則不需要這個步驟。
  5. VSPerfCmd.exe /shutdown

    現在您可以在 Visual Studio 中開啟 YourOutputFile.VSP 進行分析。

如果您已經執行的應用程式,那麼您可以將該程式碼剖析工具附加使用這些步驟上:

  1. VSPerfCmd.exe /start:CONCURRENCY、 RESOURCEONLY /output: <YourOutputFile>
  2. VSPerfCmd.exe / 附加: < PID 或程序名稱 >
  3. 執行您的案例
  4. VSPerfCmd.exe / 中斷連結
  5. VSPerfCmd.exe /shutdown

msdn.microsoft.com/library/bb385768(VS.100) 在找不到可用的命令列選項的更詳細的說明。

各種 Visual Studio 檢視可讓您仔細檢查收集的資料。有些檢視授與應用程式存留期的圖片在整個,而其他人專注於特定 contentions — 使用那些您找出最有價值。

您在分析程式碼剖析的結果時您可以使用從一個檢視的轉換到另一個超連結,透過按兩下或內容功能表,或您可以切換直接到任何可用的檢視,透過卸除上下的功能表。圖 12 簡要說明每一種檢視。

圖 12 的 分析檢視

檢視 描述
摘要 顯示摘要資訊,做為您的調查的起點。這是您所看到的第一個檢視,並自動開啟程式碼剖析工作階段是透過後結果檔案已經可以開始。
呼叫樹狀結構 所有的爭用堆疊的一個彙總的呼叫樹狀結構。這裡您可以看到哪些堆疊是負責您 contentions。
模組 每一個導致一個爭用的包含函式的模組清單。每個模組都有一份相關的函式和偵測到 contentions 數目。
呼叫端/被呼叫端 F、 所有呼叫 F 的函式和稱為 f 的函式,函式會呈現三個面板檢視 (只呼叫導致 contentions,當然)。
函式 與相關聯資料的任何爭用堆疊上的所有偵測到函數的清單。
線條 在原始程式檔中函式線條。
資源詳細資料 詳細特定的資源 (,就例如鎖定) 應用程式的生命週期期間,在其上顯示已封鎖的所有執行緒。
執行緒詳細資料 上,顯示所有的資源 (例如鎖定) 執行緒已被封鎖特定執行緒相關需的詳細資訊。
爭用 類似於呼叫] 樹狀目錄檢視,但此處呼叫樹狀結構分隔每個資源爭用。亦即此檢視會介紹幾個特定的資源已被封鎖的每個包含堆疊,呼叫樹狀結構。
標記 其中每個標記都是其時間戳記和 Windows 計數器的值相關聯的自動及手動錄製標記的清單。
處理程序 一份 inspected 處理其中每個處理序都有一份它的執行緒,而每個執行緒已經屬性化的 contentions 它遇到的數目與彙總的封鎖的時間長度。
函數詳細資料 詳細說明有關特定功能包括函式它呼叫和收集的資料。
ips 指令指標位置發生爭用問題清單 (也,函式清單喜歡 EnterCriticalSection、 WaitForSingleObject 等,因為這是實際發生爭用)。

新的資源爭用進行程式碼剖析在 Visual Studio 中的功能應該可以幫助您找出效能問題,藉由使用執行緒同步處理的程式碼中,並可讓您藉由變更,改善您的應用程式執行階段減少或消除不必要的同步處理。

Maxim Goldin 是一個資深軟體設計工程,在 Microsoft。他曾因為 2003 Visual Studio 工程小組。 他可以達到 mgoldin@microsoft.com ,和他的部落格在 blogs.msdn.com/b/mgoldin

如需有關效能調查流程的詳細資訊,請參閱我的同伴部落格張貼在 blogs.msdn.com/b/mgoldin/archive/2010/04/22/resource-contention-concurrency-profiling-in-visual-studio-2010-performance-investigation-flows.aspx

多虧來檢閱本文的下列的技術專家:Steve Carroll、 Anna Galaeva、 Daryush Laqab、 Marc Popkin Paine、 Chris Schmich 及 Colin Thomsen