11

32 ビット CPU では、整数は 4 バイトで、短整数は 2 バイトです。提供された短整数の範囲内に常に収まる多くの数値を使用する C/C++ アプリケーションを作成している場合、4 バイト整数と 2 バイト整数のどちらを使用する方が効率的ですか?

メモリから CPU へのバスの帯域幅に適合するため、4 バイト整数の方が効率的であると示唆されていると聞いたことがあります。ただし、2 つの短い整数を加算する場合、CPU は両方の値を 1 つのパスで並列にパッケージ化します (したがって、バスの 4 バイト帯域幅にまたがります)。

4

8 に答える 8

18

数値の配列が大きい場合は、機能する最小のサイズを使用してください。キャッシュ密度が 2 倍になるため、32 ビット int よりも 16 ビット short の配列を使用する方が効率的です。32 ビット レジスタで 16 ビット値を処理するために CPU が実行しなければならない符号拡張のコストは、キャッシュ ミスのコストに比べれば取るに足らないものです。

クラスでメンバー変数を他のデータ型と混合して使用している場合は、パディング要件によって 16 ビット値のスペース節約の利点が失われる可能性が高いため、あまり明確ではありません。

于 2008-10-02T16:28:09.773 に答える
15

はい、間違いなく 32 ビット CPU では 32 ビット整数を使用する必要があります。そうしないと、未使用のビットがマスクされてしまう可能性があります (つまり、常に 32 ビットで計算を行い、答えを 16 ビットに変換します)。

一度に 2 つの 16 ビット操作を実行することはできませんが、コードを自分で作成し、オーバーフローしないことが確実な場合は、自分で実行できます。

編集:「効率的」の定義にも多少依存することを追加する必要があります。32 ビット操作をより高速に実行できますが、もちろん、2 倍のメモリを使用します。

これらが内部ループの中間計算に使用されている場合は、32 ビットを使用します。ただし、これをディスクから読み取る場合、またはキャッシュ ミスの代償を払わなければならない場合でも、16 ビット整数を使用した方がうまくいく可能性があります。すべての最適化と同様に、知る方法は 1 つしかありません:プロファイルを作成することです。

于 2008-10-02T16:16:11.813 に答える
8

「多くの」整数値を使用している場合、処理のボトルネックはメモリへの帯域幅である可能性があります。16 ビット整数は、データ キャッシュにより密にパックされるため、パフォーマンスが向上します。

非常に大量のデータを計算している場合は、Ulrich Drepper によるWhat Every Programmer Should Know About Memoryを読む必要があります。データ キャッシュの効率を最大化する方法については、第 6 章に集中してください。

于 2008-10-02T16:39:01.137 に答える
5

32 ビット CPU は通常、内部で 32 ビット値を操作する CPU ですが、8/16 ビット値で同じ操作を実行する場合に遅くなるわけではありません。たとえば、x86 は 8086 まで下位互換性があり、レジスタの端数を操作できます。つまり、レジスターが 32 ビット幅であっても、そのレジスターの最初の 16 ビットまたは最初の 8 ビットでしか操作できず、速度がまったく低下しません。この概念は、レジスタが 64 ビットである x86_64 でも採用されていますが、最初の 32、16、または 8 ビットでしか動作できません。

また、x86 CPU は、まだキャッシュにない場合は常にメモリからキャッシュ ライン全体をロードし、いずれにしてもキャッシュ ラインは 4 バイトより大きい (32 ビット CPU の場合は 8 または 16 バイトではなく) ため、メモリから 2 バイトをロードするのと同じくらい高速です。メモリから 4 バイトを読み込みます。メモリから多くの値を処理する場合、メモリ転送が少ないため、16 ビット値は実際には 32 ビット値よりもはるかに高速になる場合があります。キャッシュ ラインが 8 バイトの場合、キャッシュ ラインごとに 4 つの 16 ビット値がありますが、32 ビット値は 2 つしかありません。したがって、16 ビット整数を使用すると、4 つの値ごとに 1 つのメモリ アクセスがあり、32 ビット整数を使用すると、2 つの値ごとに 1 つのメモリ アクセスがあります。となり、大きな int 配列を処理するための転送が 2 倍になります。

たとえば PPC などの他の CPU は、レジスタの一部のみを処理することはできず、常に完全なレジスタを処理します。しかし、これらの CPU には通常、メモリから 16 ビット値をロードし、それを 32 ビットに拡張してレジスタに書き込むなど、特別なロード操作があります。その後、レジスタから値を取得し、最後の 16 ビットのみをメモリに格納する特別なストア操作があります。どちらの操作も、32 ビットのロード/ストアが必要とするのと同じように、1 つの CPU サイクルしか必要としないため、速度の違いもありません。また、PPC はレジスタでしか算術演算を実行できないため (x86 とは異なり、メモリを直接操作することもできます)、このロード/ストア手順は、32 ビット整数または 16 ビット整数のどちらを使用しても実行されます。

唯一の欠点は、フル レジスタでしか操作できない 32 ビット CPU で複数の操作をチェーンする場合、次の操作を実行する前に、最後の操作の 32 ビットの結果を 16 ビットに「カットバック」する必要がある場合があることです。そうしないと、結果が正しくない可能性があります。ただし、このような削減は 1 つの CPU サイクルにすぎません (単純な AND 演算)。コンパイラは、そのような削減が本当に必要な場合と、省略した場合に最終結果に影響を与えない場合を判断するのが得意です。 、したがって、そのようなカットバックはすべての命令の後に実行されるのではなく、本当にやむを得ない場合にのみ実行されます。一部の CPU は、そのようなカットバックを不要にするさまざまな「強化された」命令を提供します。私は、生成されたアセンブリ コードを見て、そのようなカットバックを期待していた私の人生でたくさんのコードを見てきました。

したがって、ここで一般的なルールを期待している場合は、がっかりする必要があります。16 ビット操作が 32 ビット操作と同等に高速であると断言することも、32 ビット操作が常に高速であると断言することもできません。それはまた、あなたのコードがそれらの数字で何をしているのか、そしてそれがどのようにそれをしているのかにも依存します. 特定の 32 ビット CPU で 32 ビット操作が 16 ビット操作の同じコードよりも高速であるというベンチマークを見たことがありますが、その反対が当てはまることも既に確認しました。あるコンパイラから別のコンパイラに切り替えたり、コンパイラのバージョンをアップグレードしたりしても、すべてが元に戻る場合があります。私が言えることは次のことだけです: short での作業は int での作業よりも大幅に遅いと主張する人は誰でも、その主張のサンプル ソース コードを提供し、テストに使用した CPU とコンパイラの名前を付けてください。過去 10 年ほどの間、そのようなことは一度も経験したことがないからです。int を使用した方がおそらく 1 ~ 5% 速い場合もありますが、10% 未満のものは「重要」ではなく、問題は、場合によってはメモリを 2 倍無駄にする価値があるかということです。 2%のパフォーマンス?私はそうは思わない。

于 2012-08-24T18:31:07.060 に答える
3

アドバイスを聞かないで、試してみてください。

これは、使用しているハードウェア/コンパイラに大きく依存する可能性があります。簡単なテストで、この質問を簡単に解決できるはずです。おそらく、ここに質問を書くよりもテストを書く時間が少ないでしょう。

于 2009-12-05T22:58:56.367 に答える
3

It depends. If you are CPU bound, 32 bit operations on a 32 bit CPU will be faster than 16 bit. If you are memory bound (specifically if you have too many L2 cache misses), then use the smallest data you can squeeze into.

You can find out which one you are using a profiler that will measure both CPU and L2 misses like Intel's VTune. You will run your app 2 times with the same load, and it will merge the 2 runs into one view of the hotspots in your app, and you can see for each line of code how many cycles were spent on that line. If at an expensive line of code, you see 0 cache misses, you are CPU bound. If you see tons of misses, you are memory bound.

于 2008-10-02T16:34:42.817 に答える
1

32ビットと言えば、x86を意味すると思います。16 ビット演算は非常に遅くなります。オペランド サイズのプレフィックスにより、デコードが非常に遅くなります。そのため、一時変数を短い int または int16_t にしないでください。

ただし、x86 では、16 ビットおよび 8 ビットの整数を 32 ビットまたは 64 ビットのレジスタに効率的にロードできます。(movzx / movsx: ゼロおよび符号拡張)。そのため、配列と構造体フィールドには short int を自由に使用できますが、temp 変数には必ず int または long を使用してください。

ただし、2 つの短い整数を加算する場合、CPU は両方の値を 1 つのパスで並列にパッケージ化します (したがって、バスの 4 バイト帯域幅にまたがります)。

それはナンセンスです。ロード/ストア命令は L1 キャッシュと対話し、制限要因は ops の数です。幅は関係ありません。例: core2: 幅に関係なく、サイクルごとに 1 回のロードと 1 回のストア。L1 キャッシュには、L2 キャッシュへの 128 ビットまたは 256 ビットのパスがあります。

ロードがボトルネックである場合は、ロード後にシフトまたはマスクで分割する 1 つの幅の広いロードが役立ちます。または、SIMD を使用して、並列ロード後にアンパックせずにデータを並列処理します。

于 2009-12-05T22:52:31.433 に答える
1

If you are operating on a large dataset, the biggest concern is memory footprint. A good model in this case is to assume that the CPU is infinitely fast, and spend your time worrying about how much data has to be moved to/from memory. In fact, CPUs are now so fast that it is sometimes more efficient to encode (e.g., compress) the data. That way, the CPU does (potentially much) more work (decoding/coding), but the memory bandwidth is substantially reduced.

Thus, if your dataset is large, you are probably better off using 16 bit integers. If your list is sorted, you might design a coding scheme that involves differential or run-length encoding, which will reduce memory bandwidth even more.

于 2008-10-02T16:38:12.980 に答える