オーディオ レイテンシの原因

このページでは、出力レイテンシに焦点を当てて説明していますが、入力レイテンシについても同じことが当てはまります。

アナログ回路による影響が少ないと仮定した場合、表層レベルでのオーディオ レイテンシの主な原因は次のとおりです。

  • アプリ
  • パイプライン内のバッファの総数
  • 各バッファのサイズ(フレーム数)
  • アプリ プロセッサの後に発生する追加のレイテンシ(DSP からなど)

上記のリストを参照した場合でも、原因の特定が困難なことがあります。 その理由は、バッファ数とバッファサイズによる「影響」が「原因」として認識されるよりも大きいためです。通常は、任意のバッファ スキームを用いてテストを行いますが、テスト中に発生したオーディオ アンダーランまたはオーバーランはクリック音やポップ音として聞こえます。これを補正するため、システムの設計者はバッファサイズまたはバッファ数を増やします。その結果、アンダーランまたはオーバーランは発生しなくなりますが、レイテンシが増加するという副次的な作用がもたらされます。バッファサイズの詳細については、オーディオ レイテンシ: バッファサイズ(英語)を参照してください。

この場合、アンダーランとオーバーランの原因を特定し、修正することがより効果的です。これにより、可聴アーティファクトがなくなり、バッファ数を減らしてレイテンシを削減できます。

これまでの経験から、最も一般的なアンダーランとオーバーランの原因は次のとおりです。

  • Linux の CFS(Completely Fair Scheduler)
  • SCHED_FIFO スケジューリングによる高優先度スレッド
  • 優先度の逆転
  • 長時間のスケジューリング レイテンシ
  • 実行時間の長い割り込みハンドラ
  • 長時間の割り込み禁止時間
  • 電源管理
  • セキュリティ カーネル

Linux の CFS スケジューリングと SCHED_FIFO スケジューリング

Linux の CFS は、共通の CPU リソースを共有する競合したワークロードが均等になるように設計されています。この均等性は、スレッドごとに nice パラメータとして表されます。 nice 値の範囲は、-19(最小の nice 値、または最も多くの CPU 時間を割り当て)から 20(最適な CPU 時間を割り当て)までとなります。通常、任意の nice 値を持つすべてのスレッドはほぼ同等の CPU 時間を受け取り、低い nice 値を持つスレッドはより多くの CPU 時間を受け取るようになっています。ただし、CFS は比較的長期間に及ぶモニタリングを通して「均等性」を提供するため、短期的なモニタリングの場合、CFS は想定されない方法で CPU リソースを割り当てます。たとえば、数値が低い nice を持つスレッドから高い数値の nice を持つスレッドに CPU が割り当てられる場合もあります。このような場合、オーディオのアンダーランやオーバーランが発生する可能性があります。

確実な解決方法としては、高性能オーディオ スレッドの CFS を回避することがあげられます。Android 4.1 以降、このようなスレッドでは、CFS によって用いられる SCHED_NORMALSCHED_OTHER とも呼ばれます)スケジューリング ポリシーではなく、SCHED_FIFO スケジューリング ポリシーが使用されるようになりました。

SCHED_FIFO の優先度

高性能オーディオ スレッドでは現在 SCHED_FIFO が使用されていますが、依然として優先度の高い他の SCHED_FIFO スレッドの影響を受けやすい状態です。これらのスレッドは通常、カーネル ワーカー スレッドですが、ポリシー SCHED_FIFO を使用したオーディオ以外のユーザー スレッドが一部存在する場合があります。利用可能な SCHED_FIFO 優先度の範囲は 1~99 です。オーディオ スレッドは優先度 2 または 3 で実行されます。これにより、優先度 1 が優先度の低いスレッドで、また、優先度 4~99 は優先度の高いスレッドで使用可能になります。可能な限り優先度は 1 を使用し、制限された時間内に完了することが保証されること、オーディオ スレッドの周期よりも短い周期で実行されること、オーディオ スレッドのスケジューリングに干渉しないことがわかっているスレッドには、優先度 4~99 を予約することをおすすめします。

レートモノトニック スケジューリング

固定優先度の割り当てに関する理論については、Wikipedia の記事レートモノトニックス スケジューリング(RMS)を参照してください。重要なのは、固定優先度は知覚される「重要度」ではなく、より高い優先度を持つ周期に基づいて短い周期のスレッドへ厳密に割り当てられるということです。非周期的スレッドは、実行の最大頻度と各実行の最大計算を使用して、周期的スレッドとしてモデル化することができます。周期的スレッドとして非周期的スレッドをモデル化できない場合(たとえば、実行ごとに無制限の頻度または無制限の計算で実行できる場合)は、真の周期的スレッドのスケジューリングと互換性を持たないため、固定優先度を割り当てないようにしてください。

優先順位の逆転

優先順位の逆転は、リアルタイム システムで昔から存在する障害モードです。この障害では、優先順位の低いタスクがミューテックスのような(共有状態がロックされた)リソースを解放するまで、優先順位の高いタスクが無期限にブロックされてしまいます。これを緩和するには、優先度の逆転を回避するを参照してください。

スケジューリング レイテンシ

スケジューリング レイテンシとは、スレッドが実行可能な状態になってから、その結果としてコンテキストの切り替えが完了してスレッドが実際に CPU 上で実行されるまでの時間です。レイテンシが短いほど良好で、2 ミリ秒を超える場合はオーディオで問題が発生します。CPU の起動またはシャットダウン、セキュリティ カーネルと通常のカーネルの切り替え、フルパワー モードから低電力モードへの切り替え、CPU クロック周波数と電圧の調整といったモードの移行中に長時間のスケジューリング レイテンシが発生する可能性が最も高くなります。

割り込み

多くの設計において、CPU 0 はすべての外部割り込みを処理します。そのため、長時間実行の割り込みハンドラによって他の割り込み、特にオーディオ Direct Memory Access(DMA)完了割り込みが遅延する可能性があります。迅速に終了するためには、割り込みハンドラを設計して長時間の作業をスレッド(可能であれば優先度 1 の CFS スレッドまたは SCHED_FIFO スレッド)に委ねるようにします。

同様に、CPU 0 での割り込みを長時間無効にすることは、オーディオ割り込みの処理を遅延させることと同じ結果をもたらします。カーネルのスピンロックを待機している間は、長時間の割り込み無効化時間が発生します。こうしたスピンロックが制限されていることを確認します。

電力、パフォーマンス、温度の管理

電力管理とは、パフォーマンスの最適化を行いながら消費電力を監視および削減する取り組みという広い意味合いを持つ用語です。温度の管理コンピュータ冷却は似ていますが、どちらも温度の測定と制御を行い、過剰な熱による損傷を防ぐためのものです。Linux カーネルでは、CPU ガバナーが低レベルのポリシーを処理し、ユーザーモードが高レベルのポリシーを構成します。使用される手法は次のとおりです。

  • 動的電圧スケーリング
  • 動的周波数スケーリング
  • 動的コア有効化
  • クラスタ切り替え
  • パワー ゲーティング
  • hotplug(ホットスワップ)
  • 各種のスリープモード(中断、停止、アイドル、サスペンドなど)
  • プロセスの移行
  • プロセッサ アフィニティ

一部の管理操作により、「作業停止」またはアプリケーション プロセッサによって実行される有用な作業がない時間が発生する可能性があります。作業停止が音声に干渉する可能性があるため、このような管理操作については、音声がアクティブである間の許容可能な最悪のケースの作業停止に合わせて設計する必要があります。しかし、熱暴走の危険性がある場合は、音声よりも恒久的な損傷を避けることが重要です。

セキュリティ カーネル

デジタル著作権管理(DRM)のセキュリティ カーネルは、メインのオペレーティング システム カーネルおよびアプリケーション コードに使用されるものと同一のアプリケーション プロセッサ コアで実行されます。コア上でセキュリティ カーネル操作がアクティブになると、通常はそのコアで実行される通常の作業が事実上停止します。これには特に音声作業が含まれます。その性質上、セキュリティ カーネルの内部動作は上位層から検知不可能であるため、セキュリティ カーネルに起因するパフォーマンス異常は特に有害です。たとえば、セキュリティ カーネルによる操作は、通常、コンテキスト切り替えのトレースには表示されません。これは「暗黒の時間」(経過したがモニタリングできない時間)と呼ばれます。セキュリティ カーネルは、音声がアクティブである間の許容可能な最悪のケースの作業停止に合わせて設計する必要があります。