#!/usr/bin/env python3 """ CLI entry point for disk-checker. Usage: python -m disk_checker scan_latency.csv disk-checker scan_latency.csv --metric read_clat --unit ms """ import argparse import sys from pathlib import Path from disk_checker.core.extractor import load_latency_csv from disk_checker.core.helpers import percentile_table from disk_checker.plotting.plots import generate_plot def main(): parser = argparse.ArgumentParser( description="Plot fio json+ wide-format latency CSV." ) parser.add_argument("csv", help="CSV from fio_jsonplus_clat2csv") parser.add_argument("--metric", default=None, help="Metric to plot (e.g. read_clat). " "If omitted, the metric with the most I/Os is used.") parser.add_argument("--all-metrics", action="store_true", help="Plot every metric that has data") parser.add_argument("--unit", choices=["ns", "us", "ms", "s"], default="us", help="X-axis latency unit (default: us)") parser.add_argument("--log-y", action="store_true") parser.add_argument("--log-x", action="store_true") parser.add_argument("--cdf", action="store_true", help="Add a CDF subplot below the histogram") parser.add_argument("--cdf-only", action="store_true") parser.add_argument("--normalize", action="store_true", help="Normalize histogram to a probability density") parser.add_argument("--percentiles", default="50,90,99,99.9,99.99") parser.add_argument("--no-percentiles", action="store_true") parser.add_argument("--output", "-o", default=None) parser.add_argument("--dpi", type=int, default=150) parser.add_argument("--title", default="") parser.add_argument("--show", action="store_true") args = parser.parse_args() if not Path(args.csv).is_file(): sys.exit(f"error: file not found: {args.csv}") df = load_latency_csv(args.csv) if df.empty: sys.exit("error: no latency data in CSV") available = sorted(df["metric"].unique()) print("Metrics with data:", ", ".join(available)) if args.all_metrics: metrics = available elif args.metric: if args.metric not in available: sys.exit(f"error: metric {args.metric!r} not in {available}") metrics = [args.metric] else: totals = df.groupby("metric")["count"].sum().sort_values(ascending=False) metrics = [totals.index[0]] print(f"Auto-selected metric: {metrics[0]}") output = args.output or f"{Path(args.csv).stem}_latency.png" generate_plot( df=df, metrics=metrics, output_path=Path(output), unit=args.unit, log_y=args.log_y, log_x=args.log_x, normalize=args.normalize, show_cdf=args.cdf, cdf_only=args.cdf_only, title=args.title, dpi=args.dpi, ) print(f"Saved plot to {output}") if not args.no_percentiles: try: pcts = [float(x) for x in args.percentiles.split(",") if x.strip()] except ValueError: sys.exit("error: --percentiles must be comma-separated numbers") for m in metrics: print(percentile_table(df, m, args.unit, pcts)) if args.show: import matplotlib.pyplot as plt plt.show() if __name__ == "__main__": main()