feat(pwr): Log AMD CPU package power in the Script 4 loop

avt_pmpower.sh runs AVTCMD -module pmm "get_pmdata()" and summarizes
SktPwr, PPT Fast / Slow against their limits, and MemPwr. -p takes the
AVTCMD path, -q drops the raw PM table. Exit 2 = AVTCMD missing,
3 = AVTCMD failed, 4 = nothing parsed. The values are SMU telemetry, not
a measurement.

Script 4 calls it every round after the two TH6_SWB power readbacks, so
switch rails and CPU package power sit side by side in each sample.

AVT is under NDA and not shipped in Blanton_Script. It has to be
unpacked on the DUT at ~/AVT_Linux_NDA_2.8.37/ beforehand; otherwise the
call exits 2 each round and the loop continues without the reading.
Without -q the full PM table is logged once a minute.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UniUXkxgCG2Ty74advL8Pd
This commit is contained in:
2026-09-23 14:43:28 +08:00
co-authored by Claude Opus 5.5
parent 4ce4d6c62e
commit 0ad76ea8b0
2 changed files with 139 additions and 0 deletions
@@ -152,6 +152,8 @@ while 1
sendln "~/Blanton_Script/TH6_SWB0_power_readback.sh"
wait prompt_sonic_root
sendln "~/Blanton_Script/TH6_SWB1_power_readback.sh"
wait prompt_sonic_root
sendln "~/Blanton_Script/avt_pmpower.sh -p ~/AVT_Linux_NDA_2.8.37/AVTCMD"
; Background jobs Check
wait prompt_sonic_root
@@ -0,0 +1,137 @@
#!/bin/bash
#===============================================================================
# Script : avt_pmpower.sh
# Purpose : Dump AMD AVT PM table (get_pmdata) and summarize package power.
#
# Author : ETWen
# Date : 20260923
#
# Version History
# V1.0.0 20260923 Initial Version
#
# Usage : ./avt_pmpower.sh [-p <AVTCMD path>] [-q] [-h]
# -p Path to AVTCMD (default: $AVTCMD_PATH or ./AVTCMD)
# -q Quiet: summary only, suppress raw PM table
# -h Help
#
# Exit : 0 ok / 1 usage / 2 AVTCMD not found / 3 AVTCMD failed
# 4 parse failed (no power fields found)
#
# Note : Values come from SMU telemetry, not direct measurement. Absolute
# accuracy depends on BIOS SVI telemetry calibration. Cross-check
# against VR PMBus READ_POUT when accuracy matters.
#===============================================================================
set -u
set -o pipefail
#------------------------------------------------------------------------------
# Defaults
#------------------------------------------------------------------------------
AVTCMD_BIN="${AVTCMD_PATH:-./AVTCMD}"
AVT_MODULE="pmm"
AVT_CMD="get_pmdata()"
QUIET=0
#------------------------------------------------------------------------------
# usage - print help
#------------------------------------------------------------------------------
usage() {
sed -n '/^# Usage/,/^# Exit/p' "$0" | sed 's/^# \{0,1\}//'
}
#------------------------------------------------------------------------------
# Argument parsing
#------------------------------------------------------------------------------
while getopts ":p:qh" opt; do
case "$opt" in
p) AVTCMD_BIN="$OPTARG" ;;
q) QUIET=1 ;;
h) usage; exit 0 ;;
:) echo "ERROR: -$OPTARG requires an argument" >&2; usage >&2; exit 1 ;;
\?) echo "ERROR: unknown option -$OPTARG" >&2; usage >&2; exit 1 ;;
esac
done
#------------------------------------------------------------------------------
# Pre-flight check
#------------------------------------------------------------------------------
if [ ! -x "$AVTCMD_BIN" ]; then
echo "ERROR: AVTCMD not found or not executable: $AVTCMD_BIN" >&2
echo " Use -p <path> or export AVTCMD_PATH=<path>" >&2
exit 2
fi
if [ "$(id -u)" -ne 0 ]; then
echo "WARN : not running as root, AVTCMD may fail to access SMU." >&2
fi
#------------------------------------------------------------------------------
# Collect PM table
#------------------------------------------------------------------------------
RAW="$("$AVTCMD_BIN" -module "$AVT_MODULE" "$AVT_CMD" 2>&1)"
RC=$?
if [ $RC -ne 0 ]; then
echo "ERROR: AVTCMD exited with code $RC" >&2
echo "$RAW" >&2
exit 3
fi
if [ "$QUIET" -eq 0 ]; then
printf '%s\n' "$RAW"
fi
#------------------------------------------------------------------------------
# Parse & summarize
# - split on whitespace and comma, keep only "key:number" tokens
# - bracketed tokens ([Pkg:0], [MISC]) are skipped by the regex anchor
#------------------------------------------------------------------------------
printf '%s\n' "$RAW" | awk '
{
n = split($0, a, /[ ,]+/)
for (i = 1; i <= n; i++) {
if (a[i] ~ /^[A-Za-z0-9_()]+:[-0-9.]+$/) {
split(a[i], kv, ":")
m[kv[1]] = kv[2]
found++
}
}
}
# pct - usage against limit, guard divide-by-zero
function pct(v, l) {
return (l > 0) ? sprintf("%5.1f%%", 100 * v / l) : " n/a"
}
# has - field present in PM table
function has(k) {
return (k in m)
}
END {
if (found == 0) {
print "ERROR: no PM fields parsed, PM table format may have changed." > "/dev/stderr"
exit 4
}
print "===== Package Power (live) ====="
if (has("SktPwr(W)"))
printf "%-9s: %7.2f W\n", "SktPwr", m["SktPwr(W)"]
if (has("PPT_VALUE_FAST"))
printf "%-9s: %7.2f / %3d W %s\n", "PPT Fast",
m["PPT_VALUE_FAST"], m["PPT_LIMIT_FAST"],
pct(m["PPT_VALUE_FAST"], m["PPT_LIMIT_FAST"])
if (has("PPT_VALUE_SLOW"))
printf "%-9s: %7.2f / %3d W %s (%ss avg)\n", "PPT Slow",
m["PPT_VALUE_SLOW"], m["PPT_LIMIT_SLOW"],
pct(m["PPT_VALUE_SLOW"], m["PPT_LIMIT_SLOW"]),
(has("SlowPPTTimeConstant") ? m["SlowPPTTimeConstant"] : "?")
if (has("MemPwr(W)"))
printf "%-9s: %7.2f W\n", "MemPwr", m["MemPwr(W)"]
}
'
exit $?