C LANGUAGE TECHNOLOGY

【C言語】LinuxにおけるリアルタイムスケジューリングRMとEDFの実装

悩んでいる人

C言語でLinuxにおけるリアルタイムスケジューリングRMとEDFの実装を教えて!

こういった悩みにお答えします.

本記事の信頼性

  • リアルタイムシステムの研究歴12年.
  • 東大教員の時に,英語でOSの授業.
  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校コンピュータサイエンス学部2021年の世界大学学術ランキングで20位)で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発
  • プログラミング歴15年以上,習得している言語: C/C++Solidity/Vyper,Java,Python,Ruby,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開

こういった私から学べます.

C言語でLinuxにおけるリアルタイムスケジューリングRMとEDFの実装

C言語でLinuxにおけるリアルタイムスケジューリングRMとEDFの実装を紹介します.

結構難しい内容なので,じっくり読み進めて下さい.

RMとEDFの理論や比較を知りたいあなたはこちらからどうぞ.

第7回リアルタイムシステム
【第7回】元東大教員から学ぶリアルタイムシステム「Rate Monotonicスケジューリング」

こういった私から学べます. 前回を読んでいない方はこちらからどうぞ. リアルタイムシステムの記事一覧はこちらからどうぞ. 目次1 Rate Monotonic(RM)スケジューリング2 RMの最適性の ...

続きを見る

第8回リアルタイムシステム
【第8回】元東大教員から学ぶリアルタイムシステム「Earliest Deadline Firstスケジューリング」

こういった私から学べます. 前回を読んでいない方はこちらからどうぞ. リアルタイムシステムの記事一覧はこちらからどうぞ. 目次1 Earliest Deadline First(EDF)スケジューリン ...

続きを見る

第11回リアルタイムシステム
【第11回】元東大教員から学ぶリアルタイムシステム「RMとEDFの比較」

こういった私から学べます. 前回を読んでいない方はこちらからどうぞ. リアルタイムシステムの記事一覧はこちらからどうぞ. 目次1 RMとEDFの比較2 RMとEDFのシミュレーション評価3 元東大教員 ...

続きを見る

本記事では,以下の記事の内容を理解していることを前提とします.

C言語 スレッド
【C言語】スレッドの生成と実行【pthread,マルチスレッド,スレッドIDの取得,C11規格のスレッド】

こういった悩みにお答えします. こういった私から学べます. 目次1 スレッド2 pthreadによるマルチスレッドプログラミング3 pthreadでスレッドIDの取得3.1 pthread_self関 ...

続きを見る

C言語 プロセス
【C言語】プロセスの生成と実行【fork/wait/execve/getpid/getppid関数】

こういった悩みにお答えします. こういった私から学べます. 目次1 プロセス2 fork関数でプロセスの生成,wait関数で子プロセスの終了まで待機3 execve関数でコマンドの実行4 getpid ...

続きを見る

C言語 get_nprocs関数
【C言語】Linuxのプロセッサ数を取得するget_nprocs_conf/get_nprocs関数の使い方

こういった悩みにお答えします. こういった私から学べます. 目次1 get_nprocs_conf/get_nprocs関数2 get_nprocs_conf/get_nprocs関数の使い方3 CP ...

続きを見る

C言語 CPU_SET
【C言語】cpu_set_tデータ構造体とCPU_SETマクロの使い方

こういった悩みにお答えします. こういった私から学べます. 目次1 cpu_set_tデータ構造体2 CPU_SETマクロ3 cpu_set_tデータ構造体とCPU_SETマクロの使い方4 まとめ c ...

続きを見る

C言語 sched_*関数 tasksetコマンド
【C言語】sched_setaffinity/sched_getaffinity/sched_getcpu関数の使い方【tasksetコマンドでスレッドを特定のCPUで実行】

こういった悩みにお答えします. こういった私から学べます. 本記事では,以下の記事の内容を理解していることを前提とします. 目次1 sched_setaffinity/sched_getaffinit ...

続きを見る

sched_attr構造体とsched_setattr/sched_getattrシステムコール

sched_setattr/sched_getattrシステムコールは,スケジューリングポリシーと属性の設定と取得を行います.

これらのシステムコールは非標準のLinuxによる拡張であることに注意して下さい.

sched_attr構造体は,指定したスレッドの新しいスケジューリングポリシーと属性を定義した構造体で,sched_setattr/sched_getattrシステムコールの第2引数で利用します.

  • size:この構造体のサイズ
  • sched_policy:ポリシー(SCHED_*)
  • sched_flags:フラグ
  • sched_nice:nice値(SCHED_OTHER,SCHED_BATCH)
  • sched_priority:静的優先度(SCHED_FIFO,SCHED_RR)
  • sched_runtime:SCHED_DEADLINEの実行時間
  • sched_deadline:SCHED_DEADLINEの相対デッドライン
  • sched_period:SCHED_DEADLINEの周期
  • sched_util_min:SCHED_DEADLINEのCPU利用率の最小値
  • sched_util_max:SCHED_DEADLINEのCPU利用率の最大値

標準ライブラリのヘッダファイルsched.hにsched_setattr/sched_getattrシステムコールのプロトタイプ宣言とsched_attr構造体の定義があるという記載ですが,Ubuntu 22.04 LTSのヘッダファイルにはありません.

※sched_setattr/sched_getattrシステムコールは非標準のLinuxによる拡張であるからだと考えられます.

また,linux/sched/types.hヘッダファイルにsched_setattr/sched_getattrシステムコールのプロトタイプ宣言とsched_attr構造体の定義はありますが,linux/sched/types.hヘッダファイルをインクルードすると標準ライブラリのヘッダファイルsched.hとの整合性が取れていないため,ビルドエラーが発生します.

なので,自作コードでsched_attr構造体の定義とsched_setattr/sched_getattrシステムコールのプロトタイプ宣言が必要になりますので注意しましょう!

LinuxにおけるリアルタイムスレッドはCPUを100%利用できない!?

Linuxにおけるリアルタイムスレッドは,デフォルトではCPUを100%利用できない設定になっています.

catコマンドで実行すると以下のようになります.

  • sched_rt_period_usは1,000,000マイクロ秒(1秒)
  • sched_rt_runtime_usは950,000マイクロ秒(0.95秒)

つまり,リアルタイムスレッドは1秒あたり0.95秒までしか実行できません(1秒あたりのCPUの実行割合は95%).

この理由として,リアルタイムスレッドが暴走した場合の安全装置としての役割があるからです.(コアが1つしかない場合,そのコアでリアルタイムスレッドが暴走したらOSが制御不能になり,強制的に再起動しなければなりません.)

参考までに,上記の値はLinuxカーネルのkernel/core/sched.cファイルのsysctl_sched_rt_periodとsysctl_sched_rt_runtime変数に設定されています.

もしリアルタイムスレッドでCPUを100%利用したい場合は以下のコマンドを実行しましょう.

ここで,「sched_rt_runtime_us=-1」は無制限の意味です.

sched_rt_runtime_usを表示してみると,-1になっていることがわかります.

※この設定をした場合,実行するリアルタイムスレッドは注意して下さい.

LinuxにおけるRMとEDFの実装

LinuxにおけるRMとEDFの実装を紹介します.

RMはSCHED_FIFOスケジューリングポリシー,EDFはSCHED_DEADLINEスケジューリングポリシーを利用して実装します.

ここで,SCHED_FIFO/SCHED_DEADLINEスケジューリングポリシーは,管理者権限でないと利用できないことに注意して下さい(sudoコマンドで実行).

RMとEDFでスケジューリングするタスクセットは以下になります.

  • タスク数:2(RMを考慮してタスクIDが小さいほど周期が短いことを想定)
    • タスク1:実行時間0.6秒,周期1秒
    • タスク2:実行時間0.5秒,周期1.5秒
  • 実行時間は安全マージンを考慮して80%を実行(0.6秒の場合は0.6 * 80% = 0.48秒)
  • タスクセットの実行時間は3秒
  • RMの場合はタスクの実行するCPUはCPU 0で固定(migrate_thread_to_cpu関数でCPU 0にマイグレーション)
  • EDFはSCHED_DEADLINEの特性上,affinityマスクを設定できません(理由はこちら).特定のコアでSCHED_DEADLINEを実行したい場合は,以下の方法でLinuxが利用するコア数を1にしましょう!
    • VMでLinuxをゲストOSとして利用している場合,VMでLinuxが利用するコアを1コアに設定
    • ホストOSとしてLinuxを利用している場合,BIOSでLinuxが利用するコアを1コアに設定

実装方法は以下の2種類を紹介します.

  • 1プロセス,マルチスレッドの実装
  • マルチプロセスの実装(コマンドラインでタスク数分のプログラムを実行)

コード一式は,こちらからrm_and_edf.zipをダウンロードして,解凍して下さい.

解凍したrm_and_edf.zipファイルの構成は以下になります.

  • Makefile:以下のRMとEDFの2種類の実装(合計4種類)をビルドするMakefile
  • fifo.c:RMの1プロセス,マルチスレッドの実装
  • fifo2.c:RMのマルチプロセスの実装(コマンドラインでタスク数分のプログラムを実行)
  • deadline.c:EDFの1プロセス,マルチスレッドの実装
  • deadline2.c:EDFのマルチプロセスの実装(コマンドラインでタスク数分のプログラムを実行)

以下のようにrm_and_edfディレクトリに移動してmakeでビルドすると,上記の4つのプログラムの実行ファイル(fifo,fifo2,deadline,deadline2)が作成されます.

1プロセス,マルチスレッドのRMの実装

1プロセス,マルチスレッドのRMの実装は以下になります.

実行結果は以下になります.

マルチプロセスのRMの実装(コマンドラインでタスク数分のプログラムを実行)

マルチプロセスのRMの実装(コマンドラインでタスク数分のプログラムを実行)は以下になります.

実行結果の例は以下になります.(プロセスIDは実行時により変動)

1プロセス,マルチスレッドのEDFの実装

1プロセス,マルチスレッドのEDFの実装は以下になります.

実行結果の例は以下になります.(実行するCPU IDは実行時により変動)

マルチプロセスのEDFの実装(コマンドラインでタスク数分のプログラムを実行)

マルチプロセスのEDFの実装(コマンドラインでタスク数分のプログラムを実行)は以下になります.

実行結果の例は以下になります.(プロセスIDや実行するCPU IDは実行時により変動)

まとめ

C言語でLinuxにおけるリアルタイムスケジューリングRMとEDFの実装を紹介しました.

具体的には,RMとEDFで,「1プロセス,マルチスレッド」と「マルチプロセス」の実装(合計4種類)を解説しました.

これらの4種類をゼロから実装するのは結構大変ですので,是非参考にして下さい.

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

-C LANGUAGE, TECHNOLOGY
-, , , , , ,