github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/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 # This function measures the PSS average 54 # memory about the child process of each 55 # docker-containerd-shim instance in the 56 # system. 57 get_runc_pss_memory(){ 58 avg=0 59 docker_shim="docker-containerd-shim" 60 mem_amount=0 61 count=0 62 63 shim_instances=$(pgrep -f "^$docker_shim") 64 for shim in $shim_instances; do 65 child_pid="$(pgrep -P $shim)" 66 child_mem=$(sudo "$SMEM_BIN" -c "pid pss" | \ 67 awk "/^$child_pid / {print \$2}") 68 69 # Getting all individual results 70 echo $child_mem >> $MEM_TMP_FILE 71 72 if (( $child_mem > 0 ));then 73 mem_amount=$(( $child_mem + $mem_amount )) 74 (( count++ )) 75 fi 76 done 77 78 # Calculate average 79 if (( $count > 0 )); then 80 avg=$(bc -l <<< "scale=2; $mem_amount / $count") 81 fi 82 83 echo "$avg" 84 } 85 86 get_runc_individual_memory() { 87 runc_process_result=$(cat $MEM_TMP_FILE | tr "\n" " " | sed -e 's/\s$//g' | sed 's/ /, /g') 88 89 # Verify runc process result 90 if [ -z "$runc_process_result" ];then 91 die "Runc process not found" 92 fi 93 94 read -r -a runc_values <<< "${runc_process_result}" 95 96 metrics_json_start_array 97 98 local json="$(cat << EOF 99 { 100 "runc individual results": [ 101 $(for ((i=0;i<${NUM_CONTAINERS[@]};++i)); do 102 printf '%s\n\t\t\t' "${runc_values[i]}" 103 done) 104 ] 105 } 106 EOF 107 )" 108 metrics_json_add_array_element "$json" 109 metrics_json_end_array "Raw results" 110 } 111 112 # This function measures the PSS average 113 # memory of a process. 114 get_pss_memory(){ 115 ps="$1" 116 mem_amount=0 117 count=0 118 avg=0 119 120 if [ -z "$ps" ]; then 121 die "No argument to get_pss_memory()" 122 fi 123 124 # Save all the processes names 125 # This will be help us to retrieve raw information 126 echo $ps >> $PS_TMP_FILE 127 128 data=$(sudo "$SMEM_BIN" --no-header -P "^$ps" -c "pss" | sed 's/[[:space:]]//g') 129 130 # Save all the smem results 131 # This will help us to retrieve raw information 132 echo $data >> $MEM_TMP_FILE 133 134 for i in $data;do 135 if (( i > 0 ));then 136 mem_amount=$(( i + mem_amount )) 137 (( count++ )) 138 fi 139 done 140 141 if (( $count > 0 ));then 142 avg=$(bc -l <<< "scale=2; $mem_amount / $count") 143 fi 144 145 echo "$avg" 146 } 147 148 ppid() { 149 local pid 150 pid=$(ps -p "${1:-nopid}" -o ppid=) 151 echo "${pid//[[:blank:]]/}" 152 } 153 154 # This function measures the PSS average 155 # memory of virtiofsd. 156 # It is a special case of get_pss_memory, 157 # virtiofsd forks itself so, smem sees the process 158 # two times, this function sum both pss values: 159 # pss_virtiofsd=pss_fork + pss_parent 160 get_pss_memory_virtiofsd() { 161 mem_amount=0 162 count=0 163 avg=0 164 165 virtiofsd_path=${1:-} 166 if [ -z "${virtiofsd_path}" ]; then 167 die "virtiofsd_path not provided" 168 fi 169 170 echo "${virtiofsd_path}" >> $PS_TMP_FILE 171 172 virtiofsd_pids=$(ps aux | grep [v]irtiofsd | awk '{print $2}') 173 data=$(sudo smem --no-header -P "^${virtiofsd_path}" -c pid -c "pid pss") 174 175 for p in ${virtiofsd_pids}; do 176 parent_pid=$(ppid ${p}) 177 cmd="$(cat /proc/${p}/cmdline | tr -d '\0')" 178 cmd_parent="$(cat /proc/${parent_pid}/cmdline | tr -d '\0')" 179 if [ "${cmd}" != "${cmd_parent}" ]; then 180 pss_parent=$(printf "%s" "${data}" | grep "\s^${p}" | awk '{print $2}') 181 182 fork=$(pgrep -P ${p}) 183 184 pss_fork=$(printf "%s" "${data}" | grep "^\s*${fork}" | awk '{print $2}') 185 pss_process=$((pss_fork + pss_parent)) 186 187 # Save all the smem results 188 # This will help us to retrieve raw information 189 echo "${pss_process}" >>$MEM_TMP_FILE 190 191 if ((pss_process > 0)); then 192 mem_amount=$((pss_process + mem_amount)) 193 ((count++)) 194 fi 195 fi 196 done 197 198 if (( $count > 0 ));then 199 avg=$(bc -l <<< "scale=2; $mem_amount / $count") 200 fi 201 echo "${avg}" 202 } 203 204 get_individual_memory(){ 205 # Getting all the individual container information 206 first_process_name=$(cat $PS_TMP_FILE | awk 'NR==1' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g') 207 first_process_result=$(cat $MEM_TMP_FILE | awk 'NR==1' | sed 's/ /, /g') 208 209 second_process_name=$(cat $PS_TMP_FILE | awk 'NR==2' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g') 210 second_process_result=$(cat $MEM_TMP_FILE | awk 'NR==2' | sed 's/ /, /g') 211 212 third_process_name=$(cat $PS_TMP_FILE | awk 'NR==3' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g') 213 third_process_result=$(cat $MEM_TMP_FILE | awk 'NR==3' | sed 's/ /, /g') 214 215 read -r -a first_values <<< "${first_process_result}" 216 read -r -a second_values <<< "${second_process_result}" 217 read -r -a third_values <<< "${third_process_result}" 218 219 metrics_json_start_array 220 221 local json="$(cat << EOF 222 { 223 "$first_process_name memory": [ 224 $(for ((i=0;i<${NUM_CONTAINERS[@]};++i)); do 225 [ -n "${first_values[i]}" ] && 226 printf '%s\n\t\t\t' "${first_values[i]}" 227 done) 228 ], 229 "$second_process_name memory": [ 230 $(for ((i=0;i<${NUM_CONTAINERS[@]};++i)); do 231 [ -n "${second_values[i]}" ] && 232 printf '%s\n\t\t\t' "${second_values[i]}" 233 done) 234 ], 235 "$third_process_name memory": [ 236 $(for ((i=0;i<${NUM_CONTAINERS[@]};++i)); do 237 [ -n "${third_values[i]}" ] && 238 printf '%s\n\t\t\t' "${third_values[i]}" 239 done) 240 ] 241 } 242 EOF 243 )" 244 metrics_json_add_array_element "$json" 245 metrics_json_end_array "Raw results" 246 } 247 248 # Try to work out the 'average memory footprint' of a container. 249 get_docker_memory_usage(){ 250 hypervisor_mem=0 251 virtiofsd_mem=0 252 shim_mem=0 253 memory_usage=0 254 255 containers=() 256 257 for ((i=1; i<= NUM_CONTAINERS; i++)); do 258 containers+=($(random_name)) 259 ${CTR_EXE} run --runtime "${CTR_RUNTIME}" -d ${IMAGE} ${containers[-1]} ${CMD} 260 done 261 262 if [ "$AUTO_MODE" == "auto" ]; then 263 if (( ksm_on != 1 )); then 264 die "KSM not enabled, cannot use auto mode" 265 fi 266 267 echo "Entering KSM settle auto detect mode..." 268 wait_ksm_settle $WAIT_TIME 269 else 270 # If KSM is enabled, then you normally want to sleep long enough to 271 # let it do its work and for the numbers to 'settle'. 272 echo "napping $WAIT_TIME s" 273 sleep "$WAIT_TIME" 274 fi 275 276 metrics_json_start_array 277 # Check the runtime in order in order to determine which process will 278 # be measured about PSS 279 if [ "$RUNTIME" == "runc" ]; then 280 runc_workload_mem="$(get_runc_pss_memory)" 281 memory_usage="$runc_workload_mem" 282 283 local json="$(cat << EOF 284 { 285 "average": { 286 "Result": $memory_usage, 287 "Units" : "KB" 288 }, 289 "runc": { 290 "Result": $runc_workload_mem, 291 "Units" : "KB" 292 } 293 } 294 EOF 295 )" 296 297 elif [ "$RUNTIME" == "kata-qemu" ] || [ "$RUNTIME" == "kata-fc" ] || [ "$RUNTIME" == "kata-runtime" ]; then 298 # Get PSS memory of VM runtime components. 299 # And check that the smem search has found the process - we get a "0" 300 # back if that procedure fails (such as if a process has changed its name 301 # or is not running when expected to be so) 302 # As an added bonus - this script must be run as root. 303 # Now if you do not have enough rights 304 # the smem failure to read the stats will also be trapped. 305 306 hypervisor_mem="$(get_pss_memory "$HYPERVISOR_PATH")" 307 if [ "$hypervisor_mem" == "0" ]; then 308 die "Failed to find PSS for $HYPERVISOR_PATH" 309 fi 310 311 virtiofsd_mem="$(get_pss_memory_virtiofsd "$VIRTIOFSD_PATH")" 312 if [ "$virtiofsd_mem" == "0" ]; then 313 echo >&2 "WARNING: Failed to find PSS for $VIRTIOFSD_PATH" 314 fi 315 shim_mem="$(get_pss_memory "$SHIM_PATH")" 316 if [ "$shim_mem" == "0" ]; then 317 die "Failed to find PSS for $SHIM_PATH" 318 fi 319 320 mem_usage="$(bc -l <<< "scale=2; $hypervisor_mem +$virtiofsd_mem + $shim_mem")" 321 memory_usage="$mem_usage" 322 323 local json="$(cat << EOF 324 { 325 "average": { 326 "Result": $mem_usage, 327 "Units" : "KB" 328 }, 329 "qemus": { 330 "Result": $hypervisor_mem, 331 "Units" : "KB" 332 }, 333 "virtiofsds": { 334 "Result": $virtiofsd_mem, 335 "Units" : "KB" 336 }, 337 "shims": { 338 "Result": $shim_mem, 339 "Units" : "KB" 340 } 341 } 342 EOF 343 )" 344 else 345 die "Unknown runtime: $RUNTIME" 346 fi 347 348 metrics_json_add_array_element "$json" 349 metrics_json_end_array "Results" 350 351 ${CTR_EXE} t rm -f ${containers[@]} 352 ${CTR_EXE} c rm ${containers[@]} 353 } 354 355 save_config(){ 356 metrics_json_start_array 357 358 local json="$(cat << EOF 359 { 360 "containers": $NUM_CONTAINERS, 361 "ksm": $ksm_on, 362 "auto": "$AUTO_MODE", 363 "waittime": $WAIT_TIME, 364 "image": "$IMAGE", 365 "command": "$CMD" 366 } 367 EOF 368 369 )" 370 metrics_json_add_array_element "$json" 371 metrics_json_end_array "Config" 372 } 373 374 main(){ 375 # Verify enough arguments 376 if [ $# != 2 ] && [ $# != 3 ];then 377 echo >&2 "error: Not enough arguments [$@]" 378 help 379 exit 1 380 fi 381 382 #Check for KSM before reporting test name, as it can modify it 383 check_for_ksm 384 385 init_env 386 387 check_cmds "${SMEM_BIN}" bc 388 check_images "$IMAGE" 389 390 metrics_json_init 391 save_config 392 get_docker_memory_usage 393 394 if [ "$RUNTIME" == "runc" ]; then 395 get_runc_individual_memory 396 elif [ "$RUNTIME" == "cor" ] || [ "$RUNTIME" == "cc-runtime" ] || [ "$RUNTIME" == "kata-runtime" ]; then 397 get_individual_memory 398 fi 399 400 metrics_json_save 401 } 402 403 main "$@"