github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/metrics/time/launch_times.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 takes a number of time measurements through the complete 8 # launch/shutdown cycle of a single container. 9 # From those measurements it derives a number of time measures, such as: 10 # - time to payload execution 11 # - time to get to VM kernel 12 # - time in VM kernel boot 13 # - time to quit 14 # - total time (from launch to finished) 15 # 16 # Note, the <image> used for this test must support the full 'date' command 17 # syntax - the date from busybox for instance *does not* support this, so 18 # will not work with this test. 19 # 20 # Note, this test launches a single container at a time, that quits - thus, 21 # this test measures times for the 'first container' only. This test does 22 # not look for any scalability slowdowns as the number of running containers 23 # increases for instance - that is handled in other tests 24 25 set -e 26 27 SCRIPT_PATH=$(dirname "$(readlink -f "$0")") 28 source "${SCRIPT_PATH}/../lib/common.bash" 29 30 # Calculating the kernel time from dmesg stamps only really works for VM 31 # based runtimes - we dynamically enable it if we find we are using a known 32 # VM runtime 33 CALCULATE_KERNEL= 34 35 REQUIRED_CMDS=("bc" "awk") 36 37 # The date command format we use to ensure we capture the ns timings 38 # Note the no-0-padding - 0 padding the results breaks bc in some cases 39 DATECMD="date -u +%-s:%-N" 40 41 # This the minimum entropy level produced 42 # by haveged is 1000 see https://wiki.archlinux.org/index.php/Haveged 43 # Less than 1000 could potentially slow down cryptographic 44 # applications see https://www.suse.com/support/kb/doc/?id=7011351 45 entropy_level="1000" 46 47 check_entropy_level() { 48 retries="10" 49 for i in $(seq 1 "$retries"); do 50 if [ $(cat /proc/sys/kernel/random/entropy_avail) -ge ${entropy_level} ]; then 51 break; 52 fi 53 sleep 1 54 done 55 if [ $(cat /proc/sys/kernel/random/entropy_avail) -le ${entropy_level} ]; then 56 die "Not enough entropy level to run this test" 57 fi 58 } 59 60 # convert a 'seconds:nanoseconds' string into nanoseconds 61 sn_to_ns() { 62 # !!: Remove 0's from beginning otherwise the number will be converted to octal 63 s=$(echo ${1%:*} | sed 's/^0*//g') 64 ns=$(echo ${1##*:} | sed 's/^0*//g') 65 # use shell magic to strip out the 's' and 'ns' fields and print 66 # them as a 0-padded ns string... 67 printf "%d%09d" ${s} ${ns} 68 } 69 70 # convert 'nanoseconds' (since epoch) into a 'float' seconds 71 ns_to_s() { 72 printf "%.03f" $(bc <<< "scale=3; $1 / 1000000000") 73 } 74 75 run_workload() { 76 start_time=$($DATECMD) 77 78 # Check entropy level of the host 79 check_entropy_level 80 81 # Run the image and command and capture the results into an array... 82 declare workload_result 83 readarray -n 0 workload_result < <(ctr run --rm --runtime=${CTR_RUNTIME} ${IMAGE} test bash -c "$DATECMD $DMESGCMD") 84 85 end_time=$($DATECMD) 86 87 # Delay this calculation until after we have run - do not want 88 # to measure it in the results 89 start_time=$(sn_to_ns $start_time) 90 end_time=$(sn_to_ns $end_time) 91 92 # Extract the 'date' info from the first line of the log 93 # This script assumes the VM clock is in sync with the host clock... 94 workload_time=${workload_result[0]} 95 workload_time=$(echo $workload_time | tr -d '\r') 96 workload_time=$(sn_to_ns $workload_time) 97 98 # How long did the whole launch/quit take 99 total_period=$((end_time-start_time)) 100 # How long did it take to get to the workload 101 workload_period=$((workload_time-start_time)) 102 # How long did it take to quit 103 shutdown_period=$((end_time-workload_time)) 104 105 if [ -n "$CALCULATE_KERNEL" ]; then 106 # Grab the last kernel dmesg time 107 # In our case, we need to find the last real kernel line before 108 # the systemd lines begin. The last: 109 # 'Freeing unused kernel' line is a reasonable 110 # 'last in kernel line' to look for. 111 # We make a presumption here that as we are in a cold-boot VM 112 # kernel, the first dmesg is at '0 seconds', so the timestamp 113 # of that last line is the length of time in the kernel. 114 kernel_last_line=$( (fgrep "Freeing unused kernel" <<- EOF 115 ${workload_result[@]} 116 EOF 117 ) | tail -1 ) 118 119 if [ -z "$kernel_last_line" ]; then 120 echo "No kernel last line" 121 for l in "${workload_result[@]}"; do 122 echo ">: [$l]" 123 done 124 die "No kernel last line" 125 fi 126 127 128 kernel_period=$(echo $kernel_last_line | awk '{print $2}' | tr -d "]") 129 130 # And we can then work out how much time it took to get to the kernel 131 to_kernel_period=$(printf "%0f" $(bc <<<"scale=3; $(ns_to_s $workload_period) - $kernel_period")) 132 else 133 kernel_period="0.0" 134 to_kernel_period="0.0" 135 fi 136 137 # And store the results... 138 local json="$(cat << EOF 139 { 140 "total": { 141 "Result": $(ns_to_s $total_period), 142 "Units" : "s" 143 }, 144 "to-workload": { 145 "Result": $(ns_to_s $workload_period), 146 "Units" : "s" 147 }, 148 "in-kernel": { 149 "Result": $kernel_period, 150 "Units" : "s" 151 }, 152 "to-kernel": { 153 "Result": $to_kernel_period, 154 "Units" : "s" 155 }, 156 "to-quit": { 157 "Result": $(ns_to_s $shutdown_period), 158 "Units" : "s" 159 } 160 } 161 EOF 162 )" 163 metrics_json_add_array_element "$json" 164 165 # If we are doing an (optional) scaling test, then we launch a permanent container 166 # between each of our 'test' containers. The aim being to see if our launch times 167 # are linear with the number of running containers or not 168 if [ -n "$SCALING" ]; then 169 ctr run --runtime=${CTR_RUNTIME} -d ${IMAGE} test bash -c "tail -f /dev/null" 170 fi 171 } 172 173 init () { 174 TEST_ARGS="image=${IMAGE} runtime=${CTR_RUNTIME} units=seconds" 175 176 # We set the generic name here, but we save the different time results separately, 177 # and append the actual detail to the name at the time of saving... 178 TEST_NAME="boot times" 179 180 # If we are scaling, note that in the name 181 [ -n "$SCALING" ] && TEST_NAME="${TEST_NAME} scaling" 182 183 echo "Executing test: ${TEST_NAME} ${TEST_ARGS}" 184 check_cmds "${REQUIRED_CMDS[@]}" 185 186 # Only try to grab a dmesg boot time if we are pretty sure we are running a 187 # Kata runtime 188 local iskata=$(is_a_kata_runtime "$RUNTIME") 189 if [ "$iskata" == "1" ]; then 190 CALCULATE_KERNEL=1 191 DMESGCMD="; dmesg" 192 else 193 # For non-VM runtimes, we don't use the output of dmesg, and 194 # we have seen it cause some test instabilities, so do not invoke 195 # it if not needed. 196 DMESGCMD="" 197 fi 198 199 # Start from a fairly clean environment 200 init_env 201 check_images "$IMAGE" 202 } 203 204 help() { 205 usage=$(cat << EOF 206 Usage: $0 [-h] [options] 207 Description: 208 This script takes time measurements for different 209 stages of a boot/run/rm cycle 210 Options: 211 -h, Help 212 -i <name>, Image name (mandatory) 213 -n <n>, Number of containers to run (mandatory) 214 -s, Enable scaling (keep containers running) 215 EOF 216 ) 217 echo "$usage" 218 } 219 220 main() { 221 local OPTIND 222 while getopts "dhi:n:s" opt;do 223 case ${opt} in 224 h) 225 help 226 exit 0; 227 ;; 228 i) 229 IMAGE="${OPTARG}" 230 ;; 231 n) 232 TIMES="${OPTARG}" 233 ;; 234 s) 235 SCALING=true 236 ;; 237 ?) 238 # parse failure 239 help 240 die "Failed to parse arguments" 241 ;; 242 esac 243 done 244 shift $((OPTIND-1)) 245 246 [ -z "$IMAGE" ] && help && die "Mandatory IMAGE name not supplied" 247 [ -z "$TIMES" ] && help && die "Mandatory nunmber of containers not supplied" 248 # Although this is mandatory, the 'lib/common.bash' environment can set 249 # it, so we may not fail if it is not set on the command line... 250 [ -z "$RUNTIME" ] && help && die "Mandatory runtime argument not supplied" 251 252 init 253 metrics_json_init 254 metrics_json_start_array 255 for i in $(seq 1 "$TIMES"); do 256 echo " run $i" 257 run_workload 258 done 259 metrics_json_end_array "Results" 260 metrics_json_save 261 clean_env 262 } 263 264 main "$@"