linux/Documentation/admin-guide/cgroup-v1/memcg_test.rst
<<
>>
Prefs
   1=====================================================
   2Memory Resource Controller(Memcg) Implementation Memo
   3=====================================================
   4
   5Last Updated: 2010/2
   6
   7Base Kernel Version: based on 2.6.33-rc7-mm(candidate for 34).
   8
   9Because VM is getting complex (one of reasons is memcg...), memcg's behavior
  10is complex. This is a document for memcg's internal behavior.
  11Please note that implementation details can be changed.
  12
  13(*) Topics on API should be in Documentation/admin-guide/cgroup-v1/memory.rst)
  14
  150. How to record usage ?
  16========================
  17
  18   2 objects are used.
  19
  20   page_cgroup ....an object per page.
  21
  22        Allocated at boot or memory hotplug. Freed at memory hot removal.
  23
  24   swap_cgroup ... an entry per swp_entry.
  25
  26        Allocated at swapon(). Freed at swapoff().
  27
  28   The page_cgroup has USED bit and double count against a page_cgroup never
  29   occurs. swap_cgroup is used only when a charged page is swapped-out.
  30
  311. Charge
  32=========
  33
  34   a page/swp_entry may be charged (usage += PAGE_SIZE) at
  35
  36        mem_cgroup_try_charge()
  37
  382. Uncharge
  39===========
  40
  41  a page/swp_entry may be uncharged (usage -= PAGE_SIZE) by
  42
  43        mem_cgroup_uncharge()
  44          Called when a page's refcount goes down to 0.
  45
  46        mem_cgroup_uncharge_swap()
  47          Called when swp_entry's refcnt goes down to 0. A charge against swap
  48          disappears.
  49
  503. charge-commit-cancel
  51=======================
  52
  53        Memcg pages are charged in two steps:
  54
  55                - mem_cgroup_try_charge()
  56                - mem_cgroup_commit_charge() or mem_cgroup_cancel_charge()
  57
  58        At try_charge(), there are no flags to say "this page is charged".
  59        at this point, usage += PAGE_SIZE.
  60
  61        At commit(), the page is associated with the memcg.
  62
  63        At cancel(), simply usage -= PAGE_SIZE.
  64
  65Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
  66
  674. Anonymous
  68============
  69
  70        Anonymous page is newly allocated at
  71                  - page fault into MAP_ANONYMOUS mapping.
  72                  - Copy-On-Write.
  73
  74        4.1 Swap-in.
  75        At swap-in, the page is taken from swap-cache. There are 2 cases.
  76
  77        (a) If the SwapCache is newly allocated and read, it has no charges.
  78        (b) If the SwapCache has been mapped by processes, it has been
  79            charged already.
  80
  81        4.2 Swap-out.
  82        At swap-out, typical state transition is below.
  83
  84        (a) add to swap cache. (marked as SwapCache)
  85            swp_entry's refcnt += 1.
  86        (b) fully unmapped.
  87            swp_entry's refcnt += # of ptes.
  88        (c) write back to swap.
  89        (d) delete from swap cache. (remove from SwapCache)
  90            swp_entry's refcnt -= 1.
  91
  92
  93        Finally, at task exit,
  94        (e) zap_pte() is called and swp_entry's refcnt -=1 -> 0.
  95
  965. Page Cache
  97=============
  98
  99        Page Cache is charged at
 100        - add_to_page_cache_locked().
 101
 102        The logic is very clear. (About migration, see below)
 103
 104        Note:
 105          __remove_from_page_cache() is called by remove_from_page_cache()
 106          and __remove_mapping().
 107
 1086. Shmem(tmpfs) Page Cache
 109===========================
 110
 111        The best way to understand shmem's page state transition is to read
 112        mm/shmem.c.
 113
 114        But brief explanation of the behavior of memcg around shmem will be
 115        helpful to understand the logic.
 116
 117        Shmem's page (just leaf page, not direct/indirect block) can be on
 118
 119                - radix-tree of shmem's inode.
 120                - SwapCache.
 121                - Both on radix-tree and SwapCache. This happens at swap-in
 122                  and swap-out,
 123
 124        It's charged when...
 125
 126        - A new page is added to shmem's radix-tree.
 127        - A swp page is read. (move a charge from swap_cgroup to page_cgroup)
 128
 1297. Page Migration
 130=================
 131
 132        mem_cgroup_migrate()
 133
 1348. LRU
 135======
 136        Each memcg has its own vector of LRUs (inactive anon, active anon,
 137        inactive file, active file, unevictable) of pages from each node,
 138        each LRU handled under a single lru_lock for that memcg and node.
 139
 1409. Typical Tests.
 141=================
 142
 143 Tests for racy cases.
 144
 1459.1 Small limit to memcg.
 146-------------------------
 147
 148        When you do test to do racy case, it's good test to set memcg's limit
 149        to be very small rather than GB. Many races found in the test under
 150        xKB or xxMB limits.
 151
 152        (Memory behavior under GB and Memory behavior under MB shows very
 153        different situation.)
 154
 1559.2 Shmem
 156---------
 157
 158        Historically, memcg's shmem handling was poor and we saw some amount
 159        of troubles here. This is because shmem is page-cache but can be
 160        SwapCache. Test with shmem/tmpfs is always good test.
 161
 1629.3 Migration
 163-------------
 164
 165        For NUMA, migration is an another special case. To do easy test, cpuset
 166        is useful. Following is a sample script to do migration::
 167
 168                mount -t cgroup -o cpuset none /opt/cpuset
 169
 170                mkdir /opt/cpuset/01
 171                echo 1 > /opt/cpuset/01/cpuset.cpus
 172                echo 0 > /opt/cpuset/01/cpuset.mems
 173                echo 1 > /opt/cpuset/01/cpuset.memory_migrate
 174                mkdir /opt/cpuset/02
 175                echo 1 > /opt/cpuset/02/cpuset.cpus
 176                echo 1 > /opt/cpuset/02/cpuset.mems
 177                echo 1 > /opt/cpuset/02/cpuset.memory_migrate
 178
 179        In above set, when you moves a task from 01 to 02, page migration to
 180        node 0 to node 1 will occur. Following is a script to migrate all
 181        under cpuset.::
 182
 183                --
 184                move_task()
 185                {
 186                for pid in $1
 187                do
 188                        /bin/echo $pid >$2/tasks 2>/dev/null
 189                        echo -n $pid
 190                        echo -n " "
 191                done
 192                echo END
 193                }
 194
 195                G1_TASK=`cat ${G1}/tasks`
 196                G2_TASK=`cat ${G2}/tasks`
 197                move_task "${G1_TASK}" ${G2} &
 198                --
 199
 2009.4 Memory hotplug
 201------------------
 202
 203        memory hotplug test is one of good test.
 204
 205        to offline memory, do following::
 206
 207                # echo offline > /sys/devices/system/memory/memoryXXX/state
 208
 209        (XXX is the place of memory)
 210
 211        This is an easy way to test page migration, too.
 212
 2139.5 nested cgroups
 214------------------
 215
 216        Use tests like the following for testing nested cgroups::
 217
 218                mkdir /opt/cgroup/01/child_a
 219                mkdir /opt/cgroup/01/child_b
 220
 221                set limit to 01.
 222                add limit to 01/child_b
 223                run jobs under child_a and child_b
 224
 225        create/delete following groups at random while jobs are running::
 226
 227                /opt/cgroup/01/child_a/child_aa
 228                /opt/cgroup/01/child_b/child_bb
 229                /opt/cgroup/01/child_c
 230
 231        running new jobs in new group is also good.
 232
 2339.6 Mount with other subsystems
 234-------------------------------
 235
 236        Mounting with other subsystems is a good test because there is a
 237        race and lock dependency with other cgroup subsystems.
 238
 239        example::
 240
 241                # mount -t cgroup none /cgroup -o cpuset,memory,cpu,devices
 242
 243        and do task move, mkdir, rmdir etc...under this.
 244
 2459.7 swapoff
 246-----------
 247
 248        Besides management of swap is one of complicated parts of memcg,
 249        call path of swap-in at swapoff is not same as usual swap-in path..
 250        It's worth to be tested explicitly.
 251
 252        For example, test like following is good:
 253
 254        (Shell-A)::
 255
 256                # mount -t cgroup none /cgroup -o memory
 257                # mkdir /cgroup/test
 258                # echo 40M > /cgroup/test/memory.limit_in_bytes
 259                # echo 0 > /cgroup/test/tasks
 260
 261        Run malloc(100M) program under this. You'll see 60M of swaps.
 262
 263        (Shell-B)::
 264
 265                # move all tasks in /cgroup/test to /cgroup
 266                # /sbin/swapoff -a
 267                # rmdir /cgroup/test
 268                # kill malloc task.
 269
 270        Of course, tmpfs v.s. swapoff test should be tested, too.
 271
 2729.8 OOM-Killer
 273--------------
 274
 275        Out-of-memory caused by memcg's limit will kill tasks under
 276        the memcg. When hierarchy is used, a task under hierarchy
 277        will be killed by the kernel.
 278
 279        In this case, panic_on_oom shouldn't be invoked and tasks
 280        in other groups shouldn't be killed.
 281
 282        It's not difficult to cause OOM under memcg as following.
 283
 284        Case A) when you can swapoff::
 285
 286                #swapoff -a
 287                #echo 50M > /memory.limit_in_bytes
 288
 289        run 51M of malloc
 290
 291        Case B) when you use mem+swap limitation::
 292
 293                #echo 50M > memory.limit_in_bytes
 294                #echo 50M > memory.memsw.limit_in_bytes
 295
 296        run 51M of malloc
 297
 2989.9 Move charges at task migration
 299----------------------------------
 300
 301        Charges associated with a task can be moved along with task migration.
 302
 303        (Shell-A)::
 304
 305                #mkdir /cgroup/A
 306                #echo $$ >/cgroup/A/tasks
 307
 308        run some programs which uses some amount of memory in /cgroup/A.
 309
 310        (Shell-B)::
 311
 312                #mkdir /cgroup/B
 313                #echo 1 >/cgroup/B/memory.move_charge_at_immigrate
 314                #echo "pid of the program running in group A" >/cgroup/B/tasks
 315
 316        You can see charges have been moved by reading ``*.usage_in_bytes`` or
 317        memory.stat of both A and B.
 318
 319        See 8.2 of Documentation/admin-guide/cgroup-v1/memory.rst to see what value should
 320        be written to move_charge_at_immigrate.
 321
 3229.10 Memory thresholds
 323----------------------
 324
 325        Memory controller implements memory thresholds using cgroups notification
 326        API. You can use tools/cgroup/cgroup_event_listener.c to test it.
 327
 328        (Shell-A) Create cgroup and run event listener::
 329
 330                # mkdir /cgroup/A
 331                # ./cgroup_event_listener /cgroup/A/memory.usage_in_bytes 5M
 332
 333        (Shell-B) Add task to cgroup and try to allocate and free memory::
 334
 335                # echo $$ >/cgroup/A/tasks
 336                # a="$(dd if=/dev/zero bs=1M count=10)"
 337                # a=
 338
 339        You will see message from cgroup_event_listener every time you cross
 340        the thresholds.
 341
 342        Use /cgroup/A/memory.memsw.usage_in_bytes to test memsw thresholds.
 343
 344        It's good idea to test root cgroup as well.
 345