生活随笔
收集整理的這篇文章主要介紹了
Linux CGroup之freezer分析与应用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Linux Kernel:4.4.17
CGroup的freezer子系統對于成批作業管理系統很有用,可以成批啟動/停止任務,以達到及其資源的調度。
freezer子系統也有助于針對運行一組任務設置檢查點。通過強制一組任務進入靜默狀態(quiescent state),freezer子系統可以獲得任務的鏡像。如果任務處于靜默狀態,其他任務就可以查看其proc或者讀取內核接口來獲取信息。通過收集必要信息到另一個node,然后在新node重啟任務,被檢查的任務可以在cluster中不同node之間遷移。
freezer是按等級劃分的,凍結一個CGroup會凍結旗下的所有任務,并且包括他的所有子CGroup。每個freezer都有自己的狀態和從父集成的狀態。只有父子狀態都為THAWED的時候,當前的CGroup才是THAWED。
代碼解析 freezer的代碼位于kernel/cgroup_freezer.c中,執行freeze的具體函數位于kernel/freezer.c中。
freezer_cgrp_subsys結構體如下:
struct cgroup_subsys freezer_cgrp_subsys = { ??? .css_alloc??? = freezer_css_alloc, ??? .css_online??? = freezer_css_online, ??? .css_offline??? = freezer_css_offline, ??? .css_free??? = freezer_css_free, ??? .attach??????? = freezer_attach, ??? .fork??????? = freezer_fork, ??? .legacy_cftypes??? = files, };
freezer子系統用來管理CGroup的結構體如下,只有一個參數state:
struct freezer { ??? struct cgroup_subsys_state??? css; ??? unsigned int??????????? state; };
freezer的sysfs文件節點:
static struct cftype files[] = { ??? { ??????? .name = "state",? 子系統當前的狀態 ??????? .flags = CFTYPE_NOT_ON_ROOT, ??????? .seq_show = freezer_read, ??????? .write = freezer_write, ??? }, ??? { ??????? .name = "self_freezing",? 自身當前是否處于freezing狀態 ??????? .flags = CFTYPE_NOT_ON_ROOT, ??????? .read_u64 = freezer_self_freezing_read, ??? }, ??? { ??????? .name = "parent_freezing",? 父子系統是否處于freezing狀態 ??????? .flags = CFTYPE_NOT_ON_ROOT, ??????? .read_u64 = freezer_parent_freezing_read, ??? }, ??? { }??? /* terminate */ };
繼續引申出freezer的狀態:
enum freezer_state_flags { ??? CGROUP_FREEZER_ONLINE??? = (1 << 0), /* freezer is fully online */? freezer沒有被凍結 ??? CGROUP_FREEZING_SELF??? = (1 << 1), /* this freezer is freezing */? freezer自身正在凍結中 ??? CGROUP_FREEZING_PARENT??? = (1 << 2), /* the parent freezer is freezing */? 父freezer正在凍結中 ??? CGROUP_FROZEN??????? = (1 << 3), /* this and its descendants frozen */? 自身和者子freezer已經被凍結
??? /* mask for all FREEZING flags */ ??? CGROUP_FREEZING??????? = CGROUP_FREEZING_SELF | CGROUP_FREEZING_PARENT,? 自身或者父freezer處于凍結過程中 };
freezer.state 那么這些狀態和freezer.state的對應關系如何呢?
CGROUP_FREEZING?????? FREEZING (凍結中)
CGROUP_FROZEN??????? FROZEN(已凍結)
CGROUP_FREEZER_ONLINE??? THAWED(解凍狀態)
FREEZING不是一個常態,他是當前CGroup(或其子CGroup)一組任務將要轉換到FROZEN狀態的一種中間狀態。同時,如果當前或子CGroup有新任務加入,狀態會從FROZEN返回到FRZEEING,直到任務被凍結。
只有FROZEN和THAWED兩個狀態是寫有效的。如果寫入FROZEN,當CGroup沒有完全進入凍結狀態,包括其所有子CGroup都會進入FREEZING狀態。
如果寫入THAWED,當前的CGroup狀態就會變成THAWED。有一種例外是如果父CGroup還是被凍結,則不會變成THAWED。如果一個CGroup的有效狀態變成THAWED,因當前CGroup造成的凍結都會停止,并離開凍結狀態。
freezer.self_freezing 只讀。0表示狀態是THAWED,其他為1。
freezer.parent_freezing 只讀。0表示父CGroup沒有一個進入凍結狀態,其他為1。
freezer_read 此函數會從子CGroup向上遍歷所有CGroup,直到最后一個遍歷當前CGroup。
static int freezer_read(struct seq_file *m, void *v) { ??? struct cgroup_subsys_state *css = seq_css(m), *pos;
??? mutex_lock(&freezer_mutex); ??? rcu_read_lock();
??? /* update states bottom-up */ ??? css_for_each_descendant_post(pos, css) { 倒序遍歷當前css的所有子css,最后一個遍歷根css。 ??????? if (!css_tryget_online(pos)) ??????????? continue; ??????? rcu_read_unlock();
??????? update_if_frozen(pos);? 更新當前css的state,這樣確保當前css狀態是最新的。然后根css的狀態也是最新的。
??????? rcu_read_lock(); ??????? css_put(pos); ??? }
??? rcu_read_unlock(); ??? mutex_unlock(&freezer_mutex);
??? seq_puts(m, freezer_state_strs(css_freezer(css)->state)); ??? seq_putc(m, '\n'); ??? return 0; }
freezer_write static ssize_t freezer_write(struct kernfs_open_file *of, ???????????????? char *buf, size_t nbytes, loff_t off) { ??? bool freeze;
??? buf = strstrip(buf);
??? if (strcmp(buf, freezer_state_strs(0)) == 0)? 對應THAWED狀態 ??????? freeze = false; ??? else if (strcmp(buf, freezer_state_strs(CGROUP_FROZEN)) == 0)? 對應FROZEN狀態 ??????? freeze = true; ??? else ??????? return -EINVAL;
??? freezer_change_state(css_freezer(of_css(of)), freeze); 切換freezer狀態 ??? return nbytes; }
freezer_change_state static void freezer_change_state(struct freezer *freezer, bool freeze) { ??? struct cgroup_subsys_state *pos;
??? /* ???? * Update all its descendants in pre-order traversal.? Each ???? * descendant will try to inherit its parent's FREEZING state as ???? * CGROUP_FREEZING_PARENT. ???? */ ??? mutex_lock(&freezer_mutex); ??? rcu_read_lock(); ??? css_for_each_descendant_pre(pos, &freezer->css) {? 這里和freezer_read是一個相反的過程,這是從跟css開始,逐級遍歷所有css。 ??????? struct freezer *pos_f = css_freezer(pos); ??????? struct freezer *parent = parent_freezer(pos_f);
??????? if (!css_tryget_online(pos)) ??????????? continue; ??????? rcu_read_unlock();
??????? if (pos_f == freezer)? 如果是根css則進入CGROUP_FREEZING_SELF ??????????? freezer_apply_state(pos_f, freeze, ??????????????????????? CGROUP_FREEZING_SELF); ??????? else ??????????? freezer_apply_state(pos_f,? 其他css,表示是繼承CGROUP_FREEZING_PARENT ??????????????????????? parent->state & CGROUP_FREEZING, ??????????????????????? CGROUP_FREEZING_PARENT);
??????? rcu_read_lock(); ??????? css_put(pos); ??? } ??? rcu_read_unlock(); ??? mutex_unlock(&freezer_mutex); }
freezer_apply_state static void freezer_apply_state(struct freezer *freezer, bool freeze, ??????????????? unsigned int state) { ??? /* also synchronizes against task migration, see freezer_attach() */ ??? lockdep_assert_held(&freezer_mutex);
??? if (!(freezer->state & CGROUP_FREEZER_ONLINE)) ??????? return;
??? if (freeze) {? 需要freeze,調用freeze_cgroup。凍結當前Cgroup下面所有task ??????? if (!(freezer->state & CGROUP_FREEZING)) ??????????? atomic_inc(&system_freezing_cnt); ??????? freezer->state |= state; ??????? freeze_cgroup(freezer); ??? } else {? 不需要freeze ??????? bool was_freezing = freezer->state & CGROUP_FREEZING;
??????? freezer->state &= ~state;
??????? if (!(freezer->state & CGROUP_FREEZING)) {? 并且不是CGROUP_FREEZING狀態 ??????????? if (was_freezing) ??????????????? atomic_dec(&system_freezing_cnt); ??????????? freezer->state &= ~CGROUP_FROZEN; ??????????? unfreeze_cgroup(freezer);? 此CGroup下的所有tasks解凍 ??????? } ??? } }
freeze_task和__thaw_task 在kernel/freezer.c中定義了凍結和解凍task的執行函數freeze_task和__thaw_task。
在freezer的tasks中存放了所有的進程,遍歷所有進程執行freeze_task或者__thaw_task,即可凍結或解凍此freezer CGroup。
?
bool freeze_task(struct task_struct *p) { ??? unsigned long flags;
??? /* ???? * This check can race with freezer_do_not_count, but worst case that ???? * will result in an extra wakeup being sent to the task.? It does not ???? * race with freezer_count(), the barriers in freezer_count() and ???? * freezer_should_skip() ensure that either freezer_count() sees ???? * freezing == true in try_to_freeze() and freezes, or ???? * freezer_should_skip() sees !PF_FREEZE_SKIP and freezes the task ???? * normally. ???? */ ??? if (freezer_should_skip(p))? 在需要凍結的時候,是否跳過此進程 ??????? return false;
??? spin_lock_irqsave(&freezer_lock, flags); ??? if (!freezing(p) || frozen(p)) {? 如果進程不是freezing,或已經被FROZEN,返回false ??????? spin_unlock_irqrestore(&freezer_lock, flags); ??????? return false; ??? }
??? if (!(p->flags & PF_KTHREAD)) ??????? fake_signal_wake_up(p);? 不是內核線程,發送偽喚醒信號 ??? else ??????? wake_up_state(p, TASK_INTERRUPTIBLE);? 設置進程喚醒條件為TASK_INTERRUPTIBLE
??? spin_unlock_irqrestore(&freezer_lock, flags); ??? return true; }
?
void __thaw_task(struct task_struct *p) { ??? unsigned long flags;
??? spin_lock_irqsave(&freezer_lock, flags); ??? if (frozen(p))? 如果已經被FROZEN,則簡單的去喚醒 ??????? wake_up_process(p); ??? spin_unlock_irqrestore(&freezer_lock, flags); }
?
應用? 一個小實驗 為了直觀的理解,做一個小實驗。
源碼在:https://github.com/arnoldlu/common-use/blob/master/tools/loop.py
1.啟動一個占用率100%的進程:
2.top查看進程情況,CPU占用率100%:
3.新建一個freezer CGroup,并將7234進程寫入tasks:
4.將FROZEN寫入freezer.state:
5.top –p 7234查看進程情況,:
6.將THAWED寫入freezer.state之后:
7.可以看到7234的CPU占用率立馬又變成100%:
其他應用 比如LISA工具在測試的時候,為了排除干擾,只保留必須的進程,凍結其余進程:
?
參考資料 Freezer Subsystem:http://lxr.free-electrons.com/source/Documentation/cgroups/freezer-subsystem.txt?v=4.4
freezer子系統: http://www.cnblogs.com/lisperl/archive/2012/04/25/2469587.html
總結
以上是生活随笔 為你收集整理的Linux CGroup之freezer分析与应用 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。