cgroup

先做一个小实验

创建两个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 是如何在系统中生效的?

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

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);
上一篇:Linux网络解读(2) - 套接字的初始化


下一篇:ceph源码 - crush