|
| 1 | +import sys |
| 2 | +import json |
| 3 | +import numpy as np |
| 4 | +import matplotlib |
| 5 | +matplotlib.use("Agg") |
| 6 | +import matplotlib.pyplot as plt |
| 7 | + |
| 8 | +PERCENTILE_MAP = { |
| 9 | + 50: "fiftieth", |
| 10 | + 95: "ninetyFifth", |
| 11 | + 98: "ninetyEighth", |
| 12 | + 99: "ninetyNinth", |
| 13 | +} |
| 14 | + |
| 15 | +if len(sys.argv) != 2 or not sys.argv[1].isdigit() or int(sys.argv[1]) not in PERCENTILE_MAP: |
| 16 | + print(f"Usage: python plot_metrics.py <percentile>") |
| 17 | + print(f"Valid percentiles: {sorted(PERCENTILE_MAP)}") |
| 18 | + sys.exit(1) |
| 19 | + |
| 20 | +percentile = int(sys.argv[1]) |
| 21 | +percentile_key = PERCENTILE_MAP[percentile] |
| 22 | + |
| 23 | +with open("direct.json") as f: |
| 24 | + direct = json.load(f) |
| 25 | + |
| 26 | +with open("gateway.json") as f: |
| 27 | + gateway = json.load(f) |
| 28 | + |
| 29 | +def extract_data(data, key): |
| 30 | + ops = {} |
| 31 | + for entry in data: |
| 32 | + num_users = entry["numUsers"] |
| 33 | + for op in entry["operations"]: |
| 34 | + name = op["name"] |
| 35 | + if name not in ops: |
| 36 | + ops[name] = {"numUsers": [], "latency": []} |
| 37 | + ops[name]["numUsers"].append(num_users) |
| 38 | + ops[name]["latency"].append(op["latencyPercentiles"][key]) |
| 39 | + return ops |
| 40 | + |
| 41 | +def smooth(x, y): |
| 42 | + x = np.array(x) |
| 43 | + y = np.array(y) |
| 44 | + coeffs = np.polyfit(x, y, deg=min(2, len(x) - 1)) |
| 45 | + x_smooth = np.linspace(x.min(), x.max(), 300) |
| 46 | + y_smooth = np.polyval(coeffs, x_smooth) |
| 47 | + return x_smooth, y_smooth |
| 48 | + |
| 49 | +direct_ops = extract_data(direct, percentile_key) |
| 50 | +gateway_ops = extract_data(gateway, percentile_key) |
| 51 | + |
| 52 | +operation_names = list(direct_ops.keys()) |
| 53 | + |
| 54 | +fig, axes = plt.subplots(1, len(operation_names), figsize=(5 * len(operation_names), 5)) |
| 55 | +fig.suptitle(f"{percentile}th Percentile Latency by Operation", fontsize=14, fontweight="bold", y=1.02) |
| 56 | + |
| 57 | +for ax, name in zip(axes, operation_names): |
| 58 | + for ops, label, marker, color in [ |
| 59 | + (direct_ops, "Direct", "o", "tab:blue"), |
| 60 | + (gateway_ops, "Gateway", "s", "tab:orange"), |
| 61 | + ]: |
| 62 | + x = ops[name]["numUsers"] |
| 63 | + y = ops[name]["latency"] |
| 64 | + x_smooth, y_smooth = smooth(x, y) |
| 65 | + ax.plot(x_smooth, y_smooth, color=color, linewidth=1.5) |
| 66 | + ax.plot(x, y, marker=marker, linestyle="None", color=color, label=label) |
| 67 | + |
| 68 | + ax.set_title(name) |
| 69 | + ax.set_xlabel("Number of Users") |
| 70 | + ax.set_ylabel(f"Latency p{percentile} (ms)") |
| 71 | + ax.legend() |
| 72 | + ax.grid(True) |
| 73 | + |
| 74 | +plt.tight_layout() |
| 75 | +output_file = f"metrics_p{percentile}.png" |
| 76 | +plt.savefig(output_file, dpi=150, bbox_inches="tight") |
| 77 | +print(f"Saved {output_file}") |
0 commit comments