Linuxオペレーティングシステムは実際の戦闘を通じてCPUコンテキストの切り替えを理解します

前書き: Linux は、同時に実行する CPU の数をはるかに上回るタスクをサポートできるマルチタスク オペレーティング システムです。しかし、これが実際には幻想であることは誰もが知っています。実際には、システムが各タスクに CPU を割り当てます。ユーザーは、複数のタスクが同時に実行されているような錯覚を引き起こします。各プロセスが実行される前に、CPU はプロセスがどこからロードされ、どこから実行されるかを知る必要があります。つまり、システムは、事前に CPU レジスタとプログラム カウンターを設定できるようにする必要があります。

1. CPU コンテキスト

CPU コンテキストは、実際にはこれらの環境によってサポートされ、タスクを実行できるいくつかの環境であり、これらの環境のハードウェア条件は CPU レジスタとプログラム カウンタです。CPU レジスタは、CPU に組み込まれた非常に小さいですが非常に高速な記憶装置です。プログラム カウンタは、CPU がタスクを実行するために必要です。現在実行中のタスクの行数などの情報を記録します。これが CPU コンテキストです。 。

2. CPU コンテキストの切り替え


さまざまなタスクに応じて、CPU コンテキストの切り替えは、プロセス コンテキストの切り替え、スレッド コンテキストの切り替え、割り込みコンテキストの切り替え、およびプロセス コンテキストの切り替えに分類できます。

Linux では、特権レベルに応じて、プロセスの実行領域をカーネル領域とユーザー領域に分割します。

  • カーネル空間は最高の権限を持ち、すべてのリソースに直接アクセスできます。
  • ユーザー空間は制限されたリソースのみにアクセスでき、メモリなどのハードウェア デバイスに直接アクセスすることはできません。これらの特権リソースにアクセスするには、システム コールを使用する必要があります。

プロセスの場合、通常はユーザー モードで実行されますが、メモリやディスクなどのハードウェア デバイスにアクセスする必要がある場合は、カーネル モードに入る必要があります。つまり、ユーザー モードからカーネル モードに移行する必要があります。これはシステム コールによって実装されます。たとえば、ファイルを開く操作は、ファイルを開くには open()、ファイルの内容を読み取るには read()、ファイルの内容をコンソールに出力するには write() を呼び出す必要があります。最後に close() を実行してファイルを閉じます。これがシステム転送です。

CPU コンテキストの切り替えは、システム コール中にも発生します。

  • CPU レジスタ内の元のユーザー モード命令の位置を最初に保存する必要があります。その後、カーネル モード コードが実行されます。
  • CPU レジスタをカーネル モード命令の位置に更新する必要があり、カーネル モード コードが実行されます。

システム コールが終了した後、CPU レジスタは元の保存されたユーザー状態を復元してからユーザー空間に切り替える必要があるため、システム コールのプロセス中に 2 つの CPU コンテキスト スイッチが発生しますが、一般にシステム コールはコンテキスト スイッチではなく特権モード スイッチです。これは、仮想メモリやその他のプロセスのユーザー モード リソースが関与せず、プロセスの切り替えがプロセス内のコンテキスト スイッチに属さないためです。プロセスはカーネルによって管理およびスケジュールされます。プロセスの切り替えはカーネル モードでのみ発生するため、プロセスのコンテキストには、カーネル スタックやレジスタなどのカーネル空間の状態だけでなく、仮想メモリ、スタック、グローバル変数などのユーザー空間のリソースも含まれます。プロセスのコンテキスト切り替えはシステム コールよりも 1 ステップ多く、プロセスの仮想メモリを節約します。メモリやスタックなどのユーザー空間のリソースの場合、プロセス コンテキスト切り替えには通常、CPU 時間が数十ナノ秒から数マイクロ秒かかります。プロセスコンテキストスイッチングの数が比較的多いため、CPU はレジスターやカーネルで多くの時間を費やします。スタックは、仮想メモリなどのリソースの保存と回復です。さらに、Linux は仮想メモリ間のマッピング関係を管理します。 TLB 高速テーブルを介してメモリと物理メモリを共有します。仮想メモリが更新されると、キャッシュを更新する必要がありますが、このマルチプロセッシング システムでは、複数のプロセッサが単一のキャッシュを共有するため、これは非常に複雑です。

次に、プロセスのコンテキスト切り替えがいつ実行されるかについて説明します。実際、プロセスはスケジュールされたときにコンテキストを切り替える必要があります。アクティブまたはパッシブの場合があります。

  • システム プロセスの通常のスケジューリング アルゴリズムでは、プロセス コンテキストの切り替えが発生します。たとえば、現在使用されているタイム スライス ローテーション アルゴリズムでは、プロセスのタイム スライスが使い果たされると、CPU はエントリ プロセスをスケジュールし、他のプロセスに切り替えます。
  • リソースが不足している場合、プロセスは一時停止されます。たとえば、IO を待機している場合やメモリが不足している場合、プロセスは積極的に一時停止し、システムが他のプロセスをスケジュールするのを待ちます。
  • プロセスが何らかのスリープ関数 sleep() によってアクティブに一時停止されると、プロセスも再スケジュールされます。
  • 優先度の高いプロセスが実行されている場合、現在のプロセスも一時停止されます。
  • ハードウェア割り込みが発生すると、その割り込みによってCPU上のプロセスが中断されます。

3. スレッドコンテキストの切り替え

スレッドはスケジューリングの基本単位であり、プロセスはリソース所有権の基本単位です。つまり、カーネル内のタスクのスケジューリングはスレッドに基づいていますが、プロセスは仮想メモリやグローバル変数などのリソースをスレッドに提供するだけです。 . プロセスとスレッド 両者の違いはここでは紹介しませんが
、スレッドのコンテキスト切り替えは実際には 2 つの状況に分けられます。

  • 前後の2つのスレッドは別のプロセスに属しており、リソースが共有されていないため、このときのスレッドコンテキストの切り替えとプロセスコンテキストの切り替えは一貫しています。
  • 前後の 2 つのスレッドは同じプロセスに属します。仮想メモリが共有されるため、切り替え時に仮想メモリなどのリソースは変更されず、プライベート データ、レジスタ、および切り替えスレッドによって共有されないその他のリソースのみが残ります。

したがって、同じプロセス内のスレッド切り替えは、複数のプロセス内のスレッド切り替えよりも消費するリソースが少なくなります。

 

4. 割り込みコンテキスト切り替え

中断とは、ハードウェア イベントに迅速に応答することです。簡単に言うと、コンピュータは他の処理を行うために現在の処理を停止し、その後戻って前のタスクを続行します。たとえば、アセンブリの最下位層である print 関数を呼び出すとき、実際に役立ちます int 0x80 の命令を呼び出します。これは、割り込み番号 0x80 を呼び出すことです。
もちろん、割り込みは最初に現在のプロセスの状態を保存する必要があります。そうすることで、割り込みが終了した後もプロセスは元の状態から再開できます。ユーザーモードなので、ユーザーモードにあるプロセスに割り込みプログラムが割り込んだとき、仮想メモリやグローバルなどのユーザーモードのリソースを保存したり復元したりする必要がありません。このプロセスの変数は、CPU レジスタ、カーネル スタックなど、プロセスのカーネル モードでリソースを保存および復元するだけで済みます。同じ
CPU では、割り込み処理の優先順位がプロセスよりも高いため、割り込みコンテキストの切り替えは発生しません。プロセスコンテキストの切り替えと同時に、前のタスクの実行を終了します。割り込みコンテキストの切り替えが多いと、
CPU を
大量に消費し、レジスタ、カーネル スタック、仮想メモリなどのデータの保存と復元に時間がかかり、実際のプロセスの実行時間が短くなり、システム パフォーマンスが大幅に低下するため、vmstat ツールを使用してシステムのコンテキスト スイッチング ステータスをクエリできます。vmstat は、
CPU コンテキスト スイッチと割り込みの数を分析するために使用できる、一般的に使用されるシステム パフォーマンス分析ツールです。

特に懸念されるのは次のとおりです。

  • cs (コンテキスト スイッチ): 1 秒あたりのコンテキスト スイッチの数
  • in(割り込み): 1 秒あたりの割り込み数
  • r (実行中または実行可能): レディキューの長さ、つまり、実行中で CPU を待っているプロセスの長さ
  • b(ブロック): 中断不可能なスリープ状態にあるプロセスの数

Vmstat は、システム全体の全体的なコンテキスト スイッチング状況を示します。各プロセスの詳細を表示するには、pidstat を使用する必要があります。プロセスのコンテキスト スイッチング状況を表示するには、-w オプションを追加します

画像

特に懸念されるのは次のとおりです。

  • cswch(voluntary context switch): 1 秒あたりの自発的コンテキスト スイッチの数を示します。
  • nvcswch(非自発的コンテキストスイッチ): 1 秒あたりの非自発的コンテキストスイッチの数を示します。

  電車による情報: Linux カーネル ソース コード技術学習ルート + ビデオ チュートリアル カーネル ソース コード

電車で学ぶ: Linux カーネル ソース コード メモリ チューニング ファイル システム プロセス管理 デバイス ドライバー/ネットワーク プロトコル スタック

これら 2 つの概念のそれぞれの意味は次のとおりです。

  • 自発的なコンテキスト切り替え: プロセスが必要なリソースを取得できない場合、IO、メモリ、その他のリソースの不足など、結果として生じるコンテキスト切り替えが自発的に発生します。
  • 非自発的なコンテキスト スイッチング: タイム スライスが到着したため、システムによってプロセスが強制的にスケジュールされ、コンテキスト スイッチングが発生します。たとえば、多数のプロセスが CPU を獲得するために競合している場合、非自発的コンテキスト スイッチングが発生しやすくなります。

実戦解析
システムコンテキストスイッチの数は上記のツールで事前に確認できますが、システムコンテキストスイッチの数が異常な場合は?
このケースでは、sysbench ツールを使用して、マルチスレッド スケジューリングの切り替え状況をシミュレートします。sysbench は、過度のコンテキスト スイッチングの問題をシミュレートできるマルチスレッド ベンチマーク ツールです。まず、最初の端末で stsbench を実行して、マルチスレッド スイッチングの問題をシミュレートします。
#
10 スレッドの場合 マルチスレッド スイッチングの問題をシミュレートするためにベンチマーク テストを 5 分間実行します sysbench --threads=10 --max-time=300 スレッドを実行し、次に 2 番目の端末で vmstat を実行して、コンテキストのスイッチングを 1 つごとに確認し
ます2番

次の指標が観察できます。

  • R列:レディキューの長さが約8に達し、2CPUを超えたため、CPUの競合が多くなります
  • us(user) 列と sy(system) 列、これら 2 つの列の CPU 使用率が 100% に達しており、大量の CPU 使用率は sy によって引き起こされており、CPU が主にカーネルによって占有されていることを示しています。
  • in(interrupt): in列の値が10,000に達したため、割り込み処理も問題になっています

次に、pidstat を使用してどのプロセスに問題があるかを確認します。pidstat はデフォルトでプロセス インジケーター データを表示しますが、sysbench によってシミュレートされたスレッド データを使用するため、-t オプションを追加する必要があります gpw@gopuwe:~$ pidstat -
wt

画像

ここで、sysbench サブスレッドのコンテキスト スイッチが多数あることを分析できます。
別の問題があります。vmstat を使用すると、in インジケーターにさらに多くのデータがあることがわかります。そのため、どのようなタイプの中断かを調べる必要があります。割り込みが発生しました。上で、割り込みはカーネル モードで発生したはずですが、pidstat は単なるプロセス パフォーマンス分析ツールであり、割り込みに関する詳細な情報は提供しません。読み取り専用ファイル /proc/ から読み取ることができます
。割り込み、/proc は仮想ファイルです。システムはカーネル空間とユーザー空間の間の通信に使用されます。/proc/interrupts は読み取り専用の割り込みの使用法を提供します。cat コマンドを使用して /proc/interrupts を表示すると、次のことがわかります。最も速い変化速度は再スケジュール割り込み RES です。この割り込みタイプは、アイドル状態の CPU を起動して新しいタスクの実行をスケジュールすることを意味し、プロセッサ割り込みとも呼ばれます。では、コンテキスト スイッチの適切な回数は何回でしょうか
?
この値は実際にはシステム自体の CPU パフォーマンスに依存しますが、システム内のコンテキスト スイッチの数が比較的安定している場合、コンテキスト スイッチの数が数百から 10,000 未満の範囲であれば、私の考えでは正常であると考えられます
ただし、コンテキストスイッチの数が10,000を超えたり、
スイッチ数が桁違いに増加した場合には、パフォーマンス上の問題が発生している可能性が高いため、コンテキストスイッチの種類に応じて具体的な解析を行う必要があります。 :

  • 自発的なコンテキストの切り替えが増えており、プロセスがリソースを待っていることや、I/O などの他の問題が発生した可能性があることを示しています。
  • 非自発的なコンテキスト スイッチが増えています。これは、プロセスが強制的にスケジュールされている、つまりすべてのプロセスが CPU をめぐって競合していることを意味します。これは、CPU が実際にボトルネックになっていることを意味します。
  • 割り込みの数が増加していることは、CPU が割り込みハンドラーによって占有されていることを示しており、/proc/interrupts ファイルを確認する必要があります。

 

おすすめ

転載: blog.csdn.net/youzhangjing_/article/details/131436171