次の方法で共有


WavePci ミニポート ドライバーにおけるパフォーマンスの問題

オーディオ ドライバーがシステムに与えるパフォーマンスへの影響は、次の一般的な原則に従うことで大幅に削減できます。

  • 通常の操作中に実行されるコードを最小限に抑えます。

  • 必要な場合にのみコードを実行します。

  • (CPU の読み込みだけでなく) システム リソースの合計消費量を考慮してください。

  • 速度とサイズに合わせてコードを最適化します。

さらに、WavePci ミニポートドライバは、オーディオデバイス特有のいくつかの性能問題に対処しなければなりません。 次の説明では、主にオーディオ レンダリングの問題について説明しますが、推奨される手法の一部はオーディオ キャプチャにも適用されます。

ストリーム サービス メカニズム

パフォーマンスの最適化について説明する前に、ストリームを処理するための WavePci メカニズムを理解するためにいくつかの背景が必要です。

ウェーブ レンダリングまたはキャプチャ ストリームを処理する場合、オーディオ デバイスはミニポート ドライバーによる定期的なサービスを必要とします。 ストリームに対して新しいマッピングを使用できる場合、ドライバーはこれらのマッピングをストリームの DMA キューに追加します。 ドライバーは、既に処理されているマッピングをキューから削除します。 マッピングの詳細については、「WavePci の待機時間」を参照してください。

サービスを実行するために、ミニポートドライバは、インターバルがシステムタイマによって設定されるか、DMA駆動割り込みによって設定されるかに応じて、遅延プロシージャコール(DPC)または割り込みサービスルーチン(ISR)のいずれかを提供する。 後者の場合、DMA ハードウェアは通常、ある程度のストリーム データの転送が完了すると、割り込みを毎回トリガーします。

DPC または ISR が実行されるたびに、サービスが必要なストリームが決定されます。 DPC または ISR は、 IPortWavePci::Notify メソッドを呼び出すことによってストリームをサービスします。 このメソッドは、IServiceGroup型 のオブジェクトであるストリームのサービス グループを呼び出しパラメーターとして受け取ります。 Notify メソッドは、サービス グループの RequestServiceメソッドを呼び出します (IServiceSink::RequestServiceを参照)。

サービス グループ オブジェクトには、IServiceSink 型 のオブジェクトであるサービス シンクのグループが含まれています。 IServiceGroup は IServiceSink から派生し、両方のインターフェイスに RequestService メソッドがあります。 Notify メソッドがサービス グループの RequestService メソッドを呼び出すと、サービス グループは、グループ内の各サービス シンクでRequestService メソッドを呼び出すことによって応答します。

ストリームのサービス グループには、少なくとも 1 つのサービス シンクが含まれています。このシンクは、ストリームの作成直後にポート ドライバーによってサービス グループに追加されます。 ポート ドライバーは、ミニポート ドライバーの IMiniportWavePci::NewStream メソッドを呼び出して、サービス グループへのポインターを取得します。 サービス シンクの RequestService メソッドは、ポート ドライバーのストリーム固有のサービス ルーチンです。 このルーチンは以下のことを行う:

  • ミニポート ドライバーの IMiniportWavePciStream::Service メソッドを呼び出します。

  • サービス ルーチンが最後に実行されてから、ストリームで新しく保留中の位置またはクロック イベントをトリガーします。

KS Eventsで説明したように、クライアントは、ストリームが特定の位置に到達したときや、時計が特定のタイムスタンプに到達したときに通知されるように登録することができる。 NewStream メソッドには、サービス グループを指定しないオプションがあります。この場合、ポート ドライバーは、サービス ルーチンへの呼び出しの間隔をオフにするように独自のタイマーを設定します。

NewStreamメソッドと同様に、ミニポート ドライバーIMiniportWavePci::Init メソッドもサービス グループへのポインターを出力します。 Init呼び出しの後、ポート ドライバーはサービス グループにサービス シンクを追加します。 この特定のサービス シンクには、フィルター全体のサービス ルーチンが含まれています。 (前の段落では、フィルターのピンに関連付けられているストリームのサービス シンクについて説明します)。このサービス ルーチンは、ミニポート ドライバーの IMiniportWavePci::Service メソッドを呼び出します。 サービス ルーチンは、DPC または ISR がフィルターのサービス グループで Notify を呼び出すたびに実行されます。 Init メソッドには、サービス グループを指定しないオプションがあります。その場合、ポート ドライバーはフィルター サービス ルーチンを呼び出しません。

ハードウェア割り込み

一部のミニポート ドライバーは、生成されるハードウェア割り込みが多すぎるか、十分ではありません。 DirectSound ハードウェア アクセラレーションを備えた一部の WavePci レンダリング デバイスでは、マッピングの供給がほぼ使い果たされ、レンダリング エンジンが枯渇するリスクがある場合にのみ、ハードウェア割り込みが発生します。 他のハードウェアアクセラレータ WavePci デバイスでは、1 回のマッピング完了または他の比較的小さな間隔でハードウェア割り込みが発生します。 この場合、ISR は頻繁に、ほとんど行う必要がないことがわかりますが、各割り込みでは、レジスタ スワップとキャッシュの再読み込みでシステム リソースが消費されます。 ドライバーのパフォーマンスを向上させる最初の手順は、不足を危険にさらすことなく、割り込みの数をできるだけ減らすことです。 不要な割り込みを排除した後、ISR をより効率的に実行するように設計することで、パフォーマンスをさらに向上させることができます。

一部のドライバーでは、ISR は、ストリームが 実際に実行されているかどうかに関係なく、ハードウェア割り込みが発生するたびにストリームの Notify メソッドを呼び出すことによって時間を無駄にします。 ストリームが RUN 状態でない場合、DMA は非アクティブになり、ストリーム内の新しいイベントのマッピング、リリース マッピング、またはチェックの取得に費やされた時間はすべて無駄になります。 効率的なドライバーでは、ISR はストリームのNotify メソッドを呼び出す前に、ストリームが実行されていることを確認します。

ただし、この種類の ISR を持つドライバーでは、ストリームが RUN 状態を終了したときに、ストリームの保留中のイベントがトリガーされるようにする必要があります。 そうしないと、イベントが遅延または失われる可能性があります。 この問題は、Microsoft Windows XPより古いOSでRUN-to-PAUSEへの移行時にのみ発生する。 Windows XP以降では、ポートドライバは、ストリームがRUNからPAUSEに状態が変化すると、未処理のポジションイベントを即座に自動的に通知します。 しかし、古いオペレーティングシステムでは、ミニポートドライバは、ストリームが一時停止された直後にNotifyを最終的に呼び出すことによって、未処理のイベントをトリガする責任がある。 詳しくは、以下の「PAUSE/ACQUIREの最適化」を参照。

一般的な WavePci ミニポート ドライバーは、KMixer システム ドライバーからの単一の再生ストリームを 管理します。 KMixer の現在の実装では、少なくとも 3 つのマッピング IRP を使用して再生ストリームをバッファーします。 各 IRP には、約 10 ミリ秒のオーディオのための十分なバッファー 記憶域が含まれています。 ミニポート ドライバーは、DMA コントローラーが IRP の最終的なマッピングで終了するたびにハードウェア割り込みをトリガーする場合、割り込みは、DMA キューが不足しないように十分な頻度で、かなり定期的な 10 ミリ秒間隔で発生する必要があります。

タイマー DPCs

ドライバがハードウェアアクセラレーションによるDirectSoundストリームを管理する場合は、DMAによるハードウェア割り込みの代わりにタイマーDPC(タイマーオブジェクトとDPC参照)を使用する必要があります。 同様に、オンボード タイマーを備えた PCI カード上の WavePci デバイスでは、DPC の代わりにタイマー駆動ハードウェア割り込みを使用できます。

DirectSound バッファーの場合、バッファー全体を 1 つの IRP にアタッチできます。 バッファーが大きく、ミニポート ドライバーは、バッファーの末尾に達した場合にのみ、ハードウェア割り込みをスケジュールする場合は、DMA キューが不足するまでに連続した割り込みが発生する可能性があります。 また、ドライバーが多数のハードウェアで高速化された DirectSound ストリームを管理していて、各ストリームが独自の割り込みを生成する場合、すべての割り込みの累積的な影響によってシステムのパフォーマンスが低下する可能性があります。 このような状況では、ミニポート ドライバーは、個々 のストリームのサービスをスケジュールするハードウェア割り込みの使用を避ける必要があります。 代わりに、タイマーで生成された定期的な間隔で実行するようにスケジュールされている 1 つの DPC 内のすべてのストリームにサービスを提供する必要があります。

タイマー間隔を 10 ミリ秒に設定すると、連続する DPC 実行の間隔は、単一の KMixer 再生ストリームの場合のハードウェア割り込みに関して前述した間隔と似ています。 したがって、DPC は、ハードウェアアクセラレータの DirectSound ストリームに加えて、KMixer 再生ストリームを処理できます。

最後のストリームが RUN 状態を終了すると、ミニポート ドライバーは、システムの CPU サイクルを無駄にしないようにタイマー DPC を無効にする必要があります。 DPC を無効にした直後に、ドライバーは、以前に実行中のストリームで保留中のクロックまたは位置イベントがフラッシュされていることを確認する必要があります。 Windows 98/MeとWindows 2000では、ドライバはNotifyを呼び出して、一時停止中のストリームに保留中のイベントを発生させる必要があります。 Windows XP 以降では、ミニポート ドライバーによる介入を必要とせずに、ストリームが RUN 状態を終了すると、オペレーティング システムによって保留中のイベントが自動的にトリガーされます。

PAUSE/ACQUIREの最適化

Windows 98/Me および Windows 2000 では、WavePci ポート ドライバーのストリーム サービス ルーチン ( RequestService メソッド) は、ストリームが RUN 状態であるかどうかに関係なく、ミニポート ドライバーの IMiniportWavePciStream::Service メソッドへの呼び出しを常に生成します。 これらのオペレーティング システムでは、実際の作業に時間を費やす前に、ストリームが実行されているかどうかを Service メソッドでチェックする必要があります。 (ただし、ミニポート・ドライバのDPCまたはISRが、実行中のストリームに対してのみNotifyを呼び出すようにすでに最適化されている場合、Service メソッドにこのチェックを追加することは冗長になるかもしれません)。

Windows XP 以降では、Notify メソッドが実行中のストリームでのみ Service メソッドを呼び出すため、この最適化は不要です。

IPreFetchOffset インターフェイスの使用

DirectSound ユーザーは、プレイ カーソルと書き込みカーソルの 2 つの概念に精通しています。 再生カーソルは、デバイスから出力されるデータのストリーム内の位置を示します (現在 DAC にあるサンプルのドライバーの最適な推定値)。 書き込み位置は、クライアントが追加のデータを書き込むための次の安全な場所のストリーム内の位置です。 WavePci の場合、既定の前提は、書き込みカーソルが、要求された最後のマッピングの最後に配置されていることです。 ミニポート ドライバーが多数の未処理のマッピングを取得した場合、再生カーソルと書き込みカーソルの間のオフセットは非常に大きくなる可能性があります。これは、特定の WHQL オーディオ位置テストに失敗するのに十分な大きさです。 Windows XP 以降では、 IPreFetchOffset インターフェイスがこれらの問題に対処します。

ミニポート ドライバーは、IPreFetchOffset を使用して、主にハードウェア FIFO サイズによって決定されるバス マスター ハードウェアのプリフェッチ特性を指定します。 オーディオ サブシステムはこのデータを使用して、再生カーソルと書き込みカーソルの間に一定のオフセットを設定します。 この定数オフセットは、既定のオフセットよりも大幅に小さくすることができますが、プレイ カーソルがデータの書き込み先の場所から十分に離れている限り、マッピングがハードウェアに渡された後でも、データをマッピングに書き込むことができるという事実を利用します。 (このステートメントは、ドライバーがマッピング内のデータをコピーまたは操作しないことを前提としています)。一般的なオフセットは、エンジンの設計に応じて、64 サンプルの順序で行われる場合があります。 この小さいオフセットを使用すると、WavePci ドライバーは完全に応答性と機能を備えながら、多数のマッピングを要求できます。

DirectSound は現在、ハードウェアアクセラレータピンの書き込みカーソルを 10 ミリ秒パッドします。

詳細については、「プリフェッチ オフセット」を参照してください。

マッピングでのデータの処理

可能であれば、ハードウェア ドライバーがマッピング内のデータに触れないようにします。 マッピングに含まれるデータのソフトウェア処理は、ハードウェア ドライバーとは別のソフトウェア フィルターに分割する必要があります。 このような処理をハードウェア ドライバーで実行すると、効率が低下し、待機時間の問題が発生します。

ハードウェア ドライバーは、実際のハードウェア機能について透過的に努力する必要があります。 ドライバーは、ソフトウェアで実際に実行されるデータ変換のハードウェア サポートを提供することを要求しないでください。

同期プリミティブ

ドライバーのコードが可能な限りブロックされないように設計されている場合、現在および将来、ドライバーにデッドロックやパフォーマンスの問題が発生する可能性は低くなります。 具体的には、ドライバーの実行スレッドは、別のスレッドまたはリソースを待機している間にストールするリスクなしに、完了まで実行するように努める必要があります。 たとえば、ドライバー スレッドは、InterlockedXxx 関数 (InterlockedIncrement など) を使用して、ブロックされるリスクなしに特定の共有リソースへのアクセスを調整できます。

これらは強力な手法ですが、すべてのスピン ロック、ミューテックス、およびその他のブロッキング同期プリミティブを実行パスから安全に削除できない場合があります。 無期限の待機がデータ不足を引き起こす可能性があることを知って、InterlockedXxx 関数を慎重に使用します。

何よりも、カスタム同期プリミティブは作成しないでください。 組み込みの Windows プリミティブ (ミューテックス、スピン ロックなど) は、将来的に新しいスケジューラ機能をサポートするために必要に応じて変更される可能性があり、カスタム コンストラクトを使用するドライバーは、将来動作しないことが事実上保証されます。

IPinCount インターフェイス

Windows XP 以降では、IPinCountインターフェイスは、ピンを割り当てることによって消費されるハードウェア リソースをより正確に考慮するミニポート ドライバーの方法を提供します。 ミニポート ドライバーの IPinCount::P inCount メソッドを呼び出すことによって、ポート ドライバーは次の操作を行います。

  • フィルターの現在のピン数 (ポート ドライバーメイン含まれる) をミニポート ドライバーに公開します。

  • ミニポート ドライバーに、ハードウェア リソースの現在の可用性を動的に反映するようにピン数を変更する機会を提供します。

一部のオーディオ デバイスでは、異なる属性 (3-D、ステレオ/モノラルなど) を持つウェーブ ストリームでも、消費するハードウェア リソースの数に関して異なる "重み" が設定される場合があります。 "軽量" ストリームを開いたり閉じたりすると、ドライバーは使用可能なピンの数を 1 ずつインクリメントまたはデクリメントします。 ただし、"heavyweight" ストリームを開くときに、ミニポート ドライバーは、再メインリソースで作成できるピンの数をより正確に示すために、使用可能なピン数を 1 つではなく 2 つ減らす必要がある場合があります。

重いストリームが閉じられると、プロセスが逆になります。 新しく解放されたリソースから 2 つ以上の軽量ストリームを作成できることを反映するために、使用可能なピン数が複数増加する可能性があります。