mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-11 04:42:16 +00:00
This PR removes trailing commas so that the json results
file is valid.
This PR also changes the way data results are collected by
terating through the array of memory values to calculate
their average.
Fixes: #8204
Signed-off-by: David Esparza <david.esparza.borquez@intel.com>
(cherry picked from commit c2763120aa
)
Signed-off-by: Greg Kurz <groug@kaod.org>
404 lines
10 KiB
Bash
Executable File
404 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
# Copyright (c) 2017-2023 Intel Corporation
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
# Description of the test:
|
|
# This test launches a number of containers in idle mode,
|
|
# It will then sleep for a configurable period of time to allow
|
|
# any memory optimisations to 'settle, and then checks the
|
|
# amount of memory used by all the containers to come up with
|
|
# an average (using the PSS measurements)
|
|
# This test uses smem tool to get the memory used.
|
|
|
|
set -e
|
|
|
|
SCRIPT_PATH=$(dirname "$(readlink -f "$0")")
|
|
source "${SCRIPT_PATH}/../lib/common.bash"
|
|
|
|
# Busybox image: Choose a small workload image, this is
|
|
# in order to measure the runtime footprint, not the workload
|
|
# footprint.
|
|
IMAGE="quay.io/prometheus/busybox:latest"
|
|
|
|
CMD='tail -f /dev/null'
|
|
NUM_CONTAINERS="$1"
|
|
WAIT_TIME="$2"
|
|
AUTO_MODE="$3"
|
|
TEST_NAME="memory footprint"
|
|
SMEM_BIN="smem"
|
|
KSM_ENABLE_FILE="/sys/kernel/mm/ksm/run"
|
|
MEM_TMP_FILE=$(mktemp meminfo.XXXXXXXXXX)
|
|
PS_TMP_FILE=$(mktemp psinfo.XXXXXXXXXX)
|
|
|
|
# Variables used to collect memory footprint
|
|
global_hypervisor_mem=0
|
|
global_virtiofsd_mem=0
|
|
global_shim_mem=0
|
|
|
|
function remove_tmp_file() {
|
|
rm -rf "${MEM_TMP_FILE}" "${PS_TMP_FILE}"
|
|
clean_env_ctr
|
|
}
|
|
|
|
trap remove_tmp_file EXIT
|
|
|
|
# Show help about this script
|
|
function help(){
|
|
cat << EOF
|
|
Usage: $0 <count> <wait_time> [auto]
|
|
Description:
|
|
<count> : Number of containers to run.
|
|
<wait_time> : Time in seconds to wait before taking
|
|
metrics.
|
|
[auto] : Optional 'auto KSM settle' mode
|
|
waits for ksm pages_shared to settle down
|
|
EOF
|
|
}
|
|
|
|
|
|
function get_runc_pss_memory(){
|
|
ctr_runc_shim_path="/usr/local/bin/containerd-shim-runc-v2"
|
|
get_pss_memory "${ctr_runc_shim_path}"
|
|
}
|
|
|
|
function get_runc_individual_memory() {
|
|
runc_process_result=$(cat "${MEM_TMP_FILE}" | tr "\n" " " | sed -e 's/\s$//g' | sed 's/ /, /g')
|
|
|
|
# Verify runc process result
|
|
if [ -z "${runc_process_result}" ];then
|
|
die "Runc process not found"
|
|
fi
|
|
|
|
read -r -a runc_values <<< "${runc_process_result}"
|
|
|
|
metrics_json_start_array
|
|
|
|
local json="$(cat << EOF
|
|
{
|
|
"runc individual results": [
|
|
$(for ((i=0;i<"${NUM_CONTAINERS[@]}";++i)); do
|
|
printf '%s\n\t\t\t' "${runc_values[i]}"
|
|
done)
|
|
]
|
|
}
|
|
EOF
|
|
)"
|
|
metrics_json_add_array_element "$json"
|
|
metrics_json_end_array "Raw results"
|
|
}
|
|
|
|
# This function measures the PSS average
|
|
# memory of a process.
|
|
function get_pss_memory(){
|
|
local ps="${1}"
|
|
local shim_result_on="${2:-0}"
|
|
local mem_amount=0
|
|
local count=0
|
|
local avg=0
|
|
|
|
[ -z "${ps}" ] && die "No argument to get_pss_memory()"
|
|
|
|
ps="$(readlink -f ${ps})"
|
|
|
|
# Save all the processes names
|
|
# This will be help us to retrieve raw information
|
|
echo "${ps}" >> "${PS_TMP_FILE}"
|
|
|
|
data="$(sudo "${SMEM_BIN}" --no-header -P "^${ps}" -c "pss" | sed 's/[[:space:]]//g' | tr '\n' ' ' | sed 's/[[:blank:]]*$//')"
|
|
|
|
# Save all the smem results
|
|
# This will help us to retrieve raw information
|
|
echo "${data}" >> "${MEM_TMP_FILE}"
|
|
|
|
arrData=($data)
|
|
|
|
for i in "${arrData[@]}"; do
|
|
if [ ${i} -gt 0 ]; then
|
|
let "mem_amount+=i"
|
|
let "count+=1"
|
|
[ $count -eq $NUM_CONTAINERS ] && break
|
|
fi
|
|
done
|
|
|
|
[ ${count} -eq 0 ] && die "No pss memory was measured for PID: ${ps}"
|
|
|
|
avg=$(bc -l <<< "scale=2; ${mem_amount} / ${count}")
|
|
|
|
if [ "${shim_result_on}" -eq "1" ]; then
|
|
global_shim_mem="${avg}"
|
|
else
|
|
global_hypervisor_mem="${avg}"
|
|
fi
|
|
}
|
|
|
|
function ppid() {
|
|
local pid
|
|
pid=$(ps -p "${1:-nopid}" -o ppid=)
|
|
echo "${pid//[[:blank:]]/}"
|
|
}
|
|
|
|
# This function measures the PSS average
|
|
# memory of virtiofsd.
|
|
# It is a special case of get_pss_memory,
|
|
# virtiofsd forks itself so, smem sees the process
|
|
# two times, this function sum both pss values:
|
|
# pss_virtiofsd=pss_fork + pss_parent
|
|
function get_pss_memory_virtiofsd() {
|
|
mem_amount=0
|
|
count=0
|
|
avg=0
|
|
virtiofsd_path=${1:-}
|
|
|
|
[ -z "${virtiofsd_path}" ] && die "virtiofsd_path not provided"
|
|
|
|
echo "${virtiofsd_path}" >> "${PS_TMP_FILE}"
|
|
|
|
virtiofsd_pids="$(ps aux | grep '[v]irtiofsd' | awk '{print $2}' | head -1)"
|
|
|
|
data="$(sudo smem --no-header -P "^${virtiofsd_path}" -c "pid pss")"
|
|
|
|
for p in "${virtiofsd_pids}"; do
|
|
parent_pid=$(ppid "${p}")
|
|
cmd="$(cat /proc/${p}/cmdline | tr -d '\0')"
|
|
cmd_parent="$(cat /proc/${parent_pid}/cmdline | tr -d '\0')"
|
|
if [ "${cmd}" != "${cmd_parent}" ]; then
|
|
pss_parent=$(printf "%s" "${data}" | grep "\s^${p}" | awk '{print $2}')
|
|
|
|
fork=$(pgrep -P "${p}")
|
|
|
|
pss_fork=$(printf "%s" "${data}" | grep "^\s*${fork}" | awk '{print $2}')
|
|
pss_process=$((pss_fork + pss_parent))
|
|
|
|
# Save all the smem results
|
|
# This will help us to retrieve raw information
|
|
echo "${pss_process}" >>"${MEM_TMP_FILE}"
|
|
|
|
if ((pss_process > 0)); then
|
|
mem_amount=$((pss_process + mem_amount))
|
|
let "count+=1"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
[ "${count}" -gt 0 ] && global_virtiofsd_mem=$(bc -l <<< "scale=2; ${mem_amount} / ${count}")
|
|
}
|
|
|
|
function get_individual_memory(){
|
|
# Getting all the individual container information
|
|
first_process_name=$(cat "${PS_TMP_FILE}" | awk 'NR==1' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g')
|
|
first_process_result=$(cat "${MEM_TMP_FILE}" | awk 'NR==1' | sed 's/ /, /g')
|
|
|
|
second_process_name=$(cat "${PS_TMP_FILE}" | awk 'NR==2' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g')
|
|
second_process_result=$(cat "${MEM_TMP_FILE}" | awk 'NR==2' | sed 's/ /, /g')
|
|
|
|
third_process_name=$(cat "${PS_TMP_FILE}" | awk 'NR==3' | awk -F "/" '{print $NF}' | sed 's/[[:space:]]//g')
|
|
third_process_result=$(cat "${MEM_TMP_FILE}" | awk 'NR==3' | sed 's/ /, /g')
|
|
|
|
read -r -a first_values <<< "${first_process_result}"
|
|
read -r -a second_values <<< "${second_process_result}"
|
|
read -r -a third_values <<< "${third_process_result}"
|
|
|
|
declare -a fv_array
|
|
declare -a sv_array
|
|
declare -a tv_array
|
|
|
|
# remove null values from arrays of results
|
|
for ((i=0;i<"${NUM_CONTAINERS}";++i)); do
|
|
[ -n "${first_values[i]}" ] && fv_array+=( "${first_values[i]}" )
|
|
[ -n "${second_values[i]}" ] && sv_array+=( "${second_values[i]}" )
|
|
[ -n "${third_values[i]}" ] && tv_array+=( "${third_values[i]}" )
|
|
done
|
|
|
|
# remove trailing commas
|
|
fv_array[-1]="$(sed -r 's/,*$//g' <<< "${fv_array[-1]}")"
|
|
sv_array[-1]="$(sed -r 's/,*$//g' <<< "${sv_array[-1]}")"
|
|
tv_array[-1]="$(sed -r 's/,*$//g' <<< "${tv_array[-1]}")"
|
|
|
|
metrics_json_start_array
|
|
|
|
local json="$(cat << EOF
|
|
{
|
|
"${first_process_name} memory": [
|
|
$(for i in "${fv_array[@]}"; do
|
|
printf '\n\t\t\t%s' "${i}"
|
|
done)
|
|
],
|
|
"${second_process_name} memory": [
|
|
$(for i in "${sv_array[@]}"; do
|
|
printf '\n\t\t\t%s' "${i}"
|
|
done)
|
|
],
|
|
"${third_process_name} memory": [
|
|
$(for i in "${tv_array[@]}"; do
|
|
printf '\n\t\t\t%s' "${i}"
|
|
done)
|
|
]
|
|
}
|
|
EOF
|
|
)"
|
|
metrics_json_add_array_element "${json}"
|
|
metrics_json_end_array "Raw results"
|
|
}
|
|
|
|
# Try to work out the 'average memory footprint' of a container.
|
|
function get_memory_usage(){
|
|
hypervisor_mem=0
|
|
virtiofsd_mem=0
|
|
shim_mem=0
|
|
memory_usage=0
|
|
|
|
containers=()
|
|
|
|
info "Creating ${NUM_CONTAINERS} containers"
|
|
for ((i=1; i<="${NUM_CONTAINERS}"; i++)); do
|
|
containers+=($(random_name))
|
|
sudo "${CTR_EXE}" run --runtime "${CTR_RUNTIME}" -d "${IMAGE}" "${containers[-1]}" sh -c "${CMD}"
|
|
done
|
|
|
|
if [ "${AUTO_MODE}" == "auto" ]; then
|
|
if (( ksm_on != 1 )); then
|
|
die "KSM not enabled, cannot use auto mode"
|
|
fi
|
|
|
|
echo "Entering KSM settle auto detect mode..."
|
|
wait_ksm_settle "${WAIT_TIME}"
|
|
else
|
|
# If KSM is enabled, then you normally want to sleep long enough to
|
|
# let it do its work and for the numbers to 'settle'.
|
|
echo "napping ${WAIT_TIME} s"
|
|
sleep "${WAIT_TIME}"
|
|
fi
|
|
|
|
metrics_json_start_array
|
|
# Check the runtime in order in order to determine which process will
|
|
# be measured about PSS
|
|
if [ "${RUNTIME}" == "runc" ]; then
|
|
runc_workload_mem="$(get_runc_pss_memory)"
|
|
memory_usage="${runc_workload_mem}"
|
|
|
|
local json="$(cat << EOF
|
|
{
|
|
"average": {
|
|
"Result": ${memory_usage},
|
|
"Units" : "KB"
|
|
},
|
|
"runc": {
|
|
"Result": ${runc_workload_mem},
|
|
"Units" : "KB"
|
|
}
|
|
}
|
|
EOF
|
|
)"
|
|
else [ "$RUNTIME" == "kata-runtime" ] || [ "$RUNTIME" == "kata-qemu" ]
|
|
# Get PSS memory of VM runtime components.
|
|
# And check that the smem search has found the process - we get a "0"
|
|
# back if that procedure fails (such as if a process has changed its name
|
|
# or is not running when expected to be so)
|
|
# As an added bonus - this script must be run as root.
|
|
# Now if you do not have enough rights
|
|
# the smem failure to read the stats will also be trapped.
|
|
get_pss_memory ${HYPERVISOR_PATH}
|
|
|
|
if [ "${global_hypervisor_mem}" == "0" ]; then
|
|
die "Failed to find PSS for ${HYPERVISOR_PATH}"
|
|
fi
|
|
|
|
get_pss_memory_virtiofsd ${VIRTIOFSD_PATH}
|
|
|
|
if [ "${global_virtiofsd_mem}" == "0" ]; then
|
|
echo >&2 "WARNING: Failed to find PSS for ${VIRTIOFSD_PATH}"
|
|
fi
|
|
get_pss_memory ${SHIM_PATH} 1
|
|
|
|
if [ "${global_shim_mem}" == "0" ]; then
|
|
die "Failed to find PSS for ${SHIM_PATH}"
|
|
fi
|
|
mem_usage="$(bc -l <<< "scale=2; ${global_hypervisor_mem} + ${global_virtiofsd_mem} + ${global_shim_mem}")"
|
|
|
|
local json="$(cat << EOF
|
|
{
|
|
"average": {
|
|
"Result": ${mem_usage},
|
|
"Units" : "KB"
|
|
},
|
|
"qemus": {
|
|
"Result": ${global_hypervisor_mem},
|
|
"Units" : "KB"
|
|
},
|
|
"virtiofsds": {
|
|
"Result": ${global_virtiofsd_mem},
|
|
"Units" : "KB"
|
|
},
|
|
"shims": {
|
|
"Result": ${global_shim_mem},
|
|
"Units" : "KB"
|
|
}
|
|
}
|
|
EOF
|
|
)"
|
|
fi
|
|
|
|
metrics_json_add_array_element "$json"
|
|
metrics_json_end_array "Results"
|
|
}
|
|
|
|
function save_config(){
|
|
metrics_json_start_array
|
|
|
|
local json="$(cat << EOF
|
|
{
|
|
"containers": "${NUM_CONTAINERS}",
|
|
"ksm": "${ksm_on}",
|
|
"auto": "${AUTO_MODE}",
|
|
"waittime": "${WAIT_TIME}",
|
|
"image": "${IMAGE}",
|
|
"command": "${CMD}"
|
|
}
|
|
EOF
|
|
|
|
)"
|
|
metrics_json_add_array_element "$json"
|
|
metrics_json_end_array "Config"
|
|
}
|
|
|
|
function main(){
|
|
# Collect kata-env data
|
|
common_init
|
|
|
|
# Verify enough arguments
|
|
if [ $# != 2 ] && [ $# != 3 ];then
|
|
echo >&2 "error: Not enough arguments [$@]"
|
|
help
|
|
exit 1
|
|
fi
|
|
|
|
#Check for KSM before reporting test name, as it can modify it
|
|
check_for_ksm
|
|
check_cmds "${SMEM_BIN}" bc
|
|
clean_env_ctr
|
|
init_env
|
|
check_images "${IMAGE}"
|
|
if [ "${CTR_RUNTIME}" == "io.containerd.kata.v2" ]; then
|
|
export RUNTIME="kata-runtime"
|
|
elif [ "${CTR_RUNTIME}" == "io.containerd.runc.v2" ]; then
|
|
export RUNTIME="runc"
|
|
else
|
|
die "Unknown runtime ${CTR_RUNTIME}"
|
|
fi
|
|
metrics_json_init
|
|
save_config
|
|
get_memory_usage
|
|
|
|
if [ "$RUNTIME" == "runc" ]; then
|
|
get_runc_individual_memory
|
|
elif [ "$RUNTIME" == "kata-runtime" ]; then
|
|
get_individual_memory
|
|
fi
|
|
|
|
info "memory usage test completed"
|
|
metrics_json_save
|
|
}
|
|
|
|
main "$@"
|