C#にuint型の配列があります。プログラムがリトルエンディアンのマシンで動作しているかどうかを確認した後、データをビッグエンディアン型に変換したいと思います。データ量は非常に多くなる可能性がありますが、常に均等であるため、パフォーマンスを向上させてASMでプログラムするために、2つのuint型をulong型と見なすことを考えていたので、非常に高速(可能な場合は最速)を探しています。 )リトルエンディアンをビッグエンディアンに変換するアセンブラアルゴリズム。
3 に答える
大量のデータの場合は、bswap
命令 (Visual C++ の_byteswap_ushort
、_byteswap_ulong
、および_byteswap_uint64
組み込み関数で使用可能) が適しています。これは、手書きのアセンブリよりも優れています。これらは、P/Invoke を使用しない純粋な C# では使用できないため、次のようになります。
- これは、大量のデータからバイトへのスワップがある場合にのみ使用してください。
- マネージド C++ で最下位レベルのアプリケーション I/O を記述することを真剣に検討して、データをマネージド配列に取り込む前にスワッピングを実行できるようにする必要があります。既に C++ ライブラリを作成する必要があるため、失うものはほとんどなく、大規模なデータセットで動作する複雑さの低いアルゴリズムの P/Invoke 関連のパフォーマンスの問題をすべて回避できます。
PS: 多くの人は、バイト スワップの組み込み関数を認識していません。浮動小数点データは整数として処理されるため、そのパフォーマンスは驚くべきものです。1 バイト スワップのユース ケースごとにレジスタ ロードを手作業でコーディングせずにこれを打ち負かす方法はありません。それを試みると、オプティマイザでこれまでにない大きなヒットが発生する可能性があります。
問題を単純に再考することをお勧めします。これはボトルネックではありません。単純なアルゴリズムを取り上げます (楽しみのために CLI アセンブリで記述されています)。必要な番号がローカル番号0にあると仮定しましょう
LDLOC 0
SHL 24
LDLOC 0
LDC.i4 0x0000ff00
SHL 8
OR
LDLOC 0
LDC.i4 0x00ff0000
SHL.UN 8
OR
LDLOC 0
SHL.UN 24
OR
これは、1 つの数値につき最大で 13 (x86) のアセンブリ命令です (そしておそらく、インタプリタは賢いレジスタを使用することでさらに賢くなります)。そして、それはそれ以上に単純ではありません。
では、それを次のコストと比較してください。
- データをロードする (使用している周辺機器を含む!)
- データの操作 (たとえば、比較を行う)
- 結果の出力 (それが何であれ)
数値あたり 13 命令が実行時間のかなりの部分である場合、非常に高性能なタスクを実行していることになり、正しい形式で入力する必要があります。また、データのバッファーなどをより詳細に制御し、余分な配列の境界チェックを行いたくないため、おそらくマネージ言語を使用しないでしょう。
そのデータの配列がネットワークに渡った場合、単なるバイトオーダーのフリップよりもソケットの管理にはるかに大きなコストがかかると予想されます。ディスクからの場合は、このプログラムを実行する前に事前にフリップすることを検討してください。