| 431 | |
| 432 | |
| 433 | def _print_report(report: dict) -> None: |
| 434 | print(f"mode: {report['mode']} url: {report['url']}") |
| 435 | print( |
| 436 | f"requests: total={report['total']} ok={report['ok']} fail={report['fail']} " |
| 437 | f"rps_achieved={report['rps_achieved']:.2f}" |
| 438 | ) |
| 439 | if report["fail"]: |
| 440 | print(f"failures by status: {report['status_hist']}") |
| 441 | if report["err_hist"]: |
| 442 | print(f"failures by exception: {report['err_hist']}") |
| 443 | if report.get("scheduler"): |
| 444 | sch = report["scheduler"] |
| 445 | print( |
| 446 | f"scheduler: scheduled={sch['scheduled']} dropped={sch['dropped']} " |
| 447 | f"in_flight_peak={sch['in_flight_peak']}" |
| 448 | ) |
| 449 | st = report["latency_ms"] |
| 450 | if st: |
| 451 | print( |
| 452 | f"latency ms: p50={st['p50']:.0f} p90={st['p90']:.0f} " |
| 453 | f"p95={st['p95']:.0f} p99={st['p99']:.0f} max={st['max']:.0f} " |
| 454 | f"mean={st['mean']:.0f}" |
| 455 | ) |
| 456 | if report["ok"]: |
| 457 | print(f"response bytes (mean): {report['response_bytes_mean']:.0f}") |
| 458 | if "buckets" in report: |
| 459 | print("\nper-bucket (latency is ok-only):") |
| 460 | print( |
| 461 | f" {'t0_s':>6} {'n':>5} {'ok':>5} {'fail':>5} {'rps':>6} " |
| 462 | f"{'p50':>6} {'p95':>6} {'p99':>6} {'max':>6}" |
| 463 | ) |
| 464 | for b in report["buckets"]: |
| 465 | if b["n"] == 0: |
| 466 | print(f" {b['bucket_s']:>6.0f} {'-':>5}") |
| 467 | continue |
| 468 | print( |
| 469 | f" {b['bucket_s']:>6.0f} {b['n']:>5} {b['ok']:>5} {b['fail']:>5} " |
| 470 | f"{b['rps']:>6.1f} {b['p50']:>6.0f} {b['p95']:>6.0f} " |
| 471 | f"{b['p99']:>6.0f} {b['max']:>6.0f}" |
| 472 | ) |
| 473 | |
| 474 | |
| 475 | # --- slow-read attack ------------------------------------------------------- |