| 1 | |
| 2 | |
| 3 | |
| 4 |
|
| 5 | set -e
|
| 6 |
|
| 7 | err=0
|
| 8 | perfdata=$(mktemp /tmp/__perf_kvm_test.perf.data.XXXXX)
|
| 9 | qemu_pid_file=$(mktemp /tmp/__perf_kvm_test.qemu.pid.XXXXX)
|
| 10 | log_file=$(mktemp /tmp/__perf_kvm_test.live_log.XXXXX)
|
| 11 |
|
| 12 | cleanup() {
|
| 13 | rm -f "${perfdata}" "${log_file}"
|
| 14 | if [ -f "${qemu_pid_file}" ]; then
|
| 15 | if [ -s "${qemu_pid_file}" ]; then
|
| 16 | qemu_pid=$(cat "${qemu_pid_file}")
|
| 17 | if [ -n "${qemu_pid}" ]; then
|
| 18 | kill "${qemu_pid}" 2>/dev/null || true
|
| 19 | fi
|
| 20 | fi
|
| 21 | rm -f "${qemu_pid_file}"
|
| 22 | fi
|
| 23 | trap - EXIT TERM INT
|
| 24 | }
|
| 25 |
|
| 26 | trap_cleanup() {
|
| 27 | echo "Unexpected signal in ${FUNCNAME[1]}"
|
| 28 | cleanup
|
| 29 | exit 1
|
| 30 | }
|
| 31 | trap trap_cleanup EXIT TERM INT
|
| 32 |
|
| 33 | skip() {
|
| 34 | echo "Skip: $1"
|
| 35 | cleanup
|
| 36 | exit 2
|
| 37 | }
|
| 38 |
|
| 39 | test_kvm_stat() {
|
| 40 | echo "Testing perf kvm stat"
|
| 41 |
|
| 42 | local duration
|
| 43 | local success=false
|
| 44 | for duration in 1 2 4 8; do
|
| 45 | echo "Recording kvm events for pid ${qemu_pid} (duration ${duration}s)..."
|
| 46 | rm -f "${perfdata}" "${perfdata}".old
|
| 47 | if ! perf kvm stat record -p "${qemu_pid}" -o "${perfdata}" \
|
| 48 | sleep ${duration} >/dev/null 2>&1; then
|
| 49 | echo "perf kvm stat record failed, retrying..."
|
| 50 | continue
|
| 51 | fi
|
| 52 |
|
| 53 | if [ -e "${perfdata}" ] && \
|
| 54 | perf kvm -i "${perfdata}" stat report 2>&1 | grep -q "VM-EXIT"; then
|
| 55 | success=true
|
| 56 | break
|
| 57 | fi
|
| 58 | echo "No VM-EXIT events found, retrying..."
|
| 59 | done
|
| 60 |
|
| 61 | if [ "$success" = false ]; then
|
| 62 | echo "Failed to find VM-EXIT in report"
|
| 63 | perf kvm -i "${perfdata}" stat report 2>&1 || true
|
| 64 | err=1
|
| 65 | return
|
| 66 | fi
|
| 67 |
|
| 68 | echo "perf kvm stat test [Success]"
|
| 69 | }
|
| 70 |
|
| 71 | test_kvm_record_report() {
|
| 72 | echo "Testing perf kvm record/report"
|
| 73 |
|
| 74 | local duration
|
| 75 | local success=false
|
| 76 | for duration in 1 2 4 8; do
|
| 77 | echo "Recording kvm profile for pid ${qemu_pid} (duration ${duration}s)..."
|
| 78 | rm -f "${perfdata}" "${perfdata}".old
|
| 79 |
|
| 80 | perf kvm --host record -p "${qemu_pid}" -o "${perfdata}" \
|
| 81 | -e cpu-clock sleep ${duration}
|
| 82 |
|
| 83 | if [ -e "${perfdata}" ] && \
|
| 84 | perf kvm -i "${perfdata}" report --stdio 2>&1 | grep -q "Event count"; then
|
| 85 | success=true
|
| 86 | break
|
| 87 | fi
|
| 88 | echo "No samples or report failed, retrying..."
|
| 89 | done
|
| 90 |
|
| 91 | if [ "$success" = false ]; then
|
| 92 | echo "Failed to report kvm profile"
|
| 93 | perf kvm -i "${perfdata}" report --stdio 2>&1 || true
|
| 94 | err=1
|
| 95 | return
|
| 96 | fi
|
| 97 |
|
| 98 | echo "perf kvm record/report test [Success]"
|
| 99 | }
|
| 100 |
|
| 101 | test_kvm_buildid_list() {
|
| 102 | echo "Testing perf kvm buildid-list"
|
| 103 |
|
| 104 | |
| 105 | if ! perf kvm --host -i "${perfdata}" buildid-list 2>&1 | grep -q "."; then
|
| 106 | echo "Failed to list buildids"
|
| 107 | perf kvm --host -i "${perfdata}" buildid-list 2>&1
|
| 108 | err=1
|
| 109 | return
|
| 110 | fi
|
| 111 |
|
| 112 | echo "perf kvm buildid-list test [Success]"
|
| 113 | }
|
| 114 |
|
| 115 | test_kvm_stat_live() {
|
| 116 | echo "Testing perf kvm stat live"
|
| 117 |
|
| 118 | |
| 119 | |
| 120 | if ! sleep 10 | timeout 5s perf kvm stat live -p "${qemu_pid}" > "${log_file}" 2>&1; then
|
| 121 | retval=$?
|
| 122 | if [ $retval -ne 124 ] && [ $retval -ne 0 ]; then
|
| 123 | echo "perf kvm stat live [Failed: perf kvm stat live failed to start or run (ret=$retval)]"
|
| 124 | head -n 50 "${log_file}"
|
| 125 | err=1
|
| 126 | return
|
| 127 | fi
|
| 128 | fi
|
| 129 |
|
| 130 | |
| 131 | if ! grep -E -q "[0-9]+\.[0-9]+%" "${log_file}"; then
|
| 132 | echo "perf kvm stat live [Failed: no sample percentage found]"
|
| 133 | head -n 50 "${log_file}"
|
| 134 | err=1
|
| 135 | return
|
| 136 | fi
|
| 137 |
|
| 138 | echo "perf kvm stat live test [Success]"
|
| 139 | }
|
| 140 |
|
| 141 | test_kvm_default_event() {
|
| 142 | echo "Testing perf kvm record default event with command line"
|
| 143 |
|
| 144 | |
| 145 | perf kvm record -p "${qemu_pid}" -o /dev/null sleep 1
|
| 146 |
|
| 147 | echo "perf kvm record default event [Success]"
|
| 148 | }
|
| 149 |
|
| 150 | setup_qemu() {
|
| 151 | |
| 152 | if [ "$(uname -m)" = "x86_64" ]; then
|
| 153 | qemu="qemu-system-x86_64"
|
| 154 | elif [ "$(uname -m)" = "aarch64" ]; then
|
| 155 | qemu="qemu-system-aarch64"
|
| 156 | elif [ "$(uname -m)" = "s390x" ]; then
|
| 157 | qemu="qemu-system-s390x"
|
| 158 | elif [ "$(uname -m)" = "ppc64le" ]; then
|
| 159 | qemu="qemu-system-ppc64"
|
| 160 | else
|
| 161 | qemu="qemu-system-$(uname -m)"
|
| 162 | fi
|
| 163 |
|
| 164 | if ! which -s "$qemu"; then
|
| 165 | skip "$qemu not found"
|
| 166 | fi
|
| 167 |
|
| 168 | if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then
|
| 169 | skip "/dev/kvm not accessible"
|
| 170 | fi
|
| 171 |
|
| 172 | if ! perf kvm stat record -o /dev/null -a sleep 0.01 >/dev/null 2>&1; then
|
| 173 | skip "No permission to record kvm events"
|
| 174 | fi
|
| 175 |
|
| 176 | echo "Starting $qemu..."
|
| 177 | |
| 178 | |
| 179 | |
| 180 | if ! $qemu -enable-kvm -display none -daemonize -pidfile "${qemu_pid_file}" -monitor none; then
|
| 181 | echo "Failed to start qemu"
|
| 182 | err=1
|
| 183 | return
|
| 184 | fi
|
| 185 |
|
| 186 | |
| 187 | sleep 1
|
| 188 | qemu_pid=$(cat "${qemu_pid_file}")
|
| 189 |
|
| 190 | if ! kill -0 "${qemu_pid}" 2>/dev/null; then
|
| 191 | echo "Qemu process failed to stay alive"
|
| 192 | err=1
|
| 193 | return
|
| 194 | fi
|
| 195 | }
|
| 196 |
|
| 197 | setup_qemu
|
| 198 | if [ $err -eq 0 ]; then
|
| 199 | test_kvm_stat
|
| 200 | test_kvm_record_report
|
| 201 | test_kvm_buildid_list
|
| 202 | test_kvm_stat_live
|
| 203 | test_kvm_default_event
|
| 204 | fi
|
| 205 |
|
| 206 | cleanup
|
| 207 | exit $err
|