1 cgroup介紹
CGroup是control group的簡稱,它為Linux kernel提供一種任務聚集和划分的機制,可以限制、記錄、隔離進程組(process groups)所使用的資源(cpu、memory、I/O等)。CGroup也是LXC為實現虛擬化所使用的資源管理手段。CGroup本身是提供將進程進行分組化管理的功能和接口的基礎結構,I/O或內存的分配控制等具體的資源管理功能是通過這個功能來實現的。這些具體的資源管理功能稱為CGroup子系統。
CGroup子系統包含如下:
子系統 |
主要功能 |
blkio |
設置限制每個塊設備的輸入輸出控制。 |
cpu |
使用調度程序為CGroup任務提供CPU的訪問。 |
cpuacct |
產生CGroup任務的CPU資源報告,CPU Accounting Controller。 |
cpuset |
如果是多核CPU,這個子系統就會為CGroup任務分配單獨的CPU和內存。 |
devices |
允許或拒絕CGroup任務對設備的訪問。 |
freezer |
暫停或恢復CGroup任務。 |
hugetlb |
允許限制CGroup 的HubeTLB使用 |
memory |
設置每個CGroup的內存限制以及產生內存資源報告。 |
net_cls |
標記每個網絡包以供CGroup方便使用。 |
net_prio |
提供接口以供動態調節程序的網絡傳輸優先級。 |
perf_event |
增加了對沒group的檢測跟蹤的能力,即可以檢測屬於某個特定的group的所有線程以及運行在特定CPU上的線程。 |
1.1 subsystem、task、hierarchy介紹及其關系
任務task,在CGroup中,任務就是系統的一個進程。
CGroup就是一組按照某種標准進行划分的進程。CGroup中的資源控制都是以control group為單位實現。一個進程可以加入到某個控制族群,也可以一個進程組遷移到另一個控制族群。
subusystem即子系統,是CGroup中可添加刪除的模塊,是CGroup下對資源進行的一種封裝,比如內存資源、CPU資源、網絡資源等。一個子系統就是一個資源控制器,鼻子痛必須附加(attach)到一個層級上才能起作用,一個子系統附加到某個層級后,這個層級上的所有控制組全都受到這個子系統的控制。
hierarchy可以認為是一系列cgroups的集合。hierarchy是這個集合的根。
相互關系:
每次在系統中創建新層級時,該系統中的所有任務都是那個層級的默認 cgroup(我們稱之為 root cgroup,此 cgroup 在創建層級時自動創建,后面在該層級中創建的 cgroup 都是此
cgroup 的后代)的初始成員;
一個子系統最多只能附加到一個層級;
一個層級可以附加多個子系統;
一個任務可以是多個 cgroup 的成員,但是這些 cgroup 必須在不同的層級;
系統中的進程(任務)創建子進程(任務)時,該子任務自動成為其父進程所在 cgroup 的成員。然后可根據需要將該子任務移動到不同的 cgroup 中,但開始時它總是繼承其父任務的 cgroup。
圖表 1CGroup層級圖
1.2 mount介紹
更詳細信息參考:
linux內核mount系統調用源碼分析http://blog.csdn.net/wugj03/article/details/41958029/
linux系統調用mount全過程分析http://blog.csdn.net/skyflying2012/article/details/9748133
在系統啟動時,mount需要的CGroup子系統:
mount cgroup none /dev/cpuctl cpu |
在用戶空間將mount命令轉換成系統調用sys_mount:
asmlinkage long sys_mount(char __user *dev_name, char __user *dir_name, char __user *type, unsigned long flags, void __user *data); |
從sys_mount到具體文件系統的.mount調用流程如下:
sys_mount(fs/namespace.c) -->do_mount(kernel_dev, dir_name, kernel_type, flags, (void *)data_pate) -->do_new_mount (&path, type_page, flags, mnt_flags,dev_name, data_page) --> vfs_kern_mount(type, flags, name, data) --> mount_fs(type, flags, name, data) --> type->mount(type, flags, name, data) --> cgroup_mount(fs_type, flags, unused_dev_name, data) |
struct file_system_type { const char *name; 文件系統名稱 int fs_flags; … struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); 掛載文件系統的調用。 void (*kill_sb) (struct super_block *); 卸載文件系統的調用 struct module *owner; VFS內部調用時使用 struct file_system_type * next; struct hlist_head fs_supers; struct lock_class_key s_lock_key; struct lock_class_key s_umount_key; struct lock_class_key s_vfs_rename_key; struct lock_class_key s_writers_key[SB_FREEZE_LEVELS]; struct lock_class_key i_lock_key; struct lock_class_key i_mutex_key; struct lock_class_key i_mutex_dir_key; } |
2 代碼分析
2.1 核心
2.1.1 框架結構圖
CGoup核心主要創建一系列sysfs文件,用戶空間可以通過這些節點控制CGroup各子系統行為。各子系統模塊根據參數,在執行過程中或調度進程道不同CPU上,或控制CPU占用時間,或控制IO帶寬等等。另,在每個進程的proc文件系統中都有一個cgroup,顯示該進程對應的CGroup各子系統信息。
如果CGroup需要early_init,start_kernel調用cgroup_init_early在系統啟動時進行CGroup初始化。
int __init cgroup_init_early(void) { static struct cgroup_sb_opts __initdata opts; struct cgroup_subsys *ss; int i; init_cgroup_root(&cgrp_dfl_root, &opts); cgrp_dfl_root.cgrp.self.flags |= CSS_NO_REF; RCU_INIT_POINTER(init_task.cgroups, &init_css_set); for_each_subsys(ss, i) { ss->id = i; ss->name = cgroup_subsys_name[i]; if (ss->early_init) cgroup_init_subsys(ss, true); } return 0; } |
CGroup的起點是start_kernel->cgroup_init,進入CGroup的初始化,主要注冊cgroup文件系統和創建、proc文件,初始化不需要early_init的子系統。
int __init cgroup_init(void) { … for_each_subsys(ss, ssid) { 遍歷所有子系統,初始化,根據屬性配置不同文件節點 if (ss->early_init) { early_init是能的已經在cgroup_init_early中初始化 struct cgroup_subsys_state *css = init_css_set.subsys[ss->id]; css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, GFP_KERNEL); BUG_ON(css->id < 0); } else { cgroup_init_subsys(ss, false); } list_add_tail(&init_css_set.e_cset_node[ssid], &cgrp_dfl_root.cgrp.e_csets[ssid]); cgrp_dfl_root.subsys_mask |= 1 << ss->id; if (cgroup_legacy_files_on_dfl && !ss->dfl_cftypes) ss->dfl_cftypes = ss->legacy_cftypes; if (!ss->dfl_cftypes) cgrp_dfl_root_inhibit_ss_mask |= 1 << ss->id; 根據不同類型,創建不同節點列表。 if (ss->dfl_cftypes == ss->legacy_cftypes) { WARN_ON(cgroup_add_cftypes(ss, ss->dfl_cftypes)); } else { WARN_ON(cgroup_add_dfl_cftypes(ss, ss->dfl_cftypes)); WARN_ON(cgroup_add_legacy_cftypes(ss, ss->legacy_cftypes)); } if (ss->bind) ss->bind(init_css_set.subsys[ssid]); } err = sysfs_create_mount_point(fs_kobj, "cgroup"); 創建掛載節點/sys/fs/cgroup if (err) return err; err = register_filesystem(&cgroup_fs_type); 注冊cgroup_fs_type文件系統。 if (err < 0) { sysfs_remove_mount_point(fs_kobj, "cgroup"); return err; } proc_create("cgroups", 0, NULL, &proc_cgroupstats_operations); 創建/proc/cgroups節點 return 0; } |
/proc/<pid>/cgroup指向proc_cgroup_show,用於顯示此pid所對應的cgroup路徑信息:
static const struct pid_entry tid_base_stuff[] = { … #ifdef CONFIG_CGROUPS ONE("cgroup", S_IRUGO, proc_cgroup_show), #endif … } |
CGroup的debug接口在CONFIG_CGROUP_DEBUG使能后打開:
struct cgroup_subsys debug_cgrp_subsys = { .css_alloc = debug_css_alloc, .css_free = debug_css_free, .legacy_cftypes = debug_files, }; |
cgroup_fs_type作為mount命令的參數,其中cgroup_mount為各subsystem進行mount工作。
2.1.2 核心結構體分析
struct cgroup_subsys { struct cgroup_subsys_state *(*css_alloc)(struct cgroup_subsys_state *parent_css); 創建cgroup_subsys_state結構體,和css_free相對。 int (*css_online)(struct cgroup_subsys_state *css); 在subsystem相關資源分配完之后,進行online相關操作,和css_offline相對。 void (*css_offline)(struct cgroup_subsys_state *css); void (*css_released)(struct cgroup_subsys_state *css); void (*css_free)(struct cgroup_subsys_state *css); void (*css_reset)(struct cgroup_subsys_state *css); void (*css_e_css_changed)(struct cgroup_subsys_state *css); int (*allow_attach)(struct cgroup_subsys_state *css, struct cgroup_taskset *tset); int (*can_attach)(struct cgroup_subsys_state *css, struct cgroup_taskset *tset); void (*cancel_attach)(struct cgroup_subsys_state *css, struct cgroup_taskset *tset); void (*attach)(struct cgroup_subsys_state *css, struct cgroup_taskset *tset); allow_attach和can_attach都是在將task附着到cgroup之前進行檢查,如果失敗則停止附着過程。 cancel_attach是在can_attache成功之后,但是attache又失敗的情況下調用。 void (*fork)(struct task_struct *task); 將一個task寫入cgroup void (*exit)(struct cgroup_subsys_state *css, 將一個task移出cgroup struct cgroup_subsys_state *old_css, struct task_struct *task); void (*bind)(struct cgroup_subsys_state *root_css); int disabled; int early_init; 是否需要進行early_init,如果需要會在cgroup_init_early中提前進行初始化。 bool broken_hierarchy; bool warned_broken_hierarchy; /* the following two fields are initialized automtically during boot */ int id; #define MAX_CGROUP_TYPE_NAMELEN 32 const char *name; /* link to parent, protected by cgroup_lock() */ struct cgroup_root *root; /* idr for css->id */ struct idr css_idr; /* * List of cftypes. Each entry is the first entry of an array * terminated by zero length name. */ struct list_head cfts; /* * Base cftypes which are automatically registered. The two can * point to the same array. */ struct cftype *dfl_cftypes; /* for the default hierarchy */ struct cftype *legacy_cftypes; /* for the legacy hierarchies */ CGroup子系統的節點,這些節點都是在xxx_cgrp_subsys中定義的。 /* * A subsystem may depend on other subsystems. When such subsystem * is enabled on a cgroup, the depended-upon subsystems are enabled * together if available. Subsystems enabled due to dependency are * not visible to userland until explicitly enabled. The following * specifies the mask of subsystems that this one depends on. */ unsigned int depends_on; } |
legacy hierarchy類型的接口文件:
static struct cftype cgroup_legacy_base_files[] = { { .name = "cgroup.procs", … }, { .name = "cgroup.clone_children", .read_u64 = cgroup_clone_children_read, .write_u64 = cgroup_clone_children_write, }, { .name = "cgroup.sane_behavior", .flags = CFTYPE_ONLY_ON_ROOT, .seq_show = cgroup_sane_behavior_show, }, { .name = "tasks", … }, { .name = "notify_on_release", .read_u64 = cgroup_read_notify_on_release, .write_u64 = cgroup_write_notify_on_release, }, { .name = "release_agent", … }, { } /* terminate */ } |
cgroup.procs:屬於該分組的PID列表,僅包括多線程進程的線程leader的TID,這點和tasks不同。
cgroup.clone_children:僅適用於cpuset。如果使能,創建子cpuset時,就會拷貝父cpust的配置。
cgroup.sane_behavior:未實現。
tasks:屬於該分組的線程TID列表。
notify_on_release:設置是否執行release_agent,為1時使能。
release_agent:刪除分組時執行的命令,這個文件只存在於根分組。
2.2 子系統
CGroup子系統都定義在cgroup_subsys.h中;kernel/cgroup.c包含此頭文件,定義了兩個結構體數組cgroup_subsys和cgroup_subsys_name。CGroup core對於各子系統的引用都是通過cgroup_subsys這個數組。
/* generate an array of cgroup subsystem pointers */ #define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, static struct cgroup_subsys *cgroup_subsys[] = { #include <linux/cgroup_subsys.h> }; #undef SUBSYS /* array of cgroup subsystem names */ #define SUBSYS(_x) [_x ## _cgrp_id] = #_x, static const char *cgroup_subsys_name[] = { #include <linux/cgroup_subsys.h> }; #undef SUBSYS |
2.2.1 blkio
block/blk-cgroup.c中定義了blkio子系統結構體:
struct cgroup_subsys io_cgrp_subsys = { |
由於默認init.rc沒有加載,可以添加創建相關以便研究:
mkdir /dev/blkio 0700 root system |
由於cfq_iosched.c中cfq_init注冊了blkcg_policy_cfq,配置節點就變成如下列表。
CFQ,Complete Fairness Queueing。CFQ調度器主要目的提供一種進程間公平分配磁盤帶寬的調度方法。
深度閱讀:http://lxr.free-electrons.com/source/Documentation/block/cfq-iosched.txt
blkio.io_merged |
2.2.2 cpu
kernel/sched/core.c定義了cpu_cgrp_subsys結構體,需要進行early_init。
struct cgroup_subsys cpu_cgrp_subsys = { .css_alloc = cpu_cgroup_css_alloc, .css_free = cpu_cgroup_css_free, .css_online = cpu_cgroup_css_online, .css_offline = cpu_cgroup_css_offline, .fork = cpu_cgroup_fork, .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, .allow_attach = subsys_cgroup_allow_attach, .exit = cpu_cgroup_exit, .legacy_cftypes = cpu_files, .early_init = 1, }; |
這里重點分析一下cpu_files,在實際使用中打開了shares/rt_runtime_us/rt_perios_us。
其中shares是針對CFS進程的,rt_runtime_us/rt_perios_us是針對RT進程的。
另外cfs_perios_us/cfs_quota_us是設置CFS進程占用的CPU帶寬。
static struct cftype cpu_files[] = { |
下面是Android一個配置,根目錄下面對應的是前台應用,bg_non_interactive對應的是后台應用:
/dev/cpuctl/cpu.shares 1024 /dev/cpuctl/cpu.rt_runtime_us 950000 /dev/cpuctl/cpu.rt_period_us 1000000 /dev/cpuctl/bg_non_interactive/cpu.shares 52 /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 10000 /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000 |
cpu.shares:保存了整數值,用來設置cgroup分組任務獲得CPU時間的相對值。舉例來說,cgroup A和cgroup B的cpu.share值都是1024,那么cgroup A 與cgroup B中的任務分配到的CPU時間相同,如果cgroup C的cpu.share為512,那么cgroup C中的任務獲得的CPU時間是A或B的一半。
從上面的數據可以看出,默認分組與bg_non_interactive分組cpu.share值相比接近於20:1。由於Android中只有這兩個cgroup,也就是說默認分組中的應用可以利用95%的CPU,而處於bg_non_interactive分組中的應用則只能獲得5%的CPU利用率。
52/(1024+52)=4.8%
cpu.rt_runtime_us:主要用來設置cgroup獲得CPU資源的周期,單位為微妙。
cpu.rt_period_us:主要是用來設置cgroup中的任務可以最長獲得CPU資源的時間,單位為微秒。設定這個值可以訪問某個cgroup獨占CPU資源。最長的獲取CPU資源時間取決於邏輯CPU的數量。比如cpu.rt_runtime_us設置為200000(0.2秒),cpu.rt_period_us設置為1000000(1秒)。在單個邏輯CPU上的獲得時間為每秒為0.2秒。 2個邏輯CPU,獲得的時間則是0.4秒。
從上面數據可以看出,默認分組中單個邏輯CPU下每一秒內可以獲得0.95秒執行時間。bg_non_interactive分組下單個邏輯CPU下每一秒內可以獲得0.01秒。
疑問點:在shares和rt_period_us/cfs_period_us之間時間究竟如何分配?是先按照shares分組分配CPU時間,然后組內優先RT,剩下來給CFS?還是先RT進程按照shares分配,剩下來給CFS按照shares分配。分配時間shares在先還是RT/CFS之間在先?
cpu.cfs_runtime_us
cpu.cfs_quota_us
一個測試腳本:
#!/usr/bin/env python # coding=utf-8 i = 0 while True: i = i + 1 |
1.執行loop.py,python loop.py &。
2.top監控,可以看出CUP占用率在100%。
3.echo pid > tasks,將loop.py進程加入cpu組。
4.echo 10000 > cpu.cfs_quota_us,在cpu.cfs_period_us為100000的情況下占用率應該為10%.
5.下面依次為5000、50000對應占用率為5%、50%的情況。
2.2.3 cpuacct
kernel/sched/cpuacct.c中定義cpuacct_cgrp_subsys子系統結構體:
struct cgroup_subsys cpuacct_cgrp_subsys = { |
其中legacy_cftypes的files是cpuacct子系統的精髓:
static struct cftype files[] = { |
要理解每個統計信息的含義就繞不開struct cpuacct這個結構體。
usage:是所有usage_percpu之和。
usage_percpu:是每個CPU的使用量。
stat:分別統計user和system兩種類型的,user對應CPUTIME_USER、CPUTIME_NICE,system對應CPUTIME_SYSTEM、CPUTIME_IRQ、CPUTIME_SOFTIRQ。
struct cpuacct { enum cpu_usage_stat { |
下面HiKey的一個瞬間的cpuacct值:
cpuacct.stat |
user 2312 system 2662 |
我們將其轉換成每個CPU用量的百分比,結合cpuset的設置。可以得出結論:
cpu0的任務最重,所有類型的進程都可能在cpu0上調度。,cluster0要比cluster1更多的被使用。
cpu7最少被使用,因為只有top-app才會使用。
/dev/cpuset/cpus 0-7 /dev/cpuset/background/cpus 0 /dev/cpuset/foreground/cpus 0-6 /dev/cpuset/system-background/cpus 0-3 /dev/cpuset/top-app/cpus 0-7 |
2.2.4 cpuset
cpuset是一個用來分配限制CPU和Memory資源的CGroup子系統。cpuset使用sched_setaffinity系統調用來設置tasks的CPU親和性,使用mbind和set_mempolicy包含Memory策略中的Memory Nodes。調度器不會在cpuset之外的CPU上面調度tasks,頁分配器也不會在mems_allowed之外的內存中分配。
cpuset提供了一種靈活配置CPU和Memory資源的機制。Linux中已經有配置CPU資源的cpu子系統和Memory資源的memory子系統。
kernel/cpuset.c中定義了子系統cpuset結構體如下:
struct cgroup_subsys cpuset_cgrp_subsys = { .css_alloc = cpuset_css_alloc, .css_online = cpuset_css_online, .css_offline = cpuset_css_offline, .css_free = cpuset_css_free, .can_attach = cpuset_can_attach, .cancel_attach = cpuset_cancel_attach, .attach = cpuset_attach, .bind = cpuset_bind, .legacy_cftypes = files, .early_init = 1, }; |
cpu_exclusive cpu資源是否專用? cpus 當前cpuset的CPU列表。 effective_cpus 有效的CPU列表 effective_mems 有效的memory mem_exclusive memory資源是否專用? mem_hardwall memory_migrate 如果置位,則將頁面移到cpusets節點 memory_pressure 測量當前cpuset的paging壓力 memory_spread_page if set, spread page cache evenly on allowed nodes memory_spread_slab if set, spread slab cache evenly on allowed nodes mems 當前cpuset的Memory Nodes列表 sched_load_balance 當前cpuset是否進行負載均衡 sched_relax_domain_level the searching range when migrating tasks |
如果設置了cpu/memory專用,除了直接父子,其他cpuset不可以使用相應的CPU或者Memory Nodes。
其他項的詳細解釋見:Documentation/cgroups/cpust.txt。
cpuset結構體中設置的cpus_allowed、mems_allowed、effective_cpus、effective_mems都會在寫入cpus、mems節點是更行到當前cpuset下的task相關的。
其他情況還包括CPU hotplug的時候動態更新cpus_allowed信息。
cpuset_write_resmask -->update_cpumask -->update_nodemask -->update_cpumasks_hier -->update_nodemasks_hier -->update_tasks_cpumask 遍歷當前cpuset下所有的task的cpus_allowed -->update_tasks_nodemask 更新當前cpuset下所有task的mems_allowed -->set_cpus_allowed_ptr 將cpuset的cpumask賦給task->cpus_allowed,將task轉移到合適的CPU;如果CPU被拔出,則將其遷移到其它被允許的CPU上。 --> cpuset_migrate_mm 將memory區域從一個node遷移到另一個 --> do_migrate_pages 在兩個node之間移動頁 |
struct cpuset { struct cgroup_subsys_state css; unsigned long flags; /* "unsigned long" so bitops work */ /* user-configured CPUs and Memory Nodes allow to tasks */ cpumask_var_t cpus_allowed; 和task_struct->cpus_allowed相對應 nodemask_t mems_allowed; 和task_struct->mems_allowed相對應 /* effective CPUs and Memory Nodes allow to tasks */ cpumask_var_t effective_cpus; nodemask_t effective_mems; default hierarchy:effective_mask=configured_mask&parent’s effective_mask legacy hierarchy: user-configured masks = effective masks nodemask_t old_mems_allowed; struct fmeter fmeter; /* memory_pressure filter */ int attach_in_progress; /* for custom sched domain */ int relax_domain_level; } |
cpuset在Android的應用主要差異就是不同組配置不同的cpus,根據進程類型細分。
可以看出優先級越高的進程可以占用的cpu越多。
/dev/cpuset/cpus 0-7 /dev/cpuset/background/cpus 0 /dev/cpuset/foreground/cpus 0-6 /dev/cpuset/system-background/cpus 0-3 /dev/cpuset/top-app/cpus 0-7 |
只有根節點的mem_exclusive使能,其他都未使能。
/dev/cpuset/mem_exclusive 1 /dev/cpuset/background/mem_exclusive 0 /dev/cpuset/foreground/mem_exclusive 0 /dev/cpuset/system-background/mem_exclusive 0 /dev/cpuset/top-app/mem_exclusive 0 |
2.2.5 devices
security/device_cgroup.c定義devices子系統結構體:
struct cgroup_subsys devices_cgrp_subsys = { |
2.2.6 hugetlb
mm/hugetlb_cgroup.c
struct cgroup_subsys hugetlb_cgrp_subsys
2.2.7 memory
mm/memcontrol.c中定義了memory子系統memory_cgrp_subsys如下:
struct cgroup_subsys memory_cgrp_subsys = { .css_alloc = mem_cgroup_css_alloc, .css_online = mem_cgroup_css_online, .css_offline = mem_cgroup_css_offline, .css_free = mem_cgroup_css_free, .css_reset = mem_cgroup_css_reset, .can_attach = mem_cgroup_can_attach, .cancel_attach = mem_cgroup_cancel_attach, .attach = mem_cgroup_move_task, .allow_attach = mem_cgroup_allow_attach, .bind = mem_cgroup_bind, .dfl_cftypes = memory_files, .legacy_cftypes = mem_cgroup_legacy_files, .early_init = 0, }; |
memory_files和mem_cgroup_legacy_files的解釋如下:
cgroup.event_control event_fd的接口 memory.failcnt 顯示內存(進程內存+頁面緩存) 達到限制值的次數 memory.force_empty 強制釋放分配給分組的內存 memory.kmem.failcnt 顯示內存(進程內存+頁面緩存)+交換區到達限制值的次數 memory.kmem.limit_in_bytes memory.kmem.max_usage_in_bytes 顯示記錄的內存(進程內存+頁面緩存)+交換區使用量的最大值 memory.kmem.slabinfo memory.kmem.tcp.failcnt memory.kmem.tcp.limit_in_bytes memory.kmem.tcp.max_usage_in_bytes memory.kmem.tcp.usage_in_bytes memory.kmem.usage_in_bytes memory.limit_in_bytes 顯示當前內存(進程內存+頁面緩存)的使用量的限制值 memory.max_usage_in_bytes 顯示記錄的內存使用量的最大值 memory.memsw.failcnt memory.memsw.limit_in_bytes 顯示當前內存(進程內存+頁面緩存)+交換區使用量的限制值 memory.memsw.usage_in_bytes 顯示當前內存(進程內存+頁面緩存)+交換區使用量的使用值 memory.memsw.max_usage_in_bytes memory.memsw.usage_in_bytes 顯示當前內存(進程內存+頁面緩存)+交換區使用量 memory.move_charge_at_immigrate memory.oom_control memory.pressure_level 設置內存壓力通知 memory.soft_limit_in_bytes memory.stat 輸出統計信息 memory.swappiness 設置、顯示針對分組的swappiness memory.usage_in_bytes 顯示當前內存(進程內存+頁面緩存)的使用量 memory.use_hierarchy 設置、顯示層次結構的使用 |
Android下的一個實例,顯示/dev/memcfg/apps並未使用:
Item | /dev/memcfg | /dev/memcfg/apps |
memory.failcnt |
0 |
0 |
兩者的memory.stat如下:
/dev/memcfg | /dev/memcfg/apps |
cache 446832640 |
cache 0 |
2.2.8 net_cls
net/core/netclassid_cgroup.c
struct cgroup_subsys net_cls_cgrp_subsys
2.2.9 net_prio
net/core/netprio_cgroup.c
struct cgroup_subsys net_prio_cgrp_subsys
2.2.10 net_perf
kernel/event/core.c
struct cgroup_subsys perf_event_cgrp_subsys
2.2.11 perf_event
kernel/events/core.c
struct cgroup_subsys perf_event_cgrp_subsys
3 CGroup在Android中的應用
# Mount cgroup mount point for cpu accounting mount cgroup none /acct cpuacct |
schedtune是ARM/Linaro為了EAS新增的一個子系統,主要用來控制進程調度選擇CPU以及boost觸發。
這部分涉及到EAS、Android進程調度策略等相關知識,另起一篇專門介紹《Android中關於cpu/cpuset/schedtune的應用》。
https://git.linaro.org/people/john.stultz/android-dev.git
branch:remotes/origin/android-hikey-linaro-4.4-EASv5.2+aosp
# Create energy-aware scheduler tuning nodes mkdir /dev/stune mount cgroup none /dev/stune schedtune |
# root memory control cgroup, used by lmkd mkdir /dev/memcg 0700 root system mount cgroup none /dev/memcg memory |
# Create cgroup mount points for process groups mkdir /dev/cpuctl mount cgroup none /dev/cpuctl cpu |
# sets up initial cpusets for ActivityManager |
以上sysfs節點在Android中都有對應的HAL層庫文件,其中cpuctl/cpuset/stune對應libcutils.so,代碼在system/core/libcutils中,主要根據進程的不同分類,進行CPU、memory資源控制;memory子系統對應lmkd系統服務,代碼在system/core/lmkd,主要在內存緊張情況下,殺死低優先級進程,以達到釋放內存的目的。
針對libcutils.so會在《Android中關於cpu/cpuset/schedtune的應用》,lmkd會在《Android中基於CGroup的memory子系統HAL層分析-lmkd》。