web-dev-qa-db-ja.com

Cortex A9NEONとVFPの使用上の混乱

Cortex A9 ARMプロセッサ(より具体的にはOMAP4)のライブラリを構築しようとしていますが、NEONとVFPのどちらをいつ使用するかについて少し混乱しています。浮動小数点演算とSIMDのコンテキストで。2つのハードウェアコプロセッサユニットの違いを知っていることに注意してください(これも概説されています ここではSO )、それらの適切な使用法について誤解があります。

これに関連して、次のコンパイルフラグを使用しています。

GCC
-O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp
ARMCC
--cpu=Cortex-A9 --apcs=/softfp
--cpu=Cortex-A9 --fpu=VFPv3 --apcs=/softfp

ARMドキュメント、多くのwiki( このような )、フォーラム、ブログの投稿を読みましたが、NEONを使用する方が優れていることに誰もが同意しているようです。 VFPを使用するか、少なくともNEONを混合する(たとえば、本能を使用してSIMDにいくつかのアルゴリズムを実装する)とVFPはあまり良い考えではありません。これがアプリケーション/ライブラリ全体のコンテキストに当てはまるのか、それともコード内の特定の場所(関数)に。

したがって、組み込み関数も使用したいので、アプリケーションのFPUとしてネオンを使用しています。その結果、私は少し問題を抱えており、Cortex A9でこれらの機能(NEONとVFP)を最適に使用する方法についての混乱は、解決するのではなく、さらに深くなっています。アプリのベンチマークを実行し、計算が倍精度浮動小数点に基づくカスタムメイドのタイマークラスを使用するコードがいくつかあります。 NEONをFPUとして使用すると、完全に不適切な結果が得られます(これらの値を印刷しようとすると、ほとんどがinfとNaNが印刷されます。同じコードは、x86用にビルドした場合に問題なく機能します)。そこで、計算を変更して、単精度浮動小数点を使用するようにしました。NEONは倍精度浮動小数点を処理しないことが文書化されています。私のベンチマークはまだ適切な結果を出していません(そして最悪なのは、x86では機能しなくなったことです。精度が低下したためだと思いますが、よくわかりません)。そのため、私はほぼ完全に迷子になっています。SIMD機能にNEONを使用したいのですが、FPUでは適切な結果が得られないため、NEONを使用する一方で、VFPと混合するのはあまり良い考えではないようです。この分野でのアドバイスは大歓迎です!!

上記のwikiの記事で、NEONのコンテキストで浮動小数点最適化のために何をすべきかについての要約を見つけました。

「」

  • 単精度浮動小数点のみを使用してください
  • ボトルネックを見つけたときはいつでもNEON組み込み関数/ ASMを使用してくださいFP関数。コンパイラよりも優れた方法を実行できます。
  • 条件分岐を最小化する
  • RunFastモードを有効にする

Softfpの場合:

  • インライン浮動小数点コード(非常に大きい場合を除く)
  • FP引数を値ではなくポインターを介して渡し、関数呼び出しの間に整数の作業を行います。

「」

利用可能なライブラリとリンクできないため、floatABIにハードに使用することはできません。ほとんどの推奨事項は私には理にかなっています(何をすべきかを正確に理解していない「実行モード」と、現時点ではコンパイラよりもうまくいく可能性があるという事実を除いて)が、一貫性のない結果が得られ続け、今は何もわかりません。

Cortex A9/A8の浮動小数点とNEONを適切に使用する方法と、どのコンパイルフラグを使用する必要があるかについて誰かが光を当てることができますか?

20
celavek

...フォーラムやブログの投稿、そして誰もがNEONを使用する方がVFPを使用するよりも優れている、または少なくともNEONを混合する(たとえば、本能を使用してSIMDにいくつかのアルゴリズムを実装する)ことに同意しているようですが、VFPはそれほど良い考えではありません

これが正しいかどうかはわかりません。 ARM at NEON開発記事の紹介| NEONレジスタ

NEONレジスタバンクは、32個の64ビットレジスタで構成されています。 Advanced SIMDとVFPv3の両方が実装されている場合、それらはこのレジスタバンクを共有します。この場合、VFPv3は、32個の倍精度浮動小数点レジスタをサポートするVFPv3-D32形式で実装されます。この統合により、VFPコンテキストを保存および復元するのと同じルーチンがNEONコンテキストも保存および復元するため、コンテキスト切り替えサポートの実装が簡素化されます。

NEONユニットは、次と同じレジスタバンクを表示できます。

  • 16個の128ビットクアッドワードレジスタ、Q0〜Q15
  • 32個の64ビットダブルワードレジスタ、D0〜D31。

NEOND0-D31レジスタはVFPv3D0-D31レジスタと同じであり、Q0-Q15レジスタのそれぞれがDレジスタのペアにマップされます。図1.3は、共有NEONおよびVFPレジスタバンクのさまざまなビューを示しています。これらのビューはすべていつでもアクセスできます。使用される命令が適切なビューを決定するため、ソフトウェアはそれらを明示的に切り替える必要はありません。

レジスターは競合しません。むしろ、それらはレジスターバンクのビューとして共存します。 NEONとFPUのギアを分解する方法はありません。


これに関連して、次のコンパイルフラグを使用しています。

-O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp

これが私がすることです。あなたのマイレージは異なる場合があります。これは、プラットフォームとコンパイラから収集された情報のマッシュアップから派生したものです。

gnueabihfは、プラットフォームがハードフロートを使用していることを示しています。これにより、手続き型呼び出しを高速化できます。疑わしい場合は、ハードフロートと互換性があるため、softfpを使用してください。

BeagleBone Black

$ gcc -v 2>&1 | grep Target          
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
model name  : ARMv7 Processor rev 2 (v7l)
Features    : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32 
...

したがって、BeagleBoneは以下を使用します。

-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard

CubieTruck v5

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
Processor   : ARMv7 Processor rev 5 (v7l)
Features    : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 

したがって、CubieTruckは以下を使用します。

-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard

Banana Pi Pro

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
Processor   : ARMv7 Processor rev 4 (v7l)
Features    : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt

したがって、BananaPiは次のものを使用します。

-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard

Raspberry Pi 3

RPI3は、ARMv8という点で独特ですが、32ビットOSを実行しています。つまり、事実上32ビットARMまたはAarch32です。32ビットにはもう少しありますARM vs Aarch32、ただしこれによりAarch32フラグが表示されます

また、RPI3はBroadcom A53 SoCを使用し、NEONとオプションのCRC32命令がありますが、オプションのCrypto拡張機能はありません。

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo 
model name  : ARMv7 Processor rev 4 (v7l)
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
...

したがって、RaspberryPiは次のものを使用できます。

-march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard

または使用できます(-mtuneに何を使用すればよいかわかりません):

-march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard 

ODROID C2

ODROIDC2はAmlogicA53 SoCを使用しますが、64ビットOSを使用します。 ODROID C2には、NEONとオプションのCRC32命令がありますが、オプションのCrypto拡張機能(RPI3と同様の構成)がありません。

$ gcc -v 2>&1 | grep Target 
Target: aarch64-linux-gnu

$ cat /proc/cpuinfo 
Features    : fp asimd evtstrm crc32

したがって、ODROIDは以下を使用します。

-march=armv8-a+crc -mtune=cortex-a53

上記のレシピでは、データシートを調べてARMプロセッサ(Cortex A9やA53など)を学習しました。 nixおよびLinux Stack Exchange に関するこの回答によると、 /proc/cpuinfoからの出力を解読します:

CPUパーツ:パーツ番号。 0xd03は、Cortex-A53プロセッサを示します。

したがって、データベースから値を検索できる場合があります。それが存在するかどうか、どこにあるのかわかりません。

8
jww

この質問はいくつかに分割し、いくつかのコード例を追加し、ターゲットプラットフォームと使用するツールチェーンのバージョンを詳しく説明する必要があると思います。

しかし、混乱の一部をカバーするために:「FPUとしてNEONを使用する」という推奨は誤解のように聞こえます。 NEONはSIMDエンジンであり、VFPはFPUです。 NEONは、最大4つの単精度値を並列で単精度浮動小数点演算に使用できます。これは(可能な場合)パフォーマンスに優れています。

-mfpu=neonは、-mfpu=neon-vfpv3の省略形と見なすことができます。

詳細については、 http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html を参照してください。

8
unixsmurf

私はVFPに近づかないでしょう。これはThmubモードと同じです。コンパイラー向けです。それらを最適化しても意味がありません。

失礼に聞こえるかもしれませんが、NEON組み込み関数にもまったく意味がありません。それは助けよりも厄介です-もしあれば。

基本的なARMアセンブリに2、3日投資するだけです。ループ制御/終了の手順をいくつか学ぶだけで済みます。

そうすれば、コンパイラが大量のエラーや警告を吐き出すような何かをすることを心配せずに、ネイティブNEONコードの記述を開始できます。

NEON命令の学習は、これらすべての組み込みマクロよりも要求が少なくなります。そして、これ以上に、結果ははるかに優れています。

完全に最適化されたNEONネイティブコードは、通常、適切に記述された組み込み関数の2倍以上の速度で実行されます。

以下のリンクでOPのバージョンと私のバージョンを比較するだけで、私が何を意味するのかがわかります。

NEONを使用したRGBA8888からRGB565への変換の最適化

よろしく