|
9 | 9 | from io import StringIO |
10 | 10 | from pathlib import Path |
11 | 11 | from eudoxia.simulator import run_simulator, parse_args_with_defaults, get_param_defaults |
| 12 | +from eudoxia.utils import Priority |
12 | 13 | from eudoxia.scheduler.decorators import SCHEDULING_ALGOS |
13 | 14 | from eudoxia.workload.csv_io import CSVWorkloadReader, CSVWorkloadWriter, WorkloadTraceGenerator |
14 | 15 | from eudoxia.workload import WorkloadGenerator |
@@ -53,25 +54,58 @@ def run_command(params_file, workload=None): |
53 | 54 | print(f" Assignments: {stats.assignments}") |
54 | 55 | print(f" Suspensions: {stats.suspensions}") |
55 | 56 | print(f" Failures: {stats.failures}") |
56 | | - print(f" Failure/error counts: {stats.failure_error_counts}") |
| 57 | + print(f" Container failure counts: {stats.failure_error_counts}") |
57 | 58 | print(f" Mean memory allocated: {stats.mean_memory_allocated_percent:.1f}%") |
58 | 59 | print(f" Mean memory consumed: {stats.mean_memory_consumed_percent:.1f}%") |
59 | 60 | print() |
60 | 61 | print(" Pipeline Stats:") |
61 | | - print(" " + "-" * 68) |
62 | | - print(f" {'Priority':<15} {'Arrived':>10} {'Completed':>10} {'Mean (s)':>12} {'P99 (s)':>12}") |
63 | | - print(" " + "-" * 68) |
| 62 | + print(" " + "-" * 80) |
| 63 | + print(f" {'Priority':<15} {'Arrived':>10} {'Completed':>10} {'Timed Out':>10} {'Mean (s)':>12} {'P99 (s)':>12}") |
| 64 | + print(" " + "-" * 80) |
64 | 65 | pipeline_stats = [ |
65 | 66 | ("All", stats.pipelines_all), |
66 | 67 | ("Query", stats.pipelines_query), |
67 | 68 | ("Interactive", stats.pipelines_interactive), |
68 | 69 | ("Batch", stats.pipelines_batch), |
69 | 70 | ] |
70 | 71 | for name, pstats in pipeline_stats: |
71 | | - print(f" {name:<15} {pstats.arrival_count:>10} {pstats.completion_count:>10} {pstats.mean_latency_seconds:>12.2f} {pstats.p99_latency_seconds:>12.2f}") |
72 | | - print(" " + "-" * 68) |
| 72 | + print(f" {name:<15} {pstats.arrival_count:>10} {pstats.completion_count:>10} {pstats.timeout_count:>10} {pstats.mean_latency_seconds:>12.2f} {pstats.p99_latency_seconds:>12.2f}") |
| 73 | + print(" " + "-" * 80) |
73 | 74 | print() |
74 | | - print(f" Adjusted latency: {stats.adjusted_latency():.2f}s") |
| 75 | + |
| 76 | + # print adjusted latency, which puts more weight to high-priority |
| 77 | + # jobs (like query). |
| 78 | + # |
| 79 | + # it also penalizes the metric for unfinished work, with the |
| 80 | + # approach depending on whether there is a max job time. When |
| 81 | + # max_job_seconds is set, each unfinished pipeline is assigned a |
| 82 | + # penalty latency of 2x the max job time. Otherwise, the weighted |
| 83 | + # mean latency is divided by the completion rate (so finishing half |
| 84 | + # the work doubles the metric). |
| 85 | + weights = { |
| 86 | + Priority.QUERY: 10, |
| 87 | + Priority.INTERACTIVE: 5, |
| 88 | + Priority.BATCH_PIPELINE: 1, |
| 89 | + } |
| 90 | + max_job_seconds = params["max_job_seconds"] |
| 91 | + if max_job_seconds > 0: |
| 92 | + penalty = 2 * max_job_seconds |
| 93 | + adjusted = stats.adjusted_latency( |
| 94 | + weights=weights, |
| 95 | + divide_by_completion_rate=False, |
| 96 | + unfinished_penalty_seconds=penalty, |
| 97 | + ) |
| 98 | + print(f" Adjusted latency: {adjusted:.2f}s") |
| 99 | + print(f" (weights: query={weights[Priority.QUERY]}, interactive={weights[Priority.INTERACTIVE]}, batch={weights[Priority.BATCH_PIPELINE]}; " |
| 100 | + f"unfinished penalty: {penalty}s = 2 * max_job_seconds)") |
| 101 | + else: |
| 102 | + adjusted = stats.adjusted_latency( |
| 103 | + weights=weights, |
| 104 | + divide_by_completion_rate=True, |
| 105 | + ) |
| 106 | + print(f" Adjusted latency: {adjusted:.2f}s") |
| 107 | + print(f" (weights: query={weights[Priority.QUERY]}, interactive={weights[Priority.INTERACTIVE]}, batch={weights[Priority.BATCH_PIPELINE]}; " |
| 108 | + f"divided by completion rate)") |
75 | 109 |
|
76 | 110 |
|
77 | 111 | def gentrace_command(params_file, output_file, force=False): |
|
0 commit comments