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