1 <10の比較は1 <1000000よりも安価ですか?


65

z-indexCSSのaのカウントとして〜10億を使用し、比較を検討する必要がありました。非常に大きな数値と非常に小さな数値との比較で、ALUレベルでパフォーマンスに違いはありますか?

たとえば、これら2つのスニペットのうちの1つは他のスニペットよりも高価ですか?

snippet 1

for (int i = 0; i < 10000000; i++){
    if (i < 10000000000000) {
        //do nothing
    }
}

snippet 2

for (int i = 0; i < 10000000; i++){
    if (i < 1000) {
        //do nothing
    }
}

9
分岐予測の仕組みを知っていますか?
ブヨ

12
OPは、分岐にかかる時間を尋ねていません。明らかに、この例は両方のスニペットでまったく同じ時間がかかるようにすることを目的としています。問題は、個々のCMP機械命令iが大きい場合に遅くなるかどうかです。
キリアンフォス

18
これはCSSで行われるため、文字列を整数に変換することは、実行に費やされる時間の観点から比較操作自体を支配する可能性があります。

58
CSSファイルでz-indexとして1000000000を使用する必要がある場合、何か間違ったことをしました。
ベルギ

6
CSSの場合、テキストを整数に変換するオーバーヘッドは、変換される桁数によって異なります(1000000のような6桁の数字は、1のような1桁の数字の約6倍の費用がかかる場合があります)。このオーバーヘッドは、整数比較のオーバーヘッドよりも桁違いに大きい場合があります。
ブレンダン

回答:


82

私が取り組んだすべてのプロセッサは、一方のオペランドを他方から減算し、結果を破棄し、プロセッサのフラグ(ゼロ、ネガティブなど)をそのままにして比較を行います。減算は単一の操作として行われるため、オペランドの内容は重要ではありません。

質問に確実に答える最良の方法は、コードをアセンブリにコンパイルし、生成された命令についてターゲットプロセッサのドキュメントを参照することです。現在のIntel CPUの場合、それはIntel 64およびIA-32アーキテクチャソフトウェア開発者マニュアルです。

説明CMP(「比較」)命令は、ボリューム2A、ページ3から126、またはPDFのページ618にあり、且つとしてその動作を説明します。

temp ← SRC1 − SignExtend(SRC2);
ModifyStatusFlags; (* Modify status flags in the same manner as the SUB instruction*)

これは、必要に応じて第2オペランドが符号拡張され、第1オペランドから減算され、結果がプロセッサの一時領域に配置されることを意味します。その後、ステータスフラグはSUB( "減算")命令(PDFのページ1492)の場合と同じ方法で設定されます。

そこには言及しませんCMPSUBオペランドの値は、待ち時間上の任意のベアリングを持っているドキュメントは、あなたが使用するすべての値が安全です。


5
数値が32ビット演算には大きすぎる場合はどうなりますか?その後、計算を遅くするために分割されないでしょうか?
ファルコ

3
@Falco 64ビットALUを搭載したCPUではありません(最近では組み込みスペースを除き、ほとんどすべてです)
reirab

8
@Falco:はい。ただし、質問はALUのパフォーマンスについて尋ねるため、値はCPUのワードサイズまたはSIMD命令の能力に収まるということです。CPUの外部で複数の命令を使用して実装する必要がある場合、それよりも大きい数で動作します。これは、30年前に8ビットまたは16ビットのレジスタを操作するだけでよく見られました。
Blrfl

6
@Falcoどのようにデバッグが必要ですか?これはバグではありません。64ビットopをネイティブにサポートしていないCPUで64ビットopを実行するのは少し遅くなります。2 ^ 31-1を超える数を使用してはならないことを示唆するのは少しばかげているように思えます。
reirab

2
@Falcoとは言っても、ブラウザーのレンダリングエンジンは整数を使用してz指数を表現しますか?私が精通しているほとんどのレンダリングエンジンは、すべてに単精度の浮動小数点数を使用します(最終的なラスタライズ段階まで)が、ブラウザーのレンダリングエンジンについては実際に研究していません。
-reirab

25

非常に大きな数値と非常に小さな数値との比較で、ALUレベルでパフォーマンスに違いはありますか?

多数の少数から行くことあなたの数値型を変更しない限り、それは、非常に低いですから、言うintまでlong。それでも、違いはそれほど大きくないかもしれません。プログラミング言語が隠れて任意の精度の算術演算に静かに切り替わると、違いが生じる可能性が高くなります。

それにもかかわらず、あなたの特定のコンパイラは、あなたが知らないいくつかの巧妙な最適化を実行しているかもしれません。調べる方法は測定することです。 コードでプロファイラーを実行します。どの比較に最も時間がかかるかを確認してください。または、単にタイマーを開始および停止します。


質問で提案されている数値は、典型的な32ビット整数型とは異なる数値型であることに注意してください
Falco

19

多くのプロセッサには、すぐに指定された特定のオペランドに対して比較などの算術演算を実行できる「小さな」命令があります。これらの特別な値以外のオペランドは、より大きな命令形式を使用するか、場合によっては「メモリから値をロードする」命令を使用する必要があります。たとえば、ARM Cortex-M3命令セットでは、少なくとも5つの方法で値を定数と比較できます。

    cmp r0,#1      ; One-word instruction, limited to values 0-255

    cmp r0,#1000   ; Two-word instruction, limited to values 0-255 times a power of 2

    cmn r0,#1000   ; Equivalent to comparing value with -1000
                   ; Two-word instruction, limited to values 0-255 times a power of 2

    mov r1,#30000  ; Two words; can handle any value 0-65535
    cmp r0,r1      ; Could use cmn to compare to values -1 to -65535

    ldr r1,[constant1000000] ; One or two words, based upon how nearby the constant is
    cmp r0,r1
    ...

constant1000000:
    dd  1000000

最初の形式は最小です。2番目と3番目の形式は、コードがフェッチされるメモリの速度に応じて、同じくらい速く実行される場合とされない場合があります。4番目の形式はほぼ確実に最初の3つより遅くなり、5番目の形式はさらに遅くなりますが、後者はどの32ビット値でも使用できます。

古いx86プロセッサでは、短い形式の比較命令は長い形式の命令よりも高速に実行されますが、多くの新しいプロセッサは、長い形式と短い形式の両方を最初にフェッチするときに同じ表現に変換し、その統一表現をキャッシュに保存します。したがって、組み込みコントローラ(多くのモバイルプラットフォームで見られるような)には速度の違いがありますが、多くのx86ベースのコンピュータには違いがありません。

また、ループ内で定数が頻繁に使用される多くの場合、コンパイラーは、定数をレジスターに一度ロードするだけで済みます-ループが開始する前に-タイミングの違いを議論する必要があります。一方、小さなループであっても、常に発生するとは限らない状況があります。ループが小さいが頻繁に実行される場合、短い即時値を含む比較と長い即時値を含む比較の間に大きなパフォーマンスが得られる場合があります。


MIPSでは16ビットのイミディエイトしか持てないため、1との比較は1000000よりも短く、おそらく(おそらく)高速になります。SparcとPowerPCでも同じかもしれません。また、いくつかのソースから、インテルはいくつかのケースで小規模なイミディエイトの操作を最適化することを読んだと思いますが、比較するかどうかは
わかり

@LưuVĩnhPhúc:ループの前にレジスタをロードできます。その時点で、実際の比較はどちらの場合も同じ数の命令になります。
cHao

ループはopによる単なる例であり、質問はたとえばz-indexであったため、1000個のオブジェクトがあり、それぞれに独自のz-indexがあり、100000000 ... 1000000999または10000 ...に設定した場合10999で、レンダリングの前に並べ替えのためにそれらをループすると、多くの比較と多くのロード命令があります。そこで違いを生むことができます!
ファルコ

@Falco:その場合、イミディエートは考慮されません。レジスタに対するロードと比較は、ほとんど避けられないようです。
cHao

@cHao:Zインデックスを互いに比較している場合、それらはレジスタにあります。特定の範囲のインデックスを異なる方法で処理している場合、即時の比較が必要になる場合があります。通常、定数はループの開始前にロードされますが、たとえば、メモリから値のペアを読み取り、各ペアの最初の値を100000の範囲の5つの異なる(不等間隔)定数と比較する必要があるループがある場合100499、および他の5つの定数を持つ他の値では、100250を減算(レジスタに保持)してから、値-250から250と比較するとはるかに高速になる場合があります
-supercat

5

この質問に対する簡単な答えは、いいえ、それらが同じデータ型に格納されていると仮定して、それらの数値の大きさに基づいて2つの数値を比較する時間差はありません(たとえば、両方の32ビット整数または両方の64ビット長)

さらに、ALUのワードサイズまでは、2つの整数を比較するのに1クロックサイクル以上かかることはほとんどありません。これは、減算と同等の簡単な操作だからです。私がこれまでに扱ったすべてのアーキテクチャには、シングルサイクル整数比較があったと思います。

2つの数値の比較が単一サイクル操作ではなかった場合に遭遇したと考えることができる唯一のケースは次のとおりです。

  • 実際にオペランドをフェッチする際にメモリレイテンシがある命令ですが、比較自体の動作とは関係ありません(通常、RISCアーキテクチャでは不可能ですが、通常x86 / x64などのCISC設計では可能です)。
  • アーキテクチャに応じて、浮動小数点比較はマルチサイクルになる場合があります。
  • 問題の数値はALUのワードサイズに適合しないため、比較は複数の命令に分割する必要があります。

4

@RobertHarveyの答えは良いです。この回答を彼の補足と考えてください。


分岐予測も考慮する必要があります。

コンピュータアーキテクチャでは、分岐予測子は、分岐(if-then-else構造など)が確実に知られる前にどの方向に進むかを推測しようとするデジタル回路です。分岐予測の目的は、命令パイプラインのフローを改善することです。分岐予測器は、x86などの多くの最新のパイプラインマイクロプロセッサアーキテクチャで高い効果的なパフォーマンスを達成する上で重要な役割を果たします。

基本的に、あなたの例でifは、ループ内のステートメントが常に同じ答えを返す場合、システムは分岐する方法を正しく推測することでそれを最適化できます。この例でifは、最初のケースのステートメントは常に同じ結果を返すため、2番目のケースよりもわずかに高速に実行されます。

件名に関する優れたスタックオーバーフローの質問


分岐予測は分岐時間に影響しますが、比較時間自体には影響しません。
reirab

3

それは実装に依存しますが、非常にありそうにないでしょう

さまざまなブラウザエンジンの実装の詳細を読んでいないことを認めます。CSSは、数値用の特定の種類のストレージを指定しません。しかし、主要なブラウザはすべて、64ビットの倍精度浮動小数点数(「double」、C / C ++から用語を借用)を使用して、CSSでの数値ニーズのほとんどを処理していると考えるのが安全だと思いますこれはJavaScriptが数値に使用するものであり、同じ型を使用すると統合が容易になるためです。

コンピューターの観点から見ると、すべてのdoubleは同じ量のデータ(値が1または-3.14または1000000または1e100であるかどうかに関係なく64ビット)を保持します。これらの数値を操作するのにかかる時間は、常に同じ量のデータを処理しているため、それらの数値の実際の値に依存しません。このように物事を行うにはトレードオフがあります。doublesはすべての数字(または範囲内のすべての数字)を正確に表すことができませんが、ほとんどの問題に対して十分に近づくことができ、CSSが行う種類のことは数字ではありません-それ以上の精度が必要なほど要求が厳しい。これとJavaScriptとの直接的な互換性の利点を組み合わせると、倍精度の非常に強力なケースが得られます。

数値に可変長エンコードを使用してCSSを実装することは不可能ではありません。誰かが可変長符号化を使用した場合は、その後、多数のクランチより多くのデータを持っているので、小さな数字と比較することは、大きな数字と比較するよりも安価になります。これらの種類のエンコードは、バイナリよりも正確ですが、非常に低速です。特にCSSの場合、精度の向上はおそらくパフォーマンスヒットに見合うほど十分ではありません。どんなブラウザでもこのように動作することを知って非常に驚いたでしょう。

さて、理論的には、私が上で述べたことすべてに1つの例外がありますゼロとの比較は、他の数値との比較よりも速いことがよくあります。これは、ゼロが短いためではありません(それが理由である場合、1は同様に高速であるべきですが、そうではありません)。ゼロはチートできるからです。これは、すべてのビットがオフになっている唯一の数値です。したがって、値の1つがゼロであることがわかっている場合、他の値を数値として見る必要さえありません。ゼロの場合は、1ビットだけを見て、ゼロより大きいか小さいかを確認します。


0

このコードは、それが実行するたびに解釈されていた場合、それはtokeniseと解釈するのに長い時間を要するとして、違いがあると思います10000000000000に比べて1000。ただし、これはこの場合のインタープリターの明らかな最初の最適化です:一度トークン化し、トークンを解釈します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.