- 最小化傳送和接收路徑長度
- 分割數據和程序代碼,以將處理器之間的共用降至最低
- 避免偽共享
- 正確使用鎖定機制
- 使用 64 位 DMA
- 確保適當的緩衝區對齊
- 使用 Scatter-Gather DMA
- 支援接收端節流
將傳送和接收路徑長度降至最低
雖然傳送和接收路徑與驅動程式不同,但效能優化有一些一般規則:
針對一般路徑進行優化。 Kernprof.exe 工具隨附於 Windows 的開發人員版和 IDW 組建,以擷取所需的資訊。 開發人員應該查看耗用最多 CPU 週期的例程,並嘗試減少呼叫這些例程的頻率,或在這些例程中花費的時間。
減少在 DPC 中花費的時間,讓網路適配器驅動程式不會使用過多的系統資源,這會導致整體系統效能受到影響。
請確定偵錯程式代碼未編譯為驅動程式的最終發行版本;這可避免執行多餘的程序代碼。
分割數據和程序代碼,以最小化跨處理器共用
需要數據分割,才能將跨處理器的共享數據和程式代碼降到最低。 數據分割有助於減少系統總線使用率,並改善處理器快取的有效性。 若要將共用降至最低,驅動程式寫入器應考慮下列事項:
將驅動程式實作為去串行化的 NDIS 迷你埠驅動程式,如 去串行化的 NDIS 迷你埠驅動程式中所述。
使用個別處理器的數據結構來減少全域和共享數據存取。 這可讓您在不同步處理的情況下保留統計數據計數器,這樣可減少程式代碼路徑長度並提升效能。 對於重要統計數據,請在查詢時將每個處理器的計數器累加起來。 如果您必須使用全域計數器,請使用交錯操作,而不是自旋鎖來操控計數器。 如需有關如何避免使用自旋鎖的資訊,請參閱下方的正確鎖定機制使用方法。
為了方便這樣做,KeGetCurrentProcessorNumberEx 可用來判斷目前的處理器。 若要判斷配置每個處理器數據結構時的處理器數目,可以使用KeQueryGroupAffinity 。
親和性遮罩中已設定位元的總數表示系統中活躍處理器的數量。 驅動程式不應該假設在位元遮罩中的所有已設定位元都是連續的,因為處理器在未來的作業系統版本中可能不會連續編號。 SMP 機器中的處理器數目是以零起始的值。
如果您的驅動程式維護每個處理器的數據,您可以使用 KeQueryGroupAffinity 函式來減少快取行爭用。
避免誤共用
當處理器請求彼此獨立的共享變數時,就會發生偽共享。 不過,由於變數位於相同的快取行上,因此它們會在處理器之間共用。 在這種情況下,快取行會在處理器之間來回移動,以便每次存取其中任何變數,而導致快取排清和重載增加。 這會增加系統總線使用率,並減少整體系統效能。
若要避免誤共用,請使用 NdisGetSharedDataAlignment,使重要資料結構(例如旋轉鎖、緩衝區佇列標頭、單向鏈結清單)對齊於快取行界限。
正確使用鎖定機制
若未正確使用,自旋鎖可能會降低效能。 驅動程式應盡可能透過使用互鎖操作來將微調鎖的使用降到最低。 不過,在某些情況下,自旋鎖可能是某些用途的最佳選擇。 例如,如果驅動程式在處理尚未傳回給驅動程式之封包數目的參考計數時取得自旋鎖,則不需要使用互鎖操作。 如需詳細資訊,請參閱網路驅動程式 中的同步處理和通知。
以下是有效使用鎖定機制的一些秘訣:
使用 NDIS 單一鏈結串列方法,例如像以下示例來管理資源集區:
如果您需要使用自旋鎖,請只用來保護資料,而非程式碼。 請勿使用一把鎖來保護經常使用路徑中的所有資料。 例如,將傳送和接收路徑中使用的數據分成兩個數據結構,以便在傳送路徑需要鎖定其數據時,接收路徑不會受到影響。
如果您使用自旋鎖,且路徑已經在 DPC 層級,請使用以下函式 NdisDprAcquireSpinLock 和 NdisDprReleaseSpinLock,以避免在取得和釋放鎖定時增加額外程式碼。
若要將旋轉鎖的取得和釋放次數降到最低,請使用以下這些 NDIS RWLock 函數:
使用64位 DMA
64 位 DMA 如果網路適配器支援 64 位 DMA,則必須採取步驟以避免超過 4 GB 範圍之位址的額外複本。 當驅動程式呼叫 NdisMRegisterScatterGatherDma時,必須在 Flags 參數中設定 NDIS_SG_DMA_64_BIT_ADDRESS 旗標。
確保適當的緩衝區對齊
快取行界限上的緩衝區對齊可改善將數據從一個緩衝區複製到另一個緩衝區時的效能。 大部分的網路介面卡接收緩衝區會在第一次配置時正確對齊,但由於標頭佔用的空間,最終必須複製到應用程式緩衝區的使用者資料可能會不對齊。 在最常見的 TCP 數據情況中,由於 TCP、IP 和以太網封包頭的影響,造成偏移 0x36 個字節。 若要解決此問題,建議驅動程式配置稍微較大的緩衝區,並將封包數據插入位移0xA位元組。 這可確保在緩衝區的標頭向後偏移0x36個位元組之後,使用者資料會正確對齊。 如需快取行界限的詳細資訊,請參閱備註部分中的 NdisMAllocateSharedMemory一節。
使用 Scatter-Gather DMA
NDIS 散佈/收集 DMA 提供硬體支援,以在非連續的實體記憶體範圍內來回傳輸數據。 Scatter-Gather DMA 會使用 SCATTER_GATHER_LIST 結構,其中包含 SCATTER_GATHER_ELEMENT 結構的陣列和陣列中的元素數目。 從傳遞至驅動程式傳送函式的封包描述元擷取此結構。 陣列的每個元素都會提供物理上連續 Scatter-Gather 區域的長度和起始物理位址。 驅動程式會使用長度和地址資訊來傳輸數據。
使用 Scatter-Gather 例程進行 DMA 作業,可以透過避免資源的靜態鎖定來提高系統資源的利用率,而靜態鎖定會在使用映射暫存器時發生。 如需詳細資訊,請參閱 NDIS 分散/聚集 DMA。
如果網路適配器支援 TCP 分段卸載(大型傳送卸載),則驅動程式需要提供從 TCP/IP 獲得的最大緩衝區大小,並傳入 NdisMRegisterScatterGatherDma 函數中的 MaximumPhysicalMapping 參數。 這可確保驅動程式有足夠的映射暫存器來建立 Scatter-Gather 清單,並避免任何可能的緩衝器配置和複製。 如需詳細資訊,請參閱下列主題:
支援接收端節流
若要在多媒體應用程式中將媒體播放期間的中斷降到最低,NDIS 6.20 和更新版本的驅動程式必須支援接收端節流(RST)來處理接收中斷。 如需詳細資訊,請參閱:
NDIS 6.20 中的接收端節流「傳送和接收程式代碼路徑」,將迷你埠驅動程式移植到 NDIS 6.20 所需的變更摘要