github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/metrics/density/footprint_data.sh (about) 1 #!/bin/bash 2 # Copyright (c) 2017-2018, 2021 Intel Corporation 3 # 4 # SPDX-License-Identifier: Apache-2.0 5 # 6 # A script to gather memory 'footprint' information as we launch more 7 # and more containers 8 # 9 # The script gathers information about both user and kernel space consumption 10 # Output is into a .json file, named using some of the config component names 11 # (such as footprint-busybox.json) 12 13 # Pull in some common, useful, items 14 SCRIPT_PATH=$(dirname "$(readlink -f "$0")") 15 source "${SCRIPT_PATH}/../lib/common.bash" 16 17 KSM_ENABLE_FILE="/sys/kernel/mm/ksm/run" 18 19 # Note that all vars that can be set from outside the script (that is, 20 # passed in the ENV), use the ':-' setting to allow being over-ridden 21 22 # Default sleep for 10s to let containers come up and finish their 23 # initialisation before we take the measures. Some of the larger 24 # containers can take a number of seconds to get running. 25 PAYLOAD_SLEEP="${PAYLOAD_SLEEP:-10}" 26 27 ### The default config - run a small busybox image 28 # Define what we will be running (app under test) 29 # Default is we run busybox, as a 'small' workload 30 PAYLOAD="${PAYLOAD:-quay.io/prometheus/busybox:latest}" 31 PAYLOAD_ARGS="${PAYLOAD_ARGS:-tail -f /dev/null}" 32 PAYLOAD_RUNTIME_ARGS="${PAYLOAD_RUNTIME_ARGS:-5120}" 33 34 ### 35 # Define the cutoff checks for when we stop running the test 36 # Run up to this many containers 37 MAX_NUM_CONTAINERS="${MAX_NUM_CONTAINERS:-10}" 38 # Run until we have consumed this much memory (from MemFree) 39 MAX_MEMORY_CONSUMED="${MAX_MEMORY_CONSUMED:-6*1024*1024*1024}" 40 # Run until we have this much MemFree left 41 MIN_MEMORY_FREE="${MIN_MEMORY_FREE:-2*1024*1024*1024}" 42 43 # Tools we need to have installed in order to operate 44 REQUIRED_COMMANDS="smem awk" 45 46 # If we 'dump' the system caches before we measure then we get less 47 # noise in the results - they show more what our un-reclaimable footprint is 48 DUMP_CACHES="${DUMP_CACHES:-1}" 49 50 # Affects the name of the file to store the results in 51 TEST_NAME="${TEST_NAME:-footprint-busybox}" 52 53 ############# end of configurable items ################### 54 55 # vars to remember where we started so we can calc diffs 56 base_mem_avail=0 57 base_mem_free=0 58 59 # dump the kernel caches, so we get a more precise (or just different) 60 # view of what our footprint really is. 61 function dump_caches() { 62 sudo bash -c "echo 3 > /proc/sys/vm/drop_caches" 63 } 64 65 function init() { 66 sudo systemctl restart containerd 67 clean_env_ctr 68 69 CONTAINERD_RUNTIME="io.containerd.kata.v2" 70 check_cmds $REQUIRED_COMMANDS 71 sudo ctr image pull "$PAYLOAD" 72 73 # Modify the test name if running with KSM enabled 74 check_for_ksm 75 76 # Use the common init func to get to a known state 77 init_env 78 79 # Prepare to start storing results 80 metrics_json_init 81 82 # Store up baseline measures 83 base_mem_avail=$(free -b | head -2 | tail -1 | awk '{print $7}') 84 base_mem_free=$(get_memfree) 85 86 # Store our configuration for this run 87 save_config 88 } 89 90 save_config(){ 91 metrics_json_start_array 92 93 local json="$(cat << EOF 94 { 95 "testname": "${TEST_NAME}", 96 "payload": "${PAYLOAD}", 97 "payload_args": "${PAYLOAD_ARGS}", 98 "payload_runtime_args": "${PAYLOAD_RUNTIME_ARGS}", 99 "payload_sleep": ${PAYLOAD_SLEEP}, 100 "max_containers": ${MAX_NUM_CONTAINERS}, 101 "max_memory_consumed": "${MAX_MEMORY_CONSUMED}", 102 "min_memory_free": "${MIN_MEMORY_FREE}", 103 "dump_caches": "${DUMP_CACHES}" 104 } 105 EOF 106 )" 107 metrics_json_add_array_element "$json" 108 metrics_json_end_array "Config" 109 } 110 111 function cleanup() { 112 # Finish storing the results 113 metrics_json_save 114 115 clean_env_ctr 116 } 117 118 # helper function to get USS of process in arg1 119 function get_proc_uss() { 120 item=$(sudo smem -t -P "^$1" | tail -1 | awk '{print $4}') 121 ((item*=1024)) 122 echo $item 123 } 124 125 # helper function to get PSS of process in arg1 126 function get_proc_pss() { 127 item=$(sudo smem -t -P "^$1" | tail -1 | awk '{print $5}') 128 ((item*=1024)) 129 echo $item 130 } 131 132 # Get the PSS for the whole of userspace (all processes) 133 # This allows us to see if we had any impact on the rest of the system, for instance 134 # containerd grows as we launch containers, so we should account for that in our total 135 # memory breakdown 136 function grab_all_pss() { 137 item=$(sudo smem -t | tail -1 | awk '{print $5}') 138 ((item*=1024)) 139 140 local json="$(cat << EOF 141 "all_pss": { 142 "pss": $item, 143 "Units": "KB" 144 } 145 EOF 146 )" 147 148 metrics_json_add_array_fragment "$json" 149 } 150 151 function grab_user_smem() { 152 # userspace 153 item=$(sudo smem -w | head -5 | tail -1 | awk '{print $3}') 154 ((item*=1024)) 155 156 local json="$(cat << EOF 157 "user_smem": { 158 "userspace": $item, 159 "Units": "KB" 160 } 161 EOF 162 )" 163 164 metrics_json_add_array_fragment "$json" 165 } 166 167 function grab_slab() { 168 # Grabbing slab total from meminfo is easier than doing the math 169 # on slabinfo 170 item=$(fgrep "Slab:" /proc/meminfo | awk '{print $2}') 171 ((item*=1024)) 172 173 local json="$(cat << EOF 174 "slab": { 175 "slab": $item, 176 "Units": "KB" 177 } 178 EOF 179 )" 180 181 metrics_json_add_array_fragment "$json" 182 } 183 184 function get_memfree() { 185 mem_free=$(sudo smem -w | head -6 | tail -1 | awk '{print $4}') 186 ((mem_free*=1024)) 187 echo $mem_free 188 } 189 190 function grab_system() { 191 # avail memory, from 'free' 192 local avail=$(free -b | head -2 | tail -1 | awk '{print $7}') 193 local avail_decr=$((base_mem_avail-avail)) 194 195 # cached memory, from 'free' 196 local cached=$(free -b | head -2 | tail -1 | awk '{print $6}') 197 198 # free memory from smem 199 local smem_free=$(get_memfree) 200 local free_decr=$((base_mem_free-item)) 201 202 # Anon pages 203 local anon=$(fgrep "AnonPages:" /proc/meminfo | awk '{print $2}') 204 ((anon*=1024)) 205 206 # Mapped pages 207 local mapped=$(egrep "^Mapped:" /proc/meminfo | awk '{print $2}') 208 ((mapped*=1024)) 209 210 # Cached 211 local meminfo_cached=$(grep "^Cached:" /proc/meminfo | awk '{print $2}') 212 ((meminfo_cached*=1024)) 213 214 local json="$(cat << EOF 215 "system": { 216 "avail": $avail, 217 "avail_decr": $avail_decr, 218 "cached": $cached, 219 "smem_free": $smem_free, 220 "free_decr": $free_decr, 221 "anon": $anon, 222 "mapped": $mapped, 223 "meminfo_cached": $meminfo_cached, 224 "Units": "KB" 225 } 226 EOF 227 )" 228 229 metrics_json_add_array_fragment "$json" 230 } 231 232 function grab_stats() { 233 # If configured, dump the caches so we get a more stable 234 # view of what our static footprint really is 235 if [[ "$DUMP_CACHES" ]] ; then 236 dump_caches 237 fi 238 239 # user space data 240 # PSS taken all userspace 241 grab_all_pss 242 # user as reported by smem 243 grab_user_smem 244 245 # System overview data 246 # System free and cached 247 grab_system 248 249 # kernel data 250 # The 'total kernel space taken' we can work out as: 251 # ktotal = ((free-avail)-user) 252 # So, we don't grab that number from smem, as that is what it does 253 # internally anyhow. 254 # Still try to grab any finer kernel details that we can though 255 256 # totals from slabinfo 257 grab_slab 258 259 metrics_json_close_array_element 260 } 261 262 function check_limits() { 263 mem_free=$(get_memfree) 264 if ((mem_free <= MIN_MEMORY_FREE)); then 265 echo 1 266 return 267 fi 268 269 mem_consumed=$((base_mem_avail-mem_free)) 270 if ((mem_consumed >= MAX_MEMORY_CONSUMED)); then 271 echo 1 272 return 273 fi 274 275 echo 0 276 } 277 278 function go() { 279 # Init the json cycle for this save 280 metrics_json_start_array 281 282 containers=() 283 284 for i in $(seq 1 $MAX_NUM_CONTAINERS); do 285 containers+=($(random_name)) 286 sudo ctr run --memory-limit $PAYLOAD_RUNTIME_ARGS --rm --runtime=$CONTAINERD_RUNTIME $PAYLOAD ${containers[-1]} sh -c $PAYLOAD_ARGS 287 288 if [[ $PAYLOAD_SLEEP ]]; then 289 sleep $PAYLOAD_SLEEP 290 fi 291 292 grab_stats 293 294 # check if we have hit one of our limits and need to wrap up the tests 295 if (($(check_limits))); then 296 # Wrap up the results array 297 metrics_json_end_array "Results" 298 return 299 fi 300 done 301 302 # Wrap up the results array 303 metrics_json_end_array "Results" 304 } 305 306 307 function show_vars() 308 { 309 echo -e "\nEvironment variables:" 310 echo -e "\tName (default)" 311 echo -e "\t\tDescription" 312 echo -e "\tPAYLOAD (${PAYLOAD})" 313 echo -e "\t\tThe ctr image to run" 314 echo -e "\tPAYLOAD_ARGS (${PAYLOAD_ARGS})" 315 echo -e "\t\tAny arguments passed into the ctr image" 316 echo -e "\tPAYLOAD_RUNTIME_ARGS (${PAYLOAD_RUNTIME_ARGS})" 317 echo -e "\t\tAny extra arguments passed into the ctr 'run' command" 318 echo -e "\tPAYLOAD_SLEEP (${PAYLOAD_SLEEP})" 319 echo -e "\t\tSeconds to sleep between launch and measurement, to allow settling" 320 echo -e "\tMAX_NUM_CONTAINERS (${MAX_NUM_CONTAINERS})" 321 echo -e "\t\tThe maximum number of containers to run before terminating" 322 echo -e "\tMAX_MEMORY_CONSUMED (${MAX_MEMORY_CONSUMED})" 323 echo -e "\t\tThe maximum amount of memory to be consumed before terminating" 324 echo -e "\tMIN_MEMORY_FREE (${MIN_MEMORY_FREE})" 325 echo -e "\t\tThe path to the ctr binary (for 'smem' measurements)" 326 echo -e "\tDUMP_CACHES (${DUMP_CACHES})" 327 echo -e "\t\tA flag to note if the system caches should be dumped before capturing stats" 328 echo -e "\tTEST_NAME (${TEST_NAME})" 329 echo -e "\t\tCan be set to over-ride the default JSON results filename" 330 331 } 332 333 function help() 334 { 335 usage=$(cat << EOF 336 Usage: $0 [-h] [options] 337 Description: 338 Launch a series of workloads and take memory metric measurements after 339 each launch. 340 Options: 341 -h, Help page. 342 EOF 343 ) 344 echo "$usage" 345 show_vars 346 } 347 348 function main() { 349 350 local OPTIND 351 while getopts "h" opt;do 352 case ${opt} in 353 h) 354 help 355 exit 0; 356 ;; 357 esac 358 done 359 shift $((OPTIND-1)) 360 361 init 362 go 363 cleanup 364 } 365 366 main "$@"