namespace Azaion.Missions.E2E.Helpers; /// /// Median + percentile helper for the NFT-PERF-* and NFT-RES-LIM-01 /// scenarios. Inputs are wall-clock latency samples (or RSS samples) /// in any orderable numeric type; the helper sorts a defensive copy /// and uses the "nearest-rank" definition of percentile (matching the /// percentile defaults used in `docker stats` and most CI dashboards). /// public static class LatencyPercentiles { public static double P50(IReadOnlyList samples) => Percentile(samples, 50); public static double P95(IReadOnlyList samples) => Percentile(samples, 95); public static double Percentile(IReadOnlyList samples, int percentile) { if (samples.Count == 0) throw new ArgumentException("samples must contain at least one value", nameof(samples)); if (percentile < 0 || percentile > 100) throw new ArgumentOutOfRangeException(nameof(percentile), "percentile must be in [0, 100]"); var sorted = samples.ToArray(); Array.Sort(sorted); // Nearest-rank: rank = ceil(p/100 * N); index = rank - 1. var rank = (int)Math.Ceiling(percentile / 100.0 * sorted.Length); if (rank < 1) rank = 1; if (rank > sorted.Length) rank = sorted.Length; return sorted[rank - 1]; } public static double Mean(IReadOnlyList samples) { if (samples.Count == 0) throw new ArgumentException("samples must contain at least one value", nameof(samples)); return samples.Average(); } }