次の方法で共有


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

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

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

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

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

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

さらに、WavePci ミニポート ドライバーは、オーディオ デバイスに固有のいくつかのパフォーマンスの問題に対処する必要があります。 次の説明では、主にオーディオ レンダリングの問題について説明しますが、推奨される手法の一部はオーディオ キャプチャにも適用されます。

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

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

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

サービスを実行するために、ミニポート ドライバーは、 遅延プロシージャ 呼び出し (DPC) または割り込みサービス ルーチン (ISR) のいずれかを提供します。これは、間隔がシステム タイマーまたは DMA 駆動割り込みによって設定されるかどうかに応じて異なります。 後者の場合、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 イベントで説明したように、クライアントは、ストリームが特定の位置に達したとき、またはクロックが特定のタイム スタンプに達したときに通知されるように登録できます。 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 より古いオペレーティング システムの RUN から PAUSE への移行中にのみ発生します。 Windows XP 以降では、ストリームの状態が RUN から PAUSE に変わると、ポート ドライバーによって未処理の位置イベントがすぐに自動的に通知されます。 ただし、古いオペレーティング システムでは、ミニポート ドライバーは、ストリームが一時停止した直後に 通知 の最終的な呼び出しを行うことによって、未処理のイベントをトリガーする役割を担います。 詳細については、以下の「PAUSE/ACQUIRE Optimizations」を参照してください。

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

タイマー DPC

ドライバーは、ハードウェアで高速化された 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 メソッドへの呼び出しを常に生成します。 これらのオペレーティング システムでは、 サービス メソッドは、実際の作業に時間を費やす前に、ストリームが実行されているかどうかを確認する必要があります。 ただし、ミニポート ドライバーの 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 つ以上の軽量ストリームを作成できることを反映するために、使用可能なピン数が複数増加する可能性があります。