From 7aa334838b7942bfca358bf42671964f861517a5 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Fri, 26 Dec 2025 16:09:59 +0530 Subject: [PATCH 1/6] perf(lib_performance): add sysbench helper APIs Add sysbench parsers for time_sec and mem_mbps metrics. Add values helpers (append/avg) for iteration aggregation. Add fifo-based tee runner and CSV append helper for KPIs. Signed-off-by: Srikanth Muppandam --- Runner/utils/lib_performance.sh | 1281 +++++++++++++++++++++++++++++++ 1 file changed, 1281 insertions(+) diff --git a/Runner/utils/lib_performance.sh b/Runner/utils/lib_performance.sh index 8c975bf8..17158393 100755 --- a/Runner/utils/lib_performance.sh +++ b/Runner/utils/lib_performance.sh @@ -864,3 +864,1284 @@ perf_kpi_check_previous_reboot() { perf_kpi_reboot_state_save "$state_file" "$PERF_KPI_BOOT_ID" "$PERF_KPI_UPTIME_SEC" "0" "$PERF_KPI_STATE_ITER_DONE" } + +# --------------------------------------------------------------------------- +# Small math / parsing helpers (POSIX) +# --------------------------------------------------------------------------- +perf_is_number() { + printf '%s\n' "$1" | awk ' + BEGIN{ok=0} + /^[0-9]+(\.[0-9]+)?$/ {ok=1} + END{exit(ok?0:1)}' +} + +perf_avg_file() { + f=$1 + [ -s "$f" ] || { echo ""; return 0; } + + awk ' + /^[0-9]+(\.[0-9]+)?$/ {sum+=$1; n++} + END { if (n>0) printf("%.3f\n", sum/n); else print "" } + ' "$f" +} + +perf_pct_change_lower_better() { + cur=$1 + base=$2 + if ! perf_is_number "$cur" || ! perf_is_number "$base"; then + echo "" + return 0 + fi + awk -v c="$cur" -v b="$base" ' + BEGIN{ + if (b<=0) { print ""; exit } + p=((c-b)/b)*100.0 + printf("%.2f\n", p) + }' +} + +perf_pct_change_higher_better() { + cur=$1 + base=$2 + if ! perf_is_number "$cur" || ! perf_is_number "$base"; then + echo "" + return 0 + fi + awk -v c="$cur" -v b="$base" ' + BEGIN{ + if (b<=0) { print ""; exit } + p=((b-c)/b)*100.0 + printf("%.2f\n", p) + }' +} + +perf_metric_check() { + name=$1 + cur=$2 + base=$3 + direction=$4 + delta=$5 + + if [ -z "$base" ]; then + log_warn "$name: baseline missing → skipping compare (current=$cur)" + return 2 + fi + + if ! perf_is_number "$cur" || ! perf_is_number "$base"; then + log_warn "$name: non-numeric compare (current=$cur baseline=$base) → skipping" + return 2 + fi + + allowed_pct=$(printf '%s\n' "$delta" | awk '{printf("%.2f\n",$1*100.0)}') + + case "$direction" in + lower) pct=$(perf_pct_change_lower_better "$cur" "$base") ;; + higher) pct=$(perf_pct_change_higher_better "$cur" "$base") ;; + *) + log_warn "$name: unknown direction '$direction' → skipping" + return 2 + ;; + esac + + if [ -z "$pct" ]; then + log_warn "$name: could not compute delta (current=$cur baseline=$base) → skipping" + return 2 + fi + + pass=$(awk -v p="$pct" -v a="$allowed_pct" 'BEGIN{ if (p <= a) print 1; else print 0 }') + if [ "$pass" = "1" ]; then + log_info "$name: PASS current=$cur baseline=$base regression=${pct}% (allowed<=${allowed_pct}%)" + return 0 + fi + + log_error "$name: FAIL current=$cur baseline=$base regression=${pct}% (allowed<=${allowed_pct}%)" + return 1 +} + +perf_baseline_get() { + key=$1 + file=$2 + [ -f "$file" ] || { echo ""; return 0; } + + awk -v k="$key" ' + { + line=$0 + sub(/^[ \t]*/, "", line) + + # exact prefix match on key (string compare, not regex) + kl = length(k) + if (substr(line, 1, kl) != k) next + + rest = substr(line, kl + 1) + + # allow optional spaces then ":" or "=" then optional spaces + if (rest ~ /^[ \t]*[=:][ \t]*/) { + sub(/^[ \t]*[=:][ \t]*/, "", rest) + sub(/\r$/, "", rest) + print rest + exit + } + } + ' "$file" 2>/dev/null +} + +# --------------------------------------------------------------------------- +# Sysbench helpers (run + parse + average + optional CSV) +# --------------------------------------------------------------------------- + +# Run a command and stream output to console while also writing to a logfile. +# POSIX-safe: uses mkfifo + tee to preserve command exit code. +# Usage: perf_run_cmd_tee /path/to/log -- cmd args... +perf_run_cmd_tee() { + log_file=$1 + shift + + [ -n "$log_file" ] || return 1 + + dir=$(dirname "$log_file") + mkdir -p "$dir" 2>/dev/null || true + + fifo="${log_file}.fifo.$$" + rm -f "$fifo" 2>/dev/null || true + + if ! mkfifo "$fifo" 2>/dev/null; then + # Fallback: no fifo support → just log (no live console) + "$@" >"$log_file" 2>&1 + return $? + fi + + # Start tee first (reader) + tee "$log_file" <"$fifo" & + tee_pid=$! + + # Run command, write both stdout+stderr into FIFO (writer) + "$@" >"$fifo" 2>&1 + rc=$? + + # Give tee a short window to drain+exit; then kill if still alive (avoid hangs) + i=0 + while kill -0 "$tee_pid" 2>/dev/null; do + i=$((i + 1)) + [ "$i" -ge 5 ] && break + sleep 1 + done + + if kill -0 "$tee_pid" 2>/dev/null; then + # tee is still alive unexpectedly → terminate and move on + kill "$tee_pid" 2>/dev/null || true + wait "$tee_pid" 2>/dev/null || true + else + wait "$tee_pid" 2>/dev/null || true + fi + + rm -f "$fifo" 2>/dev/null || true + return $rc +} + +# Parse total time (sec) from sysbench 1.0+ output. +# Supports both: +# "total time: 30.0009s" +# "total time taken by event execution: 29.9943s" +perf_sysbench_parse_time_sec() { + log_file=$1 + [ -f "$log_file" ] || { echo ""; return 0; } + + v=$( + sed -n \ + -e 's/^[[:space:]]*total time taken by event execution:[[:space:]]*\([0-9.][0-9.]*\)s.*/\1/p' \ + -e 's/^[[:space:]]*total time:[[:space:]]*\([0-9.][0-9.]*\)s.*/\1/p' \ + "$log_file" 2>/dev/null | head -n 1 + ) + printf '%s' "$v" +} + +# Parse memory throughput (MB/sec) from sysbench memory output: +# "... transferred (2486.38 MB/sec)" +# Also tolerates MiB/sec +perf_sysbench_parse_mem_mbps() { + log_file=$1 + [ -f "$log_file" ] || { echo ""; return 0; } + + v=$( + sed -n \ + -e 's/.*(\([0-9.][0-9.]*\)[[:space:]]*MB\/sec).*/\1/p' \ + -e 's/.*(\([0-9.][0-9.]*\)[[:space:]]*MiB\/sec).*/\1/p' \ + -e 's/.*(\([0-9.][0-9.]*\)[[:space:]]*MB\/s).*/\1/p' \ + -e 's/.*(\([0-9.][0-9.]*\)[[:space:]]*MiB\/s).*/\1/p' \ + "$log_file" 2>/dev/null | head -n 1 + ) + printf '%s' "$v" +} + +# Append a numeric value to a values file (one per line). +perf_values_append() { + values_file=$1 + val=$2 + [ -n "$values_file" ] || return 0 + [ -n "$val" ] || return 0 + printf '%s\n' "$val" >>"$values_file" 2>/dev/null || true +} + +# Compute average from values file. Prints avg or empty. +perf_values_avg() { + values_file=$1 + [ -s "$values_file" ] || { echo ""; return 0; } + + awk ' + $1 ~ /^[0-9.]+$/ { s += $1; n++ } + END { if (n > 0) printf("%.3f\n", s/n); } + ' "$values_file" 2>/dev/null +} + +# Optional CSV append (only if CSV_FILE is non-empty). +# CSV format: +# timestamp,test,threads,metric,iteration,value +perf_sysbench_csv_append() { + csv=$1 + test=$2 + threads=$3 + metric=$4 + iteration=$5 + value=$6 + status=${7:-} + baseline=${8:-} + goal=${9:-} + op=${10:-} + score_pct=${11:-} + delta=${12:-} + + [ -n "$csv" ] || return 0 + [ -n "$value" ] || return 0 + + dir=$(dirname "$csv") + mkdir -p "$dir" 2>/dev/null || true + + if [ ! -f "$csv" ] || [ ! -s "$csv" ]; then + # Backward-compatible: old columns first, new columns appended. + echo "timestamp,test,threads,metric,iteration,value,status,baseline,goal,op,score_pct,delta" >"$csv" + fi + + if command -v nowstamp >/dev/null 2>&1; then + ts=$(nowstamp) + else + ts=$(date "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "unknown") + fi + + # Always write all columns; empty fields are OK. + echo "$ts,$test,$threads,$metric,$iteration,$value,$status,$baseline,$goal,$op,$score_pct,$delta" >>"$csv" 2>/dev/null || true +} + +# --------------------------------------------------------------------------- +# Sysbench helpers +# --------------------------------------------------------------------------- +# Helper: extract "key=value" from a single line of space-separated kv tokens. +kv_get() { + line=$1 + key=$2 + printf "%s\n" "$line" | awk -v k="$key" ' + { + for (i=1; i<=NF; i++) { + split($i, a, "=") + if (a[1] == k) { print a[2]; exit } + } + }' +} + +# helper: extract key=value tokens from perf_sysbench_gate_eval_line output (no function def) +kv() { + line=$1 + key=$2 + + printf "%s\n" "$line" | awk -v k="$key" ' + { + for (i = 1; i <= NF; i++) { + split($i, a, "=") + if (a[1] == k) { + print a[2] + exit + } + } + }' +} + +run_sysbench_case() { + label=$1 + out_log=$2 + shift 2 + + log_info "Running $label → $out_log" + log_info "CMD: $*" + + if command -v perf_run_cmd_tee >/dev/null 2>&1; then + perf_run_cmd_tee "$out_log" "$@" + return $? + fi + + # fallback + "$@" >"$out_log" 2>&1 + cat "$out_log" + return $? +} + +# Convert MiB/s -> MB/s (MB = MiB * 1.048576) to match baseline units +sysbench_mib_to_mb() { + v=$1 + [ -z "$v" ] && { echo ""; return 0; } + + if command -v perf_f_mul >/dev/null 2>&1; then + perf_f_mul "$v" "1.048576" + else + awk -v x="$v" 'BEGIN{printf "%.6f", x*1.048576}' + fi +} + +perf_sysbench_extract_total_time_sec() { + f=$1 + [ -f "$f" ] || { echo ""; return 0; } + + v=$(grep -E 'total time taken by event execution:' "$f" 2>/dev/null \ + | head -n 1 | sed 's/.*: *//; s/[[:space:]]*s.*$//') + if [ -z "$v" ]; then + v=$(grep -E '^total time:' "$f" 2>/dev/null \ + | head -n 1 | sed 's/.*: *//; s/[[:space:]]*s.*$//') + fi + + v=$(printf '%s\n' "$v" | awk '{print $1}') + if perf_is_number "$v"; then + printf '%.3f\n' "$v" 2>/dev/null || printf '%s\n' "$v" + else + echo "" + fi +} + +perf_sysbench_extract_memory_mbps() { + f=$1 + [ -f "$f" ] || { echo ""; return 0; } + + line=$(grep -E 'transferred.*\([0-9.]+[[:space:]]*(MiB|MB)/(sec|s)\)' "$f" 2>/dev/null | head -n 1) + if [ -z "$line" ]; then + line=$(grep -E '\([0-9.]+[[:space:]]*(MiB|MB)/(sec|s)\)' "$f" 2>/dev/null | head -n 1) + fi + [ -n "$line" ] || { echo ""; return 0; } + + v=$(printf '%s\n' "$line" \ + | sed -n 's/.*(\([0-9.][0-9.]*\)[[:space:]]*\(MiB\|MB\)\/\(sec\|s\)).*/\1/p' \ + | head -n 1) + + if perf_is_number "$v"; then + printf '%.3f\n' "$v" 2>/dev/null || printf '%s\n' "$v" + else + echo "" + fi +} + +perf_sysbench_cmd_prefix() { + core_list=$1 + if [ -n "$core_list" ]; then + printf 'taskset -c %s' "$core_list" + return 0 + fi + echo "" +} + +perf_sysbench_run_to_log() { + prefix=$1 + out_log=$2 + shift 2 + + : >"$out_log" 2>/dev/null || true + + if [ -n "$prefix" ]; then + # Intentionally word-split prefix (taskset -c ...) + # shellcheck disable=SC2086 + set -- $prefix sysbench "$@" run + "$@" >"$out_log" 2>&1 + return $? + fi + + sysbench "$@" run >"$out_log" 2>&1 +} + +perf_sysbench_values_file() { + outdir=$1 + tag=$2 + printf '%s/%s.values' "$outdir" "$tag" +} + +perf_sysbench_print_iterations() { + label=$1 + values_file=$2 + + if [ ! -s "$values_file" ]; then + log_warn "$label: no iteration values recorded" + return 0 + fi + + i=1 + while IFS= read -r v; do + [ -n "$v" ] || continue + log_info "$label: iteration $i = $v" + i=$((i + 1)) + done <"$values_file" +} + +perf_sysbench_run_n_and_avg_time() { + name=$1 + outdir=$2 + tag=$3 + iterations=$4 + prefix=$5 + shift 5 + + values_file=$(perf_sysbench_values_file "$outdir" "$tag") + : >"$values_file" 2>/dev/null || true + + i=1 + while [ "$i" -le "$iterations" ]; do + log_file="$outdir/${tag}_iter${i}.log" + log_info "Running $name (iteration $i/$iterations) → $log_file" + + perf_sysbench_run_to_log "$prefix" "$log_file" "$@" + rc=$? + if [ "$rc" -ne 0 ]; then + log_warn "$name: sysbench exited rc=$rc (continuing; will evaluate parsed metrics)" + fi + + t=$(perf_sysbench_extract_total_time_sec "$log_file") + if [ -n "$t" ]; then + echo "$t" >>"$values_file" 2>/dev/null || true + log_info "$name: iteration $i time_sec=$t" + else + log_warn "$name: iteration $i could not parse time from $log_file" + fi + + i=$((i + 1)) + done + + perf_avg_file "$values_file" +} + +perf_sysbench_run_n_and_avg_mem_mbps() { + name=$1 + outdir=$2 + tag=$3 + iterations=$4 + prefix=$5 + shift 5 + + values_file=$(perf_sysbench_values_file "$outdir" "$tag") + : >"$values_file" 2>/dev/null || true + + i=1 + while [ "$i" -le "$iterations" ]; do + log_file="$outdir/${tag}_iter${i}.log" + log_info "Running $name (iteration $i/$iterations) → $log_file" + + perf_sysbench_run_to_log "$prefix" "$log_file" "$@" + rc=$? + if [ "$rc" -ne 0 ]; then + log_warn "$name: sysbench exited rc=$rc (continuing; will evaluate parsed metrics)" + fi + + mbps=$(perf_sysbench_extract_memory_mbps "$log_file") + if [ -n "$mbps" ]; then + echo "$mbps" >>"$values_file" 2>/dev/null || true + log_info "$name: iteration $i mem_mbps=$mbps" + else + log_warn "$name: iteration $i could not parse mem MB/s from $log_file" + fi + + i=$((i + 1)) + done + + perf_avg_file "$values_file" +} + +# --------------------------------------------------------------------------- +# Optional CSV helpers (per-iteration + average) +# --------------------------------------------------------------------------- + +perf_csv_init() { + csv=$1 + [ -n "$csv" ] || return 0 + + if [ ! -f "$csv" ]; then + echo "timestamp,test,metric,unit,threads,iteration,value,core_list,seed,time_sec,extra" >"$csv" + log_info "CSV created → $csv" + log_info "CSV header: timestamp,test,metric,unit,threads,iteration,value,core_list,seed,time_sec,extra" + fi +} + +perf_csv_append_line() { + csv=$1 + line=$2 + [ -n "$csv" ] || return 0 + [ -n "$line" ] || return 0 + + echo "$line" >>"$csv" 2>/dev/null || true + log_info "CSV: $line" +} + +perf_sysbench_csv_append_values_and_avg() { + csv=$1 + test=$2 + metric=$3 + unit=$4 + threads=$5 + values_file=$6 + avg=$7 + core_list=$8 + seed=$9 + time_sec=${10} + extra=${11} + + [ -n "$csv" ] || return 0 + + perf_csv_init "$csv" + ts=$(nowstamp) + + if [ -s "$values_file" ]; then + i=1 + while IFS= read -r v; do + [ -n "$v" ] || continue + line="$ts,$test,$metric,$unit,$threads,$i,$v,${core_list:-},${seed:-},${time_sec:-},\"$(esc "${extra:-}")\"" + perf_csv_append_line "$csv" "$line" + i=$((i + 1)) + done <"$values_file" + else + line="$ts,$test,$metric,$unit,$threads,1,,${core_list:-},${seed:-},${time_sec:-},\"$(esc "${extra:-}")\"" + perf_csv_append_line "$csv" "$line" + fi + + if [ -n "$avg" ]; then + line="$ts,$test,$metric,$unit,$threads,avg,$avg,${core_list:-},${seed:-},${time_sec:-},\"$(esc "${extra:-}")\"" + perf_csv_append_line "$csv" "$line" + else + line="$ts,$test,$metric,$unit,$threads,avg,,${core_list:-},${seed:-},${time_sec:-},\"$(esc "${extra:-}")\"" + perf_csv_append_line "$csv" "$line" + fi +} + +# --------------------------------------------------------------------------- +# Final summary writer +# --------------------------------------------------------------------------- + +perf_sysbench_write_final_summary() { + summary_file=$1 + outdir=$2 + iterations=$3 + core_list=$4 + delta=$5 + cpu_tag=$6 + mem_tag=$7 + thr_tag=$8 + mtx_tag=$9 + cpu_avg=${10} + mem_avg=${11} + thr_avg=${12} + mtx_avg=${13} + + cpu_vals=$(perf_sysbench_values_file "$outdir" "$cpu_tag") + mem_vals=$(perf_sysbench_values_file "$outdir" "$mem_tag") + thr_vals=$(perf_sysbench_values_file "$outdir" "$thr_tag") + mtx_vals=$(perf_sysbench_values_file "$outdir" "$mtx_tag") + + { + echo "Sysbench Summary" + echo " timestamp : $(nowstamp)" + echo " iterations : $iterations" + echo " core_list : ${core_list:-none}" + echo " delta_allowed : $delta" + echo "" + echo "CPU (time_sec, lower better)" + if [ -s "$cpu_vals" ]; then + i=1 + while IFS= read -r v; do + [ -n "$v" ] || continue + echo " iteration_$i : $v" + i=$((i + 1)) + done <"$cpu_vals" + else + echo " iteration_1 : " + fi + echo " avg : ${cpu_avg:-}" + echo "" + echo "Memory (MB/s, higher better)" + if [ -s "$mem_vals" ]; then + i=1 + while IFS= read -r v; do + [ -n "$v" ] || continue + echo " iteration_$i : $v" + i=$((i + 1)) + done <"$mem_vals" + else + echo " iteration_1 : " + fi + echo " avg : ${mem_avg:-}" + echo "" + echo "Threads (time_sec, lower better)" + if [ -s "$thr_vals" ]; then + i=1 + while IFS= read -r v; do + [ -n "$v" ] || continue + echo " iteration_$i : $v" + i=$((i + 1)) + done <"$thr_vals" + else + echo " iteration_1 : " + fi + echo " avg : ${thr_avg:-}" + echo "" + echo "Mutex (time_sec, lower better)" + if [ -s "$mtx_vals" ]; then + i=1 + while IFS= read -r v; do + [ -n "$v" ] || continue + echo " iteration_$i : $v" + i=$((i + 1)) + done <"$mtx_vals" + else + echo " iteration_1 : " + fi + echo " avg : ${mtx_avg:-}" + echo "" + echo "Logs in: $outdir" + } >"$summary_file" 2>/dev/null || true + + log_info "Final summary written → $summary_file" +} + +# ----------------------------------------------------------------------------- +# Sysbench helpers: run with live console + file logging +# ----------------------------------------------------------------------------- +perf_run_cmd_tee() { + log_file=$1 + shift + + [ -n "$log_file" ] || return 1 + + dir=$(dirname "$log_file") + mkdir -p "$dir" 2>/dev/null || true + + fifo="${log_file}.fifo.$$" + rm -f "$fifo" 2>/dev/null || true + + if ! mkfifo "$fifo" 2>/dev/null; then + # Fallback: no fifo support → just log (no live console) + "$@" >"$log_file" 2>&1 + return $? + fi + + # Tee reads from FIFO and writes to both console + log file. + tee "$log_file" <"$fifo" & + tee_pid=$! + + # Run command, write both stdout+stderr into FIFO + "$@" >"$fifo" 2>&1 + rc=$? + + # Wait for tee to finish draining FIFO + wait "$tee_pid" 2>/dev/null || true + rm -f "$fifo" 2>/dev/null || true + + return "$rc" +} + +# ----------------------------------------------------------------------------- +# Sysbench CSV append (consistent schema) +# Header: timestamp,test,threads,metric,iteration,value +# ----------------------------------------------------------------------------- +perf_sysbench_csv_append() { + csv=$1 + test=$2 + threads=$3 + metric=$4 + iteration=$5 + value=$6 + + [ -n "$csv" ] || return 0 + [ -n "$value" ] || return 0 + + dir=$(dirname "$csv") + mkdir -p "$dir" 2>/dev/null || true + + if [ ! -f "$csv" ] || [ ! -s "$csv" ]; then + echo "timestamp,test,threads,metric,iteration,value" >"$csv" + fi + + if command -v nowstamp >/dev/null 2>&1; then + ts=$(nowstamp) + else + ts=$(date "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "unknown") + fi + + echo "$ts,$test,$threads,$metric,$iteration,$value" >>"$csv" 2>/dev/null || true +} + +# ----------------------------------------------------------------------------- +# Baseline file parsing helpers +# Format: key=value (spaces around '=' allowed), '#' comments allowed. +# ----------------------------------------------------------------------------- +perf_baseline_get_value() { + f=$1 + key=$2 + + [ -n "$f" ] || return 0 + [ -f "$f" ] || return 0 + [ -n "$key" ] || return 0 + + awk -v k="$key" ' + /^[[:space:]]*#/ {next} + /^[[:space:]]*$/ {next} + { + line=$0 + sub(/^[[:space:]]+/, "", line) + sub(/[[:space:]]+$/, "", line) + pos = index(line, "=") + if (pos <= 0) next + kk = substr(line, 1, pos-1) + vv = substr(line, pos+1) + sub(/[[:space:]]+$/, "", kk) + sub(/^[[:space:]]+/, "", vv) + sub(/[[:space:]]+$/, "", vv) + if (kk == k) { print vv; exit } + } + ' "$f" 2>/dev/null +} + +# Construct the expected key used in sysbench_baseline.conf +# Example keys: +# cpu_time_sec.t4=30.001 +# memory_mem_mbps.t4=7213.250 +# threads_time_sec.t4=30.000 +# mutex_time_sec.t4=0.241 +perf_sysbench_baseline_key() { + sb_case=$1 + metric=$2 + thr=$3 + printf "%s_%s.t%s" "$sb_case" "$metric" "$thr" +} + +# ----------------------------------------------------------------------------- +# Float helpers (POSIX) using awk +# ----------------------------------------------------------------------------- +perf_f_add() { awk -v a="$1" -v b="$2" 'BEGIN{printf "%.6f", (a+0)+(b+0)}'; } +perf_f_sub() { awk -v a="$1" -v b="$2" 'BEGIN{printf "%.6f", (a+0)-(b+0)}'; } +perf_f_mul() { awk -v a="$1" -v b="$2" 'BEGIN{printf "%.6f", (a+0)*(b+0)}'; } +perf_f_div() { awk -v a="$1" -v b="$2" 'BEGIN{ if (b==0) exit 1; printf "%.6f",(a/b)}'; } +# pct = (num/den)*100, prints with 2 decimals; empty if invalid +perf_f_pct() { + num=$1 + den=$2 + awk -v n="$num" -v d="$den" 'BEGIN{ + if ((d+0) == 0) exit 1 + printf "%.2f", ((n+0)/(d+0))*100.0 + }' 2>/dev/null || true +} + +# Returns 0 if true, 1 if false +perf_f_ge() { awk -v a="$1" -v b="$2" 'BEGIN{exit !((a+0) >= (b+0))}'; } +perf_f_le() { awk -v a="$1" -v b="$2" 'BEGIN{exit !((a+0) <= (b+0))}'; } + +# Metric direction: +# - time_sec: lower is better +perf_metric_direction() { + m=$1 + + # Lower is better only for explicit time metrics + case "$m" in + *time_sec*) echo "lower"; return 0 ;; + esac + + # Everything else (mem_mbps, fileio_*_mbps, etc.) is higher-is-better + echo "higher" + return 0 +} + +# Get baseline value for a given key from key=value file. +# - Ignores blank lines and comments (# ...) +# - Accepts optional whitespace around '=' +# Prints value (or empty string if not found). +perf_sysbench_baseline_get() { + file=$1 + key=$2 + + [ -f "$file" ] || { printf '%s' ""; return 0; } + [ -n "$key" ] || { printf '%s' ""; return 0; } + + key_esc=$(perf_sed_escape_bre "$key") + + # Match "key = value" (value is first token-ish number) + v=$( + sed -n \ + -e 's/[[:space:]]*#.*$//' \ + -e '/^[[:space:]]*$/d' \ + -e "s/^[[:space:]]*${key_esc}[[:space:]]*=[[:space:]]*\\([0-9][0-9.]*\\).*$/\\1/p" \ + "$file" 2>/dev/null | head -n 1 + ) + printf '%s' "$v" +} + +# ----------------------------------------------------------------------------- +# Baseline gating evaluation +# +# Inputs: +# baseline_file, sb_case, threads, metric, avg_value, allowed_deviation +# +# Output via globals: +# PERF_GATE_STATUS = PASS|FAIL|NO_BASELINE|NO_AVG +# PERF_GATE_BASELINE = baseline numeric +# PERF_GATE_GOAL = goal numeric +# PERF_GATE_SCORE_PCT= score percent (higher is better) +# PERF_GATE_OP = ">=" or "<=" +# +# Return: +# 0 PASS +# 1 FAIL +# 2 No baseline / cannot evaluate +# ----------------------------------------------------------------------------- +perf_sysbench_gate_eval() { + file=$1 + case_name=$2 + threads=$3 + metric=$4 + value=$5 + delta=$6 + + PERF_GATE_KEY="${case_name}_${metric}.t${threads}" + PERF_GATE_OP="" + PERF_GATE_BASELINE="" + PERF_GATE_GOAL="" + PERF_GATE_SCORE_PCT="" + PERF_GATE_STATUS="SKIP" + + # Export for external consumers (run.sh) → fixes SC2034 + export PERF_GATE_KEY PERF_GATE_OP PERF_GATE_BASELINE PERF_GATE_GOAL PERF_GATE_SCORE_PCT PERF_GATE_STATUS + + [ -f "$file" ] || return 2 + [ -n "$case_name" ] || return 2 + [ -n "$threads" ] || return 2 + [ -n "$metric" ] || return 2 + [ -n "$value" ] || return 2 + [ -n "$delta" ] || delta=0 + + base=$(perf_sysbench_baseline_get "$file" "$PERF_GATE_KEY") + [ -n "$base" ] || return 2 + + PERF_GATE_BASELINE="$base" + export PERF_GATE_BASELINE + + # Decide direction: + # - Throughput (mem_mbps): higher is better + # - time_sec: lower is better + higher_is_better=0 + if [ "$metric" = "mem_mbps" ] || echo "$metric" | grep -q "mbps"; then + higher_is_better=1 + fi + + if [ "$higher_is_better" -eq 1 ]; then + PERF_GATE_OP=">=" + goal=$(awk -v b="$base" -v d="$delta" 'BEGIN{printf "%.6f", (b*(1-d))}') + PERF_GATE_GOAL="$goal" + score=$(awk -v b="$base" -v v="$value" 'BEGIN{ if (b==0) print ""; else printf "%.2f", (v/b*100) }') + PERF_GATE_SCORE_PCT="$score" + export PERF_GATE_OP PERF_GATE_GOAL PERF_GATE_SCORE_PCT + + pass=$(awk -v v="$value" -v g="$goal" 'BEGIN{print (v+0 >= g+0) ? 1 : 0}') + else + PERF_GATE_OP="<=" + goal=$(awk -v b="$base" -v d="$delta" 'BEGIN{printf "%.6f", (b*(1+d))}') + PERF_GATE_GOAL="$goal" + # score_pct: convert to "bigger is better" by using base/value + score=$(awk -v b="$base" -v v="$value" 'BEGIN{ if (v==0) print ""; else printf "%.2f", (b/v*100) }') + PERF_GATE_SCORE_PCT="$score" + export PERF_GATE_OP PERF_GATE_GOAL PERF_GATE_SCORE_PCT + + pass=$(awk -v v="$value" -v g="$goal" 'BEGIN{print (v+0 <= g+0) ? 1 : 0}') + fi + + if [ "$pass" -eq 1 ]; then + PERF_GATE_STATUS="PASS" + export PERF_GATE_STATUS + return 0 + fi + + PERF_GATE_STATUS="FAIL" + export PERF_GATE_STATUS + return 1 +} + +# ----------------------------------------------------------------------------- +# Optional sanity warning: epoch timestamps (RTC not set) +# ----------------------------------------------------------------------------- +perf_clock_sanity_warn() { + y=$(date "+%Y" 2>/dev/null || echo "") + case "$y" in + ""|*[!0-9]*) return 0 ;; + esac + if [ "$y" -lt 2000 ]; then + if command -v log_warn >/dev/null 2>&1; then + log_warn "System clock looks unset (year=$y). Timestamps in logs/CSV may be misleading." + else + echo "[WARN] System clock looks unset (year=$y). Timestamps in logs/CSV may be misleading." >&2 + fi + fi +} + +# ----------------------------------------------------------------------------- +# Gate evaluation (no globals). Prints a single machine-parsable line: +# status= baseline=<..> goal=<..> op=<>=|<=> score_pct=<..> key=<..> +# +# Return: +# 0 PASS +# 1 FAIL +# 2 cannot evaluate (no baseline or no avg) +# ----------------------------------------------------------------------------- +perf_sysbench_gate_eval_line() { + f=$1 + sb_case=$2 + thr=$3 + metric=$4 + avg=$5 + delta=$6 + + if [ -z "$avg" ]; then + echo "status=NO_AVG baseline=NA goal=NA op=NA score_pct=NA key=NA" + return 2 + fi + + key=$(perf_sysbench_baseline_key "$sb_case" "$metric" "$thr") + base=$(perf_baseline_get_value "$f" "$key") + if [ -z "$base" ]; then + echo "status=NO_BASELINE baseline=NA goal=NA op=NA score_pct=NA key=$key" + return 2 + fi + + dir=$(perf_metric_direction "$metric") + + if [ "$dir" = "higher" ]; then + one_minus=$(perf_f_sub "1.0" "$delta") + goal=$(perf_f_mul "$base" "$one_minus") + score=$(perf_f_pct "$avg" "$base") + if perf_f_ge "$avg" "$goal"; then + echo "status=PASS baseline=$base goal=$goal op=>= score_pct=${score:-NA} key=$key" + return 0 + fi + echo "status=FAIL baseline=$base goal=$goal op=>= score_pct=${score:-NA} key=$key" + return 1 + fi + + # lower-is-better + one_plus=$(perf_f_add "1.0" "$delta") + goal=$(perf_f_mul "$base" "$one_plus") + score=$(perf_f_pct "$base" "$avg") # higher is better (baseline/avg) + if perf_f_le "$avg" "$goal"; then + echo "status=PASS baseline=$base goal=$goal op=<= score_pct=${score:-NA} key=$key" + return 0 + fi + echo "status=FAIL baseline=$base goal=$goal op=<= score_pct=${score:-NA} key=$key" + return 1 +} + +# Warn when a path is on tmpfs/ramfs (fileio numbers will be meaningless for storage perf) +perf_fs_sanity_warn() { + p=$1 + [ -n "$p" ] || return 0 + + # Find fstype for the *longest matching* mountpoint in /proc/mounts + fs=$( + awk -v path="$p" ' + function is_prefix(mp, s) { + if (mp == "/") return 1 + return (index(s, mp) == 1) + } + BEGIN { best_len = -1; best_fs = "" } + { + mp = $2 + f = $3 + if (is_prefix(mp, path)) { + l = length(mp) + if (l > best_len) { best_len = l; best_fs = f } + } + } + END { print best_fs } + ' /proc/mounts 2>/dev/null + ) + + if [ "$fs" = "tmpfs" ] || [ "$fs" = "ramfs" ]; then + log_warn "FILEIO safety: FILEIO_DIR=$p is on $fs. Results will reflect RAM/tmpfs, not storage." + log_warn "FILEIO safety: choose ext4/xfs-backed path (example: /var/tmp/sysbench_fileio or under /)." + fi +} + +# Parse sysbench fileio throughput. sysbench prints: +# read, MiB/s: +# written, MiB/s: +# Some builds show MB/s; handle both. +perf_sysbench_parse_fileio_read_mibps() { + log_file=$1 + [ -f "$log_file" ] || { echo ""; return 0; } + + v=$( + sed -n \ + -e 's/^[[:space:]]*read,[[:space:]]*MiB\/s:[[:space:]]*\([0-9.][0-9.]*\).*$/\1/p' \ + -e 's/^[[:space:]]*read,[[:space:]]*MB\/s:[[:space:]]*\([0-9.][0-9.]*\).*$/\1/p' \ + "$log_file" 2>/dev/null | head -n 1 + ) + printf '%s' "$v" +} + +perf_sysbench_parse_fileio_written_mibps() { + log_file=$1 + [ -f "$log_file" ] || { echo ""; return 0; } + + v=$( + sed -n \ + -e 's/^[[:space:]]*written,[[:space:]]*MiB\/s:[[:space:]]*\([0-9.][0-9.]*\).*$/\1/p' \ + -e 's/^[[:space:]]*written,[[:space:]]*MB\/s:[[:space:]]*\([0-9.][0-9.]*\).*$/\1/p' \ + "$log_file" 2>/dev/null | head -n 1 + ) + printf '%s' "$v" +} + +perf_mibps_to_gbps() { + mibps=$1 + [ -n "$mibps" ] || { echo ""; return 0; } + awk -v v="$mibps" 'BEGIN{printf "%.4f", (v/1024.0)}' +} + +perf_sysbench_fileio_prepare() { + dir=$1 + threads=$2 + seed=$3 + total=$4 + num=$5 + blksz=$6 + iomode=$7 + extra=$8 + out_log=$9 + + [ -n "$dir" ] || return 1 + mkdir -p "$dir" 2>/dev/null || true + + ( + cd "$dir" 2>/dev/null || exit 1 + + set -- sysbench --rand-seed="$seed" --threads="$threads" fileio \ + --file-total-size="$total" \ + --file-num="$num" \ + --file-block-size="$blksz" \ + --file-io-mode="$iomode" \ + --file-test-mode=seqwr + + if [ -n "$extra" ]; then + # shellcheck disable=SC2086 + set -- "$@" $extra + fi + + set -- "$@" prepare + perf_run_cmd_tee "$out_log" "$@" + ) +} + +perf_sysbench_fileio_cleanup() { + dir=$1 + total=$2 + num=$3 + blksz=$4 + iomode=$5 + extra=$6 + + [ -n "$dir" ] || return 0 + + ( + cd "$dir" 2>/dev/null || exit 0 + + set -- sysbench fileio \ + --file-total-size="$total" \ + --file-num="$num" \ + --file-block-size="$blksz" \ + --file-io-mode="$iomode" \ + --file-test-mode=seqwr + + if [ -n "$extra" ]; then + # shellcheck disable=SC2086 + set -- "$@" $extra + fi + + set -- "$@" cleanup + "$@" >/dev/null 2>&1 || true + ) + return 0 +} + +# Runs one fileio mode and prints one line of kv tokens: +# mode=seqwr mibps=0.40 gbps=0.0004 +perf_sysbench_fileio_run_mode() { + dir=$1 + threads=$2 + seed=$3 + time=$4 + total=$5 + num=$6 + blksz=$7 + iomode=$8 + extra=$9 + mode=${10} + out_log=${11} + + [ -n "$dir" ] || { echo ""; return 1; } + + ( + cd "$dir" 2>/dev/null || exit 1 + + set -- sysbench --time="$time" --rand-seed="$seed" --threads="$threads" fileio \ + --file-total-size="$total" \ + --file-num="$num" \ + --file-block-size="$blksz" \ + --file-io-mode="$iomode" \ + --file-test-mode="$mode" + + if [ -n "$extra" ]; then + # shellcheck disable=SC2086 + set -- "$@" $extra + fi + + set -- "$@" run + perf_run_cmd_tee "$out_log" "$@" + ) || true + + case "$mode" in + seqrd) + r=$(perf_sysbench_parse_fileio_read_mibps "$out_log") + g=$(perf_mibps_to_gbps "$r") + printf 'mode=%s mibps=%s gbps=%s\n' "$mode" "${r:-}" "${g:-}" + ;; + seqwr|rndwr) + w=$(perf_sysbench_parse_fileio_written_mibps "$out_log") + printf 'mode=%s mibps=%s gbps=\n' "$mode" "${w:-}" + ;; + *) + printf 'mode=%s mibps= gbps=\n' "$mode" + ;; + esac + return 0 +} + +# Extract sysbench fileio throughput (MiB/s) for "read" or "written" +# Example lines: +# Throughput: +# read, MiB/s: 4755.69 +# written, MiB/s: 3849.61 +perf_sysbench_parse_fileio_mibps() { + log_file=$1 + which=$2 # "read" or "written" + + [ -f "$log_file" ] || { printf '%s' ""; return 0; } + [ -n "$which" ] || which="read" + + v=$( + sed -n \ + -e "s/^[[:space:]]*$which,[[:space:]]*MiB\/s:[[:space:]]*\\([0-9][0-9.]*\\).*$/\\1/p" \ + "$log_file" 2>/dev/null | head -n 1 + ) + printf '%s' "$v" +} + +# Return filesystem type of the mount backing a path (best-effort) +perf_path_fstype() { + p=$1 + [ -n "$p" ] || { echo "unknown"; return 0; } + + # Normalize path + case "$p" in + /*) : ;; + *) p="/$p" ;; + esac + + # Pick the longest mountpoint prefix match from /proc/mounts + awk -v P="$p" ' + function is_prefix(mp, path) { + if (mp == "/") return 1 + return (index(path, mp "/") == 1 || path == mp) + } + { + mp=$2; fs=$3 + if (is_prefix(mp, P)) { + if (length(mp) > bestlen) { bestlen=length(mp); bestfs=fs; bestmp=mp } + } + } + END { + if (bestfs == "") bestfs="unknown" + print bestfs + } + ' /proc/mounts 2>/dev/null +} + +perf_is_tmpfs_path() { + p=$1 + fs=$(perf_path_fstype "$p") + case "$fs" in + tmpfs|ramfs) return 0 ;; + esac + return 1 +} + +# Choose a writable directory that is NOT on tmpfs/ramfs. +# Echoes chosen dir (creates it). +perf_pick_fileio_dir() { + # Candidates (prefer real disk) + for d in \ + "/var/tmp/sysbench_fileio" \ + "/root/sysbench_fileio" \ + "/home/root/sysbench_fileio" \ + "/sysbench_fileio" + do + mkdir -p "$d" 2>/dev/null || continue + if ! perf_is_tmpfs_path "$d"; then + echo "$d" + return 0 + fi + done + + # Last resort (will be tmpfs on many systems) + d="/tmp/sysbench_fileio" + mkdir -p "$d" 2>/dev/null || true + echo "$d" + return 0 +} + +# Sysbench default threads is 1. Only pass --threads for non-1 to keep behavior consistent. +sysbench_threads_opt() { + t=$1 + if [ -n "$t" ] && [ "$t" != "1" ]; then + printf '%s' "--threads=$t" + fi +} + +# Treat placeholder baselines (__FILL_ME__) as "no baseline" (report-only, no gate fail). +perf_sysbench_gate_eval_line_safe() { + f=$1 + sb_case=$2 + thr=$3 + metric=$4 + avg=$5 + delta=$6 + + if [ -z "$avg" ]; then + echo "status=NO_AVG baseline=NA goal=NA op=NA score_pct=NA key=NA" + return 2 + fi + + if command -v perf_sysbench_baseline_key >/dev/null 2>&1 && command -v perf_baseline_get_value >/dev/null 2>&1; then + key=$(perf_sysbench_baseline_key "$sb_case" "$metric" "$thr") + base=$(perf_baseline_get_value "$f" "$key") + if [ -z "$base" ] || [ "$base" = "__FILL_ME__" ]; then + echo "status=NO_BASELINE baseline=NA goal=NA op=NA score_pct=NA key=$key" + return 2 + fi + fi + + perf_sysbench_gate_eval_line "$f" "$sb_case" "$thr" "$metric" "$avg" "$delta" + return $? +} From 56afb8598f34e7a0e6d7cae9544c3aaac7f20f0c Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Fri, 26 Dec 2025 16:12:42 +0530 Subject: [PATCH 2/6] perf(sysbench): add baseline KPI config Add baseline KPIs for CPU/Memory/Threads/Mutex averages. Document thread-key naming used by the gate evaluator. Enable PASS/FAIL comparisons using delta threshold in run.sh. Signed-off-by: Srikanth Muppandam --- .../Sysbench_Performance/sysbench_baseline.conf | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Runner/suites/Performance/Sysbench_Performance/sysbench_baseline.conf diff --git a/Runner/suites/Performance/Sysbench_Performance/sysbench_baseline.conf b/Runner/suites/Performance/Sysbench_Performance/sysbench_baseline.conf new file mode 100644 index 00000000..006105d5 --- /dev/null +++ b/Runner/suites/Performance/Sysbench_Performance/sysbench_baseline.conf @@ -0,0 +1,16 @@ +# Sysbench_Performance baseline (key=value) +# Notes: +# - time_sec: lower is better +# - mem_mbps / io_mbps: higher is better +# - Keep units consistent with parser outputs (MB/sec or MiB/sec). If you have GB/sec, convert to MB/sec. +# Threads=1 baselines +cpu_time_sec.t1=3.67 +memory_mem_mbps.t1=3980 +threads_time_sec.t1=3.64 +mutex_time_sec.t1=0.0052 + +# File I/O style KPIs (seq/rnd read/write) — store as MB/sec for gating consistency +fileio_seqwr_mbps.t1=0.4 +fileio_seqrd_mbps.t1=28.6 +fileio_rndwr_mbps.t1=0.61 +# fileio_rndrd_mbps.t1=__FILL_ME__ From 475fd2b1bf092a41ad1db955bfaa3365717c2670 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Fri, 2 Jan 2026 22:13:03 +0530 Subject: [PATCH 3/6] functestlib: expand ensure_reasonable_clock for no-network systems - Log timedatectl status/show-timesync/timesync-status outputs when epoch detected - Log systemctl status for systemd-timesyncd for debug - Try RTC restore (hwclock / rtc0 since_epoch) before falling back - Seed time from kernel build timestamp (uname -v / /proc/version) if available - Continue gracefully if clock remains invalid Signed-off-by: Srikanth Muppandam --- Runner/utils/functestlib.sh | 191 +++++++++++++++++++++++++++++++++--- 1 file changed, 177 insertions(+), 14 deletions(-) diff --git a/Runner/utils/functestlib.sh b/Runner/utils/functestlib.sh index 55feae5e..af503462 100755 --- a/Runner/utils/functestlib.sh +++ b/Runner/utils/functestlib.sh @@ -293,28 +293,191 @@ ensure_reasonable_clock() { now="$(date +%s 2>/dev/null || echo 0)" cutoff="$(date -d '2020-01-01 UTC' +%s 2>/dev/null || echo 1577836800)" [ -z "$cutoff" ] && cutoff=1577836800 + [ "$now" -ge "$cutoff" ] 2>/dev/null && return 0 - log_warn "System clock looks invalid (epoch=$now). Attempting quick time sync..." + log_warn "System clock looks invalid (epoch=$now). Trying local time sources (no network)..." + + # Optional diagnostics file (caller may set this, e.g. CLOCK_DIAG_FILE="$OUT_DIR/clock_diag.txt") + diag_file="${CLOCK_DIAG_FILE:-}" + + # ---- Diagnostics (only when invalid clock) ---- + if [ -n "$diag_file" ]; then + { + echo "==== CLOCK DIAGNOSTICS ====" + echo "timestamp=$(date '+%Y-%m-%d %H:%M:%S' 2>/dev/null || true)" + echo "epoch_now=$now cutoff=$cutoff" + echo + } >>"$diag_file" 2>/dev/null || true + fi + + # Log minimal summaries to stdout; write full outputs to diag file. + # date summary + date_out="$(date 2>&1 || true)" + if [ -n "$diag_file" ]; then + { + echo "---- date ----" + echo "$date_out" + echo + } >>"$diag_file" 2>/dev/null || true + fi + log_info "date: $(printf '%s' "$date_out" | head -n 1)" + + # timedatectl summaries + full dump if command -v timedatectl >/dev/null 2>&1; then - timedatectl set-ntp true 2>/dev/null || true + td_status="$(timedatectl status 2>&1 || true)" + if [ -n "$diag_file" ]; then + { + echo "---- timedatectl status ----" + echo "$td_status" + echo + } >>"$diag_file" 2>/dev/null || true + fi + + # minimal, stable-ish summaries + td_local="$(printf '%s\n' "$td_status" | sed -n 's/^[[:space:]]*Local time:[[:space:]]*//p' | head -n 1)" + td_sync="$(printf '%s\n' "$td_status" | sed -n 's/^[[:space:]]*System clock synchronized:[[:space:]]*//p' | head -n 1)" + td_ntp="$(printf '%s\n' "$td_status" | sed -n 's/^[[:space:]]*NTP service:[[:space:]]*//p' | head -n 1)" + td_rtc="$(printf '%s\n' "$td_status" | sed -n 's/^[[:space:]]*RTC time:[[:space:]]*//p' | head -n 1)" + + [ -n "$td_local" ] && log_info "timedatectl: Local time: $td_local" + [ -n "$td_rtc" ] && log_info "timedatectl: RTC time: $td_rtc" + [ -n "$td_sync" ] && log_info "timedatectl: System clock synchronized: $td_sync" + [ -n "$td_ntp" ] && log_info "timedatectl: NTP service: $td_ntp" + + td_show="$(timedatectl show-timesync --all 2>&1 || true)" + if [ -n "$diag_file" ]; then + { + echo "---- timedatectl show-timesync --all ----" + echo "$td_show" + echo + } >>"$diag_file" 2>/dev/null || true + fi + + td_server="$(printf '%s\n' "$td_show" | sed -n 's/^ServerName=//p' | head -n 1)" + td_addr="$(printf '%s\n' "$td_show" | sed -n 's/^ServerAddress=//p' | head -n 1)" + td_sysntp="$(printf '%s\n' "$td_show" | sed -n 's/^SystemNTPServers=//p' | head -n 1)" + td_fallback="$(printf '%s\n' "$td_show" | sed -n 's/^FallbackNTPServers=//p' | head -n 1)" + + if [ -n "$td_server" ] || [ -n "$td_addr" ]; then + log_info "timesync: server=${td_server:-NA} addr=${td_addr:-NA}" + fi + if [ -n "$td_sysntp" ]; then + # Keep it short + short_sysntp="$(printf '%s' "$td_sysntp" | awk '{print $1" "$2" "$3" "$4}')" + log_info "timesync: SystemNTPServers: ${short_sysntp:-NA}" + elif [ -n "$td_fallback" ]; then + short_fb="$(printf '%s' "$td_fallback" | awk '{print $1" "$2" "$3" "$4}')" + log_info "timesync: FallbackNTPServers: ${short_fb:-NA}" + fi + + td_ts="$(timedatectl timesync-status 2>&1 || true)" + if [ -n "$diag_file" ]; then + { + echo "---- timedatectl timesync-status ----" + echo "$td_ts" + echo + } >>"$diag_file" 2>/dev/null || true + fi + + td_pkt="$(printf '%s\n' "$td_ts" | sed -n 's/^[[:space:]]*Packet count:[[:space:]]*//p' | head -n 1)" + td_srvline="$(printf '%s\n' "$td_ts" | sed -n 's/^[[:space:]]*Server:[[:space:]]*//p' | head -n 1)" + [ -n "$td_srvline" ] && log_info "timesync-status: Server: $td_srvline" + [ -n "$td_pkt" ] && log_info "timesync-status: Packet count: $td_pkt" + else + log_info "timedatectl: not available" + if [ -n "$diag_file" ]; then + echo "timedatectl: not available" >>"$diag_file" 2>/dev/null || true + fi fi - grace=25 - start="$(date +%s 2>/dev/null || echo 0)" - end=$((start + grace)) - while :; do - cur="$(date +%s 2>/dev/null || echo 0)" - if [ "$cur" -ge "$cutoff" ] 2>/dev/null; then - log_pass "Clock synchronized." + + # systemctl status summaries + full dump + if command -v systemctl >/dev/null 2>&1; then + sdts="$(systemctl status systemd-timesyncd --no-pager --full 2>&1 || true)" + if [ -n "$diag_file" ]; then + { + echo "---- systemctl status systemd-timesyncd ----" + echo "$sdts" + echo + } >>"$diag_file" 2>/dev/null || true + fi + + sd_active="$(printf '%s\n' "$sdts" | sed -n 's/^[[:space:]]*Active:[[:space:]]*//p' | head -n 1)" + sd_pid="$(printf '%s\n' "$sdts" | sed -n 's/^[[:space:]]*Main PID:[[:space:]]*//p' | head -n 1)" + [ -n "$sd_active" ] && log_info "systemd-timesyncd: Active: $sd_active" + [ -n "$sd_pid" ] && log_info "systemd-timesyncd: Main PID: $sd_pid" + else + log_info "systemctl: not available" + if [ -n "$diag_file" ]; then + echo "systemctl: not available" >>"$diag_file" 2>/dev/null || true + fi + fi + + # 1) Try RTC (if it is sane) + if command -v hwclock >/dev/null 2>&1 && [ -e /dev/rtc0 ]; then + hwclock -s 2>/dev/null || true + now="$(date +%s 2>/dev/null || echo 0)" + if [ "$now" -ge "$cutoff" ] 2>/dev/null; then + log_pass "Clock restored from RTC." return 0 fi - if [ "$cur" -ge "$end" ] 2>/dev/null; then - break + + if [ -r /sys/class/rtc/rtc0/since_epoch ]; then + rtc_epoch="$(tr -cd 0-9 < /sys/class/rtc/rtc0/since_epoch 2>/dev/null)" + if [ -n "$rtc_epoch" ]; then + log_info "rtc0: since_epoch=$rtc_epoch" + if [ -n "$diag_file" ]; then + echo "rtc0: since_epoch=$rtc_epoch" >>"$diag_file" 2>/dev/null || true + fi + fi + if [ -n "$rtc_epoch" ] && [ "$rtc_epoch" -ge "$cutoff" ] 2>/dev/null; then + if date -d "@$rtc_epoch" >/dev/null 2>&1; then + date -s "@$rtc_epoch" >/dev/null 2>&1 || true + fi + now="$(date +%s 2>/dev/null || echo 0)" + if [ "$now" -ge "$cutoff" ] 2>/dev/null; then + log_pass "Clock restored from rtc0 since_epoch." + return 0 + fi + fi fi - sleep 1 - done + else + log_info "RTC: hwclock or /dev/rtc0 not available" + if [ -n "$diag_file" ]; then + echo "RTC: hwclock or /dev/rtc0 not available" >>"$diag_file" 2>/dev/null || true + fi + fi + + # 2) Try kernel build timestamp from /proc/version or uname -v + kb="$(uname -v 2>/dev/null || cat /proc/version 2>/dev/null || true)" + if [ -n "$diag_file" ]; then + { + echo "---- kernel version string ----" + echo "$kb" + echo + } >>"$diag_file" 2>/dev/null || true + fi + + kb_date="$(printf '%s\n' "$kb" | sed -n \ + 's/.*\([A-Z][a-z][a-z] [A-Z][a-z][a-z] [ 0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [A-Z][A-Za-z0-9+:-]* [0-9][0-9][0-9][0-9]\).*/\1/p' \ + | head -n 1)" + + if [ -n "$kb_date" ]; then + log_info "kernel-build-time: parsed='$kb_date'" + kb_epoch="$(date -d "$kb_date" +%s 2>/dev/null || echo 0)" + if [ "$kb_epoch" -ge "$cutoff" ] 2>/dev/null; then + date -s "$kb_date" >/dev/null 2>&1 || true + now="$(date +%s 2>/dev/null || echo 0)" + if [ "$now" -ge "$cutoff" ] 2>/dev/null; then + log_pass "Clock seeded from kernel build time: $kb_date" + return 0 + fi + fi + else + log_info "kernel-build-time: could not parse from uname -v / /proc/version" + fi - log_warn "Clock still invalid; TLS downloads may fail. Treating as limited network." + log_warn "Clock still invalid; continuing (timestamps may be epoch)." return 1 } From c862d2b5af43fe6ae72e89c276243a81b7b0ddbb Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Fri, 26 Dec 2025 16:10:57 +0530 Subject: [PATCH 4/6] perf(sysbench): add Sysbench_Performance runner Run CPU/Memory/Threads/Mutex workloads with iterations support. Capture per-iteration logs while streaming output to console. Compute KPI averages and optionally gate against baseline+delta. Signed-off-by: Srikanth Muppandam --- .../Performance/Sysbench_Performance/run.sh | 598 ++++++++++++++++++ 1 file changed, 598 insertions(+) create mode 100755 Runner/suites/Performance/Sysbench_Performance/run.sh diff --git a/Runner/suites/Performance/Sysbench_Performance/run.sh b/Runner/suites/Performance/Sysbench_Performance/run.sh new file mode 100755 index 00000000..64844724 --- /dev/null +++ b/Runner/suites/Performance/Sysbench_Performance/run.sh @@ -0,0 +1,598 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +SCRIPT_DIR="$( + cd "$(dirname "$0")" || exit 1 + pwd +)" + +TESTNAME="Sysbench_Performance" +RES_FILE="./${TESTNAME}.res" + +# Defaults (env overrides; CLI can override further) +OUT_DIR="${OUT_DIR:-./sysbench_out}" +ITERATIONS="${ITERATIONS:-1}" +TIME="${TIME:-30}" +RAND_SEED="${RAND_SEED:-1234}" +# Default should cover both single-thread and multi-thread baselines +THREADS_LIST="${THREADS_LIST:-1 4}" + +CPU_MAX_PRIME="${CPU_MAX_PRIME:-20000}" + +THREAD_LOCKS="${THREAD_LOCKS:-20}" +THREAD_YIELDS="${THREAD_YIELDS:-}" + +MEMORY_OPER="${MEMORY_OPER:-write}" +MEMORY_ACCESS_MODE="${MEMORY_ACCESS_MODE:-rnd}" +MEMORY_BLOCK_SIZE="${MEMORY_BLOCK_SIZE:-1M}" +MEMORY_TOTAL_SIZE="${MEMORY_TOTAL_SIZE:-100G}" + +MUTEX_NUM="${MUTEX_NUM:-}" +MUTEX_LOCKS="${MUTEX_LOCKS:-}" +MUTEX_LOOPS="${MUTEX_LOOPS:-}" + +TASKSET_CPU_LIST="${TASKSET_CPU_LIST:-}" + +BASELINE_FILE="${BASELINE_FILE:-}" +ALLOWED_DEVIATION="${ALLOWED_DEVIATION:-0.10}" + +CSV_FILE="${CSV_FILE:-}" +VERBOSE="${VERBOSE:-0}" + +# FileIO defaults (env overrides; CLI can override) +# If not explicitly set, prefer a real-disk location (not /tmp tmpfs). +FILEIO_DIR="${FILEIO_DIR:-}" +FILEIO_TOTAL_SIZE="${FILEIO_TOTAL_SIZE:-1G}" +FILEIO_BLOCK_SIZE="${FILEIO_BLOCK_SIZE:-4K}" +FILEIO_NUM="${FILEIO_NUM:-128}" +FILEIO_IO_MODE="${FILEIO_IO_MODE:-sync}" +FILEIO_FSYNC_FREQ="${FILEIO_FSYNC_FREQ:-0}" +FILEIO_EXTRA_FLAGS="${FILEIO_EXTRA_FLAGS:-none}" + +# Optional: run without init_env (minimal) +STANDALONE="${STANDALONE:-0}" + +usage() { + cat <&2 + usage + exit 2 + ;; + *) + echo "[ERROR] Unexpected argument: $1" >&2 + usage + exit 2 + ;; + esac +done + +# ---------------- locate and source init_env → functestlib.sh + lib_performance.sh ---------------- +if [ "$STANDALONE" = "1" ]; then + : "${TOOLS:=}" +else + INIT_ENV="" + SEARCH="$SCRIPT_DIR" + while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") + done + + if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR). Use --standalone 1 to bypass." >&2 + exit 1 + fi + + if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 + fi +fi + +if [ -z "${TOOLS:-}" ] || [ ! -f "$TOOLS/functestlib.sh" ] || [ ! -f "$TOOLS/lib_performance.sh" ]; then + echo "[ERROR] Missing TOOLS/functestlib.sh or TOOLS/lib_performance.sh. (TOOLS=$TOOLS)" >&2 + exit 1 +fi + +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" +# shellcheck disable=SC1091 +. "$TOOLS/lib_performance.sh" + +: >"$RES_FILE" +mkdir -p "$OUT_DIR" 2>/dev/null || true + +# Baseline auto-detect from same folder as run.sh +if [ -z "$BASELINE_FILE" ] && [ -f "$SCRIPT_DIR/sysbench_baseline.conf" ]; then + BASELINE_FILE="$SCRIPT_DIR/sysbench_baseline.conf" +fi + +# Auto-pick FILEIO_DIR if not set: prefer non-tmpfs on real disk +if [ -z "$FILEIO_DIR" ]; then + if [ -d /var/tmp ] && [ -w /var/tmp ]; then + FILEIO_DIR="/var/tmp/sysbench_fileio" + else + FILEIO_DIR="/tmp/sysbench_fileio" + fi +fi + +# ---------------- baseline presence check (non-fatal) ---------------- +if [ -n "$BASELINE_FILE" ] && [ ! -f "$BASELINE_FILE" ]; then + log_warn "Baseline file set but not found: $BASELINE_FILE (will run report-only)" + BASELINE_FILE="" +fi + +cleanup() { + restore_governor 2>/dev/null || true +} +trap cleanup EXIT + +# --------------------------------------------------------------------------- +# Clock sanity (avoid epoch time breaking logs / gating) +# --------------------------------------------------------------------------- +if command -v ensure_reasonable_clock >/dev/null 2>&1; then + log_info "Ensuring system clock is reasonable before sysbench..." + if ! ensure_reasonable_clock; then + log_error "Clock is not reasonable, Running sysbench_Performance benchmark may lead to invalid results." + fi +else + log_info "ensure_reasonable_clock() not available, continuing without clock sanity check." +fi + +log_info "Sysbench runner starting" +log_info "OUTDIR=$OUT_DIR BASELINE=${BASELINE_FILE:-none} DELTA=$ALLOWED_DEVIATION ITERATIONS=$ITERATIONS CORE_LIST=${TASKSET_CPU_LIST:-none}" +log_info "TIME=$TIME SEED=$RAND_SEED THREADS_LIST=$THREADS_LIST" +log_info "CPU_MAX_PRIME=$CPU_MAX_PRIME MEM=${MEMORY_OPER}/${MEMORY_ACCESS_MODE} blk=$MEMORY_BLOCK_SIZE total=$MEMORY_TOTAL_SIZE THREAD_LOCKS=$THREAD_LOCKS" +log_info "FILEIO dir=$FILEIO_DIR total=$FILEIO_TOTAL_SIZE blk=$FILEIO_BLOCK_SIZE num=$FILEIO_NUM io_mode=$FILEIO_IO_MODE fsync_freq=$FILEIO_FSYNC_FREQ extra_flags=$FILEIO_EXTRA_FLAGS" + +# Warn if RTC is broken (epoch timestamps) +perf_clock_sanity_warn 2>/dev/null || true + +# ---------------- deps check ---------------- +deps_list="sysbench awk sed grep date mkfifo tee" +if [ -n "${TASKSET_CPU_LIST:-}" ]; then + deps_list="$deps_list taskset" +fi + +# Use single call (no loop) +if ! check_dependencies "$deps_list"; then + log_skip "$TESTNAME SKIP - missing one or more dependencies: $deps_list" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +set_performance_governor 2>/dev/null || true + +# --------- FileIO prepare (safety warning + prepare) ---------- +case "$FILEIO_DIR" in + /tmp/*|/var/tmp/*) : ;; + *) + log_warn "FILEIO_DIR=$FILEIO_DIR is not under /tmp or /var/tmp. This can stress rootfs if it is on /. Use --fileio-dir to point to a dedicated mount if needed." + ;; +esac + +# Ensure FILEIO_DIR is usable (addresses /tmp missing / not writable) +if ! mkdir -p "$FILEIO_DIR" 2>/dev/null; then + log_skip "$TESTNAME SKIP - FILEIO_DIR not creatable: $FILEIO_DIR (set FILEIO_DIR to a writable path)" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi +if [ ! -w "$FILEIO_DIR" ]; then + log_skip "$TESTNAME SKIP - FILEIO_DIR not writable: $FILEIO_DIR (set FILEIO_DIR to a writable path)" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +log_info "Preparing sysbench fileio dataset in $FILEIO_DIR" +fileio_prepare_log="$OUT_DIR/fileio_prepare.log" +set -- sysbench fileio \ + --file-total-size="$FILEIO_TOTAL_SIZE" \ + --file-num="$FILEIO_NUM" \ + --file-block-size="$FILEIO_BLOCK_SIZE" \ + --file-io-mode="$FILEIO_IO_MODE" \ + --file-fsync-freq="$FILEIO_FSYNC_FREQ" +[ "$FILEIO_EXTRA_FLAGS" != "none" ] && set -- "$@" --file-extra-flags="$FILEIO_EXTRA_FLAGS" +set -- "$@" prepare +run_sysbench_case "FileIO prepare" "$fileio_prepare_log" "$@" || true + +suite_rc=0 +gate_fail=0 + +summary="$OUT_DIR/sysbench_summary.txt" +: >"$summary" + +ITER_LIST=$(awk -v n="$ITERATIONS" 'BEGIN{for (k=1; k<=n; k++) printf "%d ", k}') + +for sb_threads in $THREADS_LIST; do + cpu_vals="$OUT_DIR/cpu_t${sb_threads}.values" + mem_vals="$OUT_DIR/mem_t${sb_threads}.values" + thr_vals="$OUT_DIR/threads_t${sb_threads}.values" + mtx_vals="$OUT_DIR/mutex_t${sb_threads}.values" + + fio_seqwr_vals="$OUT_DIR/fileio_seqwr_t${sb_threads}.values" + fio_seqrd_vals="$OUT_DIR/fileio_seqrd_t${sb_threads}.values" + fio_rndwr_vals="$OUT_DIR/fileio_rndwr_t${sb_threads}.values" + fio_rndrd_vals="$OUT_DIR/fileio_rndrd_t${sb_threads}.values" + + : >"$cpu_vals" 2>/dev/null || true + : >"$mem_vals" 2>/dev/null || true + : >"$thr_vals" 2>/dev/null || true + : >"$mtx_vals" 2>/dev/null || true + : >"$fio_seqwr_vals" 2>/dev/null || true + : >"$fio_seqrd_vals" 2>/dev/null || true + : >"$fio_rndwr_vals" 2>/dev/null || true + : >"$fio_rndrd_vals" 2>/dev/null || true + + thr_opt=$(sysbench_threads_opt "$sb_threads") + + for sb_iter in $ITER_LIST; do + cpu_time="" + mem_mbps="" + thr_time="" + mtx_time="" + + seqwr_mbps="" + seqrd_mbps="" + rndwr_mbps="" + rndrd_mbps="" + + # CPU (NOTE: total time is meaningful only if NOT forced by --time) + cpu_log="$OUT_DIR/cpu_t${sb_threads}_iter${sb_iter}.log" + set -- sysbench --rand-seed="$RAND_SEED" + [ -n "$thr_opt" ] && set -- "$@" "$thr_opt" + set -- "$@" cpu --cpu-max-prime="$CPU_MAX_PRIME" run + if [ -n "$TASKSET_CPU_LIST" ]; then + set -- taskset -c "$TASKSET_CPU_LIST" "$@" + fi + run_sysbench_case "CPU (threads=$sb_threads iteration $sb_iter/$ITERATIONS)" "$cpu_log" "$@" || true + cpu_time=$(perf_sysbench_parse_time_sec "$cpu_log" 2>/dev/null || true) + if [ -n "$cpu_time" ]; then + log_info "CPU: iteration $sb_iter time_sec=$cpu_time" + perf_values_append "$cpu_vals" "$cpu_time" + [ -n "$CSV_FILE" ] && perf_sysbench_csv_append "$CSV_FILE" "cpu" "$sb_threads" "time_sec" "$sb_iter" "$cpu_time" + else + log_warn "CPU: iteration $sb_iter could not parse time from $cpu_log" + suite_rc=1 + fi + + # Memory + mem_log="$OUT_DIR/mem_t${sb_threads}_iter${sb_iter}.log" + set -- sysbench --time="$TIME" --rand-seed="$RAND_SEED" + [ -n "$thr_opt" ] && set -- "$@" "$thr_opt" + set -- "$@" memory \ + --memory-oper="$MEMORY_OPER" \ + --memory-access-mode="$MEMORY_ACCESS_MODE" \ + --memory-block-size="$MEMORY_BLOCK_SIZE" \ + --memory-total-size="$MEMORY_TOTAL_SIZE" run + if [ -n "$TASKSET_CPU_LIST" ]; then + set -- taskset -c "$TASKSET_CPU_LIST" "$@" + fi + run_sysbench_case "Memory (threads=$sb_threads iteration $sb_iter/$ITERATIONS)" "$mem_log" "$@" || true + mem_mbps=$(perf_sysbench_parse_mem_mbps "$mem_log" 2>/dev/null || true) + if [ -n "$mem_mbps" ]; then + log_info "Memory: iteration $sb_iter mem_mbps=$mem_mbps" + perf_values_append "$mem_vals" "$mem_mbps" + [ -n "$CSV_FILE" ] && perf_sysbench_csv_append "$CSV_FILE" "memory" "$sb_threads" "mem_mbps" "$sb_iter" "$mem_mbps" + else + log_warn "Memory: iteration $sb_iter could not parse MB/sec from $mem_log" + suite_rc=1 + fi + + # Threads (same note as CPU: do NOT force --time if you want “total time” as KPI) + thr_log="$OUT_DIR/threads_t${sb_threads}_iter${sb_iter}.log" + set -- sysbench --rand-seed="$RAND_SEED" + [ -n "$thr_opt" ] && set -- "$@" "$thr_opt" + set -- "$@" threads --thread-locks="$THREAD_LOCKS" + if [ -n "$THREAD_YIELDS" ]; then + set -- "$@" --thread-yields="$THREAD_YIELDS" + fi + set -- "$@" run + if [ -n "$TASKSET_CPU_LIST" ]; then + set -- taskset -c "$TASKSET_CPU_LIST" "$@" + fi + run_sysbench_case "Threads (threads=$sb_threads iteration $sb_iter/$ITERATIONS)" "$thr_log" "$@" || true + thr_time=$(perf_sysbench_parse_time_sec "$thr_log" 2>/dev/null || true) + if [ -n "$thr_time" ]; then + log_info "Threads: iteration $sb_iter time_sec=$thr_time" + perf_values_append "$thr_vals" "$thr_time" + [ -n "$CSV_FILE" ] && perf_sysbench_csv_append "$CSV_FILE" "threads" "$sb_threads" "time_sec" "$sb_iter" "$thr_time" + else + log_warn "Threads: iteration $sb_iter could not parse time from $thr_log" + suite_rc=1 + fi + + # Mutex + mtx_log="$OUT_DIR/mutex_t${sb_threads}_iter${sb_iter}.log" + set -- sysbench --rand-seed="$RAND_SEED" + [ -n "$thr_opt" ] && set -- "$@" "$thr_opt" + set -- "$@" mutex + [ -n "$MUTEX_NUM" ] && set -- "$@" --mutex-num="$MUTEX_NUM" + [ -n "$MUTEX_LOCKS" ] && set -- "$@" --mutex-locks="$MUTEX_LOCKS" + [ -n "$MUTEX_LOOPS" ] && set -- "$@" --mutex-loops="$MUTEX_LOOPS" + set -- "$@" run + if [ -n "$TASKSET_CPU_LIST" ]; then + set -- taskset -c "$TASKSET_CPU_LIST" "$@" + fi + run_sysbench_case "Mutex (threads=$sb_threads iteration $sb_iter/$ITERATIONS)" "$mtx_log" "$@" || true + mtx_time=$(perf_sysbench_parse_time_sec "$mtx_log" 2>/dev/null || true) + if [ -n "$mtx_time" ]; then + log_info "Mutex: iteration $sb_iter time_sec=$mtx_time" + perf_values_append "$mtx_vals" "$mtx_time" + [ -n "$CSV_FILE" ] && perf_sysbench_csv_append "$CSV_FILE" "mutex" "$sb_threads" "time_sec" "$sb_iter" "$mtx_time" + else + log_warn "Mutex: iteration $sb_iter could not parse time from $mtx_log" + suite_rc=1 + fi + + # -------- FileIO modes (MiB/s -> MB/s; store as *_mbps) -------- + for mode in seqwr seqrd rndwr rndrd; do + fio_log="$OUT_DIR/fileio_${mode}_t${sb_threads}_iter${sb_iter}.log" + set -- sysbench --time="$TIME" --rand-seed="$RAND_SEED" + [ -n "$thr_opt" ] && set -- "$@" "$thr_opt" + set -- "$@" fileio \ + --file-total-size="$FILEIO_TOTAL_SIZE" \ + --file-num="$FILEIO_NUM" \ + --file-block-size="$FILEIO_BLOCK_SIZE" \ + --file-io-mode="$FILEIO_IO_MODE" \ + --file-test-mode="$mode" \ + --file-fsync-freq="$FILEIO_FSYNC_FREQ" + [ "$FILEIO_EXTRA_FLAGS" != "none" ] && set -- "$@" --file-extra-flags="$FILEIO_EXTRA_FLAGS" + set -- "$@" run + run_sysbench_case "FileIO $mode (threads=$sb_threads iteration $sb_iter/$ITERATIONS)" "$fio_log" "$@" || true + + case "$mode" in + seqwr) + raw=$(perf_sysbench_parse_fileio_written_mibps "$fio_log" 2>/dev/null || true) + seqwr_mbps=$(sysbench_mib_to_mb "$raw" 2>/dev/null || true) + [ -n "$seqwr_mbps" ] && perf_values_append "$fio_seqwr_vals" "$seqwr_mbps" + [ -n "$CSV_FILE" ] && perf_sysbench_csv_append "$CSV_FILE" "fileio" "$sb_threads" "seqwr_mbps" "$sb_iter" "$seqwr_mbps" + ;; + seqrd) + raw=$(perf_sysbench_parse_fileio_read_mibps "$fio_log" 2>/dev/null || true) + seqrd_mbps=$(sysbench_mib_to_mb "$raw" 2>/dev/null || true) + [ -n "$seqrd_mbps" ] && perf_values_append "$fio_seqrd_vals" "$seqrd_mbps" + [ -n "$CSV_FILE" ] && perf_sysbench_csv_append "$CSV_FILE" "fileio" "$sb_threads" "seqrd_mbps" "$sb_iter" "$seqrd_mbps" + ;; + rndwr) + raw=$(perf_sysbench_parse_fileio_written_mibps "$fio_log" 2>/dev/null || true) + rndwr_mbps=$(sysbench_mib_to_mb "$raw" 2>/dev/null || true) + [ -n "$rndwr_mbps" ] && perf_values_append "$fio_rndwr_vals" "$rndwr_mbps" + [ -n "$CSV_FILE" ] && perf_sysbench_csv_append "$CSV_FILE" "fileio" "$sb_threads" "rndwr_mbps" "$sb_iter" "$rndwr_mbps" + ;; + rndrd) + raw=$(perf_sysbench_parse_fileio_read_mibps "$fio_log" 2>/dev/null || true) + rndrd_mbps=$(sysbench_mib_to_mb "$raw" 2>/dev/null || true) + [ -n "$rndrd_mbps" ] && perf_values_append "$fio_rndrd_vals" "$rndrd_mbps" + [ -n "$CSV_FILE" ] && perf_sysbench_csv_append "$CSV_FILE" "fileio" "$sb_threads" "rndrd_mbps" "$sb_iter" "$rndrd_mbps" + ;; + esac + done + + log_info "ITER_SUMMARY threads=$sb_threads iter=$sb_iter/$ITERATIONS cpu_time_sec=${cpu_time:-NA} mem_mbps=${mem_mbps:-NA} threads_time_sec=${thr_time:-NA} mutex_time_sec=${mtx_time:-NA} seqwr_mbps=${seqwr_mbps:-NA} seqrd_mbps=${seqrd_mbps:-NA} rndwr_mbps=${rndwr_mbps:-NA} rndrd_mbps=${rndrd_mbps:-NA}" + done + + cpu_avg=$(perf_values_avg "$cpu_vals") + mem_avg=$(perf_values_avg "$mem_vals") + thr_avg=$(perf_values_avg "$thr_vals") + mtx_avg=$(perf_values_avg "$mtx_vals") + + seqwr_avg=$(perf_values_avg "$fio_seqwr_vals") + seqrd_avg=$(perf_values_avg "$fio_seqrd_vals") + rndwr_avg=$(perf_values_avg "$fio_rndwr_vals") + rndrd_avg=$(perf_values_avg "$fio_rndrd_vals") + + { + echo "Threads=$sb_threads" + [ -n "$cpu_avg" ] && echo " cpu_avg_time_sec : $cpu_avg" || echo " cpu_avg_time_sec : unknown" + [ -n "$mem_avg" ] && echo " mem_avg_mbps : $mem_avg" || echo " mem_avg_mbps : unknown" + [ -n "$thr_avg" ] && echo " threads_avg_time_sec : $thr_avg" || echo " threads_avg_time_sec : unknown" + [ -n "$mtx_avg" ] && echo " mutex_avg_time_sec : $mtx_avg" || echo " mutex_avg_time_sec : unknown" + [ -n "$seqwr_avg" ] && echo " fileio_seqwr_avg_mbps : $seqwr_avg" || echo " fileio_seqwr_avg_mbps : unknown" + [ -n "$seqrd_avg" ] && echo " fileio_seqrd_avg_mbps : $seqrd_avg" || echo " fileio_seqrd_avg_mbps : unknown" + [ -n "$rndwr_avg" ] && echo " fileio_rndwr_avg_mbps : $rndwr_avg" || echo " fileio_rndwr_avg_mbps : unknown" + [ -n "$rndrd_avg" ] && echo " fileio_rndrd_avg_mbps : $rndrd_avg" || echo " fileio_rndrd_avg_mbps : unknown" + } >>"$summary" + + # ---------------- Baseline gating per AVG ---------------- + if [ -n "$BASELINE_FILE" ] && command -v perf_sysbench_gate_eval_line >/dev/null 2>&1; then + # cpu time_sec + if [ -n "$cpu_avg" ]; then + line=$(perf_sysbench_gate_eval_line_safe "$BASELINE_FILE" "cpu" "$sb_threads" "time_sec" "$cpu_avg" "$ALLOWED_DEVIATION") + rc=$? + base=$(kv "$line" "baseline"); goal=$(kv "$line" "goal"); op=$(kv "$line" "op"); score=$(kv "$line" "score_pct"); status=$(kv "$line" "status") + log_info "GATE cpu threads=$sb_threads avg=$cpu_avg baseline=${base:-NA} goal${op}${goal:-NA} delta=$ALLOWED_DEVIATION score_pct=${score:-NA} status=${status:-NA}" + echo " gate_cpu_time_sec : status=${status:-NA} baseline=${base:-NA} goal${op}${goal:-NA} score_pct=${score:-NA} delta=$ALLOWED_DEVIATION" >>"$summary" + [ "$rc" -eq 1 ] && gate_fail=1 + fi + + # memory mem_mbps + if [ -n "$mem_avg" ]; then + line=$(perf_sysbench_gate_eval_line_safe "$BASELINE_FILE" "memory" "$sb_threads" "mem_mbps" "$mem_avg" "$ALLOWED_DEVIATION") + rc=$? + base=$(kv "$line" "baseline"); goal=$(kv "$line" "goal"); op=$(kv "$line" "op"); score=$(kv "$line" "score_pct"); status=$(kv "$line" "status") + log_info "GATE memory threads=$sb_threads avg=$mem_avg baseline=${base:-NA} goal${op}${goal:-NA} delta=$ALLOWED_DEVIATION score_pct=${score:-NA} status=${status:-NA}" + echo " gate_memory_mem_mbps : status=${status:-NA} baseline=${base:-NA} goal${op}${goal:-NA} score_pct=${score:-NA} delta=$ALLOWED_DEVIATION" >>"$summary" + [ "$rc" -eq 1 ] && gate_fail=1 + fi + + # threads time_sec + if [ -n "$thr_avg" ]; then + line=$(perf_sysbench_gate_eval_line_safe "$BASELINE_FILE" "threads" "$sb_threads" "time_sec" "$thr_avg" "$ALLOWED_DEVIATION") + rc=$? + base=$(kv "$line" "baseline"); goal=$(kv "$line" "goal"); op=$(kv "$line" "op"); score=$(kv "$line" "score_pct"); status=$(kv "$line" "status") + log_info "GATE threads threads=$sb_threads avg=$thr_avg baseline=${base:-NA} goal${op}${goal:-NA} delta=$ALLOWED_DEVIATION score_pct=${score:-NA} status=${status:-NA}" + echo " gate_threads_time_sec : status=${status:-NA} baseline=${base:-NA} goal${op}${goal:-NA} score_pct=${score:-NA} delta=$ALLOWED_DEVIATION" >>"$summary" + [ "$rc" -eq 1 ] && gate_fail=1 + fi + + # mutex time_sec + if [ -n "$mtx_avg" ]; then + line=$(perf_sysbench_gate_eval_line_safe "$BASELINE_FILE" "mutex" "$sb_threads" "time_sec" "$mtx_avg" "$ALLOWED_DEVIATION") + rc=$? + base=$(kv "$line" "baseline"); goal=$(kv "$line" "goal"); op=$(kv "$line" "op"); score=$(kv "$line" "score_pct"); status=$(kv "$line" "status") + log_info "GATE mutex threads=$sb_threads avg=$mtx_avg baseline=${base:-NA} goal${op}${goal:-NA} delta=$ALLOWED_DEVIATION score_pct=${score:-NA} status=${status:-NA}" + echo " gate_mutex_time_sec : status=${status:-NA} baseline=${base:-NA} goal${op}${goal:-NA} score_pct=${score:-NA} delta=$ALLOWED_DEVIATION" >>"$summary" + [ "$rc" -eq 1 ] && gate_fail=1 + fi + + # -------- FileIO gating in MB/s (mbps) -------- + if [ -n "$seqwr_avg" ]; then + line=$(perf_sysbench_gate_eval_line_safe "$BASELINE_FILE" "fileio" "$sb_threads" "seqwr_mbps" "$seqwr_avg" "$ALLOWED_DEVIATION") + rc=$? + base=$(kv "$line" "baseline"); goal=$(kv "$line" "goal"); op=$(kv "$line" "op"); score=$(kv "$line" "score_pct"); status=$(kv "$line" "status") + log_info "GATE fileio seqwr threads=$sb_threads avg=$seqwr_avg baseline=${base:-NA} goal${op}${goal:-NA} delta=$ALLOWED_DEVIATION score_pct=${score:-NA} status=${status:-NA}" + echo " gate_fileio_seqwr_mbps : status=${status:-NA} baseline=${base:-NA} goal${op}${goal:-NA} score_pct=${score:-NA} delta=$ALLOWED_DEVIATION" >>"$summary" + [ "$rc" -eq 1 ] && gate_fail=1 + fi + + if [ -n "$seqrd_avg" ]; then + line=$(perf_sysbench_gate_eval_line_safe "$BASELINE_FILE" "fileio" "$sb_threads" "seqrd_mbps" "$seqrd_avg" "$ALLOWED_DEVIATION") + rc=$? + base=$(kv "$line" "baseline"); goal=$(kv "$line" "goal"); op=$(kv "$line" "op"); score=$(kv "$line" "score_pct"); status=$(kv "$line" "status") + log_info "GATE fileio seqrd threads=$sb_threads avg=$seqrd_avg baseline=${base:-NA} goal${op}${goal:-NA} delta=$ALLOWED_DEVIATION score_pct=${score:-NA} status=${status:-NA}" + echo " gate_fileio_seqrd_mbps : status=${status:-NA} baseline=${base:-NA} goal${op}${goal:-NA} score_pct=${score:-NA} delta=$ALLOWED_DEVIATION" >>"$summary" + [ "$rc" -eq 1 ] && gate_fail=1 + fi + + if [ -n "$rndwr_avg" ]; then + line=$(perf_sysbench_gate_eval_line_safe "$BASELINE_FILE" "fileio" "$sb_threads" "rndwr_mbps" "$rndwr_avg" "$ALLOWED_DEVIATION") + rc=$? + base=$(kv "$line" "baseline"); goal=$(kv "$line" "goal"); op=$(kv "$line" "op"); score=$(kv "$line" "score_pct"); status=$(kv "$line" "status") + log_info "GATE fileio rndwr threads=$sb_threads avg=$rndwr_avg baseline=${base:-NA} goal${op}${goal:-NA} delta=$ALLOWED_DEVIATION score_pct=${score:-NA} status=${status:-NA}" + echo " gate_fileio_rndwr_mbps : status=${status:-NA} baseline=${base:-NA} goal${op}${goal:-NA} score_pct=${score:-NA} delta=$ALLOWED_DEVIATION" >>"$summary" + [ "$rc" -eq 1 ] && gate_fail=1 + fi + + if [ -n "$rndrd_avg" ]; then + line=$(perf_sysbench_gate_eval_line_safe "$BASELINE_FILE" "fileio" "$sb_threads" "rndrd_mbps" "$rndrd_avg" "$ALLOWED_DEVIATION") + rc=$? + base=$(kv "$line" "baseline"); goal=$(kv "$line" "goal"); op=$(kv "$line" "op"); score=$(kv "$line" "score_pct"); status=$(kv "$line" "status") + log_info "GATE fileio rndrd threads=$sb_threads avg=$rndrd_avg baseline=${base:-NA} goal${op}${goal:-NA} delta=$ALLOWED_DEVIATION score_pct=${score:-NA} status=${status:-NA}" + echo " gate_fileio_rndrd_mbps : status=${status:-NA} baseline=${base:-NA} goal${op}${goal:-NA} score_pct=${score:-NA} delta=$ALLOWED_DEVIATION" >>"$summary" + [ "$rc" -eq 1 ] && gate_fail=1 + fi + fi + + echo >>"$summary" +done + +log_info "Final summary written → $summary" +log_info "----- SYSBENCH SUMMARY (stdout) -----" +cat "$summary" || true +log_info "----- END SUMMARY -----" + +if [ -n "$BASELINE_FILE" ] && [ "$gate_fail" -ne 0 ]; then + log_fail "$TESTNAME FAIL - one or more KPIs did not meet baseline thresholds" + echo "$TESTNAME FAIL" >"$RES_FILE" + exit 1 +fi + +log_pass "$TESTNAME PASS" +echo "$TESTNAME PASS" >"$RES_FILE" +exit "$suite_rc" From d898109eec5240c30f2b0507e535e98bfa6e0344 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Fri, 26 Dec 2025 16:11:30 +0530 Subject: [PATCH 5/6] docs(sysbench): add usage and KPI guidance Document CLI/env options, output artifacts, and examples. Explain baseline file format and recommended delta threshold. Describe CSV/KPI summary fields for CI and local runs. Signed-off-by: Srikanth Muppandam --- .../Sysbench_Performance/README_sysbench.md | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 Runner/suites/Performance/Sysbench_Performance/README_sysbench.md diff --git a/Runner/suites/Performance/Sysbench_Performance/README_sysbench.md b/Runner/suites/Performance/Sysbench_Performance/README_sysbench.md new file mode 100644 index 00000000..8dd06bc6 --- /dev/null +++ b/Runner/suites/Performance/Sysbench_Performance/README_sysbench.md @@ -0,0 +1,227 @@ +# Sysbench_Performance + +This suite runs a **repeatable Sysbench performance baseline** on Yocto/QLI targets in a CI-friendly way. + +It runs the following test cases for one or more thread counts and for N iterations: + +- **CPU** (`sysbench cpu`) +- **Memory bandwidth** (`sysbench memory`) +- **Threads** (`sysbench threads`) +- **Mutex** (`sysbench mutex`) +- **File I/O throughput** (`sysbench fileio`) — **seqwr / seqrd / rndwr / rndrd** + +For each case it: +- prints sysbench output live to console (and saves per-iteration logs), +- records per-iteration KPIs into `*.values` files, +- prints a compact per-iteration KPI line (`ITER_SUMMARY`) to console, +- computes averages and writes `OUT_DIR/sysbench_summary.txt`, +- optionally appends per-iteration + avg rows to a CSV (only if `CSV_FILE` is provided), +- optionally enforces PASS/FAIL **baseline gating** (when a baseline file is provided or auto-detected). + +--- + +## KPIs collected (and “better” direction) + +| Case | KPI name (run.sh / baseline key) | Unit | Better | +|---|---|---:|---| +| CPU | `cpu_time_sec` | seconds | **lower** | +| Memory | `memory_mem_mbps` | MB/s | **higher** | +| Threads | `threads_time_sec` | seconds | **lower** | +| Mutex | `mutex_time_sec` | seconds | **lower** | +| File I/O seq write | `fileio_seqwr_mbps` | MB/s | **higher** | +| File I/O seq read | `fileio_seqrd_mbps` | MB/s | **higher** | +| File I/O rnd write | `fileio_rndwr_mbps` | MB/s | **higher** | +| File I/O rnd read | `fileio_rndrd_mbps` | MB/s | **higher** | + +> Note: even if you think of reads as “GB/s”, the suite **stores and gates in MB/s** for consistency. +> If you have a baseline in GB/s, convert to MB/s (GB/s × 1024). + +--- + +## Baseline gating (PASS/FAIL) + +Baseline gating is enabled when either: +- `BASELINE_FILE` / `--baseline FILE` is set, **or** +- `./sysbench_baseline.conf` exists in the **same folder as `run.sh`** (auto-detected). + +`ALLOWED_DEVIATION` / `--delta` controls tolerance: + +- **Higher-is-better** metrics (MB/s): + **PASS** if `avg >= baseline * (1 - delta)` + (recommend **0.05** → “>= 95% of baseline”) +- **Lower-is-better** metrics (seconds): + **PASS** if `avg <= baseline * (1 + delta)` + (recommend **0.05** → “<= 105% of baseline”) + +The console shows a per-metric GATE line and `sysbench_summary.txt` includes a `gate_*` section. + +--- + +## Baseline file format (`sysbench_baseline.conf`) + +Plain `key=value` format (comments allowed with `#`). Keys are per-thread-count: + +``` +# ---- Threads = 4 ---- +cpu_time_sec.t4=3.483 +memory_mem_mbps.t4=4120.000 +threads_time_sec.t4=3.703 +mutex_time_sec.t4=0.004 + +fileio_seqwr_mbps.t4=0.400 +fileio_seqrd_mbps.t4=29.300 +fileio_rndwr_mbps.t4=0.610 +fileio_rndrd_mbps.t4=29.300 +``` + +Use `t1`, `t4`, `t8`, … matching your `THREADS_LIST`. + +--- + +## Parameters (env vars / CLI) + +The suite is controlled by environment variables (and equivalent CLI flags). Typical params: + +### Common +- `OUT_DIR` (default `./sysbench_out`) – where logs / values / summary go +- `ITERATIONS` (default `1`) +- `TIME` (default `30`) +- `RAND_SEED` (default `1234`) +- `THREADS_LIST` (default `"4"`) – space-separated list of thread counts +- `TASKSET_CPU_LIST` (default empty) – passed to `taskset -c`, e.g. `"6-7"` +- `BASELINE_FILE` (default empty; auto-detects `sysbench_baseline.conf` next to `run.sh`) +- `ALLOWED_DEVIATION` (default `0.10`; recommended `0.05`) +- `CSV_FILE` (default empty → **no CSV by default**) + +### CPU +- `CPU_MAX_PRIME` (default `20000`) + +### Threads +- `THREAD_LOCKS` (default `20`) +- `THREAD_YIELDS` (default empty → sysbench default) + +### Memory +- `MEMORY_OPER` (default `write`) – `read|write` +- `MEMORY_ACCESS_MODE` (default `rnd`) – `seq|rnd` +- `MEMORY_BLOCK_SIZE` (default `1M`) +- `MEMORY_TOTAL_SIZE` (default `100G`) + +### File I/O +File I/O uses sysbench `fileio` with a **prepare → run → cleanup** flow. + +Recommended knobs (names match the suite params): +- `FILEIO_DIR` – directory where files are created (recommended: **tmpfs** like `/tmp`) +- `FILE_TOTAL_SIZE` – total size per file, e.g. `1G` +- `FILE_BLOCK_SIZE` – e.g. `4K`, `1M` +- `FILE_NUM` – number of files, e.g. `1`, `4` +- `FILE_IO_MODE` – e.g. `sync` (stable), `async` +- `FILE_FSYNC_FREQ` – optional, e.g. `0` (disable) or `1` (every op) + +> Your `run.sh` may expose additional `FILE_*` knobs; keep them documented here as you add them. + +--- + +## Safety warning for File I/O + +`sysbench fileio` **creates files and performs reads/writes** in `FILEIO_DIR`. + +To avoid accidental wear / regression noise: +- Prefer `FILEIO_DIR=/tmp/...` (tmpfs) for CI gating. +- If you must test real storage, point to a **dedicated mount** (not `/`), and keep sizes small. +- Do **NOT** point fileio at your root filesystem (`/`) unless you fully understand the impact. + +--- + +## Outputs + +In `OUT_DIR/` you will see: + +- `*_iterN.log` — full sysbench stdout/stderr per test case + iteration +- `*.values` — one KPI value per iteration (for averaging) +- `sysbench_summary.txt` — averages + gating summary +- Optional CSV (only when `CSV_FILE` is set) + +Result file: +- `./Sysbench_Performance.res` — `PASS` / `FAIL` / `SKIP` + +--- + +## Examples (using our `run.sh`) + +All examples are run from: + +``` +cd Runner/suites/Performance/Sysbench_Performance/ +``` + +### 1) Full suite (CPU + memory + threads + mutex + fileio) +``` +./run.sh +``` + +### 2) 3 iterations, pin to big cores, tighter gating (95% baseline) +(Uses `./sysbench_baseline.conf` automatically if present.) +``` +./run.sh --iterations 3 --threads-list "4" --taskset-cpu-list "6-7" --delta 0.05 +``` + +### 3) Explicit baseline file path +``` +./run.sh --baseline ./sysbench_baseline.conf --delta 0.05 +``` + +### 4) Enable CSV (NOT default) +``` +./run.sh --csv ./sysbench_out/sysbench.csv +``` + +### 5) CPU time focus (reduce noise) +You can’t “run only CPU” without editing the script, but you can reduce runtime: +``` +./run.sh --iterations 1 --time 15 --cpu-max-prime 20000 --threads-list "4" +``` +Then read: +- console `ITER_SUMMARY ... cpu_time_sec=...` +- `OUT_DIR/cpu_t4.values` +- CSV rows (if enabled) + +### 6) Memory bandwidth focus (use seq vs rnd) +``` +MEMORY_ACCESS_MODE=seq ./run.sh --iterations 1 --threads-list "4" +MEMORY_ACCESS_MODE=rnd ./run.sh --iterations 1 --threads-list "4" +``` + +### 7) File I/O on tmpfs (recommended for CI) +``` +FILEIO_DIR=/tmp/sysbench_fileio ./run.sh --iterations 1 --threads-list "4" +``` + +### 8) File I/O heavier workload (be careful) +``` +FILEIO_DIR=/tmp/sysbench_fileio FILE_TOTAL_SIZE=1G FILE_BLOCK_SIZE=4K FILE_NUM=4 ./run.sh --iterations 1 --threads-list "4" +``` + +### 9) Verifying seq/rnd IO KPIs +After the run, check: +- `sysbench_summary.txt` for: + - `fileio_seqwr_mbps`, `fileio_seqrd_mbps`, `fileio_rndwr_mbps`, `fileio_rndrd_mbps` +- per-iteration logs: + - `fileio_*_iter*.log` + +--- + +## LAVA YAML integration + +Your LAVA test definition should: +- `cd Runner/suites/Performance/Sysbench_Performance/` +- run `./run.sh` +- publish `Sysbench_Performance.res` via `send-to-lava.sh` + +Keep `CSV_FILE` empty by default (to avoid extra artifacts) and enable only when you explicitly need CSV. + +--- + +## License + +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause-Clear From 3511269997d7deb8563e70205e27e412ddf4379e Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Fri, 26 Dec 2025 16:12:05 +0530 Subject: [PATCH 6/6] lava(sysbench): add Sysbench_Performance job template Provide LAVA YAML to run sysbench suite on target devices. Expose key parameters (threads, iterations, delta, taskset). Store logs and summaries as job artifacts for analysis. Signed-off-by: Srikanth Muppandam --- .../Sysbench_Performance.yaml | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Runner/suites/Performance/Sysbench_Performance/Sysbench_Performance.yaml diff --git a/Runner/suites/Performance/Sysbench_Performance/Sysbench_Performance.yaml b/Runner/suites/Performance/Sysbench_Performance/Sysbench_Performance.yaml new file mode 100644 index 00000000..4a01befe --- /dev/null +++ b/Runner/suites/Performance/Sysbench_Performance/Sysbench_Performance.yaml @@ -0,0 +1,72 @@ +metadata: + name: sysbench-performance + format: "Lava-Test Test Definition 1.0" + description: "Sysbench performance suite (CPU / memory / threads / mutex + fileio seqwr/seqrd/rndwr/rndrd) with per-iteration logs + summary averages + optional baseline gating." + os: + - linux + scope: + - performance + - functional + +params: + OUT_DIR: "./logs_Sysbench_Performance" + + # Iteration controls + ITERATIONS: "3" + TIME: "30" + RAND_SEED: "1234" + THREADS_LIST: "4" # space-separated list, e.g. "1 4 8 16" + + # CPU + CPU_MAX_PRIME: "20000" + + # Threads test + THREAD_LOCKS: "20" + THREAD_YIELDS: "" # optional override; empty uses sysbench default + + # Memory test + MEMORY_OPER: "write" # read|write + MEMORY_ACCESS_MODE: "rnd" # seq|rnd + MEMORY_BLOCK_SIZE: "1M" + MEMORY_TOTAL_SIZE: "100G" # keep explicit for stability + + # Mutex test + MUTEX_NUM: "" + MUTEX_LOCKS: "" + MUTEX_LOOPS: "" + + # Core pinning (optional) + TASKSET_CPU_LIST: "" + + # Baselines + thresholds (optional gating; empty => report-only) + # If empty, run.sh may auto-pick ./sysbench_baseline.conf from the test folder (if present) + BASELINE_FILE: "" + ALLOWED_DEVIATION: "0.10" # 0.05..0.10 typical + + # Optional CSV append (NOT default). If empty, no CSV is written. + CSV_FILE: "" + + VERBOSE: "0" # 1|0 + + # ---------------- FileIO (storage-backed) ---------------- + # IMPORTANT: use storage-backed path (avoid tmpfs if you want stable IO numbers) + FILEIO_DIR: "/var/tmp/sysbench_fileio" + + # Stable fileio parameters (must match run.sh variable names) + FILEIO_TOTAL_SIZE: "1G" + FILEIO_NUM: "64" # <-- FIXED (was FILEIO_NUM_FILES, but run.sh reads FILEIO_NUM) + FILEIO_BLOCK_SIZE: "4K" + FILEIO_IO_MODE: "sync" # sync|async + FILEIO_FSYNC_FREQ: "0" + FILEIO_EXTRA_FLAGS: "none" # use "none" to disable extra flags in run.sh + + # NOTE: run.sh currently runs all 4 modes (seqwr seqrd rndwr rndrd) unconditionally. + # If you want FILEIO_MODE_LIST support, run.sh must be updated accordingly. + # FILEIO_MODE_LIST: "seqwr seqrd rndwr" + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Performance/Sysbench_Performance/ + - ./run.sh || true + - $REPO_PATH/Runner/utils/send-to-lava.sh Sysbench_Performance.res || true