← Documents Documentation/admin-guide/cgroup-v1/memcg_test.rst GitHub 원문 ↗

Linux 6.18.37 · Administration / Cgroup v1

Memory Resource Controller Implementation Memo

Memcg charge·swap·shmem·LRU 내부 구조와 race, migration, OOM, threshold test 절차를 설명합니다.

Source pathDocumentation/admin-guide/cgroup-v1/memcg_test.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

Accounting internals

memcg_test.rst:1-139

Charge object와 page/swap/shmem state transition을 설명합니다.

Race and topology tests

memcg_test.rst:140-244

Small limit, shmem, migration, hotplug와 nested test를 다룹니다.

Swap, OOM and notifications

memcg_test.rst:245-344

Swapoff, OOM, charge migration과 threshold notification을 정리합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 =====================================================
2 Memory Resource Controller(Memcg) Implementation Memo
3 =====================================================
4
5 Last Updated: 2010/2
6
7 Base Kernel Version: based on 2.6.33-rc7-mm(candidate for 34).
8
9 Because VM is getting complex (one of reasons is memcg...), memcg's behavior
10 is complex. This is a document for memcg's internal behavior.
11 Please note that implementation details can be changed.
12
13 (*) Topics on API should be in Documentation/admin-guide/cgroup-v1/memory.rst)
14
15 0. 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
31 1. Charge
32 =========
33
34 a page/swp_entry may be charged (usage += PAGE_SIZE) at
35
36 mem_cgroup_try_charge()
37
38 2. 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
50 3. 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
65 Under below explanation, we assume CONFIG_SWAP=y.
66
67 4. 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
96 5. Page Cache
97 =============
98
99 Page Cache is charged at
100 - filemap_add_folio().
101
102 The logic is very clear. (About migration, see below)
103
104 Note:
105 __filemap_remove_folio() is called by filemap_remove_folio()
106 and __remove_mapping().
107
108 6. 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
129 7. Page Migration
130 =================
131
132 mem_cgroup_migrate()
133
134 8. 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
140 9. Typical Tests.
141 =================
142
143 Tests for racy cases.
144
145 9.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
155 9.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
162 9.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
200 9.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
213 9.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
233 9.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
245 9.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
272 9.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
298 9.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
322 9.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

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

구현 메모의 기준과 범위

1-14

이 문서는 2010년 2월에 갱신된 Memory Resource Controller(Memcg) 구현 메모이며 base kernel은 `2.6.33-rc7-mm(candidate for 34)`입니다. VM과 memcg behavior가 복잡해 internal 동작을 설명하지만 implementation detail은 바뀔 수 있습니다.

Memcg memo scope
ItemValue
Last Updated2010/2
Base Kernel Version2.6.33-rc7-mm(candidate for 34)
FocusInternal memcg behavior and tests
Public API topicsDocumentation/admin-guide/cgroup-v1/memory.rst

이 문서와 API 문서의 역할을 구분합니다.

page_cgroup과 swap_cgroup

15-30

Usage 기록에는 page마다 하나인 `page_cgroup` object와 `swp_entry`마다 하나인 `swap_cgroup` entry를 사용합니다.

Memcg accounting objects
ObjectGranularityAllocateFree
page_cgroupPer pageBoot or memory hotplugMemory hot removal
swap_cgroupPer swp_entryswapon()swapoff()

Object의 allocation·free 시점과 역할입니다.

Page and swap charge tracking
Charge page_cgroupSet USED bitPrevent double countCharged page swapped outTrack charge in swap_cgroup

`USED` bit가 page double charge를 막고 swap-out 때 swap_cgroup으로 추적합니다.

Charge와 uncharge entry points

31-49

Page 또는 `swp_entry` charge는 `mem_cgroup_try_charge()`에서 `usage += PAGE_SIZE`로 수행합니다.

Charge lifecycle functions
FunctionAccounting changeCalled when
mem_cgroup_try_charge()usage += PAGE_SIZECharge attempt
mem_cgroup_uncharge()usage -= PAGE_SIZEPage refcount reaches 0
mem_cgroup_uncharge_swap()Remove swap chargeswp_entry refcnt reaches 0

Reference가 사라질 때 object 유형에 맞춰 usage를 내립니다.

Basic charge and uncharge
Page or swp_entry becomes chargeablemem_cgroup_try_charge()Usage increases by PAGE_SIZEReference count reaches zeroMatching uncharge function

Page와 swap entry는 각각 reference lifetime 끝에서 uncharge됩니다.

try·commit·cancel 두 단계 charge

50-66

Memcg page charge는 `mem_cgroup_try_charge()` 뒤 `mem_cgroup_commit_charge()` 또는 `mem_cgroup_cancel_charge()`로 끝나는 두 단계 transaction입니다. 아래 설명은 `CONFIG_SWAP=y`를 가정합니다.

Charge transaction
mem_cgroup_try_charge()No page charged flag yetusage += PAGE_SIZEmem_cgroup_commit_charge()Associate page with memcg
mem_cgroup_try_charge()Later operation failsmem_cgroup_cancel_charge()usage -= PAGE_SIZE

Try 시 usage를 먼저 올리고 성공 여부에 따라 page association 또는 rollback을 수행합니다.

Anonymous page swap-in/out state

67-95

Anonymous page는 `MAP_ANONYMOUS` mapping의 page fault 또는 Copy-On-Write에서 새로 allocate됩니다. Swap-in 때 page는 swap cache에서 오며, 새로 allocate해 read한 SwapCache라 charge가 없거나 이미 process에 map되어 charge된 두 경우가 있습니다.

Anonymous swap-out transition
Add page to swap cache and mark SwapCacheswp_entry refcnt += 1Fully unmap pagerefcnt += number of PTEsWrite back to swapDelete from swap cacherefcnt -= 1Task exit calls zap_pte()refcnt reaches 0

Swap entry reference count가 cache와 PTE lifetime을 함께 추적합니다.

Page cache와 shmem charge

96-128

일반 page cache는 `filemap_add_folio()`에서 charge됩니다. Migration은 뒤 절에서 다룹니다. `__filemap_remove_folio()`는 `filemap_remove_folio()`와 `__remove_mapping()`에서 호출됩니다.

Page-cache charge points
Page kindCharge event
File page cachefilemap_add_folio()
New shmem pageAdded to shmem inode radix-tree
Swapped shmem pageRead swp page; move charge swap_cgroup -> page_cgroup

일반 file page와 shmem page의 charge event입니다.

Shmem의 자세한 state transition은 `mm/shmem.c`에서 확인합니다. Leaf shmem page는 inode radix-tree, SwapCache 또는 swap-in/out 중 두 곳 모두에 존재할 수 있습니다.

Shmem charge movement
Charged shmem data in swap_cgroupRead swp pagePage enters SwapCache/radix-tree transitionMove charge to page_cgroup

Swap-backed page가 memory로 돌아올 때 charge owner object도 이동합니다.

Page migration과 per-memcg LRU

129-139

Page migration entry point는 `mem_cgroup_migrate()`입니다.

Per-memcg LRU vectors
LRU listContent
inactive anonInactive anonymous pages
active anonActive anonymous pages
inactive fileInactive file-backed pages
active fileActive file-backed pages
unevictablePages that cannot be evicted

각 memcg는 node별 LRU vector를 가지며 memcg·node 조합마다 하나의 lru_lock으로 보호합니다.

작은 limit·shmem·NUMA migration test

140-199

Race test에서는 GB보다 xKB 또는 xxMB처럼 작은 memcg limit이 더 효과적입니다. GB와 MB 범위의 memory behavior가 매우 달라 작은 limit test에서 많은 race가 발견됐습니다.

Shmem은 page cache이면서 SwapCache가 될 수 있어 역사적으로 memcg handling 문제가 많았습니다. 따라서 shmem/tmpfs test는 항상 가치가 있습니다.

High-value memcg race tests
TestWhy
Small limitAmplifies charge/reclaim races
Shmem/tmpfsPage-cache and SwapCache dual state
NUMA migrationCharge and page movement across nodes

초기 세 test가 겨냥하는 취약 지점입니다.

	is useful. Following is a sample script to do migration::

		mount -t cgroup -o cpuset none /opt/cpuset

		mkdir /opt/cpuset/01
		echo 1 > /opt/cpuset/01/cpuset.cpus
		echo 0 > /opt/cpuset/01/cpuset.mems
		echo 1 > /opt/cpuset/01/cpuset.memory_migrate
		mkdir /opt/cpuset/02
		echo 1 > /opt/cpuset/02/cpuset.cpus
		echo 1 > /opt/cpuset/02/cpuset.mems
		echo 1 > /opt/cpuset/02/cpuset.memory_migrate

	In above set, when you moves a task from 01 to 02, page migration to
	node 0 to node 1 will occur. Following is a script to migrate all
	under cpuset.::

		--
		move_task()
		{
		for pid in $1
		do
			/bin/echo $pid >$2/tasks 2>/dev/null
			echo -n $pid
			echo -n " "
		done
		echo END
		}

		G1_TASK=`cat ${G1}/tasks`
		G2_TASK=`cat ${G2}/tasks`
		move_task "${G1_TASK}" ${G2} &
Cpuset-driven migration test
Create cpuset 01: CPU 1, mem 0, memory_migrate=1Create cpuset 02: CPU 1, mem 1, memory_migrate=1Read tasks from both groupsmove_task writes each PID to destination tasksPages migrate node 0 -> node 1

Task를 cpuset 01에서 02로 옮겨 node 0 page를 node 1로 migration합니다.

Memory hotplug·nested cgroup·mixed controller test

200-244

Memory hotplug은 page migration을 쉽게 시험하는 방법입니다. `/sys/devices/system/memory/memoryXXX/state`에 `offline`을 써서 XXX 위치 memory를 offline합니다.

	memory hotplug test is one of good test.

	to offline memory, do following::

		# echo offline > /sys/devices/system/memory/memoryXXX/state

Nested test는 `/opt/cgroup/01/child_a`와 `child_b`를 만들고 parent 01과 child_b에 limit을 둔 뒤 두 child에서 job을 실행합니다. Job이 도는 동안 `child_aa`, `child_bb`, `child_c`를 무작위 생성·삭제하고 새 group에도 job을 시작합니다.

Topology and integration tests
TestOperations
Memory hotplugOffline memoryXXX and observe migration
Nested cgroupsLimits, jobs, random mkdir/rmdir in descendants
Mixed subsystemsMount cpuset,memory,cpu,devices together

Dynamic hierarchy와 다른 controller lock dependency를 함께 자극합니다.

9.6 Mount with other subsystems
-------------------------------

	Mounting with other subsystems is a good test because there is a
	race and lock dependency with other cgroup subsystems.

	example::

		# mount -t cgroup none /cgroup -o cpuset,memory,cpu,devices

	and do task move, mkdir, rmdir etc...under this.
Mixed-controller race surface
Mount cpuset,memory,cpu,devicesMove tasksmkdir/rmdir cgroupsExercise cross-subsystem race and locks

Task move와 hierarchy mutation이 controller 간 lock dependency를 드러냅니다.

swapoff와 memcg OOM test

245-297

Swap management는 memcg의 복잡한 부분이며 `swapoff` 중 swap-in call path는 일반 swap-in과 다르므로 명시적으로 test해야 합니다.


	(Shell-A)::

		# mount -t cgroup none /cgroup -o memory
		# mkdir /cgroup/test
		# echo 40M > /cgroup/test/memory.limit_in_bytes
		# echo 0 > /cgroup/test/tasks

	Run malloc(100M) program under this. You'll see 60M of swaps.

	(Shell-B)::

		# move all tasks in /cgroup/test to /cgroup
		# /sbin/swapoff -a
		# rmdir /cgroup/test
		# kill malloc task.

	Of course, tmpfs v.s. swapoff test should be tested, too.
swapoff test
Create /cgroup/test with 40M limitRun malloc(100M)Observe about 60M swapMove tasks to parent/sbin/swapoff -armdir testKill malloc task

40M limit 아래 100M allocation으로 60M swap을 만든 뒤 task 이동과 swapoff cleanup을 시험합니다.

Tmpfs와 swapoff 조합도 함께 test해야 합니다. Memcg limit으로 발생한 OOM은 해당 memcg 또는 hierarchy 아래 task를 kill해야 하며 `panic_on_oom`을 호출하거나 다른 group의 task를 kill하면 안 됩니다.

9.8 OOM-Killer
--------------

	Out-of-memory caused by memcg's limit will kill tasks under
	the memcg. When hierarchy is used, a task under hierarchy
	will be killed by the kernel.

	In this case, panic_on_oom shouldn't be invoked and tasks
	in other groups shouldn't be killed.

	It's not difficult to cause OOM under memcg as following.

	Case A) when you can swapoff::

		#swapoff -a
		#echo 50M > /memory.limit_in_bytes

	run 51M of malloc

	Case B) when you use mem+swap limitation::

		#echo 50M > memory.limit_in_bytes
		#echo 50M > memory.memsw.limit_in_bytes

	run 51M of malloc
Two memcg OOM cases
Case A: swapoff -aSet memory.limit_in_bytes=50MRun malloc(51M)Memcg-local OOM kill
Case B: memory=50M and memsw=50MRun malloc(51M)Memcg-local OOM kill

Swap을 없애거나 mem+swap limit을 함께 제한해 51M allocation으로 OOM을 만듭니다.

Charge migration과 threshold notification

298-344

Task migration과 함께 task에 연결된 charge도 옮길 수 있습니다. Group A에서 memory를 사용한 program을 실행하고 group B의 `memory.move_charge_at_immigrate`를 1로 설정한 뒤 PID를 B의 `tasks`에 쓰면 charge가 이동합니다.

	(Shell-A)::

		#mkdir /cgroup/A
		#echo $$ >/cgroup/A/tasks

	run some programs which uses some amount of memory in /cgroup/A.

	(Shell-B)::

		#mkdir /cgroup/B
		#echo 1 >/cgroup/B/memory.move_charge_at_immigrate
		#echo "pid of the program running in group A" >/cgroup/B/tasks

	You can see charges have been moved by reading ``*.usage_in_bytes`` or
	memory.stat of both A and B.
Move charge with task
Run memory-using program in /cgroup/ACreate /cgroup/BSet memory.move_charge_at_immigrate=1Move program PID to B/tasksRead A/B usage and memory.stat

`*.usage_in_bytes`와 `memory.stat`에서 A 감소와 B 증가를 확인합니다.

`move_charge_at_immigrate`에 쓸 값의 의미는 `Documentation/admin-guide/cgroup-v1/memory.rst` 8.2절을 참고합니다.

Memory controller threshold는 cgroup notification API로 구현됩니다. `tools/cgroup/cgroup_event_listener.c`를 사용해 memory usage가 5M threshold를 오르내릴 때마다 event message가 오는지 시험합니다.

9.10 Memory thresholds
----------------------

	Memory controller implements memory thresholds using cgroups notification
	API. You can use tools/cgroup/cgroup_event_listener.c to test it.

	(Shell-A) Create cgroup and run event listener::

		# mkdir /cgroup/A
		# ./cgroup_event_listener /cgroup/A/memory.usage_in_bytes 5M

	(Shell-B) Add task to cgroup and try to allocate and free memory::

		# echo $$ >/cgroup/A/tasks
		# a="$(dd if=/dev/zero bs=1M count=10)"
		# a=
Threshold notification test
Listen on memory.usage_in_bytes at 5MAttach shell to /cgroup/AAllocate 10M with dd command substitutionCross threshold upwardClear variableCross threshold downwardListener reports each event

10M를 allocate했다가 free해 threshold 양방향 crossing을 만듭니다.

Additional threshold coverage
TargetPurpose
/cgroup/A/memory.memsw.usage_in_bytesMem+swap threshold
Root cgroupRoot-level notification behavior

같은 notification path를 다른 accounting scope에도 적용합니다.