integ/virt/kvm-timer-advance/files/setup_kvm_timer_advance.sh
Al Bailey 56c534ad98 Add back kvm_timer_advance_setup.service
The kvm_timer_advance_setup service was packaged and
installed as part of nova-compute package prior to
containerizing nova.

The service file has been updated to start before kubelet.

The service becomes enabled by puppet which writes a
config file containing the vcpu_pin_set information.

The utility script has been updated.
The .sh extension has been added, and it passes bashate.

Updated the license to GPLv2 since the tuned package
where the script was dervied from is GPLv2.

Change-Id: Iff90c46826a88283e42a980e7823593599f03206
Closes-Bug: 1823751
Signed-off-by: Al Bailey <Al.Bailey@windriver.com>
2019-07-24 16:04:58 -05:00

116 lines
3.7 KiB
Bash

#!/bin/bash
#
# SPDX-License-Identifier: GPLv2
#
# The qemu command details and the 98-102% range is taken from
# find-lapictscdeadline-optimal.sh and script.sh
# from the tuned package available at
# https://github.com/redhat-performance/tuned/tree/master/profiles/realtime-virtual-host
#
# The tuned package is GPLv2 therefore this component is GPLv2
#
# Copyright(c) 2019 Wind River Systems, Inc. All rights reserved.
#
QEMU=/usr/libexec/qemu-kvm
ADVANCE_FILE="/sys/module/kvm/parameters/lapic_timer_advance_ns"
ADVANCE_CALIB="/etc/kvm-timer-advance/calibrated_lapic_timer_advance_ns"
function log {
logger -p local1.info -t $0 $@
echo $0: "$@"
}
# This is a check for a virtualbox machine where kvm modules are not loaded
if [ ! -f $ADVANCE_FILE ]; then
exit 1
fi
# Use previous calibrated advance result
if [ -f $ADVANCE_CALIB ]; then
read -r advance < $ADVANCE_CALIB
if [[ "$advance" =~ ^[0-9]+$ ]]; then
echo $advance > $ADVANCE_FILE
log "using previously calibrated advance value of" $(cat $ADVANCE_FILE)
exit 0
fi
fi
# Use the application cpus calculated by puppet. This will ensure that
# we run on a CPU that isn't being used by management or vswitch.
VCPU_PIN_STR=$(grep vcpu_pin_set /etc/kvm-timer-advance/kvm-timer-advance.conf)
VCPU_PIN_STR=${VCPU_PIN_STR//\"/}
FLOAT_CPUS=${VCPU_PIN_STR##*=}
if [ -z "${FLOAT_CPUS}" ]; then
log "skip calibration, we have not configured yet"
exit 0
fi
log "Calibrating with FLOAT_CPUS: ${FLOAT_CPUS}"
taskset --pid --cpu-list ${FLOAT_CPUS} $$ &> /dev/null
dir=$(mktemp -d)
advance=1500
latency=1000000
for i in $(seq 1500 500 7000); do
log "test advance ${i}"
echo $i > $ADVANCE_FILE
timeout --foreground --signal TERM 10s \
chrt -f 1 stdbuf -oL ${QEMU} -enable-kvm -device pc-testdev \
-device isa-debug-exit,iobase=0xf4,iosize=0x4 \
-display none -serial stdio -device pci-testdev \
-kernel /usr/share/qemu-kvm/tscdeadline_latency.flat \
-cpu host | awk 'NF==2 && /latency:/ {print $2}' > ${dir}/out0
# chomp last line since output may be incomplete
sed \$d < ${dir}/out0 > ${dir}/out
# Calculate the average of all the latency numbers output by
# the test image.
A=0
while read l; do
A=$(($A + $l))
done < $dir/out
lines=$(wc -l $dir/out | cut -f 1 -d " ")
if [ ${lines} -eq 0 ]; then
# this shouldn't happen
log "got no output from test, aborting"
break
fi
ans=$(($A/$lines))
# Get the current latency as a percentage of the previous latency
value=$((${ans}*100/${latency}))
if [ $value -ge 102 ]; then
# Latency has increased by too much, we don't want to use this
# much advance. I didn't see this in practice, this is just
# a sanity check.
advance=$((${i} - 500))
log "latency too large, reverting to advance of ${advance}"
echo $advance > $ADVANCE_FILE
break
elif [ $value -ge 98 ]; then
# If we're close to the previous latency, then use the current
# advance. The algorithm has a tendency to underestimate a bit,
# so we don't want to use the previous advance value.
break
else
# We're substantially lower than the previous latency, so store
# the current advance and latency numbers and loop through again
# to see if it improves further with a bit higher advance.
latency=$ans
advance=$i
fi
done
# Save calibrated result
cat $ADVANCE_FILE > $ADVANCE_CALIB
log "using advance value of" $(cat $ADVANCE_FILE)
rm -rf $dir
exit 0