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@cn.fujitsu.com> ## 22## ## 23################################################################################ 24 25TST_NEEDS_CHECKPOINTS=1 26. test.sh 27 28if [ "x$(grep -w memory /proc/cgroups | cut -f4)" != "x1" ]; then 29 tst_brkm TCONF "Kernel does not support the memory resource controller" 30fi 31 32PAGESIZE=$(getconf PAGESIZE) 33if [ $? -ne 0 ]; then 34 tst_brkm TBROK "getconf PAGESIZE failed" 35fi 36 37HUGEPAGESIZE=$(awk '/Hugepagesize/ {print $2}' /proc/meminfo) 38[ -z $HUGEPAGESIZE ] && HUGEPAGESIZE=0 39HUGEPAGESIZE=$(( $HUGEPAGESIZE * 1024 )) 40orig_memory_use_hierarchy="" 41 42MEMSW_USAGE_FLAG=0 43MEMSW_LIMIT_FLAG=0 44 45tst_tmpdir 46TMP_DIR="$PWD" 47 48cleanup() 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} 76TST_CLEANUP=cleanup 77 78shmmax_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 86shmmax_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 96check_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 111signal_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 144stop_memcg_process() 145{ 146 local pid=$1 147 kill -s INT $pid 2> /dev/null 148 wait $pid 149} 150 151warmup() 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 174test_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 ? 212test_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 240malloc_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 255test_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 270test_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 319test_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 351test_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 401test_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 432test_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 472cleanup_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 497setup_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 526run_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