先做一个小实验
创建两个python进程,然后分别绑定在第0,1号CPU上.
创建cpuset的cgroup
➜ / mkdir -p /cgroup/cpuset1 ➜ / mount -t cgroup -o cpuset cpuset1 /cgroup/cpuset1 ➜ / ls /cgroup/cpuset1/ cgroup.clone_children cpuset.effective_cpus cpuset.memory_pressure cpuset.sched_load_balance cgroup.procs cpuset.effective_mems cpuset.memory_pressure_enabled cpuset.sched_relax_domain_level cgroup.sane_behavior cpuset.mem_exclusive cpuset.memory_spread_page notify_on_release cpuset.cpu_exclusive cpuset.mem_hardwall cpuset.memory_spread_slab release_agent cpuset.cpus cpuset.memory_migrate cpuset.mems tasks
创建python进程
➜ / echo 'while True: pass' | python & [1] 19983 19985 ➜ / echo 'while True: pass' | python & [2] 20006 20012
通过cgrup的cpuset子系统绑定cpu
绑定第一个python进程
mkdir /cgroup/cpuset1/foo1 echo 0 > /cgroup/cpuset1/foo1/cpuset.mems echo 0 > /cgroup/cpuset1/foo1/cpuset.cpus echo 20012 > /cgroup/cpuset1/foo1/tasks 其中, cpuset.mems是绑定内存节点,参见NUMA. cpuset.cpus是绑定cpu
绑定第二个python进程
mkdir /cgroup/cpuset1/foo1 echo 0 > /cgroup/cpuset1/foo1/cpuset.mems echo 1 > /cgroup/cpuset1/foo1/cpuset.cpus echo 19985 > /cgroup/cpuset1/foo1/tasks
绑定效果
cgroup 是如何在系统中生效的?
cgroup是通过文件系统VFS的接口在内核中生效的.
cgroup的术语
cgroup
关联一组task和一组subsystem的配置参数。一个task对应一个进程, cgroup是资源分片的最小单位。cgroup是树状组织起来.
subsystem
资源管理器,一个subsystem对应一项资源的管理,如 cpu, cpuset, memory, blkio, ns, net_cls等.
hierarchy
关联一个到多个subsystem和一组树形结构的cgroup. 和cgroup不同,hierarchy包含的是可管理的subsystem而非具体参数.
总结
cgroup对资源的管理是一个树形结构,类似进程。子cgroup继承父cgroup. 但是, cgroup可以有多个根,每mount一次都有一个根.
进程和cgroup的关系
cgroup mount进kernel的过程
mount -t cgroup -o cpuset cpuset1 /cgroup/cpuset1
-t, 指定了文件系统的类型是cgroup. -o, 指定了子系统是cpuset, 这个字符串会一直传给具体的文件系统解析函数.
cgroup文件系统的注册
kernel在启动过程中会注册,并且初始化cgroup文件系统.
调用栈:
asmlinkage void __init start_kernel(void) { cgroup_init(); } int __init cgroup_init(void) { for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { struct cgroup_subsys *ss = subsys[i]; if (!ss->early_init) cgroup_init_subsys(ss); if (ss->use_id) cgroup_subsys_init_idr(ss); } err = register_filesystem(&cgroup_fs_type); hhead = css_set_hash(init_css_set.subsys); }
其中,
static struct file_system_type cgroup_fs_type = { .name = "cgroup", .get_sb = cgroup_get_sb, .kill_sb = cgroup_kill_sb, };
cgroup的super block
static int cgroup_get_sb(struct file_system_type *fs_type, int flags, const char *unused_dev_name, void *data, struct vfsmount *mnt) { // 解析 "-o cpuset" ret = parse_cgroupfs_options(data, &opts); // 分配一个 cgroupfs_root // 注意,如果是mount一个已经被mount过了的子系统, 则通用一个cgroupfs_root. // 也就是说, 此时对其中一个操作,另一个会看到同样的视图.好比,一块磁盘被rebind了. new_root = cgroup_root_from_opts(&opts); // 分配一个super block, 或者服用已经有的. sb = sget(fs_type, cgroup_test_super, cgroup_set_super, &opts); // 分配 link ret = allocate_cg_links(css_set_count, &tmp_cg_links); // 绑定指定的子系统到新的cgroupfs_root上 ret = rebind_subsystems(root, root->subsys_bits); sb->s_root->d_fsdata = root_cgrp; root->top_cgroup.dentry = sb->s_root; // 将现存的所有的css_set挂入到新的cgroup中 for (i = 0; i < CSS_SET_TABLE_SIZE; i++) { struct hlist_head *hhead = &css_set_table[i]; struct hlist_node *node; struct css_set *cg; hlist_for_each_entry(cg, node, hhead, hlist) link_css_set(&tmp_cg_links, cg, root_cgrp); } // 生成虚拟的文件 cgroup_populate_dir(root_cgrp);