摘要一下讀了 TLPI 後的心得。
scheduling policy
POSIX 規定了幾種 scheduling policy, 它們的優先權如下:
SCHED_FIFO = SCHED_RR > SCHED_OTHER ~ SCHED_BATCH > SCHED_IDLE
舉例來說: SCHED_FIFO (99) > SCHED_FIFO (1) > SCHED_OTHER -20 (0) > SCHED_OTHER 19 (0) > SCHED_IDLE (0)
括號裡的數字是 process 的 static priority; -20 和 19 是 nice value, 見後文說明。
各 policy 的效果為:
- 所有 policy 都是 preemptive, 也就是高優先權 process 想執行的時候, 會搶走執行中低優先權 process 的 CPU
- SCHED_FIFO 和 SCHED_RR 的 static priority 範圍必須落在 1 ~ 99, 剩下三個 (SCHED_OTHER、...) 只能設 priority = 0。達到的效果是 SCHED_FIFO 和 SCHED_RR 永遠會比後幾種 policy 先執行
- SCHED_FIFO 和 SCHED_RR 是 real-time scheduling, 不過是 linux kernel 盡可能做到即時, 真的要做 real-time system (如汽車), 得用改過的 linux kernel
- SCHED_OTHER 和 SCHED_BATCH 的 static priority 都為 0, 所以會另外參考 dynamic priority 來決定順序, 這個值主要取決於 nice value (用 nice/renice 設), 只是參考值, 較低的 nice value 不會永遠表示較高的 dynamic priority
- 沒做設定的話, 預設 policy 是 SCHED_OTHER
- SCHED_BATCH 用在不需互動的程式, 會減少 wake-up 的頻率
- nice value 對 SCHED_IDLE 無效, 這個 policy 會保證有最低優先權
- 以上所有效果都會繼承到 sub-process
所以, 若用 SHCED_OTHER 配上 nice value, 可達到優先效果, 也不會有 process 餓死, 都搶不到 CPU。若用了 SCHED_FIFO 和 SCHED_RR, 要小心搶光 CPU 資源的情況。用 SCHED_OTHER 配上負值 nice value 也要小心。
保險機制
做為保險, 可用 setrlimit(RLIMIT_CPU) 限制執行時間, 超過 soft limit 會收到 SIGXCPU, 預設會掛掉該 process。若沒掛的話, 之後每秒鐘會收到一次 SIGXCPU, 直到超過 hard limit 收到 SIGKILL, 保證掛掉該 process。在這之間就有操作空間來調整自己的優先權。
或用 setrlimit(RLIMIT_RTTIME), 來限制在 real-time scheduling policy 下最長執行的時間, 遇到 blocking system call 後會歸零, 可避免失控超時。超時後的行為和 setrlimit(RLIMIT_CPU) 相同。 setrlimit 也和設 scheduling 一樣, 會繼承到 sub-process。
Affinity
Linux 另有特別的 system call 可限制 process 只能跑在那些 CPU, 在 man sched_setaffinity 的 CONFORMING TO 該節有註明這是 linux-specific 的功能。
透過 set affinity, 可以滿足一些特殊需求:
- 一台 8 core 的 server, 跑 8 個 process 限制它們各自用同一個 core 來服務大量 client, 讓 context switch 的次數降到最低
- 限制某些類型的 process 只能用部份 CPU, 確保隨時有餘力服務其它 process。比方說留一個 CPU 不跑 real-time process, 至少失控時還能登入使用 shell 處理
- 若 multi-thread 的程式沒寫好容易掛, 限制它們只跑在一個 core, 也許比較不會當 (這是我看 stackoverflow 裡某位路人提到他的用法 ...)
sched_setaffinity() 可以設在 process 也可設在 thread 上, 用的時候注意一下 man page 針對 pid 的說明。這個值也會繼承到 sub-process
另外, 經 wens 提醒, 還有 pthread_setaffinity_np() 可用來設 thread 的 affinity。查了一下 man page, 它是基於 sched_setaffinity() 的實作。待比較熟 multi-thread、pthread 的事情後, 大概會比較清楚為什麼要多包一個 pthread_setaffinity_np() 吧。
參考資料
- TLPI ch35
- man sched_setscheduler
- man sched_setaffinity
- man pthread_setaffinity_np
你漏掉 pthread_setaffinity_np / pthread_getaffinity_np
回覆刪除補進文內了, 謝啦
回覆刪除