| #!/bin/sh -e | |
| # SPDX-License-Identifier: GPL-2.0-only | |
| # hyp-trace-test - Tracefs for pKVM hypervisor test | |
| # | |
| # Copyright (C) 2024 - Google LLC | |
| # Author: Vincent Donnefort <vdonnefort@google.com> | |
| # | |
| log_and_die() | |
| { | |
| echo "$1" | |
| exit 1 | |
| } | |
| host_clock() | |
| { | |
| # BOOTTIME clock | |
| awk '/now/ { printf "%.6f\n", $3 / 1000000000 }' /proc/timer_list | |
| } | |
| page_size() | |
| { | |
| echo "$(awk '/KernelPageSize/ {print $2; exit}' /proc/self/smaps) * 1024" | bc | |
| } | |
| goto_hyp_trace() | |
| { | |
| if [ -d "/sys/kernel/debug/tracing/hypervisor" ]; then | |
| cd /sys/kernel/debug/tracing/hypervisor | |
| return | |
| fi | |
| if [ -d "/sys/kernel/tracing/hypervisor" ]; then | |
| cd /sys/kernel/tracing/hypervisor | |
| return | |
| fi | |
| echo "ERROR: hyp tracing folder not found!" | |
| exit 1 | |
| } | |
| reset_hyp_trace() | |
| { | |
| echo 0 > tracing_on | |
| echo 0 > trace | |
| for event in events/hypervisor/*; do | |
| echo 0 > $event/enable | |
| done | |
| } | |
| setup_hyp_trace() | |
| { | |
| reset_hyp_trace | |
| echo 16 > buffer_size_kb | |
| echo 1 > events/hypervisor/selftest/enable | |
| echo 1 > tracing_on | |
| } | |
| stop_hyp_trace() | |
| { | |
| echo 0 > tracing_on | |
| } | |
| hyp_trace_loaded() | |
| { | |
| grep -q "(loaded)" buffer_size_kb | |
| } | |
| write_events() | |
| { | |
| local num="$1" | |
| local func="$2" | |
| for i in $(seq 1 $num); do | |
| echo 1 > selftest_event | |
| [ -z "$func" -o $i -eq $num ] || eval $func | |
| done | |
| } | |
| consuming_read() | |
| { | |
| local output=$1 | |
| cat trace_pipe > $output & | |
| echo $! | |
| } | |
| run_test_consuming() | |
| { | |
| local nr_events=$1 | |
| local func=$2 | |
| local tmp="$(mktemp)" | |
| local start_ts=0 | |
| local end_ts=0 | |
| local pid=0 | |
| echo "Output trace file: $tmp" | |
| setup_hyp_trace | |
| pid=$(consuming_read $tmp) | |
| start_ts=$(host_clock) | |
| write_events $nr_events $func | |
| stop_hyp_trace | |
| end_ts=$(host_clock) | |
| kill $pid | |
| validate_test $tmp $nr_events $start_ts $end_ts | |
| rm $tmp | |
| } | |
| validate_test() | |
| { | |
| local output=$1 | |
| local expected_events=$2 | |
| local start_ts=$3 | |
| local end_ts=$4 | |
| local prev_ts=$3 | |
| local ts=0 | |
| local num_events=0 | |
| IFS=$'\n' | |
| for line in $(cat $output); do | |
| echo "$line" | grep -q -E "^# " && continue | |
| ts=$(echo "$line" | awk '{print $2}' | cut -d ':' -f1) | |
| if [ $(echo "$ts<$prev_ts" | bc) -eq 1 ]; then | |
| log_and_die "Error event @$ts < $prev_ts" | |
| fi | |
| prev_ts=$ts | |
| num_events=$((num_events + 1)) | |
| done | |
| if [ $(echo "$ts>$end_ts" | bc) -eq 1 ]; then | |
| log_and_die "Error event @$ts > $end_ts" | |
| fi | |
| if [ $num_events -ne $expected_events ]; then | |
| log_and_die "Expected $expected_events events, got $num_events" | |
| fi | |
| } | |
| test_ts() | |
| { | |
| echo "Test Timestamps..." | |
| run_test_consuming 1000 | |
| echo "done." | |
| } | |
| test_extended_ts() | |
| { | |
| echo "Test Extended Timestamps..." | |
| run_test_consuming 1000 "sleep 0.1" | |
| echo "done." | |
| } | |
| assert_loaded() | |
| { | |
| hyp_trace_loaded || log_and_die "Expected loaded buffer" | |
| } | |
| assert_unloaded() | |
| { | |
| ! hyp_trace_loaded || log_and_die "Expected unloaded buffer" | |
| } | |
| test_unloading() | |
| { | |
| local tmp="$(mktemp)" | |
| echo "Test unloading..." | |
| setup_hyp_trace | |
| assert_loaded | |
| echo 0 > tracing_on | |
| assert_unloaded | |
| pid=$(consuming_read $tmp) | |
| sleep 1 | |
| assert_loaded | |
| kill $pid | |
| assert_unloaded | |
| echo 1 > tracing_on | |
| write_events 1 | |
| echo 0 > trace | |
| assert_loaded | |
| echo 0 > tracing_on | |
| assert_unloaded | |
| echo "done." | |
| } | |
| test_reset() | |
| { | |
| local tmp="$(mktemp)" | |
| echo "Test Reset..." | |
| setup_hyp_trace | |
| write_events 5 | |
| echo 0 > trace | |
| write_events 5 | |
| pid=$(consuming_read $tmp) | |
| sleep 1 | |
| stop_hyp_trace | |
| kill $pid | |
| validate_test $tmp 5 0 $(host_clock) | |
| rm $tmp | |
| echo "done." | |
| } | |
| test_big_bpacking() | |
| { | |
| local hyp_buffer_page_size=48 | |
| local page_size=$(page_size) | |
| local min_buf_size=$(echo "$page_size * $page_size / ($hyp_buffer_page_size * $(nproc))" | bc) | |
| min_buf_size=$(echo "$min_buf_size * 2 / 1024" | bc) | |
| echo "Test loading $min_buf_size kB buffer..." | |
| reset_hyp_trace | |
| echo $min_buf_size > buffer_size_kb | |
| echo 1 > tracing_on | |
| stop_hyp_trace | |
| echo "done." | |
| } | |
| goto_hyp_trace | |
| test_reset | |
| test_unloading | |
| test_big_bpacking | |
| test_ts | |
| test_extended_ts | |
| exit 0 |