Home | History | Annotate | Download | only in functional
      1 #! /bin/sh
      2 
      3 ################################################################################
      4 ##                                                                            ##
      5 ## Copyright (c) 2012 FUJITSU LIMITED                                         ##
      6 ##                                                                            ##
      7 ## This program is free software;  you can redistribute it and#or modify      ##
      8 ## it under the terms of the GNU General Public License as published by       ##
      9 ## the Free Software Foundation; either version 2 of the License, or          ##
     10 ## (at your option) any later version.                                        ##
     11 ##                                                                            ##
     12 ## This program is distributed in the hope that it will be useful, but        ##
     13 ## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ##
     14 ## or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License   ##
     15 ## for more details.                                                          ##
     16 ##                                                                            ##
     17 ## You should have received a copy of the GNU General Public License          ##
     18 ## along with this program;  if not, write to the Free Software               ##
     19 ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    ##
     20 ##                                                                            ##
     21 ## Author: Peng Haitao <penght (at] cn.fujitsu.com>                                ##
     22 ##                                                                            ##
     23 ################################################################################
     24 
     25 TST_NEEDS_CHECKPOINTS=1
     26 . test.sh
     27 
     28 if [ "x$(grep -w memory /proc/cgroups | cut -f4)" != "x1" ]; then
     29 	tst_brkm TCONF "Kernel does not support the memory resource controller"
     30 fi
     31 
     32 PAGESIZE=$(getconf PAGESIZE)
     33 if [ $? -ne 0 ]; then
     34 	tst_brkm TBROK "getconf PAGESIZE failed"
     35 fi
     36 
     37 HUGEPAGESIZE=$(awk '/Hugepagesize/ {print $2}' /proc/meminfo)
     38 [ -z $HUGEPAGESIZE ] && HUGEPAGESIZE=0
     39 HUGEPAGESIZE=$(( $HUGEPAGESIZE * 1024 ))
     40 orig_memory_use_hierarchy=""
     41 
     42 MEMSW_USAGE_FLAG=0
     43 MEMSW_LIMIT_FLAG=0
     44 
     45 tst_tmpdir
     46 TMP_DIR="$PWD"
     47 
     48 cleanup()
     49 {
     50 	if [ -n "$LOCAL_CLEANUP" ]; then
     51 		$LOCAL_CLEANUP
     52 	fi
     53 
     54 	killall -9 memcg_process 2> /dev/null
     55 	wait
     56 
     57 	cd "$TMP_DIR"
     58 
     59 	if [ -n "$TEST_ID" -a -d "/dev/memcg/$TEST_ID" ]; then
     60 		for i in "/dev/memcg/$TEST_ID/"*; do
     61 			if [ -d "$i" ]; then
     62 				rmdir "$i"
     63 			fi
     64 		done
     65 
     66 		rmdir "/dev/memcg/$TEST_ID"
     67 	fi
     68 
     69 	if [ -d "/dev/memcg" ]; then
     70 		umount /dev/memcg
     71 		rmdir /dev/memcg
     72 	fi
     73 
     74 	tst_rmdir
     75 }
     76 TST_CLEANUP=cleanup
     77 
     78 shmmax_setup()
     79 {
     80 	shmmax=`cat /proc/sys/kernel/shmmax`
     81 	if [ $shmmax -lt $HUGEPAGESIZE ]; then
     82 		ROD echo "$HUGEPAGESIZE" \> /proc/sys/kernel/shmmax
     83 	fi
     84 }
     85 
     86 shmmax_cleanup()
     87 {
     88 	if [ -n "$shmmax" ]; then
     89 		echo "$shmmax" > /proc/sys/kernel/shmmax
     90 	fi
     91 }
     92 
     93 # Check size in memcg
     94 # $1 - Item name
     95 # $2 - Expected size
     96 check_mem_stat()
     97 {
     98 	if [ -e $1 ]; then
     99 		item_size=`cat $1`
    100 	else
    101 		item_size=`grep -w $1 memory.stat | cut -d " " -f 2`
    102 	fi
    103 
    104 	if [ "$2" = "$item_size" ]; then
    105 		tst_resm TPASS "$1 is $2 as expected"
    106 	else
    107 		tst_resm TFAIL "$1 is $item_size, $2 expected"
    108 	fi
    109 }
    110 
    111 signal_memcg_process()
    112 {
    113 	local pid=$1
    114 	local size=$2
    115 	local path=$3
    116 	local usage_start=$(cat ${path}memory.usage_in_bytes)
    117 
    118 	kill -s USR1 $pid 2> /dev/null
    119 
    120 	if [ -z "$size" ]; then
    121 		return
    122 	fi
    123 
    124 	local loops=100
    125 
    126 	while kill -0 $pid 2> /dev/null; do
    127 		local usage=$(cat ${path}memory.usage_in_bytes)
    128 		local diff_a=$((usage_start - usage))
    129 		local diff_b=$((usage - usage_start))
    130 
    131 		if [ "$diff_a" -ge "$size" -o "$diff_b" -ge "$size" ]; then
    132 			return
    133 		fi
    134 
    135 		tst_sleep 100ms
    136 
    137 		loops=$((loops - 1))
    138 		if [ $loops -le 0 ]; then
    139 			tst_brkm TBROK "timeouted on memory.usage_in_bytes"
    140 		fi
    141 	done
    142 }
    143 
    144 stop_memcg_process()
    145 {
    146 	local pid=$1
    147 	kill -s INT $pid 2> /dev/null
    148 	wait $pid
    149 }
    150 
    151 warmup()
    152 {
    153 	local pid=$1
    154 
    155 	tst_resm TINFO "Warming up pid: $pid"
    156 	signal_memcg_process $pid
    157 	signal_memcg_process $pid
    158 	sleep 1
    159 
    160 	kill -0 $pid
    161 	if [ $? -ne 0 ]; then
    162 		wait $pid
    163 		tst_resm TFAIL "Process $pid exited with $? after warm up"
    164 		return 1
    165 	else
    166 		tst_resm TINFO "Process is still here after warm up: $pid"
    167 	fi
    168 
    169 	return 0
    170 }
    171 
    172 # Run test cases which checks memory.stat after make
    173 # some memory allocation
    174 test_mem_stat()
    175 {
    176 	local memtypes="$1"
    177 	local size=$2
    178 	local total_size=$3
    179 	local stat_name=$4
    180 	local exp_stat_size=$5
    181 	local check_after_free=$6
    182 
    183 	tst_resm TINFO "Running memcg_process $memtypes -s $size"
    184 	memcg_process $memtypes -s $size &
    185 	TST_CHECKPOINT_WAIT 0
    186 
    187 	warmup $!
    188 	if [ $? -ne 0 ]; then
    189 		return
    190 	fi
    191 
    192 	echo $! > tasks
    193 	signal_memcg_process $! $size
    194 
    195 	check_mem_stat $stat_name $exp_stat_size
    196 
    197 	signal_memcg_process $! $size
    198 	if $check_after_free; then
    199 		check_mem_stat $stat_name 0
    200 	fi
    201 
    202 	stop_memcg_process $!
    203 }
    204 
    205 # Run test cases which checks memory.max_usage_in_bytes after make
    206 # some memory allocation
    207 # $1 - the parameters of 'process', such as --shm
    208 # $2 - the -s parameter of 'process', such as 4096
    209 # $3 - item name
    210 # $4 - the expected size
    211 # $5 - check after free ?
    212 test_max_usage_in_bytes()
    213 {
    214 	tst_resm TINFO "Running memcg_process $1 -s $2"
    215 	memcg_process $1 -s $2 &
    216 	TST_CHECKPOINT_WAIT 0
    217 
    218 	warmup $!
    219 	if [ $? -ne 0 ]; then
    220 		return
    221 	fi
    222 
    223 	echo $! > tasks
    224 	signal_memcg_process $! $2
    225 	signal_memcg_process $! $2
    226 
    227 	check_mem_stat $3 $4
    228 
    229 	if [ $5 -eq 1 ]; then
    230 		echo 0 > $3
    231 		check_mem_stat $3 0
    232 	fi
    233 
    234 	stop_memcg_process $!
    235 }
    236 
    237 # make some memory allocation
    238 # $1 - the parameters of 'process', such as --shm
    239 # $2 - the -s parameter of 'process', such as 4096
    240 malloc_free_memory()
    241 {
    242 	tst_resm TINFO "Running memcg_process $1 -s $2"
    243 	memcg_process $1 -s $2 &
    244 	TST_CHECKPOINT_WAIT 0
    245 
    246 	echo $! > tasks
    247 	signal_memcg_process $! $2
    248 	signal_memcg_process $! $2
    249 
    250 	stop_memcg_process $!
    251 }
    252 
    253 # Test if failcnt > 0, which means page reclamation occured
    254 # $1 - item name in memcg
    255 test_failcnt()
    256 {
    257 	failcnt=`cat $1`
    258 	if [ $failcnt -gt 0 ]; then
    259 		tst_resm TPASS "$1 is $failcnt, > 0 as expected"
    260 	else
    261 		tst_resm TFAIL "$1 is $failcnt, <= 0 expected"
    262 	fi
    263 }
    264 
    265 # Test process will be killed due to exceed memory limit
    266 # $1 - the value of memory.limit_in_bytes
    267 # $2 - the parameters of 'process', such as --shm
    268 # $3 - the -s parameter of 'process', such as 4096
    269 # $4 - use mem+swap limitation
    270 test_proc_kill()
    271 {
    272 	echo $1 > memory.limit_in_bytes
    273 	if [ $4 -eq 1 ]; then
    274 		if [ -e memory.memsw.limit_in_bytes ]; then
    275 			echo $1 > memory.memsw.limit_in_bytes
    276 		else
    277 			tst_resm TCONF "mem+swap is not enabled"
    278 			return
    279 		fi
    280 	fi
    281 
    282 	memcg_process $2 -s $3 &
    283 	pid=$!
    284 	TST_CHECKPOINT_WAIT 0
    285 	echo $pid > tasks
    286 
    287 	signal_memcg_process $pid $3
    288 
    289 	tpk_pid_exists=1
    290 	for tpk_iter in $(seq 20); do
    291 		if [ ! -d "/proc/$pid" ] ||
    292 			grep -q 'Z (zombie)' "/proc/$pid/status"; then
    293 			tpk_pid_exists=0
    294 			break
    295 		fi
    296 
    297 		tst_sleep 250ms
    298 	done
    299 
    300 	if [ $tpk_pid_exists -eq 0 ]; then
    301 		wait $pid
    302 		ret=$?
    303 		if [ $ret -eq 1 ]; then
    304 			tst_resm TFAIL "process $pid is killed by error"
    305 		elif [ $ret -eq 2 ]; then
    306 			tst_resm TPASS "Failed to lock memory"
    307 		else
    308 			tst_resm TPASS "process $pid is killed"
    309 		fi
    310 	else
    311 		stop_memcg_process $!
    312 		tst_resm TFAIL "process $pid is not killed"
    313 	fi
    314 }
    315 
    316 # Test limit_in_bytes will be aligned to PAGESIZE
    317 # $1 - user input value
    318 # $2 - use mem+swap limitation
    319 test_limit_in_bytes()
    320 {
    321 	echo $1 > memory.limit_in_bytes
    322 	if [ $2 -eq 1 ]; then
    323 		if [ -e memory.memsw.limit_in_bytes ]; then
    324 			echo $1 > memory.memsw.limit_in_bytes
    325 			limit=`cat memory.memsw.limit_in_bytes`
    326 		else
    327 			tst_resm TCONF "mem+swap is not enabled"
    328 			return
    329 		fi
    330 	else
    331 		limit=`cat memory.limit_in_bytes`
    332 	fi
    333 
    334 	# Kernels prior to 3.19 were rounding up but newer kernels
    335 	# are rounding down
    336 	if [ \( $(($PAGESIZE*($1/$PAGESIZE))) -eq $limit \) \
    337 	    -o \( $(($PAGESIZE*(($1+$PAGESIZE-1)/$PAGESIZE))) -eq $limit \) ]; then
    338 		tst_resm TPASS "input=$1, limit_in_bytes=$limit"
    339 	else
    340 		tst_resm TFAIL "input=$1, limit_in_bytes=$limit"
    341 	fi
    342 }
    343 
    344 # Never used, so untested
    345 #
    346 # Test memory controller doesn't charge hugepage
    347 # $1 - the value of /proc/sys/vm/nr_hugepages
    348 # $2 - the parameters of 'process', --mmap-file or --shm
    349 # $3 - the -s parameter of 'process', such as $HUGEPAGESIZE
    350 # $4 - 0: expected failure, 1: expected success
    351 test_hugepage()
    352 {
    353 	TMP_FILE="$TMP_DIR/tmp"
    354 	nr_hugepages=`cat /proc/sys/vm/nr_hugepages`
    355 
    356 	mkdir /hugetlb
    357 	mount -t hugetlbfs none /hugetlb
    358 
    359 	echo $1 > /proc/sys/vm/nr_hugepages
    360 
    361 	memcg_process $2 --hugepage -s $3 > $TMP_FILE 2>&1 &
    362 	TST_CHECKPOINT_WAIT 0
    363 
    364 	signal_memcg_process $! $3
    365 
    366 	check_mem_stat "rss" 0
    367 
    368 	echo "TMP_FILE:"
    369 	cat $TMP_FILE
    370 
    371 	if [ $4 -eq 0 ]; then
    372 		test -s $TMP_FILE
    373 		if [ $? -eq 0 ]; then
    374 			tst_resm TPASS "allocate hugepage failed as expected"
    375 		else
    376 			signal_memcg_process $! $3
    377 			stop_memcg_process $!
    378 			tst_resm TFAIL "allocate hugepage should fail"
    379 		fi
    380 	else
    381 		test ! -s $TMP_FILE
    382 		if [ $? -eq 0 ]; then
    383 			signal_memcg_process $! $3
    384 			stop_memcg_process $!
    385 			tst_resm TPASS "allocate hugepage succeeded"
    386 		else
    387 			tst_resm TFAIL "allocate hugepage failed"
    388 		fi
    389 	fi
    390 
    391 	sleep 1
    392 	rm -rf $TMP_FILE
    393 	umount /hugetlb
    394 	rmdir /hugetlb
    395 	echo $nr_hugepages > /proc/sys/vm/nr_hugepages
    396 }
    397 
    398 # Test the memory charge won't move to subgroup
    399 # $1 - memory.limit_in_bytes in parent group
    400 # $2 - memory.limit_in_bytes in sub group
    401 test_subgroup()
    402 {
    403 	mkdir subgroup
    404 	echo $1 > memory.limit_in_bytes
    405 	echo $2 > subgroup/memory.limit_in_bytes
    406 
    407 	tst_resm TINFO "Running memcg_process --mmap-anon -s $PAGESIZE"
    408 	memcg_process --mmap-anon -s $PAGESIZE &
    409 	TST_CHECKPOINT_WAIT 0
    410 
    411 	warmup $! $PAGESIZE
    412 	if [ $? -ne 0 ]; then
    413 		return
    414 	fi
    415 
    416 	echo $! > tasks
    417 	signal_memcg_process $! $PAGESIZE
    418 	check_mem_stat "rss" $PAGESIZE
    419 
    420 	cd subgroup
    421 	echo $! > tasks
    422 	check_mem_stat "rss" 0
    423 
    424 	# cleanup
    425 	cd ..
    426 	echo $! > tasks
    427 	stop_memcg_process $!
    428 	rmdir subgroup
    429 }
    430 
    431 # Run test cases which test memory.move_charge_at_immigrate
    432 test_move_charge()
    433 {
    434 	local memtypes="$1"
    435 	local size=$2
    436 	local total_size=$3
    437 	local move_charge_mask=$4
    438 	local b_rss=$5
    439 	local b_cache=$6
    440 	local a_rss=$7
    441 	local a_cache=$8
    442 
    443 	mkdir subgroup_a
    444 
    445 	tst_resm TINFO "Running memcg_process $memtypes -s $size"
    446 	memcg_process $memtypes -s $size &
    447 	TST_CHECKPOINT_WAIT 0
    448 	warmup $!
    449 	if [ $? -ne 0 ]; then
    450 		rmdir subgroup_a
    451 		return
    452 	fi
    453 
    454 	echo $! > subgroup_a/tasks
    455 	signal_memcg_process $! $total_size "subgroup_a/"
    456 
    457 	mkdir subgroup_b
    458 	echo $move_charge_mask > subgroup_b/memory.move_charge_at_immigrate
    459 	echo $! > subgroup_b/tasks
    460 
    461 	cd subgroup_b
    462 	check_mem_stat "rss" $b_rss
    463 	check_mem_stat "cache" $b_cache
    464 	cd ../subgroup_a
    465 	check_mem_stat "rss" $a_rss
    466 	check_mem_stat "cache" $a_cache
    467 	cd ..
    468 	stop_memcg_process $!
    469 	rmdir subgroup_a subgroup_b
    470 }
    471 
    472 cleanup_test()
    473 {
    474 	TEST_ID="$1"
    475 
    476 	if [ -n "$orig_memory_use_hierarchy" ];then
    477 		echo $orig_memory_use_hierarchy > \
    478 		     /dev/memcg/memory.use_hierarchy
    479 		if [ $? -ne 0 ];then
    480 			tst_resm TINFO "restore "\
    481 				 "/dev/memcg/memory.use_hierarchy failed"
    482 		fi
    483 		orig_memory_use_hierarchy=""
    484 	fi
    485 
    486 	killall -9 memcg_process 2>/dev/null
    487 	wait
    488 
    489 	ROD cd "$TMP_DIR"
    490 
    491 	ROD rmdir "/dev/memcg/$TEST_ID"
    492 	TEST_ID=""
    493 	ROD umount /dev/memcg
    494 	ROD rmdir /dev/memcg
    495 }
    496 
    497 setup_test()
    498 {
    499 	TEST_ID="$1"
    500 
    501 	ROD mkdir /dev/memcg
    502 	ROD mount -t cgroup -omemory memcg /dev/memcg
    503 
    504 	# The default value for memory.use_hierarchy is 0 and some of tests
    505 	# (memcg_stat_test.sh and memcg_use_hierarchy_test.sh) expect it so
    506 	# while there are distributions (RHEL7U0Beta for example) that sets
    507 	# it to 1.
    508 	orig_memory_use_hierarchy=$(cat /dev/memcg/memory.use_hierarchy)
    509 	if [ -z "orig_memory_use_hierarchy" ];then
    510 		tst_resm TINFO "cat /dev/memcg/memory.use_hierarchy failed"
    511 	elif [ "$orig_memory_use_hierarchy" = "0" ];then
    512 		orig_memory_use_hierarchy=""
    513 	else
    514 		echo 0 > /dev/memcg/memory.use_hierarchy
    515 		if [ $? -ne 0 ];then
    516 			tst_resm TINFO "set /dev/memcg/memory.use_hierarchy" \
    517 				"to 0 failed"
    518 		fi
    519 	fi
    520 
    521 	ROD mkdir "/dev/memcg/$TEST_ID"
    522 	ROD cd "/dev/memcg/$TEST_ID"
    523 }
    524 
    525 # Run all the test cases
    526 run_tests()
    527 {
    528 	for i in $(seq 1 $TST_TOTAL); do
    529 
    530 		tst_resm TINFO "Starting test $i"
    531 
    532 		setup_test $i
    533 
    534 		if [ -e memory.memsw.limit_in_bytes ]; then
    535 			MEMSW_LIMIT_FLAG=1
    536 		fi
    537 
    538 		if [ -e memory.memsw.max_usage_in_bytes ]; then
    539 			MEMSW_USAGE_FLAG=1
    540 		fi
    541 
    542 		testcase_$i
    543 
    544 		cleanup_test $i
    545 	done
    546 }
    547