はじめに
Linuxでは、CPUはアプリケーションだけでなく、ネットワークパケットの受信やストレージI/Oの完了など、ハードウェアから発生するイベントにも対応する必要があります。
そこで利用されるのが「割り込み(Interrupt)」です。割り込みが発生すると、CPUは実行中の処理を一時的に中断し、必要な処理を実行した後、元の処理へ戻ります。
またLinuxでは、時間のかかる処理をSoftIRQなどに分離して後から実行することで、割り込みを効率的に処理しています。
本記事では、ハードウェア割り込みやSoftIRQの仕組み、割り込み処理の流れ、Linuxでの確認方法について分かりやすく解説します。
ハードウェア割り込みの仕組み
ハードウェア割り込み(Hardware Interrupt)とは、NICやストレージなどのハードウェアデバイスからCPUへ、処理が必要であることを通知する仕組みです。
例えばNICがネットワークパケットを受信した場合、CPUはそのタイミングを事前に知ることができません。そこでNICなどのデバイスは割り込みを利用して、CPUへイベントの発生を通知します。
大まかな流れは次のようになります。

Interrupt Controllerの役割
実際には、デバイスからの割り込みがそのままCPUへ直接通知されるとは限りません。
複数のデバイスから発生する割り込みを管理し、適切なCPUへ通知するために「Interrupt Controller(割り込みコントローラ)」が利用されます。
単純化すると、次のような関係になります。

Interrupt Controllerは、デバイスから発生した割り込みを受け取り、割り込みの種類や設定などに応じてCPUへ通知します。
マルチコアCPUでは、割り込みをどのCPUで処理するかも重要になります。LinuxではIRQ affinityを設定することで、特定の割り込みを処理するCPUを制御することもできます。
IRQとは
Linuxの割り込みを理解するうえでよく登場するのが「IRQ(Interrupt Request)」です。IRQ(Interrupt Request)は、デバイスなどからCPUへ割り込み処理を要求する仕組みです。Linuxでは、割り込みを識別・管理するためにIRQ番号が割り当てられます。
Linuxでは、現在どのような割り込みが発生しているのかを/proc/interruptsから確認できます。

左側にはIRQ番号などが表示され、その右側にはCPUごとの割り込み処理回数が表示されます。
例えば上記のvirtio0を見ると、NICに関連する割り込みがほぼCPU0で処理されていることが分かります。
CPUが割り込みを受け取る
Interrupt Controllerから割り込みが通知されると、CPUは通常の命令実行とは異なる割り込み処理へ移ります。
例えば、CPUがユーザーモードでアプリケーションを実行している最中にNICから割り込みを受け取った場合、概念的には次のような流れになります。

CPUは元の処理へ戻れるように必要な実行状態を保存したうえで、カーネルの割り込み処理へ制御を移します。
Interrupt Handlerが割り込みを処理する
CPUが割り込みを受け取ると、その割り込みに対応するカーネル側の処理が実行されます。このデバイス固有の処理を担うものが、一般にInterrupt Handler(割り込みハンドラ)と呼ばれます。例えばNICの場合、デバイスドライバの割り込み処理が実行されます。
ただし、割り込みハンドラの中ですべての処理を長時間実行すると、その間CPUが他の処理を行いにくくなります。そのためLinuxでは、割り込み発生直後に必要な処理をできるだけ短時間で行い、後回しにできる処理を別の仕組みで実行します。
この考え方が、次の章で説明するTop Half / Bottom Halfにつながります。
このようにハードウェア割り込みは、デバイスで発生したイベントをCPUへ通知し、Linuxカーネルに必要な処理を実行させるための仕組みです。
Linuxの割り込み処理 ― Top Half / Bottom Half
Linuxでは、ハードウェア割り込みが発生したときに、必要なすべての処理をその場で実行するわけではありません。割り込みに関連する処理を長時間実行すると、他の割り込みへの対応や通常のタスクの実行に影響する可能性があるためです。
そこでLinuxの割り込み処理を理解する際には、処理を大きく Top Half(緊急性の高い処理) と Bottom Half (後回しにできる処理)に分けて考えると分かりやすくなります。
Top Halfとは
Top Halfは、ハードウェア割り込みを受け取った直後に実行する処理です。デバイスに対応する割り込みハンドラが実行され、割り込みに対してすぐに行う必要がある処理を実行します。
例えばNICの場合、パケットを受信するとNICから割り込みが発生します。LinuxカーネルはNICドライバの割り込みハンドラを実行し、割り込みに対する必要最低限の処理を行います。
重要なのは、Top Halfでは時間のかかる処理をできるだけ行わないことです。
割り込み処理を長時間実行するとCPUを占有し、他の処理に影響する可能性があるため、後回しにできる処理はBottom Halfへ回します。
Bottom Halfとは
Bottom Halfは、割り込み発生直後に実行する必要がない処理を後から実行するための仕組みです。
Top Halfでは必要最低限の処理だけを行い、残りの処理をBottom Halfとして実行することで、割り込みハンドラの実行時間を短くできます。LinuxではBottom Halfを実現する仕組みとして、SoftIRQなどが利用されています。
例えばネットワーク受信では、大まかに次のように処理されます。

つまり、NICから割り込みを受け取った直後にネットワークパケットの処理をすべて完了させるのではなく、一部を後続処理へ回しています。
Top HalfとBottom Halfの違い
簡単に整理すると、次のようになります。
| 項目 | Top Half | Bottom Half |
|---|---|---|
| 実行タイミング | ハードウェア割り込み発生直後 | Top Halfの後 |
| 主な役割 | 緊急性の高い処理 | 後回しにできる処理 |
| ポイント | 短時間で終了させる | 比較的重い後続処理を担当 |
| Linuxでの例 | IRQハンドラ | SoftIRQなど |
なお、Top Half / Bottom Halfは処理を理解するための概念的な呼び方です。現在のLinuxでは、Bottom Half側の処理を実現する仕組みとしてSoftIRQなどが使われています。
特にネットワーク処理ではSoftIRQが重要であり、大量のパケットを処理する環境ではCPU使用率の%softが上昇したり、ksoftirqdのCPU使用率が高くなったりすることがあります。
SoftIRQとは
SoftIRQ(Software Interrupt)は、Linuxカーネル内部で非同期に実行する必要がある処理を扱う仕組みです。ハードウェア割り込みに関連する後続処理などにも利用されます。
前章で説明したように、ハードウェア割り込みが発生した際に、割り込みハンドラですべての処理を実行するとCPUを長時間占有してしまう可能性があります。
そこでLinuxでは、割り込み発生直後に必要な処理だけを行い、残りの処理をSoftIRQなどによって後から実行します。
ハードウェア割り込みとSoftIRQの違い
ハードウェア割り込みは、NICなどのハードウェアからCPUへ通知される割り込みです。
一方、SoftIRQはハードウェアから直接発生するものではなく、Linuxカーネル内部で後続処理を実行するための仕組みです。
例えばNICがパケットを受信した場合、最初のきっかけはNICからのハードウェア割り込みです。その後、割り込みハンドラで必要な処理を行い、パケットの後続処理をSoftIRQへ回します。
簡単に整理すると、次のようになります。
| 種類 | 主な役割 |
|---|---|
| Hardware Interrupt | ハードウェアからCPUへイベントを通知 |
| SoftIRQ | カーネル内部で後続処理を実行 |
SoftIRQには複数の種類がある
SoftIRQには、処理内容によって複数の種類があります。Linuxでは、現在のSoftIRQの発生・処理回数を/proc/softirqsから確認できます。

代表的なものは次のとおりです。
| SoftIRQ | 主な処理 |
|---|---|
| NET_RX | ネットワーク受信処理 |
| NET_TX | ネットワーク送信処理 |
| TIMER | タイマー関連処理 |
| BLOCK | ブロックデバイス関連処理 |
| SCHED | スケジューラ関連処理 |
特にネットワーク性能を調査するときは、NET_RXやNET_TXを確認することがあります。
ネットワーク受信とNET_RX_SOFTIRQ
SoftIRQの代表的な例がネットワーク受信です。NICがパケットを受信すると、ハードウェア割り込みをきっかけとしてNICドライバの処理が実行されます。現在のLinuxではNAPI(New API)という仕組みが利用されており、大まかには次のように処理されます。

大量のパケットを受信するたびにハードウェア割り込みを発生させると、CPUが割り込み処理に多くの時間を使ってしまいます。
NAPIでは、高負荷時には割り込みだけに頼らずポーリングを組み合わせて複数のパケットをまとめて処理します。これによって、大量のパケットを効率的に処理できます。

これが、Linuxのネットワーク受信で「割り込みとポーリングを組み合わせている」といわれる理由です。
ksoftirqdとは
SoftIRQは通常、割り込み処理から戻るタイミングなどで実行されます。しかし、大量のSoftIRQをそのまま処理し続けると、CPUがSoftIRQの処理に長時間使われ、通常のプロセスやスレッドを実行しにくくなる可能性があります。
そこでLinuxには、SoftIRQを処理するためのカーネルスレッドとしてksoftirqdがあります。例えば4 CPUの環境では、次のようなスレッドを確認できます。

CPUごとにksoftirqdが存在し、SoftIRQをその場で処理しきれない場合などには、残りの処理がCPUごとのksoftirqdによって処理されることがあります。
そのため、ネットワーク高負荷時などに、ksoftirqd/0 → CPU使用率が高いNET_RX → %soft急増といった状態が確認された場合、CPUがネットワーク受信などのSoftIRQ処理に多くの時間を使っている可能性があります。
SoftIRQもCPUを使用する
SoftIRQは「後回しにする仕組み」ですが、処理そのものがなくなるわけではありません。最終的にはCPUを使用して処理する必要があります。
そのため、大量のネットワークパケットなどによってSoftIRQが増加すると、アプリケーションが利用できるCPU時間にも影響する可能性があります。
Linuxではtopやmpstatの%soft、/proc/softirqs、ksoftirqdなどを確認することで、SoftIRQによるCPU負荷を調査できます。
ネットワーク受信を例に割り込み処理を見る
ここまで、ハードウェア割り込み、Top Half / Bottom Half、SoftIRQについて説明してきました。これらの仕組みが実際にどのように利用されているのか、NICがネットワークパケットを受信した場合を例に見ていきます。

① NICがパケットを受信する
外部からEthernetフレームが届くと、NICがそのデータを受信します。
この時点では、アプリケーションが直接パケットを受け取っているわけではありません。まずNICとデバイスドライバによって受信処理が開始されます。
② DMAでメモリへ転送する
NICが受信したデータは、一般的にDMA(Direct Memory Access)を利用してメインメモリ上の受信用バッファへ転送されます。
DMAを利用することで、CPUがパケットデータをNICから1バイトずつコピーする必要はありません。CPUはデータ転送そのものではなく、その後のパケット処理を担当します。
③ ハードウェア割り込みが発生する
NICはパケットを受信すると、受信したパケットを処理する必要があることをCPUへ通知します。そのために利用されるのがハードウェア割り込みです。
実際の環境では、複数のパケットをまとめて通知するInterrupt Coalescing※などが利用されることもあり、必ずしも「1パケット = 1割り込み」ではありません。
※Interrupt Coalescing(割り込み集約)は、NICがパケットを受信するたびにCPUへ割り込みを通知するのではなく、複数のパケット分をまとめて1回の割り込みで通知する仕組み
④ NICドライバの割り込み処理を実行する
CPUがNICからの割り込みを受け取ると、NICドライバの割り込み処理が実行されます。ここでパケットに対するすべての処理を行うわけではありません。
割り込み処理を長時間実行し続けないように、必要最低限の処理を行い、後続の受信処理をNAPIへ引き継ぎます。
⑤ NAPIをスケジュールする
NICドライバの割り込み処理からNAPIの処理をスケジュールし、受信したパケットの本格的な処理を後続処理へ回します。
一般的なNICドライバでは、NAPIがスケジュールされると対象キューの受信割り込みを抑制し、NAPI Pollによって複数のパケットをまとめて処理します。
これによって、高負荷時に大量のハードウェア割り込みが発生することを抑えられます。
⑥ NET_RX_SOFTIRQが実行される
NAPIによる受信処理は、NET_RX_SOFTIRQから実行されます。ここから、ハードウェア割り込み直後の処理ではなく、SoftIRQによる後続処理になります。
ネットワーク負荷が高い環境では、このNET_RXの処理回数やCPUの%softが大きく増加することがあります。
⑦ NAPI Pollでパケットを取得する
NET_RX_SOFTIRQでは、NAPIのpoll処理が呼び出されます。
NAPI Pollでは、設定された処理上限(budget)の範囲で複数の受信パケットをまとめて処理します。例えば大量のパケットが到着している場合でも、パケットごとにハードウェア割り込みを処理するのではなく、以下のように複数のパケットをまとめて処理できます。
⑧ Linuxネットワークスタックで処理する
NAPIによって取り出されたパケットは、Linuxのネットワークスタックへ渡され、Ethernet、IP、TCP/UDPなど、それぞれのプロトコルに応じた処理が行われます。
例えばTCP通信の場合、大まかにはEthernet → IP → TCPの順に処理されます。その後、宛先IPアドレスやポート番号などの情報を基に対応するSocketが特定され、受信したデータがそのSocketの受信キューへ渡されます。
⑨ Socketの受信バッファへ格納する
TCP/UDPなどの処理を経てアプリケーション向けのデータになると、対象Socketの受信キュー/バッファへ渡されます。
この時点でも、データが自動的にアプリケーションのユーザー空間へコピーされるわけではありません。データはカーネル側にあり、アプリケーションが読み出すのを待ちます。
⑩ アプリケーションがデータを取得する
アプリケーションがrecv()やread()などのシステムコールを実行すると、Socketの受信バッファに到着しているデータがユーザー空間へ渡され、アプリケーションから利用できるようになります。
割り込みとSoftIRQを分けて考える
ネットワーク受信処理で特に重要なのは、ハードウェア割り込みとSoftIRQは別の処理だという点です。
前半ではNICからのイベントをハードウェア割り込みとしてCPUへ通知し、後半ではNAPIとNET_RX_SOFTIRQを使って実際のパケット処理を進めます。
この仕組みを理解しておくと、Linuxでネットワーク負荷が高くなった際に、/proc/interrupts、/proc/softirqs、%irq、%soft、ksoftirqdなどの情報が何を意味しているのか理解しやすくなります。
Linuxで割り込みを確認する
Linuxでは、ハードウェア割り込みやSoftIRQの発生状況を/proc配下の情報やtop、mpstatなどのコマンドから確認できます。割り込みによるCPU負荷を調査する場合は、主に次の情報を確認します。
・/proc/interrupts:ハードウェア割り込み
・/proc/softirqs:SoftIRQ
・top:CPU全体のhi、si
・mpstat:CPUごとの%irq、%soft
/proc/interruptsでハードウェア割り込みを確認する
ハードウェア割り込みの発生状況は、/proc/interruptsから確認できます。

CPU0~CPU3の列には、それぞれのCPUで処理された割り込みの累積回数が表示されます。
例えばvirtioに対応する行を見ることで、NICから発生した割り込みがどのCPUで処理されているのか確認できます。
なお、NICの割り込み回数は受信パケット数と一致するとは限りません。Interrupt CoalescingやNAPIなどにより、複数のパケットをまとめて処理することがあるためです。

特定のCPUだけ割り込み回数が大きく増えている場合、そのCPUへ割り込み処理が集中している可能性があります。
/proc/softirqsでSoftIRQを確認する
SoftIRQの発生・処理状況は/proc/softirqsから確認できます。

ネットワーク受信を調査する場合は、特にNET_RXに注目します。

これは各CPUで処理されたNET_RX SoftIRQの累積回数です。ネットワーク負荷が高くなるとNET_RXが増加します。ただし、この値も累積値なので、単純に値が大きいだけで負荷が高いとは判断できません。一定時間の差分を確認することが重要です。
なお、NET_RXの値は受信パケット数そのものではなく、NET_RX SoftIRQが処理された回数を示します。
topでirq / softirqのCPU使用率を確認する
割り込み処理がCPUをどの程度使用しているのかを簡単に確認する場合は、topが便利です。

割り込み処理を見る場合は、主にhiとsiに注目します。
| 項目 | 意味 |
|---|---|
hi | ハードウェア割り込み処理に使用したCPU時間 |
si | SoftIRQ処理に使用したCPU時間 |
例えば、「7.0 hi, 9.6 si」 であれば、CPU時間の約7.0%がハードウェア割り込み、約9.6%がSoftIRQの処理に使われていることを示します。
ネットワーク負荷が非常に高い場合などは、siが大きく上昇することがあります。
mpstatでCPUごとの割り込み負荷を確認する
topではCPU全体の傾向を簡単に確認できますが、どのCPUで割り込み処理の負荷が高いのか確認したい場合はmpstatが便利です。
出力例は次のようになります。

特に、以下を確認します。
%irq:ハードウェア割り込み処理に使用したCPU時間%soft:SoftIRQ処理に使用したCPU時間
上記の例では、CPU1、CPU3の%softが他のCPUより高くなっています。
ksoftirqdのCPU使用率を確認する
SoftIRQの負荷が高い場合は、topコマンドでksoftirqdのリソース使用状況も確認します。

ネットワーク高負荷時にksoftirqdのCPU使用率が高くなっていた場合は、/proc/softirqsのNET_RXやmpstatの%softなども合わせて確認します。
割り込みは複数の情報を組み合わせて確認する
割り込みによるCPU負荷を調査するときは、1つの値だけで判断するのではなく、複数の情報を組み合わせることが重要です。
例えばネットワーク受信による割り込み負荷を調査する場合は、以下の流れで確認すると分かりやすいでしょう。

また、割り込み回数が多いというだけで性能問題とは判断できません。ネットワークトラフィックが増えれば、割り込みやSoftIRQの処理が増えるのは自然な動作です。
重要なのは、割り込みやSoftIRQの増加と同時にCPU使用率やアプリケーション性能に問題が発生していないかを確認することです。
まとめ
本記事では、Linuxにおけるハードウェア割り込みとSoftIRQの仕組みについて解説しました。
Linuxでは、NICなどからのハードウェア割り込みを受けると、必要最低限の処理を行い、後続処理をSoftIRQなどで実行します。特にネットワーク受信では、NAPIとNET_RX_SOFTIRQによって大量のパケットを効率的に処理しています。
割り込みによるCPU負荷を調査する場合は、/proc/interrupts、/proc/softirqs、top、mpstat、ksoftirqdなどを組み合わせて確認することが重要です。
これらの仕組みを理解しておくことで、%irqや%softが高くなった場合の原因を切り分けやすくなります。


コメント