Cgroup之Resource Counter机制

原创 2015年11月03日 23:23:21

Resource Counter机制概述

Cgroup中提供了众多子系统用于实现系统资源管理,其中有一个子系统就是Memory子系统,这个子系统提供了对内存资源和swap资源的使用限制和统计。但是Cgroup中的Memory子系统中的资源使用统计其实用的是resource counter机制来实现的,本文就resource counter机制进行了一次全方位的分析主要分析其相关的基础数据结构,和一些内核API信息,以及resource counter机制是如何作用于Memory子系统。

本文参考linux内核Cgroup文档中关于resource counter的文档

Resource Counter结构体概述

resource counter机制中最核心的数据结构是res_counter这个数据结构这个数据结构是用过嵌入到其他数据结构中进行使用的,这个数据结构的定义如下:

struct res_counter {
 /*
  * the current resource consumption level
  */
          unsigned long long usage; //这个成员是用来进行资源统计的,记录资源的当前的使用量,其单位是根据被嵌入结构来决定的。
  /*
   * the maximal value of the usage from the counter creation
   */
          unsigned long long max_usage; //这个资源是用来记录历史记录中使用过的最大资源量。这个字段是用来进行调优的下文会说到
  /*
   * the limit that usage cannot exceed
   */
          unsigned long long limit; //资源最大限制,一旦分配超过这个限制将会导致失败,并且会让failcnt,资源分配失败次数加1
  /*
   * the limit that usage can be exceed
   */
          unsigned long long soft_limit; //资源软限制,是可以超过的,但是无法超过资源最大限制
  /*
   * the number of unsuccessful attempts to consume the resource
   */
          unsigned long long failcnt; //资源分配失败的次数
  /*
   * the lock to protect all of the above.
   * the routines below consider this to be IRQ-safe
   */
          spinlock_t lock; //自旋锁
  /*
   * Parent counter, used for hierarchial resource accounting
   */
          struct res_counter *parent; //形成资源统计组
  };

resource counter机制中是具有父子关系,子资源控制中可以设置的资源限制是无法超过父资源限制的。这个结构体用于放到Memory子系统对应的核心结构体中实现Memory子系统的资源统计。

Resource Counter相关API概述

内核为了方便进行资源统计,也提供了一系列的API用来进行资源统计,这里仅列出一些常见的API

  • res_counter_init 用于实现res_counter结构体的初始化
void res_counter_init(struct res_counter *counter, struct res_counter *parent)
{
 spin_lock_init(&counter->lock);
 counter->limit = RESOURCE_MAX;
 counter->soft_limit = RESOURCE_MAX;
 counter->parent = parent;
}
其实现很简单,初始化自旋锁,然后设置了最大资源限制,指定了其父资源限制,但是我发现这里应该少了对conuter的usage字段进行初始化为0,我猜想
应该在是分配内存的时候已经进行了内存置0了。
  • res_counter_charge 用于实现资源使用统计

 int res_counter_charge_locked(struct res_counter *counter, unsigned long val,
                                bool force)
  {
          int ret = 0;

          if (counter->usage + val > counter->limit) {
                  counter->failcnt++;
                  ret = -ENOMEM;
                  if (!force)
                          return ret;
          } 
          counter->usage += val;
          if (counter->usage > counter->max_usage)
                  counter->max_usage = counter->usage;
          return ret;
 }
资源使用进行统计,并记录分配失败的次数和更新资源最大使用数量。父资源使用量是所有孩子的资源使用量总和。

 static int __res_counter_charge(struct res_counter *counter, unsigned long val,
                                  struct res_counter **limit_fail_at, bool force)
  {
          int ret, r;
          unsigned long flags;
          struct res_counter *c, *u;

          r = ret = 0;
          *limit_fail_at = NULL;
          local_irq_save(flags);
          for (c = counter; c != NULL; c = c->parent) {
                  spin_lock(&c->lock);
                  r = res_counter_charge_locked(c, val, force);
                  spin_unlock(&c->lock);
                  if (r < 0 && !ret) {
                          ret = r;
                          *limit_fail_at = c;
                          if (!force)
                                  break;
                  }
          }

          if (ret < 0 && !force) {
                  for (u = counter; u != c; u = u->parent) {
                          spin_lock(&u->lock);
                          res_counter_uncharge_locked(u, val);
                          spin_unlock(&u->lock);
                  }
          }
          local_irq_restore(flags);

          return ret;
  }
递归对资统计组进行资源使用统计,统计的时候进行了加锁,如果资源使用统计失败则使用limit_fail_at进行记录,如果没有设置force标志则不继续进行资源统计了,否则继续递归进行资源统计,  
  int res_counter_charge(struct res_counter *counter, unsigned long val,
                          struct res_counter **limit_fail_at)
  {
          return __res_counter_charge(counter, val, limit_fail_at, false);
  }
传入要统计的资源也就是val,以及相关的资源统计结构体。还有一个limit_fail_at这是用来指向资源使用统计失败的res_counter结构体的。
  • res_counter_charge_locked 实际进行资源使用统计的API,需要使用自旋锁进行保护
 int res_counter_charge_locked(struct res_counter *counter, unsigned long val,
                                bool force)
  {
          int ret = 0;

          if (counter->usage + val > counter->limit) {
                  counter->failcnt++;
                  ret = -ENOMEM;
                  if (!force)
                          return ret;
          } 
          counter->usage += val;
          if (counter->usage > counter->max_usage)
                  counter->max_usage = counter->usage;
          return ret;
 }
  • res_counter_uncharge[_locked]这是在资源释放的时候使用,分为需要锁保护的,和不需要锁保护的。
 u64 res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
  {
          if (WARN_ON(counter->usage < val))
                  val = counter->usage;

          counter->usage -= val;
          return counter->usage;
  }
需要锁保护的资源释放统计,这里使用了WARN_ON来对这个counter->usage < val进行条件测试,即使条件不成立也不会导致系统出现严重的问题所以这里选择了WARN_ON而不是BUG_ON。使用BUG_ON会导致内核panic.
  u64 res_counter_uncharge_until(struct res_counter *counter,
                                 struct res_counter *top,
                                unsigned long val)
 {
         unsigned long flags;
         struct res_counter *c;
         u64 ret = 0;

         local_irq_save(flags);
         for (c = counter; c != top; c = c->parent) {
                 u64 r;
                 spin_lock(&c->lock);
                 r = res_counter_uncharge_locked(c, val);
                 if (c == counter)
                         ret = r;
                 spin_unlock(&c->lock);
         }
         local_irq_restore(flags);
         return ret;
 }

 u64 res_counter_uncharge(struct res_counter *counter, unsigned long val)
 {
         return res_counter_uncharge_until(counter, NULL, val);
 }
关中断然后开始递归进行资源回收计数。

关于resource counter相关的内核API还有其它的一些可以参考内核源码,其声明在include/linux/res_counter.h

资源限制调优

resource counter中核心结构体中的一些成员对于我们进行资源限制调优有着很重要的帮助

  • 如果failcnt成员的值不断的增长,那么说明limit的的值过于紧了,需要调节大点
  • 如果max_usage成员的值小于limit,但是failcnt不断增长,则表明系统曾经分配了很大的一块内存一次性超过了limit
  • 如果max_usage成员的值小于limit,但是failcnt等于0,则表明limit过大了

使用Resource Counter

Resource Counter机制如何在内核中去使用呢?,下面给出了一般情况下Resource Counter的使用

Step1: 将Resource Countre机制中的核心数据结构嵌入目标数据结构

struct my_group {
 struct res_counter res;
  <other fields>
}

Setp2: 在资源分配中进行资源统计

int alloc_something(...)
{
 if (res_counter_charge(res_counter_ptr, amount) < 0)
         return -ENOMEM;

 <allocate the resource and return to the caller>
}

Setp3: 在资源回收中进行资源统计

void release_something(...)
{
 res_counter_uncharge(res_counter_ptr, amount);

 <release the resource>
}

Setp4: 提供一些读取这些资源值的API

Setp5: Compile and Run it

版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

Cgroup之Resource Counter机制

Resource Counter机制概述Cgroup中提供了众多子系统用于实现系统资源管理,其中有一个子系统就是Memory子系统,这个子系统提供了对内存资源和swap资源的使用限制和统计。但是Cgr...

Linux cgroup机制分析之cpuset subsystem

------------------------------------------ 本文系本站原创,欢迎转载! 转载请注明出处:http://ericxiao.cublog.cn/ ...

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

jstorm的cgroup资源隔离机制

本文研究一下jstorm使用cgroup做资源隔离的情况,github有文档: https://github.com/alibaba/jstorm/wiki/%E8%B5%84%E6%BA%90%E7...

linux的qos机制 - cgroup篇 (3)

从这篇开始介绍cgroup的原理,这两篇文章很不错先放这里 http://blog.csdn.net/ustc_dylan/article/details/4030824 http://blog...

cgroup中内存超限通知机制

1.背景 CloudFoudry会使用warden,warden使用了cgroup,本文描述cgroup中memory子系统的一些机制,所以本文面向Linux容器管理者比较合适。   现在Lin...

linux的qos机制 - cgroup篇 (1)

cgroups全称control groups,在RHEL6的2.6.32内核中已经包括了cgroup的patch。这里强烈建议安装RHEL6(CentOS6)来使用cgroups,如果没有的话,只能...

linux的qos机制 - cgroup篇 (3)

从这篇开始介绍cgroup的原理,这两篇文章很不错先放这里 http://blog.csdn.net/ustc_dylan/article/details/4030824 http://blo...

linux的qos机制 - cgroup篇 (4)

下面来看各个子系统对cgroup的支持,第一篇先研究blkio子系统 blkio子系统支持三种类型的QoS控制: blkio.weight, blkio.weight_device:这些是...

注解@Resource实现机制

spring3.X为我们引入了组件自动扫描机制,它可以在classPath路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳...

Kubernetes Resource QoS机制解读

Kubernetes Resource QoS介绍,机制解析和简单的源码分析。
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)