オペレーティングシステムの概念を学ぶつもりです。以下は2つの簡単なPythonコードです。
while True:
pass
これ:
from time import sleep
while True:
sleep(0.00000001)
質問:なぜ最初のコードを実行するときはCPU使用量が100%ですが、2番目のコードを実行するときは1〜2%程度ですか?愚かに聞こえるかもしれませんが、なぜsleep
睡眠システムコールを使わずにユーザースペースモードのようなものを実装できないのですか?
注:私は睡眠を理解しようとしています。Linuxカーネルのシステムコールしかし、正直なところ、そこで何が起こっているのか理解できません。また、NOPアセンブリコードを検索した結果、実際には機能しないことがわかりました。何もないしかし、役に立たないこと(例:xchg eax、eax)を実行すると、CPU使用率が100%になるようです。しかし、よくわかりません。
ユーザー空間モードで実行できない省電力システムコールのアセンブリコードは何ですか? HLTに似ていますか?
また、次のようにコードでアセンブリを試しましたHLT
。
section .text
global _start
_start:
hlt
halter:
jmp _start
section .data
msg db 'Hello world',0xa
len equ $ - msg
ただし、このコードを実行すると、次のような一般的なカーネル保護エラーが表示されます。
[15499.991751] traps: hello[22512] general protection fault ip:401000 sp:7ffda4e83980 error:0 in hello[401000+1000]
たぶん何か関係があるかもしれませんが、保護リングそれとも私のコードが間違っていますか?ここで別の質問は、オペレーティングシステムがシステムコールで、HLT
または他の保護されたアセンブリコマンドを使用することですかsleep
?
答え1
最初のコードを実行するときにCPU使用率が100%で、2番目のコードを実行したときに約1〜2%の理由は何ですか?
最初は「使用中のループ」なので、常にコードを実行しています。 2つ目は、オペレーティングシステムがこの特定のプロセスを一時停止(休止)することを望んでいることを示しているため、オペレーティングシステムはプロセスのスケジュールをキャンセルし、CPUを使用する他のプロセスがない場合、CPUはアイドル状態になります。
また、NOPアセンブリコードを検索した結果、実際には何もしないことがわかりました。
NOP =タスクなし:何の効果もないコードを積極的に実行しています。これを使用してコードを入力できますが、CPUを低電力状態に切り替えることはできません。
ユーザー空間モードで実行できない省電力システムコールのアセンブリコードは何ですか?
x86 CPUの最新のオペレーティングシステムは、mwait
他のCPUアーキテクチャは異なるコマンドを使用します。
ただし、このコードを実行すると、次のような一般的なカーネル保護エラーが表示されます。
これは、オペレーティングシステムが管理者モードでこれを行うようになっているためです。上記のように、オペレーティングシステムはプロセスのスケジュールを維持できる必要があるため、プロセス自体がCPUをアイドルモードにすることはできません。
ここでもう1つの問題は、オペレーティングシステムがスリープシステムコールでHLTまたは他の保護されたアセンブリコマンドを使用することです。
はい、そうです。スリープコール中は実行されませんが、スケジューラループ内でスケジューラが実行するプロセスがないことを検出すると実行されます。
パート1に関する質問です。いくつかの期間を使用している場合、つまり
sleep(0.0000000000000001)
スケジューラはまだ次のプロセスに進みますか?
実際のオペレーティングシステムの呼び出しについては、man 3 sleep
(秒単位の解像度)、man usleep
(マイクロ秒単位の解像度)、およびman nanosleep
(ナノ秒単位の解像度)を参照してください。
Pythonコードでどの浮動小数点を使用しても、Pythonが使用するシステムコールよりも優れた解像度を得ることはできません(変形が何であれ関係ありません)。
マンページには、「(少なくとも)usecマイクロ秒の間に呼び出しスレッドの実行を一時停止します」と記載されています。等なので、遅延がゼロであっても(そして直ちにスケジュールが変更されても)スケジュールがキャンセルされると仮定します。しかし、私はこれをテストしておらず、カーネルコードも読みませんでした。 。
答え2
オペレーティングシステムの「CPU使用量」測定は、ユーザースペースのプロセス/スレッド(タスク)がCPUで実行されているかどうかに基づいています。たとえそのコマンドが時間の無駄に過ぎないとしても同じです。ジョブが CPU 時間を使用しない場合、オペレーティング・システムが別のジョブを実行している可能性があることを意味します。
CPUを強制的に低電力状態にすることができますが、ユーザースペースが忙しく待っている場合はそうではありません。 marcelmが述べたように、CPUの電源状態は重要ではありません。重要なことは、タスクがスリープモードに切り替える必要があることをOSに通知するかどうかです。オペレーティングシステムはCPUをスリープモードに切り替えることができます。もしその他の作業はありません。
x86pause
命令図しないでくださいオペレーティングシステムCPUで各種ジョブをスケジュール。 CPUをC0.1またはC0.2の省電力状態に切り替えることができますが、最新の製品tpause
も同様umonitor
です。umwait
また、バックエンド実行ユニットがないx86-64の真のnop
NOPです。xchg eax,eax
64ビットモードのNOPではなくEAXをRAXにゼロ拡張するので、0x90
64ビットモードではエンコーディングは使用できず、16ビットモードまたは32ビットモードでのみ使用できます。だからこそnop
自分のアイテムインテルのマニュアルにあります。もちろん、32ビットモードでも、最新のCPUは0x90
他の長いnop opcodeと一緒にno-opと特別なケースとしてそれを認識します。
しかし、繰り返しますが、それは関連性がありません。CPU 使用量は、CPU がスリープ状態に入るか、他のジョブを実行できるかを示します。コアこのプロセスには実行するものはありません。
hlt
特権命令です(CPL = 0とも呼ばれるリング0でのみ有効です。)インテルの手動入力例外:現在の権限レベルが0以外の場合は#GP(0)です。
ユーザースペースは、次の割り込みが到着するまでCPUをスリープモードにすることはできませんsleep
。
またはWAITPKG CPU機能(TremontおよびAlder Lake)が出るまでumwait
カーネルがユーザースペースで開始されたスリープモードの期間制限を設定して、オペレーティングシステムがユーザースペースのスリープモードを長くしないように制限できるようにします。そして、睡眠の深さはhlt
(C1)よりも浅く制限されており、覚醒待ち時間にとって重要です。おそらく、リアルタイムオペレーティングシステムは、重要な割り込みが近づいていることを知り、CPUが追加のウェイクアップ遅延を持たないことを望むでしょう。あるいは、CPUをスリープモードに切り替えたくありません。 (umwait
コントロールはカーネルが設定したいことを知っていますが、hlt
そうではありません。)
ただし、ユーザースペースは次の割り込みまでCPU時間を無駄にする可能性があります。これは、ユーザースペースでシステムコールやCPU例外が発生しない限り、プリエンプティブマルチタスクカーネルがCPU制御を取得する唯一の方法です。 (おそらく、このようなシステムコールは、オペレーティングシステムが空きyield()
CPUコアを待っている他のタスクに切り替えるようにコンテキストを指定するように設計されている可能性があります。)
サイト間レプリケーション:
関連質問と回答:
https://stackoverflow.com/questions/58386042/multiple-nop-instructions-do-not-contentionly-take-longer-than-a-single-nop-inst(NOPは固定時間を消費しません。順序が間違ったスーパースカラーCPUは、線形追加命令ごとに別途コストを発生しません。)
https://stackoverflow.com/questions/1719071/how-is-sleep-implemented-at-the-os-level
この質問IMOは、[アセンブリ][オペレーティングシステム][x86][CPUアーキテクチャ]タグ付きのスタックオーバーフローに属します。少なくともそこにはより良いフィットネスがあります。 SEはほとんどについてです。使用オペレーティングシステムの理論/概念ではありません。
可能であれば、小さなスリープモードをあまり使用しないでください。代わりに、ファイル記述子でアクティビティを使用またはpoll
待ちます。select
これにより、プロセス(およびCPU)は、他のシステムコールのために目を覚ますのではなく、スリープ状態を維持できます。
待つのが忙しい場合、そのループにスリープモードを入れるとそれほど悪くはありませんが、スリープモードややることがあるときにOSが目覚める場所をブロックするのと比べると、まだ悪いです。
例えれば、人々が銀行で並んで待っていると想像してください。 銀行員はCPUであり、顧客(プロセス)からの要求を実行します。
sleep()
窓口のスタッフを離れて、指定された時間の後に再びラインを立てるために椅子に座るのと同じです。 (ほとんどの人がこれを行うと、通常行が空になります。CPUがアイドル状態になっているため、新しいジョブがすぐに実行される可能性があります。)- NOPを繰り返し実行することは、天候について話しながら窓口の従業員にやるべきことを提供しますが、銀行業務を実行しないようです。カウンセラーは他の顧客をアイドル状態にするため、サービスを提供できません。
(実際の銀行とは異なり、プリエンプティブマルチタスクには、窓口の従業員が顧客が望むすべての作業を行っていなくても、顧客が行に戻ることを強制することが含まれます。)
答え3
ちょうどdirktに追加されました。できること、やるべきこと、やらないことに対する良い答えです。
一定期間コードが何もしないようにするには、2つの主な方法があります。
ㅏ/タイマーをプログラミングし、他の活動のためにCPUを確保することで、コードが目覚め、タイマー割り込みに追いつくことができると期待します。
これは間違いなく共有時間マルチタスクシステムでコーディングされたプログラムを実行するときに従うべき最も公平なアプローチです(特にSCHED_OTHER予約ポリシーに従ってタスクが実行されるように設計されたCFSに関して)。
第二/CPUを予約する以外は何もしないでください。タイマ割り込みで覚醒を期待するのは期待だからです。どんな状況でも保証されません。割り込みがトリガされると、システムが使用中になる可能性があります。
- リアルタイムのスケジュールポリシーに従っていくつかのタスクを実行します。
- すべての割り込みまたは割り込み不可能なカーネルコードの一部をマスクするいくつかの割り込みハンドラを実行します(いわゆるプリエンプティブLinuxカーネルにはまだいくつかの割り込みハンドラがあります)。
- 選択したタイマーシステムによっては、割り込みがまったく実行されない可能性があるというわけではありません。
それにもかかわらず、コードが再実行されると予想される瞬間と実際に再実行される瞬間の間の遅延(時間差)はまったく予測できません。
これは状況によっては明らかに許容できません。
一部のデバイスとの通信(デバイスのメモリアドレスへの書き込み)では、2つの連続操作間で厳しい最小タイミングを確保する必要があります。 。
もちろん、このアプローチによれば、ほとんどのカーネルコードの効率が容易に壊れる可能性があるため、いわゆる話すコードのみを使用する必要があります。原子的文脈特別なカーネル機能を実行するため、ユーザースペースが制限され、特権としてマークされた特定のCPU opcodeを直接使用することはできません。 (HLTに類似)
ところで、それでは、タイトルで表現された実際の質問に答えてみましょう。、非常に正確な数量を待たなければならないときに、時にはNOPに頼っていた記憶があります。CPUサイクル。 (これはオペコードで確認できる唯一のものです。)最新のアーキテクチャでは、メモリ、デバイスがバス上にあり、CPUと比較して異なる(時には関連しない)クロック周波数で動作するため、このアプローチは結果が悪いです。移植可能でデバッグしにくいコード。これは明らかにもはや正しい長さではありません。
ブレークポイントを設定するためにNOPを維持することをお勧めします。
答え4
NOPは無作為であると考える方が良いかもしれません。少なくとも理論的には何かを行いますが、プログラムカウンタを除いて何も変更しません。
これは、特にいくつかのハードウェアが準備されるまでクロックサイクルを待つ古いシステムまたは分岐する場合は、次のコマンドを実行する必要があるSPARcなどの実行後分岐システムで多くの用途に使用されます。分岐しないと実行されます!コンピュータを交換する前にすべき重要なことはありませんか? NOPを追加するだけです!