github.com/kata-containers/tests@v0.0.0-20240307153542-772105b56064/metrics/density/memory_usage.sh (about) 1 #!/bin/bash 2 # Copyright (c) 2017-2021 Intel Corporation 3 # 4 # SPDX-License-Identifier: Apache-2.0 5 # 6 # Description of the test: 7 # This test launches a number of containers in idle mode, 8 # It will then sleep for a configurable period of time to allow 9 # any memory optimisations to 'settle, and then checks the 10 # amount of memory used by all the containers to come up with 11 # an average (using the PSS measurements) 12 # This test uses smem tool to get the memory used. 13 14 set -e 15 16 SCRIPT_PATH=$(dirname "$(readlink -f "$0")") 17 source "${SCRIPT_PATH}/../lib/common.bash" 18 19 # Busybox image: Choose a small workload image, this is 20 # in order to measure the runtime footprint, not the workload 21 # footprint. 22 IMAGE='quay.io/prometheus/busybox:latest' 23 24 CMD='tail -f /dev/null' 25 NUM_CONTAINERS="$1" 26 WAIT_TIME="$2" 27 AUTO_MODE="$3" 28 TEST_NAME="memory footprint" 29 SMEM_BIN="smem" 30 KSM_ENABLE_FILE="/sys/kernel/mm/ksm/run" 31 MEM_TMP_FILE=$(mktemp meminfo.XXXXXXXXXX) 32 PS_TMP_FILE=$(mktemp psinfo.XXXXXXXXXX) 33 34 function remove_tmp_file() { 35 rm -rf $MEM_TMP_FILE $PS_TMP_FILE 36 } 37 38 trap remove_tmp_file EXIT 39 40 # Show help about this script 41 help(){ 42 cat << EOF 43 Usage: $0 <count> <wait_time> [auto] 44 Description: 45 <count> : Number of containers to run. 46 <wait_time> : Time in seconds to wait before taking 47 metrics. 48 [auto] : Optional 'auto KSM settle' mode 49 waits for ksm pages_shared to settle down 50 EOF 51 } 52 53 54 get_runc_pss_memory(){ 55 ctr_runc_shim_path="/usr/local/bin/containerd-shim-runc-v2" 56 get_pss_memory "$ctr_runc_shim_path" 57 } 58 59 get_runc_individual_memory() { 60 runc_process_result=$(cat $MEM_TMP_FILE | tr "\n" " " | sed -e 's/\s$//g' | sed 's/ /, /g') 61 62 # Verify runc process result 63 if [ -z "$runc_process_result" ];then 64 die "Runc process not found" 65 fi 66 67 read -r -a runc_values <<< "${runc_process_result}" 68 69 metrics_json_start_array 70 71 local json="$(cat << EOF 72 { 73 "runc individual results": [ 74 $(for ((i=0;i<${NUM_CONTAINERS[@]};++i)); do 75 printf '%s\n\t\t\t' "${runc_values[i]}" 76 done) 77 ] 78 } 79 EOF 80 )" 81 metrics_json_add_array_element "$json" 82 metrics_json_end_array "Raw results" 83 } 84 85 # This function measures the PSS average 86 # memory of a process. 87 get_pss_memory(){ 88 ps="$1" 89 mem_amount=0 90 count=0 91 avg=0 92 93 if [ -z "$ps" ]; then 94 die "No argument to get_pss_memory()" 95 fi 96 97 # Save all the processes names 98 # This will be help us to retrieve raw information 99 echo $ps >> $PS_TMP_FILE 100 101 data=$(sudo "$SMEM_BIN" --no-header -P "^$ps" -c "pss" | sed 's/[[:space:]]//g') 102 103 # Save all the smem results 104 # This will help us to retrieve raw information 105 echo $data >> $MEM_TMP_FILE 106 107 for i in $data;do 108 if (( i > 0 ));then 109 mem_amount=$(( i + mem_amount )) 110 (( count++ )) 111 fi 112 done 113 114 if (( $count > 0 ));then 115 avg=$(bc -l <<< "scale=2; $mem_amount / $count") 116 fi 117 118 echo "$avg" 119 } 120 121 ppid() { 122 local pid 123 pid=$(ps -p "${1:-nopid}" -o ppid=) 124 echo "${pid//[[:blank:]]/}" 125 } 126 127 # This function measures the PSS average 128 # memory of virtiofsd. 129 # It is a special case of get_pss_memory, 130 # virtiofsd forks itself so, smem sees the process 131 # two times, this function sum both pss values: 132 # pss_virtiofsd=pss_fork + pss_parent 133 get_pss_memory_virtiofsd() { 134 mem_amount=0 135 count=0 136 avg=0 137 138 virtiofsd_path=${1:-} 139 if [ -z "${virtiofsd_path}" ]; then 140 die "virtiofsd_path not provided" 141 fi 142 143 echo "${virtiofsd_path}" >> $PS_TMP_FILE 144 145 virtiofsd_pids=$(ps aux | grep [v]irtiofsd | awk '{print $2}') 146 data=$(sudo smem --no-header -P "^${virtiofsd_path}" -c pid -c "pid pss") 147 148 for p in ${virtiofsd_pids}; do 149 parent_pid=$(ppid ${p}) 150 cmd="$(cat /proc/${p}/cmdline | tr -d '\0')" 151 cmd_parent="$(cat /proc/${parent_pid}/cmdline | tr -d '\0')" 152 if [ "${cmd}" != "${cmd_parent}" ]; then 153 pss_parent=$(printf "%s" "${data}" | grep "\s^${p}" | awk '{print $2}') 154 155 fork=$(pgrep -P ${p}) 156 157 pss_fork=$(printf "%s" "${data}" | grep "^\s*${fork}" | awk '{print $2}') 158 pss_process=$((pss_fork + pss_parent)) 159 160 # Save all the smem results 161 # This will help us to retrieve raw information 162 echo "${pss_process}" >>$MEM_TMP_FILE 163 164 if ((pss_process > 0)); then 165 mem_amount=$((pss_process + mem_amount)) 166 ((count++)) 167 fi 168 fi 169 done 170 171 if (( $count > 0 ));then 172 avg=$(bc -l <<< "scale=2; $mem_amount / $count") 173 fi 174 echo "${avg}" 175 } 176 177 get_individual_memory(){ 178 # Getting all the individual container information 179 first_process_name=$(cat $PS_TMP_FILE | awk 'NR==1' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g') 180 first_process_result=$(cat $MEM_TMP_FILE | awk 'NR==1' | sed 's/ /, /g') 181 182 second_process_name=$(cat $PS_TMP_FILE | awk 'NR==2' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g') 183 second_process_result=$(cat $MEM_TMP_FILE | awk 'NR==2' | sed 's/ /, /g') 184 185 third_process_name=$(cat $PS_TMP_FILE | awk 'NR==3' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g') 186 third_process_result=$(cat $MEM_TMP_FILE | awk 'NR==3' | sed 's/ /, /g') 187 188 read -r -a first_values <<< "${first_process_result}" 189 read -r -a second_values <<< "${second_process_result}" 190 read -r -a third_values <<< "${third_process_result}" 191 192 metrics_json_start_array 193 194 local json="$(cat << EOF 195 { 196 "$first_process_name memory": [ 197 $(for ((i=0;i<${NUM_CONTAINERS[@]};++i)); do 198 [ -n "${first_values[i]}" ] && 199 printf '%s\n\t\t\t' "${first_values[i]}" 200 done) 201 ], 202 "$second_process_name memory": [ 203 $(for ((i=0;i<${NUM_CONTAINERS[@]};++i)); do 204 [ -n "${second_values[i]}" ] && 205 printf '%s\n\t\t\t' "${second_values[i]}" 206 done) 207 ], 208 "$third_process_name memory": [ 209 $(for ((i=0;i<${NUM_CONTAINERS[@]};++i)); do 210 [ -n "${third_values[i]}" ] && 211 printf '%s\n\t\t\t' "${third_values[i]}" 212 done) 213 ] 214 } 215 EOF 216 )" 217 metrics_json_add_array_element "$json" 218 metrics_json_end_array "Raw results" 219 } 220 221 # Try to work out the 'average memory footprint' of a container. 222 get_docker_memory_usage(){ 223 hypervisor_mem=0 224 virtiofsd_mem=0 225 shim_mem=0 226 memory_usage=0 227 228 containers=() 229 230 for ((i=1; i<= NUM_CONTAINERS; i++)); do 231 containers+=($(random_name)) 232 ${CTR_EXE} run --runtime "${CTR_RUNTIME}" -d ${IMAGE} ${containers[-1]} ${CMD} 233 done 234 235 if [ "$AUTO_MODE" == "auto" ]; then 236 if (( ksm_on != 1 )); then 237 die "KSM not enabled, cannot use auto mode" 238 fi 239 240 echo "Entering KSM settle auto detect mode..." 241 wait_ksm_settle $WAIT_TIME 242 else 243 # If KSM is enabled, then you normally want to sleep long enough to 244 # let it do its work and for the numbers to 'settle'. 245 echo "napping $WAIT_TIME s" 246 sleep "$WAIT_TIME" 247 fi 248 249 metrics_json_start_array 250 # Check the runtime in order in order to determine which process will 251 # be measured about PSS 252 if [ "$RUNTIME" == "runc" ]; then 253 runc_workload_mem="$(get_runc_pss_memory)" 254 memory_usage="$runc_workload_mem" 255 256 local json="$(cat << EOF 257 { 258 "average": { 259 "Result": $memory_usage, 260 "Units" : "KB" 261 }, 262 "runc": { 263 "Result": $runc_workload_mem, 264 "Units" : "KB" 265 } 266 } 267 EOF 268 )" 269 270 else [ "$RUNTIME" == "kata-runtime" ] || [ "$RUNTIME" == "kata-qemu" ] 271 # Get PSS memory of VM runtime components. 272 # And check that the smem search has found the process - we get a "0" 273 # back if that procedure fails (such as if a process has changed its name 274 # or is not running when expected to be so) 275 # As an added bonus - this script must be run as root. 276 # Now if you do not have enough rights 277 # the smem failure to read the stats will also be trapped. 278 279 hypervisor_mem="$(get_pss_memory "$HYPERVISOR_PATH")" 280 if [ "$hypervisor_mem" == "0" ]; then 281 die "Failed to find PSS for $HYPERVISOR_PATH" 282 fi 283 284 virtiofsd_mem="$(get_pss_memory_virtiofsd "$VIRTIOFSD_PATH")" 285 if [ "$virtiofsd_mem" == "0" ]; then 286 echo >&2 "WARNING: Failed to find PSS for $VIRTIOFSD_PATH" 287 fi 288 shim_mem="$(get_pss_memory "$SHIM_PATH")" 289 if [ "$shim_mem" == "0" ]; then 290 die "Failed to find PSS for $SHIM_PATH" 291 fi 292 293 mem_usage="$(bc -l <<< "scale=2; $hypervisor_mem +$virtiofsd_mem + $shim_mem")" 294 memory_usage="$mem_usage" 295 296 local json="$(cat << EOF 297 { 298 "average": { 299 "Result": $mem_usage, 300 "Units" : "KB" 301 }, 302 "qemus": { 303 "Result": $hypervisor_mem, 304 "Units" : "KB" 305 }, 306 "virtiofsds": { 307 "Result": $virtiofsd_mem, 308 "Units" : "KB" 309 }, 310 "shims": { 311 "Result": $shim_mem, 312 "Units" : "KB" 313 } 314 } 315 EOF 316 )" 317 fi 318 319 metrics_json_add_array_element "$json" 320 metrics_json_end_array "Results" 321 322 clean_env_ctr 323 } 324 325 save_config(){ 326 metrics_json_start_array 327 328 local json="$(cat << EOF 329 { 330 "containers": $NUM_CONTAINERS, 331 "ksm": $ksm_on, 332 "auto": "$AUTO_MODE", 333 "waittime": $WAIT_TIME, 334 "image": "$IMAGE", 335 "command": "$CMD" 336 } 337 EOF 338 339 )" 340 metrics_json_add_array_element "$json" 341 metrics_json_end_array "Config" 342 } 343 344 main(){ 345 # Verify enough arguments 346 if [ $# != 2 ] && [ $# != 3 ];then 347 echo >&2 "error: Not enough arguments [$@]" 348 help 349 exit 1 350 fi 351 352 #Check for KSM before reporting test name, as it can modify it 353 check_for_ksm 354 355 init_env 356 357 check_cmds "${SMEM_BIN}" bc 358 check_images "$IMAGE" 359 360 if [ "${CTR_RUNTIME}" == "io.containerd.kata.v2" ]; then 361 export RUNTIME="kata-runtime" 362 elif [ "${CTR_RUNTIME}" == "io.containerd.runc.v2" ]; then 363 export RUNTIME="runc" 364 else 365 die "Unknown runtime ${CTR_RUNTIME}" 366 fi 367 368 metrics_json_init 369 save_config 370 get_docker_memory_usage 371 372 if [ "$RUNTIME" == "runc" ]; then 373 get_runc_individual_memory 374 elif [ "$RUNTIME" == "kata-runtime" ]; then 375 get_individual_memory 376 fi 377 378 metrics_json_save 379 } 380 381 main "$@"