github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/metrics/lib/common.bash (about)

     1  #!/bin/bash
     2  #
     3  # Copyright (c) 2017-2021 Intel Corporation
     4  #
     5  # SPDX-License-Identifier: Apache-2.0
     6  
     7  THIS_FILE=$(readlink -f ${BASH_SOURCE[0]})
     8  LIB_DIR=${THIS_FILE%/*}
     9  RESULT_DIR="${LIB_DIR}/../results"
    10  
    11  source ${LIB_DIR}/../../lib/common.bash
    12  source ${LIB_DIR}/json.bash
    13  source /etc/os-release || source /usr/lib/os-release
    14  
    15  # Set variables to reasonable defaults if unset or empty
    16  CTR_EXE="${CTR_EXE:-ctr}"
    17  DOCKER_EXE="${DOCKER_EXE:-docker}"
    18  CTR_RUNTIME="${CTR_RUNTIME:-io.containerd.run.kata.v2}"
    19  RUNTIME="${RUNTIME:-containerd-shim-kata-v2}"
    20  KATA_RUNTIME_NAME="containerd-shim-kata-v2"
    21  CONTAINERD_RUNTIME="io.containerd.kata.v2"
    22  
    23  KSM_BASE="/sys/kernel/mm/ksm"
    24  KSM_ENABLE_FILE="${KSM_BASE}/run"
    25  KSM_PAGES_FILE="${KSM_BASE}/pages_to_scan"
    26  KSM_SLEEP_FILE="${KSM_BASE}/sleep_millisecs"
    27  KSM_PAGES_SHARED="${KSM_BASE}/pages_shared"
    28  
    29  # The settings we use for an 'aggresive' KSM setup
    30  # Scan 1000 pages every 50ms - 20,000 pages/s
    31  KSM_AGGRESIVE_PAGES=1000
    32  KSM_AGGRESIVE_SLEEP=50
    33  
    34  # If we fail for any reason, exit through here and we should log that to the correct
    35  # place and return the correct code to halt the run
    36  die(){
    37  	msg="$*"
    38  	echo "ERROR: $msg" >&2
    39  	exit 1
    40  }
    41  
    42  # Sometimes we just want to warn about something - let's have a standard
    43  # method for that, so maybe we can make a standard form that can be searched
    44  # for in the logs/tooling
    45  warning(){
    46  	msg="$*"
    47  	echo "WARNING: $msg" >&2
    48  }
    49  
    50  # This function checks existence of commands.
    51  # They can be received standalone or as an array, e.g.
    52  #
    53  # cmds=(“cmd1” “cmd2”)
    54  # check_cmds "${cmds[@]}"
    55  check_cmds()
    56  {
    57  	local cmd req_cmds=( "$@" )
    58  	for cmd in "${req_cmds[@]}"; do
    59  		if ! command -v "$cmd" > /dev/null 2>&1; then
    60  			die "command $cmd not available"
    61  		fi
    62  		echo "command: $cmd: yes"
    63  	done
    64  }
    65  
    66  # This function performs a pull on the image names
    67  # passed in (notionally as 'about to be used'), to ensure
    68  #  - that we have the most upto date images
    69  #  - that any pull/refresh time (for a first pull) does not
    70  #    happen during the test itself.
    71  #
    72  # The image list can be received standalone or as an array, e.g.
    73  #
    74  # images=(“img1” “img2”)
    75  # check_imgs "${images[@]}"
    76  check_images()
    77  {
    78  	local img req_images=( "$@" )
    79  	for img in "${req_images[@]}"; do
    80  		echo "ctr pull'ing: $img"
    81  		if ! ctr image pull "$img"; then
    82  			die "Failed to pull image $img"
    83  		fi
    84  		echo "ctr pull'd: $img"
    85  	done
    86  }
    87  
    88  # This function performs a build on the image names
    89  # passed in, to ensure that we have the latest changes from
    90  # the dockerfiles
    91  build_dockerfile_image()
    92  {
    93  	local image="$1"
    94  	local dockerfile_path="$2"
    95  	local dockerfile_dir=${2%/*}
    96  
    97  	echo "docker building $image"
    98  	if ! ${DOCKER_EXE} build --label "$image" --tag "${image}" -f "$dockerfile_path" "$dockerfile_dir"; then
    99  		die "Failed to docker build image $image"
   100  	fi
   101  }
   102  
   103  # This function removes the ctr image, builds a new one using a dockerfile
   104  # and imports the image from docker to ctr
   105  check_ctr_images()
   106  {
   107  	local ctr_image="$1"
   108  	local dockerfile_path="$2"
   109  	local docker_image="$(echo ${ctr_image} | cut -d/ -f3 | cut -d: -f1)"
   110  
   111  	if [ -z "$ctr_image" ] || [ -z "$dockerfile_path" ]; then
   112  		die "Missing image or dockerfile path variable"
   113  	fi
   114  
   115  	ctr i rm "${ctr_image}"
   116  	build_dockerfile_image "${docker_image}" "${dockerfile_path}"
   117  	${DOCKER_EXE} save -o "${docker_image}.tar" "${docker_image}"
   118  	ctr i import "${docker_image}.tar"
   119  	rm -rf ${docker_image}.tar
   120  }
   121  
   122  # A one time (per uber test cycle) init that tries to get the
   123  # system to a 'known state' as much as possible
   124  metrics_onetime_init()
   125  {
   126  	# The onetime init must be called once, and only once
   127  	if [ ! -z "$onetime_init_done" ]; then
   128  		die "onetime_init() called more than once"
   129  	fi
   130  
   131  	# Restart services
   132  	sudo systemctl restart docker containerd
   133  
   134  	# We want this to be seen in sub shells as well...
   135  	# otherwise init_env() cannot check us
   136  	export onetime_init_done=1
   137  }
   138  
   139  # Print a banner to the logs noting clearly which test
   140  # we are about to run
   141  test_banner()
   142  {
   143  	echo -e "\n===== starting test [$1] ====="
   144  }
   145  
   146  # Initialization/verification environment. This function makes
   147  # minimal steps for metrics/tests execution.
   148  init_env()
   149  {
   150  	test_banner "${TEST_NAME}"
   151  
   152  	cmd=("docker" "ctr")
   153  
   154  	# check dependencies
   155  	check_cmds "${cmd[@]}"
   156  
   157  	# Remove all stopped containers
   158  	clean_env
   159  	clean_env_ctr
   160  
   161  	# This clean up is more aggressive, this is in order to
   162  	# decrease the factors that could affect the metrics results.
   163  	kill_processes_before_start
   164  }
   165  
   166  # This function checks if there are containers or
   167  # shim/proxy/hypervisor processes up, if found, they are
   168  # killed to start test with clean environment.
   169  kill_processes_before_start() {
   170  	DOCKER_PROCS=$(${DOCKER_EXE} ps -q)
   171  	[[ -n "${DOCKER_PROCS}" ]] && clean_env
   172  
   173  	CTR_PROCS=$(${CTR_EXE} t list -q)
   174  	[[ -n "${CTR_PROCS}" ]] && clean_env_ctr
   175  
   176  	check_processes
   177  }
   178  
   179  # Generate a random name - generally used when creating containers, but can
   180  # be used for any other appropriate purpose
   181  random_name() {
   182  	mktemp -u kata-XXXXXX
   183  }
   184  
   185  show_system_ctr_state() {
   186  	echo "Showing system state:"
   187  	echo " --Check containers--"
   188  	sudo ctr c list
   189  	echo " --Check tasks--"
   190  	sudo ctr task list
   191  
   192  	local processes="containerd-shim-kata-v2"
   193  
   194  	for p in ${processes}; do
   195  		echo " --pgrep ${p}--"
   196  		pgrep -a ${p}
   197  	done
   198  }
   199  
   200  common_init(){
   201  
   202  	# If we are running a kata runtime, go extract its environment
   203  	# for later use.
   204  	local iskata=$(is_a_kata_runtime "$RUNTIME")
   205  
   206  	if [ "$iskata" == "1" ]; then
   207  		extract_kata_env
   208  	else
   209  		# We know we have nothing to do for runc or shimv2
   210  		if [ "$RUNTIME" != "runc" ]; then
   211  			warning "Unrecognised runtime ${RUNTIME}"
   212  		fi
   213  	fi
   214  }
   215  
   216  
   217  # Save the current KSM settings so we can restore them later
   218  save_ksm_settings(){
   219  	echo "saving KSM settings"
   220  	ksm_stored_run=$(cat ${KSM_ENABLE_FILE})
   221  	ksm_stored_pages=$(cat ${KSM_ENABLE_FILE})
   222  	ksm_stored_sleep=$(cat ${KSM_ENABLE_FILE})
   223  }
   224  
   225  set_ksm_aggressive(){
   226  	echo "setting KSM to aggressive mode"
   227  	# Flip the run off/on to ensure a restart/rescan
   228  	sudo bash -c "echo 0 > ${KSM_ENABLE_FILE}"
   229  	sudo bash -c "echo ${KSM_AGGRESIVE_PAGES} > ${KSM_PAGES_FILE}"
   230  	sudo bash -c "echo ${KSM_AGGRESIVE_SLEEP} > ${KSM_SLEEP_FILE}"
   231  	sudo bash -c "echo 1 > ${KSM_ENABLE_FILE}"
   232  
   233  	# Disable virtio-fs and save whether it was enabled previously
   234  	set_virtio_out=$(sudo -E "${LIB_DIR}/../../.ci/set_kata_config.sh" shared_fs virtio-9p)
   235  	echo "${set_virtio_out}"
   236  	grep -q "already" <<< "${set_virtio_out}" || was_virtio_fs=true;
   237  }
   238  
   239  restore_virtio_fs(){
   240  	# Re-enable virtio-fs if it was enabled previously
   241  	[ -n "${was_virtio_fs}" ] && sudo -E "${LIB_DIR}/../../.ci/set_kata_config.sh" shared_fs virtio-fs || \
   242  		info "Not restoring virtio-fs since it wasn't enabled previously"
   243  }
   244  
   245  restore_ksm_settings(){
   246  	echo "restoring KSM settings"
   247  	# First turn off the run to ensure if we are then re-enabling
   248  	# that any changes take effect
   249  	sudo bash -c "echo 0 > ${KSM_ENABLE_FILE}"
   250  	sudo bash -c "echo ${ksm_stored_pages} > ${KSM_PAGES_FILE}"
   251  	sudo bash -c "echo ${ksm_stored_sleep} > ${KSM_SLEEP_FILE}"
   252  	sudo bash -c "echo ${ksm_stored_run} > ${KSM_ENABLE_FILE}"
   253  	restore_virtio_fs
   254  }
   255  
   256  disable_ksm(){
   257  	echo "disabling KSM"
   258  	sudo bash -c "echo 0 > ${KSM_ENABLE_FILE}"
   259  	restore_virtio_fs
   260  }
   261  
   262  # See if KSM is enabled.
   263  # If so, amend the test name to reflect that
   264  check_for_ksm(){
   265  	if [ ! -f ${KSM_ENABLE_FILE} ]; then
   266  		return
   267  	fi
   268  
   269  	ksm_on=$(< ${KSM_ENABLE_FILE})
   270  
   271  	if [ $ksm_on == "1" ]; then
   272  		TEST_NAME="${TEST_NAME} ksm"
   273  	fi
   274  }
   275  
   276  # Wait for KSM to settle down, or timeout waiting
   277  # The basic algorithm is to look at the pages_shared value
   278  # at the end of every 'full scan', and if the value
   279  # has changed very little, then we are done (because we presume
   280  # a full scan has managed to do few new merges)
   281  #
   282  # arg1 - timeout in seconds
   283  wait_ksm_settle(){
   284  	[[ "$RUNTIME" == "runc" ]] || [[ "$RUNTIME" == "kata-fc" ]] && return
   285  	local t pcnt
   286  	local oldscan=-1 newscan
   287  	local oldpages=-1 newpages
   288  
   289  	oldscan=$(cat /sys/kernel/mm/ksm/full_scans)
   290  
   291  	# Wait some time for KSM to kick in to avoid early dismissal
   292  	for ((t=0; t<5; t++)); do
   293  		pages=$(cat "${KSM_PAGES_SHARED}")
   294  		[[ "$pages" -ne 0 ]] && echo "Discovered KSM activity" && break
   295  		sleep 1
   296  	done
   297  
   298  	# Go around the loop until either we see a small % change
   299  	# between two full_scans, or we timeout
   300  	for ((t=0; t<$1; t++)); do
   301  
   302  		newscan=$(cat /sys/kernel/mm/ksm/full_scans)
   303  		newpages=$(cat "${KSM_PAGES_SHARED}")
   304  		[[ "$newpages" -eq 0 ]] && echo "No need to wait for KSM to settle" && return
   305  
   306  		if (( newscan != oldscan )); then
   307  			echo -e "\nnew full_scan ($oldscan to $newscan)"
   308  
   309  			# Do we have a previous scan to compare with
   310  			echo "check pages $oldpages to $newpages"
   311  
   312  			if (( oldpages != -1 )); then
   313  				# avoid divide by zero problems
   314  				if (( $oldpages > 0 )); then
   315  					pcnt=$(( 100 - ((newpages * 100) / oldpages) ))
   316  					# abs()
   317  					pcnt=$(( $pcnt * -1 ))
   318  
   319  					echo "$oldpages to $newpages is ${pcnt}%"
   320  
   321  					if (( $pcnt <= 5 )); then
   322  						echo "KSM stabilised at ${t}s"
   323  						return
   324  					fi
   325  				else
   326  					echo "$oldpages KSM pages... waiting"
   327  				fi
   328  			fi
   329  			oldscan=$newscan
   330  			oldpages=$newpages
   331  		else
   332  			echo -n "."
   333  		fi
   334  		sleep 1
   335  	done
   336  	echo "Timed out after ${1}s waiting for KSM to settle"
   337  }
   338  
   339  common_init