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 if [ "x$(grep -w memory /proc/cgroups | cut -f4)" != "x1" ]; then
     26 	echo "WARNING:";
     27 	echo "Either Kernel does not support for memory resource controller or feature not enabled";
     28 	echo "Skipping all memcgroup testcases....";
     29 	exit 0
     30 fi
     31 
     32 cd $LTPROOT/testcases/bin
     33 
     34 TEST_PATH=$PWD
     35 PAGESIZE=`./memcg_getpagesize`
     36 HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{ print $2 }'`
     37 [ -z $HUGEPAGESIZE ] && HUGEPAGESIZE=0
     38 HUGEPAGESIZE=$(( $HUGEPAGESIZE * 1024 ))
     39 PASS=0
     40 FAIL=1
     41 orig_memory_use_hierarchy=""
     42 
     43 cur_id=0
     44 failed=0
     45 
     46 # Record the test result of a test case
     47 # $1 - The result of the test case, $PASS or $FAIL
     48 # $2 - The output information
     49 result()
     50 {
     51 	local pass=$1
     52 	local info="$2"
     53 
     54 	if [ $pass -eq $PASS ]; then
     55 		tst_resm TPASS "$info"
     56 	else
     57 		tst_resm TFAIL "$info"
     58 		: $(( failed += 1 ))
     59 	fi
     60 }
     61 
     62 # Check size in memcg
     63 # $1 - Item name
     64 # $2 - Expected size
     65 check_mem_stat()
     66 {
     67 	if [ -e $1 ]; then
     68 		item_size=`cat $1`
     69 	else
     70 		item_size=`grep -w $1 memory.stat | cut -d " " -f 2`
     71 	fi
     72 
     73 	if [ "$2" = "$item_size" ]; then
     74 		pass=$PASS
     75 	else
     76 		pass=$FAIL
     77 	fi
     78 
     79 	result $pass "$1=$item_size/$2"
     80 }
     81 
     82 warmup()
     83 {
     84 	pid=$1
     85 
     86 	echo "Warming up for test: $cur_id, pid: $pid"
     87 	kill -s USR1 $pid 2> /dev/null
     88 	sleep 1
     89 	kill -s USR1 $pid 2> /dev/null
     90 	sleep 1
     91 
     92 	kill -0 $pid
     93 	if [ $? -ne 0 ]; then
     94 		result $FAIL "cur_id=$cur_id"
     95 		return 1
     96 	else
     97 		echo "Process is still here after warm up: $pid"
     98 	fi
     99 
    100 	return 0
    101 }
    102 
    103 # Run test cases which checks memory.stat after make
    104 # some memory allocation
    105 # $1 - the parameters of 'process', such as --shm
    106 # $2 - the -s parameter of 'process', such as 4096
    107 # $3 - item name in memory.stat
    108 # $4 - the expected size
    109 # $5 - check after free ?
    110 test_mem_stat()
    111 {
    112 	echo "Running $TEST_PATH/memcg_process $1 -s $2"
    113 	$TEST_PATH/memcg_process $1 -s $2 &
    114 	sleep 1
    115 
    116 	warmup $!
    117 	if [ $? -ne 0 ]; then
    118 		return
    119 	fi
    120 
    121 	echo $! > tasks
    122 	kill -s USR1 $! 2> /dev/null
    123 	sleep 1
    124 
    125 	check_mem_stat $3 $4
    126 
    127 	kill -s USR1 $! 2> /dev/null
    128 	sleep 1
    129 	if [ $5 -eq 1 ]; then
    130 		check_mem_stat $3 0
    131 	fi
    132 
    133 	kill -s INT $! 2> /dev/null
    134 }
    135 
    136 # Run test cases which checks memory.max_usage_in_bytes after make
    137 # some memory allocation
    138 # $1 - the parameters of 'process', such as --shm
    139 # $2 - the -s parameter of 'process', such as 4096
    140 # $3 - item name
    141 # $4 - the expected size
    142 # $5 - check after free ?
    143 test_max_usage_in_bytes()
    144 {
    145 	echo "Running $TEST_PATH/memcg_process $1 -s $2"
    146 	$TEST_PATH/memcg_process $1 -s $2 &
    147 	sleep 1
    148 
    149 	warmup $!
    150 	if [ $? -ne 0 ]; then
    151 		return
    152 	fi
    153 
    154 	echo $! > tasks
    155 	kill -s USR1 $! 2> /dev/null
    156 	sleep 1
    157 
    158 	kill -s USR1 $! 2> /dev/null
    159 	sleep 1
    160 
    161 	check_mem_stat $3 $4
    162 
    163 	if [ $5 -eq 1 ]; then
    164 		echo 0 > $3
    165 		check_mem_stat $3 0
    166 	fi
    167 
    168 	kill -s INT $! 2> /dev/null
    169 }
    170 
    171 # make some memory allocation
    172 # $1 - the parameters of 'process', such as --shm
    173 # $2 - the -s parameter of 'process', such as 4096
    174 malloc_free_memory()
    175 {
    176 	echo "Running $TEST_PATH/memcg_process $1 -s $2"
    177 	$TEST_PATH/memcg_process $1 -s $2 &
    178 	sleep 1
    179 
    180 	echo $! > tasks
    181 	kill -s USR1 $! 2> /dev/null
    182 	sleep 1
    183 
    184 	kill -s USR1 $! 2> /dev/null
    185 	sleep 1
    186 
    187 	kill -s INT $! 2> /dev/null
    188 }
    189 
    190 # Test if failcnt > 0, which means page reclamation occured
    191 # $1 - item name in memcg
    192 test_failcnt()
    193 {
    194 	failcnt=`cat $1`
    195 	if [ $failcnt -gt 0 ]; then
    196 		pass=$PASS
    197 	else
    198 		pass=$FAIL
    199 	fi
    200 
    201 	result $pass "$1=$failcnt"
    202 }
    203 
    204 # Test process will be killed due to exceed memory limit
    205 # $1 - the value of memory.limit_in_bytes
    206 # $2 - the parameters of 'process', such as --shm
    207 # $3 - the -s parameter of 'process', such as 4096
    208 # $4 - use mem+swap limitation
    209 test_proc_kill()
    210 {
    211 	echo $1 > memory.limit_in_bytes
    212 	if [ $4 -eq 1 ]; then
    213 		if [ -e memory.memsw.limit_in_bytes ]; then
    214 			echo $1 > memory.memsw.limit_in_bytes
    215 		else
    216 			tst_resm TCONF "mem+swap is not enabled"
    217 			return
    218 		fi
    219 	fi
    220 
    221 	$TEST_PATH/memcg_process $2 -s $3 &
    222 	pid=$!
    223 	sleep 1
    224 	echo $pid > tasks
    225 
    226 	kill -s USR1 $pid 2> /dev/null
    227 	sleep 1
    228 
    229 	ps -p $pid > /dev/null 2> /dev/null
    230 	if [ $? -ne 0 ]; then
    231 		wait $pid
    232 		ret=$?
    233 		if [ $ret -eq 1 ]; then
    234 			result $FAIL "process $pid is killed by error"
    235 		elif [ $ret -eq 2 ]; then
    236 			result $PASS "Failed to lock memory"
    237 		else
    238 			result $PASS "process $pid is killed"
    239 		fi
    240 	else
    241 		kill -s INT $pid 2> /dev/null
    242 		result $FAIL "process $pid is not killed"
    243 	fi
    244 }
    245 
    246 # Test limit_in_bytes will be aligned to PAGESIZE
    247 # $1 - user input value
    248 # $2 - use mem+swap limitation
    249 test_limit_in_bytes()
    250 {
    251 	echo $1 > memory.limit_in_bytes
    252 	if [ $2 -eq 1 ]; then
    253 		if [ -e memory.memsw.limit_in_bytes ]; then
    254 			echo $1 > memory.memsw.limit_in_bytes
    255 			limit=`cat memory.memsw.limit_in_bytes`
    256 		else
    257 			tst_resm TCONF "mem+swap is not enabled"
    258 			return
    259 		fi
    260 	else
    261 		limit=`cat memory.limit_in_bytes`
    262 	fi
    263 
    264 	# Kernels prior to 3.19 were rounding up but newer kernels
    265 	# are rounding down
    266 	if [ \( $(($PAGESIZE*($1/$PAGESIZE))) -eq $limit \) \
    267 	    -o \( $(($PAGESIZE*(($1+$PAGESIZE-1)/$PAGESIZE))) -eq $limit \) ]; then
    268 		result $PASS "input=$1, limit_in_bytes=$limit"
    269 	else
    270 		result $FAIL "input=$1, limit_in_bytes=$limit"
    271 	fi
    272 }
    273 
    274 # Test memory controller doesn't charge hugepage
    275 # $1 - the value of /proc/sys/vm/nr_hugepages
    276 # $2 - the parameters of 'process', --mmap-file or --shm
    277 # $3 - the -s parameter of 'process', such as $HUGEPAGESIZE
    278 # $4 - 0: expected failure, 1: expected success
    279 test_hugepage()
    280 {
    281 	TMP_FILE=$TEST_PATH/tmp
    282 	nr_hugepages=`cat /proc/sys/vm/nr_hugepages`
    283 
    284 	mkdir /hugetlb
    285 	mount -t hugetlbfs none /hugetlb
    286 
    287 	echo $1 > /proc/sys/vm/nr_hugepages
    288 
    289 	$TEST_PATH/memcg_process $2 --hugepage -s $3 > $TMP_FILE 2>&1 &
    290 	sleep 1
    291 
    292 	kill -s USR1 $! 2> /dev/null
    293 	sleep 1
    294 
    295 	check_mem_stat "rss" 0
    296 
    297 	echo "TMP_FILE:"
    298 	cat $TMP_FILE
    299 
    300 	if [ $4 -eq 0 ]; then
    301 		test -s $TMP_FILE
    302 		if [ $? -eq 0 ]; then
    303 			result $PASS "allocate hugepage failed as expected"
    304 		else
    305 			kill -s USR1 $! 2> /dev/null
    306 			kill -s INT $! 2> /dev/null
    307 			result $FAIL "allocate hugepage shoud fail"
    308 		fi
    309 	else
    310 		test ! -s $TMP_FILE
    311 		if [ $? -eq 0 ]; then
    312 			kill -s USR1 $! 2> /dev/null
    313 			kill -s INT $! 2> /dev/null
    314 			result $PASS "allocate hugepage succeeded"
    315 		else
    316 			result $FAIL "allocate hugepage failed"
    317 		fi
    318 	fi
    319 
    320 	sleep 1
    321 	rm -rf $TMP_FILE
    322 	umount /hugetlb
    323 	rmdir /hugetlb
    324 	echo $nr_hugepages > /proc/sys/vm/nr_hugepages
    325 }
    326 
    327 # Test the memory charge won't move to subgroup
    328 # $1 - memory.limit_in_bytes in parent group
    329 # $2 - memory.limit_in_bytes in sub group
    330 test_subgroup()
    331 {
    332 	mkdir subgroup
    333 	echo $1 > memory.limit_in_bytes
    334 	echo $2 > subgroup/memory.limit_in_bytes
    335 
    336 	echo "Running $TEST_PATH/memcg_process --mmap-anon -s $PAGESIZE"
    337 	$TEST_PATH/memcg_process --mmap-anon -s $PAGESIZE &
    338 	sleep 1
    339 
    340 	warmup $!
    341 	if [ $? -ne 0 ]; then
    342 		return
    343 	fi
    344 
    345 	echo $! > tasks
    346 	kill -s USR1 $! 2> /dev/null
    347 	sleep 1
    348 	check_mem_stat "rss" $PAGESIZE
    349 
    350 	cd subgroup
    351 	echo $! > tasks
    352 	check_mem_stat "rss" 0
    353 
    354 	# cleanup
    355 	cd ..
    356 	echo $! > tasks
    357 	kill -s INT $! 2> /dev/null
    358 	sleep 1
    359 	rmdir subgroup
    360 }
    361 
    362 # Run test cases which test memory.move_charge_at_immigrate
    363 # $1 - the parameters of 'process', such as --shm
    364 # $2 - the -s parameter of 'process', such as 4096
    365 # $3 - some positive value, such as 1
    366 # $4 - the expected size
    367 # $5 - the expected size
    368 test_move_charge()
    369 {
    370 	mkdir subgroup_a
    371 
    372 	$TEST_PATH/memcg_process $1 -s $2 &
    373 	sleep 1
    374 	warmup $!
    375 	if [ $? -ne 0 ]; then
    376 		rmdir subgroup_a
    377 		return
    378 	fi
    379 
    380 	echo $! > subgroup_a/tasks
    381 	kill -s USR1 $!
    382 	sleep 1
    383 
    384 	mkdir subgroup_b
    385 	echo $3 > subgroup_b/memory.move_charge_at_immigrate
    386 	echo $! > subgroup_b/tasks
    387 
    388 	cd subgroup_b
    389 	check_mem_stat "rss" $4
    390 	check_mem_stat "cache" $5
    391 	cd ../subgroup_a
    392 	check_mem_stat "rss" $6
    393 	check_mem_stat "cache" $7
    394 
    395 	cd ..
    396 	echo $! > tasks
    397 	kill -s USR1 $!
    398 	kill -s INT $!
    399 	sleep 1
    400 	rmdir subgroup_a subgroup_b
    401 }
    402 
    403 cleanup()
    404 {
    405 	if [ -n "$orig_memory_use_hierarchy" ];then
    406 		echo $orig_memory_use_hierarchy > \
    407 		     /dev/memcg/memory.use_hierarchy
    408 		if [ $? -ne 0 ];then
    409 			tst_resm TINFO "restore "\
    410 				 "/dev/memcg/memory.use_hierarchy failed"
    411 		fi
    412 		orig_memory_use_hierarchy=""
    413 	fi
    414 
    415 	killall -9 memcg_process 2>/dev/null
    416 	if [ -e /dev/memcg ]; then
    417 		umount /dev/memcg 2>/dev/null
    418 		rmdir /dev/memcg 2>/dev/null
    419 	fi
    420 }
    421 
    422 do_mount()
    423 {
    424 	cleanup
    425 
    426 	mkdir /dev/memcg 2> /dev/null
    427 	mount -t cgroup -omemory memcg /dev/memcg
    428 
    429 	# The default value for memory.use_hierarchy is 0 and some of tests
    430 	# (memcg_stat_test.sh and memcg_use_hierarchy_test.sh) expect it so
    431 	# while there are distributions (RHEL7U0Beta for example) that sets
    432 	# it to 1.
    433 	orig_memory_use_hierarchy=$(cat /dev/memcg/memory.use_hierarchy)
    434 	if [ -z "orig_memory_use_hierarchy" ];then
    435 		tst_resm TINFO "cat /dev/memcg/memory.use_hierarchy failed"
    436 	elif [ "$orig_memory_use_hierarchy" = "0" ];then
    437 		orig_memory_use_hierarchy=""
    438 	else
    439 		echo 0 > /dev/memcg/memory.use_hierarchy
    440 		if [ $? -ne 0 ];then
    441 			tst_resm TINFO "set /dev/memcg/memory.use_hierarchy" \
    442 				"to 0 failed"
    443 		fi
    444 	fi
    445 }
    446