特定のコンピューターシステムが与えられた場合、アセンブリコードの実際の正確な実行時間を推定することは可能ですか?


23

これはアセンブリコードの一部です

section .text
    global _start       ;must be declared for using gcc
_start:                     ;tell linker entry point
    mov edx, len    ;message length
    mov ecx, msg    ;message to write
    mov ebx, 1      ;file descriptor (stdout)
    mov eax, 4      ;system call number (sys_write)
    int 0x80        ;call kernel
    mov eax, 1      ;system call number (sys_exit)
    int 0x80        ;call kernel

section .data

msg db  'Hello, world!',0xa ;our dear string
len equ $ - msg         ;length of our dear string

特定のコンピューターシステムを前提として、アセンブリコードの実際の実行時間を正確に予測することは可能ですか。


30
「そのコンピューターでコードを実行し、ストップウォッチを使用する」ことは有効な答えですか?
ドラコニス

4
このコードの実行に費やされる時間の大半は、I / Oを待機していると思われます。個々の命令を実行するのにかかる時間は、コードのメモリ位置とプロセッサに関するすべての詳細(最近では非常に複雑です)を知っていればある程度予測可能ですが、速度はメモリとディスクの影響も受けるため、 dについても非常に多くの詳細を知る必要があります。したがって、物理的な現象(時間にも影響を与える)を考慮しない限り、予測可能ですが、そうすることは想像を絶するほど難しいと言えます。
IllidanS4は、

4
推定は常に可能です...
sudo rm -rf slash

3
停止の問題が原因でこれも不可能ではありませんか?一部のコードについては、停止するかどうかを証明できますが、考えられるすべてのコードについてこれを決定するアルゴリズムを持つことはできません。
kutschkem

2
@Falcoこれは、特定のシステムのプロパティです。一部の独立したC実装には、オペレーティングシステムがありません。実行中のすべては、入力のためにハードウェアアドレスから読み取る場合と読み取らない場合があるメインループ(またはループでさえない;-))です。
ピーター-モニカの復活

回答:


47

1986年頃の68020プロセッサというかなり原始的なCPUのマニュアルから引用できるのは、「プロセッサの実装に関する正確な知識がある場合でも、命令シーケンスの正確な実行時間を計算することは困難です」です。持っていないもの。そして、最新のプロセッサーと比較して、そのCPUは原始的でした。

そのコードの実行時間を予測することはできません。また、予測することもできません。しかし、プロセッサに大量のキャッシュと大量の異常機能がある場合、コードの「実行時」を定義することさえできません。典型的な最新のプロセッサは、「実行中」、つまり実行のさまざまな段階にある200個の命令を持つことができます。そのため、最初の命令バイトを読み取ってから最後の命令を廃止するまでの時間が非常に長くなる可能性があります。ただし、プロセッサが実行する必要のある他のすべての作業に対する実際の遅延は、はるかに少ない可能性があります(通常はそうです)。

もちろん、オペレーティングシステムに対して2つの呼び出しを行うと、これはまったく予測不可能になります。「標準出力への書き込み」が実際に何をするのかわからないため、時間を予測することはできません。

また、コードを実行した正確な瞬間にコンピューターのクロック速度を知ることはできません。いくつかの省電力モードになっている可能性があります。コンピューターは、高温になったためにクロック速度が低下している可能性があります。

全体として:完全に予測不可能です。


11
あなたの結論は強すぎると思います。遅延とスループットは、プログラムの「実行時」を測定する一般的な指標です。また、「ランタイム」の適切な定義に単純に落ち着くことができます。さらに、システム状態、ハードウェアおよびソフトウェアの完全なスナップショット、およびCPU内部の完全な知識がある場合は、ランタイムを予測できます。インテルでは、おそらくランタイムを見積もることができます。ここでも、サイクル精度でレイテンシとスループットを予測できます。この場合、syscallsに加えて、それほど難しくありません。
マーガレットブルーム

9
@MargaretBloomもそうではありません。携帯電話をオーブンに近づけすぎて、CPUが温度を管理するためにアンダークロックします。ランタイムの推定値が突然低すぎます。また、サイクルを数えてsyscallを行わない場合でも、他のスレッドとCPUがRAMの内容をうまく処理したり、スワップアウト中に予測不可能な状況に基づいてメモリからハードドライブにダンプしたりすることがあります。競合するスレッドがあなたのメモリを破壊するのに十分なメモリを確保するのに十分なだけハードドライブの速度を低下させ、最後までローリングサイコロをスレッド処理して無駄な時間を確認します。
ジョンドヴォルザーク

6
それに加えて、「システムの状態、ハードウェア、およびソフトウェアに関する完全な知識」は非常に高い順序です。「10ミリ秒前に」を追加すると、すでに不可能を求めています。また、CPUのハードウェア乱数生成の実装が量子現象を使用し(おそらく使用する)、CPU上のスレッドがそれを呼び出す場合、コンピューターの周囲3000 kmの宇宙の完全な状態を知らなくても節約できます。そして、MWIでは、あなたも正しく推測することはできません。
ジョンドヴォルザーク

8
@Nat:暗号化においても、「一定時間」は実際には絶対に一定ではありませんそれは単に、実行時間に秘密データに依存する体系的な変動がなく、統計的に相関できることを意味します。そして実際には、実行されるコードパスと実行されるメモリアクセスのパターンが秘密データに依存せず、可変時間を要することがわかっている特定の命令が回避される場合(またはその入力がマスクされる場合)うまくいけば相関関係を排除します)、おそらく十分に良いでしょう。それを超えて、あなたは本当にそれを測定する必要があります。
イルマリカロネン

2
68020は複雑な獣です... MCS51を試してください....
rackandboneman

29

一般的にこれを行うことはできませんが、ある意味では、非常に多くのことができ、実際に必要ないくつかの歴史的なケースがありました。

アタリ2600(またはアタリビデオコンピュータシステム)は、アタリはCPUが持っていたことを意味し、デバイスにフレームバッファを与えるために余裕がなかった最も初期の家庭用ビデオゲームシステムの一つであったと第一の時代のそれ以降のシステムとは異なり、1978年にリリースされました。すべてのスキャンラインでコードを実行して何を生成するかを決定します-このコードの実行に17.08マイクロ秒(HBlank間隔)以上かかった場合、スキャンラインが描画を開始する前にグラフィックが適切に設定されません。さらに悪いことに、プログラマがAtariで通常許可されているよりも複雑なコンテンツを描画したい場合、命令の正確な時間を測定し、ビームが描画されているときにグラフィックレジスタを変更する必要がありました。スキャンライン全体で57.29マイクロ秒のスパンです。

ただし、Atari 2600は、6502に基づく他の多くのシステムと同様に、このシナリオに必要な注意深い時間管理を可能にする非常に重要な機能を備えていました。CPU、RAM、およびTV信号はすべて、同じマスタークロック。TV信号は3.98 MHzクロックから流れ、上記の時間をTV信号を管理する整数の「カラークロック」に分割し、CPUおよびRAMクロックのサイクルは正確に3カラークロックであったため、CPUのクロックは現在の進行中のTV信号に対する時間の正確な測定値。(これに関する詳細については、Stella Atari 2600エミュレーター向けに書かれたStella Programmer's Guideをご覧ください)。

さらに、この動作環境は、すべてのCPU命令がすべての場合に必要なサイクルの定義された量を持ち、多くの6502開発者がこの情報を参照表に公開することを意味しました。たとえばCMPこの表から取られた(アキュムレータとメモリを比較する)命令のこのエントリを考えてみましょう

CMP  Compare Memory with Accumulator

     A - M                            N Z C I D V
                                    + + + - - -

     addressing    assembler    opc  bytes  cycles
     --------------------------------------------
     immediate     CMP #oper     C9    2     2
     zeropage      CMP oper      C5    2     3
     zeropage,X    CMP oper,X    D5    2     4
     absolute      CMP oper      CD    3     4
     absolute,X    CMP oper,X    DD    3     4*
     absolute,Y    CMP oper,Y    D9    3     4*
     (indirect,X)  CMP (oper,X)  C1    2     6
     (indirect),Y  CMP (oper),Y  D1    2     5*

*  add 1 to cycles if page boundary is crossed

このすべての情報を使用して、Atari 2600(および他の6502開発者)は、コードの実行にかかった時間を正確に判断し、必要な機能を実行し、AtariのTV信号タイミング要件に準拠したルーチンを構築できました。また、このタイミングは非常に正確だったため(特にNOPのような時間の無駄な命令)、描画中にグラフィックを変更するためにそれを使用することさえできました。


もちろん、Atariの6502は非常に特殊なケースであり、これはすべて、システムに次のすべてがあるためにのみ可能です。

  • RAMを含むすべてを実行するマスタークロック。最近のシステムには、CPUとRAMに独立したクロックがあり、RAMクロックはしばしば遅く、2つは必ずしも同期していません。
  • キャッシュは一切ありません-6502は常にDRAMに直接アクセスします。現代のシステムには、状態を予測するのをより困難にするSRAMキャッシュがあります-キャッシュを使用してシステムの動作を予測することはおそらくまだ可能ですが、間違いなくより困難です。
  • 同時に実行される他のプログラムはありません-カートリッジ上のプログラムはシステムを完全に制御していました。現代のシステムは、非決定的なスケジューリングアルゴリズムを使用して複数のプログラムを一度に実行します。
  • クロック速度が十分に遅いため、信号が時間内にシステムを通過できます。クロック速度が4 GHz(たとえば)の最新システムでは、0.5メートルのマザーボードの長さを移動するのに光の光子6.67クロックサイクルがかかります-最新のプロセッサがボード上の他の何かと対話することは期待できませんボード上の信号がデバイスに到達するまでに1サイクル以上かかるため、たった1サイクルで。
  • まれにしか変化しない明確なクロック速度(Atariの場合は1.19 MHz)-現代のシステムのCPU速度は常に変化しますが、AtariはTV信号に影響を与えることなくこれを行うことはできませんでした。
  • 公開されたサイクルタイミング-x86は、命令の所要時間を定義しません。

これらすべてが一緒になって、正確な時間を要する命令セットを作成できるシステムを作成しました。このアプリケーションでは、まさにそれが要求されていました。ほとんどのシステムには、単に必要がないため、この程度の精度はありません。計算が完了すると計算が完了するか、正確な時間が必要な場合は、独立したクロックを照会できます。ただし、一部の組み込みシステムなどでニーズが適切な場合でも、それは引き続き発生する可能性があり、これらの環境でコードを実行するのにかかる時間を正確に判断できます。


また、このすべては、正確な時間を要するアセンブリ命令のセットの構築にのみ適用されるという大きな大規模な免責事項を追加する必要があります。これらの環境でも、任意のアセンブリを実行して、「実行にどれくらい時間がかかるか」を尋ねる場合、それを断固として行うことはできません-それは解決不可能であることが証明されている停止問題です。


編集1:この回答の以前のバージョンでは、Atari 2600にはプロセッサにテレビ信号のどこにあるかを知らせる方法がなく、プログラム全体を最初からカウントして同期させなければならないと述べました。コメントで私に指摘したように、これはZX Spectrumのような一部のシステムには当てはまりますが、次の水平ブランキング間隔が発生するまでCPUを停止するハードウェアレジスタが含まれているため、Atari 2600には当てはまりません。自由に垂直ブランキング期間を開始する関数。したがって、サイクルのカウントの問題は各スキャンラインに限定され、開発者がスキャンラインの描画中にコンテンツを変更したい場合にのみ正確になります。


3
また、ほとんどのゲームが完全に機能しなかったことにも注意してください-プログラマーのエラー(CPUタイミングの誤った推定)または単純に多すぎるために、ビデオ信号のタイミングが一致しないため、ビデオ出力に多くのアーティファクトが見られる可能性がありますやらなければならないこと。また、非常に脆弱でした。バグを修正したり、新しい機能を追加したりする必要がある場合、タイミングを壊す可能性が非常に高く、場合によっては避けられません。楽しかっただけでなく、悪夢でもありました:)過熱や干渉など、クロック速度が常に正確であったかどうかはわかりませんが、それでも確かにそれが困難だったことを示しています。
ルアーン

1
良い答えですが、Atari 2600の各命令のサイクル数をカウントする必要はないことを一目で確認したいと思います。これを行う必要のない2つの機能があります。次に、ポーリングして0に達したかどうかを確認し、次の水平ブランキングが開始されるまでCPUを停止するレジスタを使用します。ZX Spectrumのような他の多くのデバイスには、そのようなものはありません。実際、画面のどこにいるかを知るために、垂直ブランキング割り込み後に費やされるすべてのサイクルをカウントする必要があります。
マーティンビルカンズ

1
停止の問題は厳密にはアタリには当てはまらないと主張します。AtariのI / O機能を除外し、通常のカートリッジROMに制限する場合、有限量のストレージがあります。その時点で有限状態マシンがあり、その上でプログラムは停止するか、前に入力した状態に移行する必要があり、有限時間で証明可能な無限ループに至ります。
user1937198

1
@ user1937198 128バイトの状態(およびレジスタ内にあるもの)は、それとチューリングマシンの理論上の無限テープとの違いを、理論上のみ重要な区別とするのに十分な状態空間です。地獄、AESキーのような128 BITSを実際に検索することはできません。「割り込みを無効にする」に相当するものを忘れないでください。停止することはほぼ確実に可能でした。
ダン・ミルズ

1
「それは解決不可能であることが証明されている停止問題です。これに遭遇した場合は、ストップウォッチを中断して実際にコードを実行する必要があります。」- これは意味がありません。コードをシミュレートする代わりに「実際に」実行することで、チューリングの証明を回避することはできません。停止した場合は、停止するまでの時間を計ることができます。停止しない場合、将来的に停止するのか、永久に実行するのか(一般的に)確信が持てません。これは、実際のストップウォッチやシミュレートされたストップウォッチでも同じ問題です。少なくともシミュレーションでは、ループの兆候がないか内部状態をより簡単に検査できます。
ベンブルグ

15

ここには2つの側面があります

@ gnasher729が指摘しているように、実行する正確な命令を知っている場合、キャッシング、分岐予測、スケーリングなどの理由により、正確なランタイムを推定することは依然として困難です。

ただし、状況はさらに悪化します。アセンブリのチャンクを考えると、どの命令が実行されるか、さらには実行される命令の数を知ることさえ不可能です。これは、ライスの定理によるものです。正確に判断できれば、その情報を使用して停止不可能な問題を解決できます。

アセンブリコードには、プログラムの完全なトレースを無限にするのに十分なジャンプとブランチを含めることができます。コストセマンティクスや注釈付きの型システムなどを通じて、実行の上限を与える、実行時間の控えめな近似に関する作業がありました。私は具体的にアセンブリのことは何もよく知りませんが、そのようなものが存在しても驚かないでしょう。


4
つまり、実行時間を知っていれば停止するかどうかがわかるので、停止問題はここで直接適用されます。また、x86ではmovチューリング完全
BlueRaja-Danny Pflughoeft

7
RiceとHalting Problemは、任意の(任意の)プログラムに関する記述です。しかし、ここでのOPは、問題の特定のコードを特定しています。プログラムの個々のまたは限られたカテゴリに関するセマンティックおよび停止プロパティを決定できますか?すべてのプログラムをカバーする一般的な手順がないというだけです。
ダニエルR.コリンズ

2
私たちはできる決定的に私たちが今までヒットした場合、次の実行する命令を知って、私たちが言うことができないことであるsys_exitので、ストップウォッチを止めます。このような実際的な質問に対して合理的なプログラムの終了に制限する場合、答えは実際に「はい」です(プログラムを開始する直前にシステムの状態、hw、swの完全なスナップショットがあることを保証します)。
マーガレットブルーム

1
@ BlueRaja-DannyPflughoeft Movはチューリング完全ですが、OPのコードの一部ではありません。しかし、いずれにせよポイント以外のことを- intsが任意のコード、任意のI / O操作などのための待機実行することができます
Luaan

2

「コンピューターシステム」の選択には、マイクロコントローラーが含まれますか?一部のマイクロコントローラは非常に予測可能な実行時間を持っています。たとえば、8ビットPICシリーズは、命令が異なるアドレスに分岐する、フラッシュから読み取る、または特別な2ワード命令でない限り、命令ごとに4クロックサイクルを持ちます。

割り込みは明らかにこの種のtimimgを混乱させますが、「ベアメタル」構成では割り込みハンドラなしで多くのことを行うことができます。

アセンブリと特別なコーディングスタイルを使用すると、実行に常に同じ時間がかかるコードを記述することができます。現在、ほとんどのPICバリアントに複数のタイマーがあることはそれほど一般的ではありませんが、可能です。


2

8ビットコンピューターの時代に戻って、一部のゲームはそのようなことをしました。プログラマーは、ビデオおよびオーディオハードウェアの正確なタイミングと同期するために、かかった時間とCPUの既知のクロック速度に基づいて、命令の実行にかかった正確な時間を使用します。当時は、ディスプレイはブラウン管モニターで、画面の各行を一定の速度で循環し、陰極線をオン/オフして蛍光体をアクティブまたは非アクティブにすることでピクセルの行をペイントしていました。プログラマーは、ビームが画面のその部分に到達する直前に表示するものをビデオハードウェアに指示し、残りのコードを残りの時間に合わせる必要があるため、「ビームのレーシング」と呼びました。

最新のコンピューターや、例のようなコードでは絶対に機能しません。

何故なの?以下は、単純で予測可能なタイミングを台無しにするいくつかのことです。

CPU速度とメモリフェッチは、どちらも実行時間のボトルネックです。CPUを実行する命令をフェッチするよりも速くCPUを実行したり、CPUが受け入れることができるよりも高速にバイトを配信できるメモリをインストールしたりするのは無駄です。このため、古いコンピューターは両方とも同じクロックで実行されていました。最新のCPUは、メインメモリよりもはるかに高速に実行されます。彼らは、命令とデータのキャッシュを持っていることによってそれを管理します。キャッシュにないバイトを待機する必要がある場合、CPUは停止します。したがって、同じ命令は、既にキャッシュにある場合よりも、キャッシュにない場合よりもはるかに高速に実行されます。

さらに、最新のCPUには長いパイプラインがあります。チップの別の部分にパイプラインの次のいくつかの命令で予備作業を行わせることにより、高いスループットを維持します。CPUが次の命令が何であるかを知らない場合、これは失敗します。これは分岐がある場合に発生する可能性があります。したがって、CPUは条件付きジャンプを予測しようとします。 (このコードスニペットには何もありませんが、パイプラインを詰まらせる誤った条件付きジャンプがあった可能性があります。さらに、その伝説的な答えをリンクする良い言い訳があります。)同様に、int 80実際にカーネルモードにトラップするシステム予測不可能な遅延をもたらす複雑なCPU機能、割り込みゲートを使用しています。

OSがプリエンプティブマルチタスクを使用している場合、このコードを実行しているスレッドはいつでもタイムスライスを失う可能性があります。

プログラムがベアメタルで実行され、ハードウェアで直接叩かれたため、ビームのレースも機能しました。ここではint 80、システムコールを行うために呼び出しています。これにより、制御がオペレーティングシステムに渡されるため、タイミングが保証されません。次に、任意のデバイスにリダイレクトされた可能性のある任意のストリームでI / Oを実行するよう指示します。I / Oにかかる時間を言うのは非常に抽象的ですが、命令の実行に費やされる時間を確実に支配します。

最新のシステムで正確なタイミングが必要な場合は、遅延ループを導入する必要があります。より速い反復を最も遅い速度で実行する必要がありますが、その逆は不可能です。人々が現実の世界でそうする理由の1つは、暗号化情報が攻撃者に漏洩するのを防ぐためです。


1

これはやや接線的ですが、スペースシャトルには4台の冗長コンピューターがあり、それらは正確に同期、つまり実行時の正確な一致に依存していました。

バックアップフライトソフトウェア(BFS)コンピューターが4つのプライマリアビオニクスソフトウェアシステム(PASS)コンピューターとの同期を拒否したとき、スペースシャトルの最初の打ち上げの試みはスクラブされました。詳細については、「世界を巡るバグ」をご覧ください。サイクルごとに一致するようにソフトウェアがどのように開発されたかについての興味深い読み物は、あなたに興味深い背景を与えるかもしれません。


0

ここでは、2つの異なる問題が混在していると思います。(そして、はい、これは他の人から言われたことを知っていますが、私はそれをより明確に表現できることを望みます。)

最初に、ソースコードから実際に実行される命令のシーケンスに到達する必要があります(これは入力データとコードの知識を必要とします-ループを何回実行しますか?テスト後にどの分岐が行われますか? )。停止の問題のため、命令のシーケンスは無限(終了ではない)である可能性があり、入力データの知識があっても常に静的に決定できるとは限りません。

実行する命令のシーケンスを確立したら、実行時間を決定します。これは、システムアーキテクチャのある程度の知識があれば推定できます。しかし問題は、最近の多くのマシンでは、実行時間がメモリフェッチのキャッシュに大きく依存することです。つまり、実行される命令と同じくらい入力データに依存します。また、条件分岐先の正しい推測にも依存しますが、これもデータに依存します。したがって、これは推定値に過ぎず、正確にはなりません。

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