#!/usr/bin/env bash set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" LOG_DIR="${REPO_ROOT}/_logs" SOF_BIN_ROOT="${SOF_BIN_ROOT:-/var/tmp/sof-bin-upgrade/sof-bin-2025.12.2}" SOF_LOGGER="${SOF_LOGGER:-${SOF_BIN_ROOT}/tools/sof-logger}" SOF_LDC_DEFAULT="${SOF_LDC_DEFAULT:-${SOF_BIN_ROOT}/sof/sof-cml.ldc}" mkdir -p "${LOG_DIR}" ts="$(date +%Y%m%d_%H%M%S)" start_ts_human="$(date '+%F %T')" sof_log="${LOG_DIR}/sof-logger_${ts}.log" kernel_log="${LOG_DIR}/kernel_sof_ipc_${ts}.log" pipewire_log="${LOG_DIR}/user_pipewire_${ts}.log" sof_debug_snapshot="${LOG_DIR}/sof-debugfs_${ts}.txt" echo "[INFO] repo=${REPO_ROOT}" echo "[INFO] log_dir=${LOG_DIR}" echo "[INFO] start_ts=${start_ts_human}" echo if [[ "${EUID}" -ne 0 ]]; then echo "[ERROR] 请用 sudo 运行:sudo bash scripts/sof-trace-capture.sh" >&2 exit 1 fi echo "[STEP] 1) 确保 debugfs 已挂载 (/sys/kernel/debug)" if ! mountpoint -q /sys/kernel/debug; then mount -t debugfs none /sys/kernel/debug fi if [[ ! -d /sys/kernel/debug ]]; then echo "[ERROR] /sys/kernel/debug 不存在?" >&2 exit 1 fi echo "[INFO] debugfs: OK" echo echo "[STEP] 2) 检查 sof-logger 工具" if [[ ! -x "${SOF_LOGGER}" ]]; then echo "[ERROR] 找不到可执行的 sof-logger:" >&2 echo " ${SOF_LOGGER}" >&2 echo " 可通过环境变量覆盖:SOF_BIN_ROOT 或 SOF_LOGGER" >&2 exit 1 fi echo "[INFO] sof-logger=${SOF_LOGGER}" echo echo "[STEP] 2.1) 确认 SOF dictionary (.ldc)" SOF_LDC="${SOF_LDC:-${SOF_LDC_DEFAULT}}" if [[ ! -e "${SOF_LDC}" ]]; then echo "[ERROR] 未找到 SOF .ldc 文件:" >&2 echo " ${SOF_LDC}" >&2 echo " 可通过环境变量覆盖:SOF_LDC" >&2 exit 1 fi echo "[INFO] SOF_LDC=${SOF_LDC}" echo echo "[STEP] 2.2) 确认 debugfs 下的 SOF trace 节点" # We expect one of these to exist when SOF is running. SOF_TRACE_NODE="" SOF_TRACE_MODE="" for p in /sys/kernel/debug/sof/trace /sys/kernel/debug/sof/etrace; do if [[ -e "$p" ]]; then SOF_TRACE_NODE="$p" if [[ "$p" == */trace ]]; then SOF_TRACE_MODE="trace" else SOF_TRACE_MODE="etrace" fi break fi done if [[ -z "${SOF_TRACE_NODE}" ]]; then echo "[ERROR] 未找到 /sys/kernel/debug/sof/{trace,etrace}(可能权限或内核配置问题)" >&2 echo " 你可以先用 root 查看:ls -la /sys/kernel/debug/sof" >&2 exit 1 fi echo "[INFO] SOF_TRACE_NODE=${SOF_TRACE_NODE}" echo "[INFO] SOF_TRACE_MODE=${SOF_TRACE_MODE}" echo echo "[STEP] 2.3) 记录 SOF debugfs 快照(用于后续定位)" { echo "=== snapshot ts=${start_ts_human} ===" echo "SOF_TRACE_NODE=${SOF_TRACE_NODE}" echo "SOF_TRACE_MODE=${SOF_TRACE_MODE}" echo echo "## ls -la /sys/kernel/debug/sof" ls -la /sys/kernel/debug/sof 2>&1 || true echo for f in fw_version dsp_state ipc4_fw_status ipc4_bldr_status; do if [[ -e "/sys/kernel/debug/sof/${f}" ]]; then echo "## cat /sys/kernel/debug/sof/${f}" cat "/sys/kernel/debug/sof/${f}" 2>&1 || true echo fi done } > "${sof_debug_snapshot}" 2>&1 || true echo "[DONE] sof debugfs snapshot: ${sof_debug_snapshot}" cleanup() { echo echo "[STEP] 4) 收集日志窗口 (since ${start_ts_human})" # Kernel: capture SOF/ASoC/HDMI related lines since start journalctl -k -b --since "${start_ts_human}" --no-pager 2>/dev/null | \ grep -nE 'sof-audio|snd_sof|sof_ipc3_pcm_hw_params|ipc tx error|STREAM_PCM_PARAMS|ASoC error|set_hw_params|HDMI[0-9]|pcm[0-9]+' \ > "${kernel_log}" || true # User PipeWire: capture since start journalctl --user -u pipewire -b --since "${start_ts_human}" --no-pager 2>/dev/null \ > "${pipewire_log}" || true echo "[DONE] sof-logger: ${sof_log}" echo "[DONE] kernel window: ${kernel_log}" echo "[DONE] pipewire window: ${pipewire_log}" echo echo "[NEXT] 请把这三份日志发我分析:" echo " - ${sof_log}" echo " - ${kernel_log}" echo " - ${pipewire_log}" } trap cleanup INT TERM EXIT echo echo "[STEP] 3) 开始抓取 SOF trace(前台运行,按 Ctrl+C 结束并收集窗口日志)" echo "[ACTION] 现在请在另一个终端复现一次问题(例如触发 HDMI pcm2 的播放/切换)。" echo echo "[INFO] capturing to: ${sof_log}" echo # sof-logger 参数说明(关键): # -l: 传入 .ldc dictionary(不是输出文件) # -t: 选择 DMA trace stream(会强制读取 /sys/kernel/debug/sof/trace) # -i/-o: 将输入流解码输出到文件 echo "[INFO] NOTE: etrace 通常是“读完当前缓冲就退出”,所以这里使用循环追加,直到 Ctrl+C。" echo touch "${sof_log}" echo "=== sof-trace-capture start ${start_ts_human} ===" >> "${sof_log}" capture_once() { local tmp="${LOG_DIR}/.sof-logger_${ts}.tmp" rm -f "${tmp}" if [[ "${SOF_TRACE_MODE}" == "trace" ]]; then "${SOF_LOGGER}" -l "${SOF_LDC}" -t -i "${SOF_TRACE_NODE}" -o "${tmp}" || true else # etrace mailbox: do NOT pass -t, otherwise sof-logger will try /sys/kernel/debug/sof/trace "${SOF_LOGGER}" -l "${SOF_LDC}" -i "${SOF_TRACE_NODE}" -o "${tmp}" || true fi if [[ -s "${tmp}" ]]; then { echo echo "=== sof-logger chunk @ $(date '+%F %T') ===" cat "${tmp}" } >> "${sof_log}" fi rm -f "${tmp}" } while true; do capture_once sleep 0.2 done