157 lines
4.2 KiB
Python
157 lines
4.2 KiB
Python
"""
|
||
05_visualize_runs.py – Detaillierte Zeitreihen-Visualisierung der Läufe
|
||
======================================================================
|
||
Visualisiert pro Lauf:
|
||
- Durchsatz (Net_out / network_sent_mb_s)
|
||
- Net_in (network_recv_mb_s)
|
||
- CPU-Auslastung (%)
|
||
- RAM-Verbrauch (MB)
|
||
- Injektions-Fenster (Hintergrund-Shading)
|
||
- Detektierte Anomalien (Marker)
|
||
"""
|
||
|
||
import sys
|
||
|
||
import matplotlib.dates as mdates
|
||
import matplotlib.pyplot as plt
|
||
import pandas as pd
|
||
|
||
sys.path.insert(0, ".")
|
||
from config import *
|
||
|
||
|
||
def _to_utc(ts):
|
||
ts = pd.Timestamp(ts)
|
||
return ts.tz_localize("UTC") if ts.tzinfo is None else ts.tz_convert("UTC")
|
||
|
||
|
||
def plot_run_details(run_key: str, windows_df: pd.DataFrame):
|
||
print(f" Erstelle Plot für {run_key}...")
|
||
|
||
# 1. Daten laden
|
||
try:
|
||
bm = load_baseline_metrics(run_key)
|
||
anom = load_anomalies(run_key)
|
||
except Exception as e:
|
||
print(f" Fehler beim Laden der Daten für {run_key}: {e}")
|
||
return
|
||
|
||
# Zeitstempel normalisieren
|
||
bm["timestamp"] = bm["timestamp"].apply(_to_utc)
|
||
anom["timestamp"] = anom["timestamp"].apply(_to_utc)
|
||
|
||
# Injektionen für diesen Lauf filtern
|
||
inj = windows_df[windows_df["run"] == run_key].copy()
|
||
|
||
# Plot-Setup: 3 Subplots (Netzwerk, CPU, RAM)
|
||
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(16, 10), sharex=True)
|
||
|
||
# --- Subplot 1: Netzwerk ---
|
||
ax1.plot(
|
||
bm["timestamp"],
|
||
bm["network_sent_mb_s"],
|
||
color="tab:blue",
|
||
lw=1.2,
|
||
label="Net Out (Throughput)",
|
||
)
|
||
ax1.plot(
|
||
bm["timestamp"],
|
||
bm["network_recv_mb_s"],
|
||
color="tab:cyan",
|
||
lw=0.8,
|
||
alpha=0.6,
|
||
label="Net In",
|
||
)
|
||
ax1.set_ylabel("Durchsatz [MB/s]")
|
||
ax1.set_title(f"Detaillierter Laufverlauf: {run_key}")
|
||
ax1.legend(loc="upper right", fontsize=8)
|
||
|
||
# --- Subplot 2: CPU ---
|
||
ax2.plot(
|
||
bm["timestamp"],
|
||
bm["cpu_percent"],
|
||
color="tab:green",
|
||
lw=1.0,
|
||
label="CPU Auslastung",
|
||
)
|
||
# Detektierte Anomalien einzeichnen (als Punkte auf der CPU-Linie)
|
||
detected_only = anom[anom["is_anomaly"] == True]
|
||
if not detected_only.empty:
|
||
ax2.scatter(
|
||
detected_only["timestamp"],
|
||
[2] * len(detected_only),
|
||
color="red",
|
||
s=25,
|
||
label="Pipeline Alarm",
|
||
zorder=5,
|
||
marker="^",
|
||
)
|
||
|
||
ax2.set_ylabel("CPU [%]")
|
||
ax2.set_ylim(0, 100)
|
||
ax2.legend(loc="upper right", fontsize=8)
|
||
|
||
# --- Subplot 3: RAM ---
|
||
ax3.plot(
|
||
bm["timestamp"],
|
||
bm["memory_used_mb"],
|
||
color="tab:purple",
|
||
lw=1.2,
|
||
label="RAM Used",
|
||
)
|
||
ax3.set_ylabel("RAM [MB]")
|
||
ax3.set_xlabel("Zeit [UTC]")
|
||
ax3.legend(loc="upper right", fontsize=8)
|
||
|
||
# --- Anomalie-Bänder über alle Subplots ---
|
||
for _, row in inj.iterrows():
|
||
t0, t1 = _to_utc(row["t_inj"]), _to_utc(row["t_stop"])
|
||
for ax in [ax1, ax2, ax3]:
|
||
ax.axvspan(t0, t1, color="red", alpha=0.1, zorder=0)
|
||
if ax == ax1:
|
||
ax.text(
|
||
t0,
|
||
ax.get_ylim()[1] * 0.9,
|
||
row["scenario"],
|
||
rotation=90,
|
||
color="darkred",
|
||
fontsize=7,
|
||
va="top",
|
||
alpha=0.7,
|
||
)
|
||
|
||
for ax in [ax1, ax2, ax3]:
|
||
ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M:%S"))
|
||
ax.grid(True, alpha=0.3)
|
||
|
||
plt.tight_layout()
|
||
save_fig(f"05_details_{run_key}")
|
||
|
||
|
||
def main():
|
||
print_section("05 – Detaillierte Zeitreihen-Visualisierung")
|
||
|
||
try:
|
||
windows_df = pd.read_csv(OUTPUT_DIR / "injection_windows.csv")
|
||
except:
|
||
print(
|
||
" Fehler: injection_windows.csv nicht gefunden. Bitte erst 01_ground_truth.py ausführen."
|
||
)
|
||
return
|
||
|
||
sample_runs = [
|
||
"full_cycle_run1",
|
||
"high_bw_run1",
|
||
"high_iops_run1",
|
||
"batch_out_run1",
|
||
]
|
||
|
||
for run_key in sample_runs:
|
||
if run_key in RUNS:
|
||
plot_run_details(run_key, windows_df)
|
||
|
||
print(f"\n→ Detaillierte Plots unter {OUTPUT_DIR}/05_details_*.png gespeichert.")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|