memcgで実際に課金してるところめも

mm/memcontorl.cのmem_cgroup_charge_statistics()のとこです。カーネルは毎度ながら4.1.15。

mem_cgroup_charge_statistics()のコードはこんな感じです。見たままですね。

 828 static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
 829                                          struct page *page,
 830                                          int nr_pages)
 831 {
 832         /*
 833          * Here, RSS means 'mapped anon' and anon's SwapCache. Shmem/tmpfs is
 834          * counted as CACHE even if it's on ANON LRU.
 835          */
 836         if (PageAnon(page))
 837                 __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS],
 838                                 nr_pages);
 839         else
 840                 __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE],
 841                                 nr_pages);
 842 
 843         if (PageTransHuge(page))
 844                 __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE],
 845                                 nr_pages);
 846 
 847         /* pagein of a big page is an event. So, ignore page size */
 848         if (nr_pages > 0)
 849                 __this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGPGIN]);
 850         else {
 851                 __this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGPGOUT]);
 852                 nr_pages = -nr_pages; /* for event */
 853         }
 854 
 855         __this_cpu_add(memcg->stat->nr_page_events, nr_pages);
 856 }

chargeはmem_cgroup構造体のメンバ変数statに対して行っています。変数はmem_cgroup構造体のこの部分で定義されていて、__percpuが付いているのでcpu毎にデータがあります。この構造体はmm/memcontrol.cで宣言されていてるので他では使わないようです。

 321         /*
 322          * percpu counter.
 323          */
 324         struct mem_cgroup_stat_cpu __percpu *stat;

mem_cgroup_stat_cpu構造体もmm/memcontrol.cにあります。内容はこのようになってます。

 128 struct mem_cgroup_stat_cpu {
 129         long count[MEM_CGROUP_STAT_NSTATS];
 130         unsigned long events[MEMCG_NR_EVENTS];
 131         unsigned long nr_page_events;
 132         unsigned long targets[MEM_CGROUP_NTARGETS];
 133 };

targetsについては今回のコード中では使用されてません。 MEM_CGROUP_STAT_NSTATSなどはenum型でinclude/linux/memcontrol.hにて定義されています。

  32 /*
  33  * The corresponding mem_cgroup_stat_names is defined in mm/memcontrol.c,
  34  * These two lists should keep in accord with each other.
  35  */
  36 enum mem_cgroup_stat_index {
  37         /*
  38          * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss.
  39          */
  40         MEM_CGROUP_STAT_CACHE,          /* # of pages charged as cache */
  41         MEM_CGROUP_STAT_RSS,            /* # of pages charged as anon rss */
  42         MEM_CGROUP_STAT_RSS_HUGE,       /* # of pages charged as anon huge */
  43         MEM_CGROUP_STAT_FILE_MAPPED,    /* # of pages charged as file rss */
  44         MEM_CGROUP_STAT_WRITEBACK,      /* # of pages under writeback */
  45         MEM_CGROUP_STAT_SWAP,           /* # of pages, swapped out */
  46         MEM_CGROUP_STAT_NSTATS,
  47 };

例えば、RSSページの場合は↓なので、インデックス1番目の要素にnr_pagesを足してます。

__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS], nr_pages);

nr_pagesはmem_cgroup_commit_charge()で設定していて、THPでない場合は1、THPの場合は以下の部分で計算してます。

5542         if (PageTransHuge(page)) {
5543                 nr_pages <<= compound_order(page);
5544                 VM_BUG_ON_PAGE(!PageTransHuge(page), page);
5545         }

mem_cgroup_charge_statistics()の前半はページの種別に応じたchargeを行っていて、後半のところはpagein/pageoutのどちらのイベントかで処理が変わりますが、基本はそれぞれのイベント発生回数を増やしてますね。pageoutの場合はnr_pagesの符号を負にしてます。 そして、最後にnr_page_eventsにnr_pagesを足します。pageout時は引く感じですね。

 855         __this_cpu_add(memcg->stat->nr_page_events, nr_pages);

( ´ー`)フゥー...

IoTエンジニア養成読本

IoTエンジニア養成読本