次の方法で共有


ネットワーク ドライバーのパフォーマンス

送受信パスの長さを最小限に抑える

送受信パスはドライバーによって異なりますが、パフォーマンスの最適化に関する一般的な規則がいくつかあります。

  • 共通パスに合わせて最適化します。 Kernprof.exe ツールには、必要な情報を抽出する Windows の開発者および IDW ビルドが用意されています。 開発者は、ほとんどの CPU サイクルを消費するルーチンを調べ、これらのルーチンが呼び出される頻度またはこれらのルーチンで費やされた時間を減らすようにする必要があります。

  • ネットワーク アダプター ドライバーが過剰なシステム リソースを使用しないように、DPC で費やされる時間を短縮します。これにより、全体的なシステム パフォーマンスが低下します。

  • デバッグ コードがドライバーの最終リリース バージョンにコンパイルされていないことを確認します。これにより、余分なコードの実行が回避されます。

データとコードをパーティション分割してプロセッサ間の共有を最小限に抑える

パーティション分割は、プロセッサ間の共有データとコードを最小限に抑えるために必要です。 パーティション分割により、システム バスの使用率が低下し、プロセッサ キャッシュの有効性が向上します。 共有を最小限に抑えるには、ドライバーライターは次の点を考慮する必要があります。

  • 「逆シリアル化された NDIS ミニポート ドライバー」の説明に従って、 ドライバーを逆シリアル化されたミニポートとして実装します。

  • プロセッサごとのデータ構造を使用して、グローバルおよび共有データ アクセスを減らします。 これにより、統計カウンターを同期せずに保持できるため、コード パスの長さが短くなり、パフォーマンスが向上します。 重要な統計の場合は、クエリ時に一緒に追加されるプロセッサごとのカウンターがあります。 グローバル カウンターが必要な場合は、スピン ロックの代わりにインターロック操作を使用してカウンターを操作します。 スピン ロックの使用を回避する方法については、以下の「ロック メカニズムを適切に使用する」を参照してください。

    これを容易にするために、 KeGetCurrentProcessorNumberEx を使用して現在のプロセッサを特定できます。 プロセッサごとのデータ構造を割り当てるときにプロセッサの数を決定するために、 KeQueryGroupAffinity を使用できます。

    アフィニティ マスクに設定されているビットの合計数は、システム内のアクティブなプロセッサの数を示します。 ドライバーは、プロセッサがオペレーティング システムの将来のリリースで連続して番号付けされない可能性があるため、マスク内のすべてのセット ビットが連続していると想定しないでください。 SMP マシン内のプロセッサの数は 0 から始まる値です。

    ドライバーがプロセッサごとのデータを保持している場合は、 KeQueryGroupAffinity 関数を使用してキャッシュ ラインの競合を減らすことができます。

誤った共有の回避

誤共有は、プロセッサが互いに独立した共有変数を要求するときに発生します。 ただし、変数は同じキャッシュ ライン上にあるため、プロセッサ間で共有されます。 このような状況では、キャッシュ ラインは、その中の任意の変数にアクセスするたびにプロセッサ間を行き来し、キャッシュ フラッシュと再読み込みの増加を引き起こします。 これにより、システム バスの使用率が向上し、システム全体のパフォーマンスが低下します。

誤った共有を回避するには、 NdisGetSharedDataAlignment を使用して、重要なデータ構造 (スピン ロック、バッファー キュー ヘッダー、単一リンク リストなど) をキャッシュ ライン境界に合わせます。

ロック メカニズムを適切に使用する

スピン ロックを使用すると、適切に使用しないとパフォーマンスが低下する可能性があります。 ドライバーは、可能な限りインターロック操作を使用して、スピン ロックの使用を最小限に抑える必要があります。 ただし、場合によっては、スピン ロックが一部の目的に最適な選択肢になる場合があります。 たとえば、ドライバーに戻って示されていないパケットの数に対する参照カウントを処理している間、ドライバーがスピンロックを取得する場合、インターロック操作を使用する必要はありません。 詳細については、「ネットワーク ドライバー の同期と通知をする」を参照してください。

ロック メカニズムを効果的に使用するためのヒントを次に示します。

  • リソース プールを管理するために、次のような NDIS の 1 つのリンクされたリスト関数を使用します。

    NdisInitializeSListHead

    NdisInterlockedPushEntrySList

    NdisInterlockedPopEntrySList

    NdisQueryDepthSList

  • スピン ロックを使用する必要がある場合は、コードではなくデータのみを保護するために使用します。 共通パスで使用されるすべてのデータを保護するために 1 つのロックを使用しないでください。 たとえば、送信パスと受信パスで使用されるデータを 2 つのデータ構造に分割して、送信パスでデータをロックする必要があるときに受信パスが影響を受けないようにします。

  • スピン ロックを使用していて、パスが既に DPC レベルにある場合は、 NdisDprAcquireSpinLock 関数と NdisDprReleaseSpinLock 関数を 使用して、ロックを取得および解放するときに追加のコードを回避します。

  • スピン ロックの取得とリリースの数を最小限に抑えるには、次の NDIS RWLock 関数を使用します。

    NdisAllocateRWLock

    NdisAcquireRWLockRead

    NdisAcquireRWLockWrite

    NdisReleaseRWLock

64 ビット DMA の使用

64 ビット DMA ネットワーク アダプターが 64 ビット DMA をサポートしている場合は、4 GB の範囲を超えるアドレスの追加コピーを回避するための手順を実行する必要があります。 ドライバーが NdisMRegisterScatterGatherDma を呼び出すときは、 NDIS_SG_DMA_64_BIT_ADDRESS フラグを Flags パラメーターに設定する必要があります。

バッファーの適切な配置の確認

キャッシュ ライン境界でのバッファー配置により、あるバッファーから別のバッファーにデータをコピーするときのパフォーマンスが向上します。 ほとんどのネットワーク アダプター受信バッファーは、最初に割り当てられるときに適切に配置されますが、最終的にアプリケーション バッファーにコピーする必要があるユーザー データは、ヘッダー領域が消費されるため、配置が正しくありません。 TCP データの場合 (最も一般的なシナリオ)、TCP、IP、およびイーサネット ヘッダーによるシフトにより、0x36 バイトのシフトが発生します。 この問題を解決するには、ドライバーが少し大きなバッファーを割り当て、0xA バイトのオフセットにパケット データを挿入することをお勧めします。 これにより、バッファーがヘッダーの0x36 バイト単位でシフトされた後、ユーザー データが適切にアラインされます。 キャッシュ ライン境界の詳細については、 NdisMAllocateSharedMemory の「解説」セクションを参照してください。

Scatter-Gather DMA の使用

NDIS スキャッター/ギャザー DMA は、物理メモリの非連続領域との間でデータを転送するためのサポートをハードウェアに提供します。 Scatter-Gather DMA では 、SCATTER_GATHER_LIST 構造体が使用されます。これには、 SCATTER_GATHER_ELEMENT 構造体の配列と配列内の要素の数が含まれます。 この構造体は、ドライバーの送信関数に渡されるパケット記述子から取得されます。 配列の各要素は、物理的に連続する Scatter-Gather 領域の長さと開始物理アドレスを提供します。 ドライバーは、データの転送に長さと住所の情報を使用します。

DMA 操作に Scatter-Gather ルーチンを使用すると、マップ レジスタが使用された場合と同様に、これらのリソースを静的にロックダウンしないことで、システム リソースの使用率を向上させることができます。 詳細については、「 NDIS 散布図/DMA の収集」を参照してください。

ネットワーク アダプターが TCP セグメント化オフロード (Large Send Offload) をサポートしている場合、ドライバーは、TCP/IP から取得できる最大バッファー サイズを NdisMRegisterScatterGatherDma 関数内の MaximumPhysicalMapping パラメーターに渡す必要があります。 これにより、ドライバーが Scatter-Gather リストをビルドし、バッファーの割り当てとコピーの可能性を排除するのに十分なマップ レジスタがあることを保証します。 詳細については、次のトピックを参照してください。

受信側スロットルのサポート

マルチメディア アプリケーションでのメディア再生中の中断を最小限に抑えるには、NDIS 6.20 以降のドライバーは、受信割り込みの処理で受信側スロットル (RST) をサポートする必要があります。 詳細については、以下を参照してください。

NDIS 6.20 の受信側スロットルNDIS 6.20 にミニポート ドライバーを移植するために必要な変更の概要で"送信および受信コード パス"