#!/usr/bin/env python3 """Parse ALSA status log file and plot avail value over time.""" import sys import re import os from datetime import datetime import matplotlib.pyplot as plt TIMESTAMP_RE = re.compile(r"^===== (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+) =====") AVAIL_RE = re.compile(r"^avail\s*:\s*(\d+)") def parse_log(log_path): timestamps = [] avail_values = [] with open(log_path, "r") as f: current_timestamp = None for line in f: line = line.strip() # Check for timestamp line ts_match = TIMESTAMP_RE.match(line) if ts_match: current_timestamp = datetime.strptime(ts_match.group(1), "%Y-%m-%d %H:%M:%S.%f") continue # Check for avail line (only if we have a timestamp) if current_timestamp: avail_match = AVAIL_RE.match(line) if avail_match: timestamps.append(current_timestamp) avail_values.append(int(avail_match.group(1))) current_timestamp = None # Reset until next timestamp if not timestamps: print("No valid timestamp/avail pairs found in the log file.", file=sys.stderr) sys.exit(1) # Convert to relative seconds from first timestamp t0 = timestamps[0] seconds = [(t - t0).total_seconds() for t in timestamps] return seconds, avail_values def plot(seconds, avail_values, out_path): plt.figure(figsize=(12, 6)) plt.plot(seconds, avail_values, label="avail", linewidth=1, alpha=0.7) # Add moving average (windowed mean) if len(avail_values) >= 10: # Only if we have enough data points window_size = min(50, len(avail_values) // 10) # Adaptive window size import numpy as np moving_avg = np.convolve(avail_values, np.ones(window_size)/window_size, mode='valid') # Adjust timestamps for the moving average (they align with window centers) ma_seconds = seconds[window_size-1:] plt.plot(ma_seconds, moving_avg, label=f"moving mean (window={window_size})", linewidth=2) plt.xlabel("Time (s)") plt.ylabel("Available samples") plt.title("ALSA Available Samples Over Time") plt.legend() plt.grid(True) plt.tight_layout() plt.savefig(out_path, dpi=150) print(f"Plot saved to {out_path}") def main(): if len(sys.argv) != 2: print(f"Usage: {sys.argv[0]} ", file=sys.stderr) sys.exit(1) log_path = sys.argv[1] if not os.path.isfile(log_path): print(f"File not found: {log_path}", file=sys.stderr) sys.exit(1) seconds, avail_values = parse_log(log_path) log_dir = os.path.dirname(os.path.abspath(log_path)) log_base = os.path.splitext(os.path.basename(log_path))[0] out_path = os.path.join(log_dir, f"{log_base}_avail_plot.png") plot(seconds, avail_values, out_path) if __name__ == "__main__": main()