9

オーディオのピークメーターをリアルタイムで描画する必要があります。1秒あたり最小44100サンプル×最小40ストリーム。各バッファは64〜1024サンプルです。各バッファーからabsmaxを取得する必要があります。(これらは、一種のローパスフィルターを介して供給され、約20ms間隔で描画されます。)

for(int i = 0; i < numSamples; i++)
{ 
      absMaxOfBuffer = MAX( fabs( buffer[i] ), absMaxOfBuffer);
}

それが私が今それをする方法です。もっと早くやりたいです。バッファには-1から1の範囲のフロートがあるため、ファブがあります。

質問、これをより速く行うためのトリッキーなcomp-sciクイックソート風の方法はありますか?

それができない場合、フロート用のブランチレスABSおよびMAX関数は存在しますか?

編集:プライマリプラットフォームはLinux / gccですが、Windowsポートが計画されています(おそらくmingwを使用)。

編集、2番目:
質問の中心であった実際のアルゴ構造に関するビットのために、私は1人ずつ受け入れました。
ループを一度に4に展開し、符号ビットをゼロにしてから、SSE(maxps命令)で最大値を取得して、バナナが剥がれないかどうかを確認します。提案をありがとう、私は次点者としてあなたの何人かに賛成票を投じました。:)

4

7 に答える 7

5

ファブと比較はどちらもIEEEフロートに対して非常に高速です(たとえば、原則として単一整数演算が高速です)。

コンパイラが両方の操作をインライン化していない場合は、インライン化するまでそれを突くか、アーキテクチャの実装を見つけて自分でインライン化します。

のIEEEフロートが同じビットパターンの整数と同じ順序で実行されるという事実から、何かを得ることができるかもしれません。あれは、

f > g   iff   *(int*)&f > *(int*)&g

したがって、ファブを作成したら、intのブランチフリーmaxはfloatでも機能すると思います(もちろん同じサイズであると仮定します)。これが機能する理由の説明がここにあります:http ://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm 。ただし、CPUと同様に、コンパイラはこれらすべてをすでに認識しているため、違いがない場合があります。

複雑さはありません-それを行うためのより速い方法。あなたのアルゴリズムはすでにO(n)であり、それを打ち負かすことはできず、それでもすべてのサンプルを見ることができます。

おそらく、プロセッサのSIMD(つまり、IntelのSSE2)には、コードよりもクロックサイクルごとに多くのデータを処理することで役立つものがあると思います。しかし、私は何を知りません。ある場合は、おそらく数倍速くなります。

とにかく40の独立したストリームを扱っているので、おそらくマルチコアCPUで並列化できます。それはせいぜいいくつかの要因より速くなるでしょう。「ただ」適切な数の追加のスレッドを起動し、それらの間で作業を分割し、それらがすべて完了したことを示すことができる最も軽量のプリミティブを使用します(おそらくスレッドバリア)。40のストリームすべての最大値をプロットするのか、それぞれの最大値を個別にプロットするのかはよくわかりません。そのため、結果が次のステージに確実に配信されるようにする以外に、実際にワーカースレッドを同期する必要はないかもしれません。データ破壊なし。

逆アセンブルを調べて、コンパイラーがループをどれだけ展開したかを確認することはおそらく価値があります。もう少し展開してみて、違いが生じるかどうかを確認してください。

もう1つ考慮すべきことは、取得しているキャッシュミスの数と、キャッシュにいくつかの手がかりを与えて適切なページを事前にロードできるようにすることで、その数を減らすことができるかどうかです。しかし、私はこれについての経験がなく、あまり希望を持ちません。__builtin_prefetchはgccの魔法の呪文であり、最初の実験は「このブロックのループに入る前に次のブロックの先頭をプリフェッチする」ようなものになると思います。

現在、必要な速度の何パーセントですか?それとも「できるだけ早く」の場合ですか?

于 2009-05-03T18:30:59.300 に答える
2

試すべきこと:

  • fabs()はインライン関数ではない可能性があります。
  • 特別な組み立て手順が役立つ場合があります。Intelでは、SSEには、一度に最大4つのfloatを計算する命令があります。
  • それができない場合、IEEE 754仕様では、aとbが非負の浮動小数点数である場合、a <bは*(int *)&a <*(int *)&bと同等になります。さらに、任意のaについて、MSBを反転することでaから-aを計算できます。一緒に、これらのプロパティはいくつかのビットをいじるハックを可能にするかもしれません。
  • 本当にすべてのサンプルの最大値が必要ですか?おそらく、最大値が複数回発生する可能性があり、すべての入力を調べない可能性があります。
  • ストリーミング方式で最大値を計算できますか?
于 2009-05-03T18:34:13.537 に答える
2

http://www.scribd.com/doc/2348628/The-Aggregate-Magic-Algorithmsに文書化されたブランチレスファブがあります

fabsまた、最近のバージョンのGCCは、MMX命令を使用して、ブランチレスをインライン化することに注意してください。およびもありますがfminfmaxGCCはそれらをインライン化しません(を取得しますcall fmin)。

于 2009-05-03T18:35:43.767 に答える
1

あなたはEigenを見たいかもしれません。

これは、 SSE(2以降)およびAltiVec命令セットを使用するC ++テンプレートライブラリであり、ベクトル化されていないコードへの適切なフォールバックを備えています。

速い。(ベンチマークを参照)。
式テンプレートを使用すると、適切な場合に一時的なものをインテリジェントに削除して遅延評価を有効にできます。Eigenはこれを自動的に処理し、ほとんどの場合、エイリアシングも処理します。
明示的なベクトル化は、SSE(2以降)およびAltiVec命令セットに対して実行され、ベクトル化されていないコードへの適切なフォールバックが行われます。式テンプレートを使用すると、式全体に対してこれらの最適化をグローバルに実行できます。
固定サイズのオブジェクトを使用すると、動的メモリ割り当てが回避され、必要に応じてループが展開されます。
大きな行列の場合、キャッシュの使いやすさに特別な注意が払われます。

于 2009-05-04T03:54:23.627 に答える
0

私が見る簡単な最適化:

  • ループをポインター演算バージョンに変換します(コンパイラーがこれを認識しないと仮定します)
  • IEEE 754標準では、その表現を符号の大きさとして定義しています。したがって、最上位ビットを0に設定することは、fabs()を呼び出すことと同じです。たぶん、この関数はすでにこのトリックを使用しています。
于 2009-05-03T18:47:16.297 に答える
0

あなたの目的のために、絶対値を取る代わりにそれを二乗することができます。数学的に|a| <| b | a ^ 2 <b ^ 2の場合、およびその逆の場合。一部のマシン(?)では、乗算はfabs()よりも高速である可能性があります。

于 2009-05-04T06:29:27.157 に答える
0

別の質問で質問に答えることは正確に答えることではありませんが、ちょっと...私もC++開発者ではありません。

これをC++で開発していて、dspを実行しているので、matlabまたはoctave(オープンソース)に接続して、数学に接続して結果を得ることができませんか?

これらのソフトウェアには、すでに関数(conv、fft、ifft、fir、およびfreqz、stem、graph、plot、meshなどのプロットutil関数など)が実装されています。Photoshopを調べたところ、MATLABという大きなフォルダーがあります...アプリケーションから呼び出しを取得し、動的なmatlabに送信して、結果をアプリケーションに返す.mファイルがいくつかあります。

それが役に立てば幸い。

于 2009-05-03T18:30:31.923 に答える