Module: Perfgate::Comparison::WorkloadComparison
- Defined in:
- lib/perfgate/comparison/workload_comparison.rb
Overview
Matches baseline/candidate workloads by id and produces each workload's decision entry in the comparison-result document (spec 14.2), including the deterministic per-workload diagnostics (spec 20.3). Split out of Engine to keep both modules under RuboCop's module-length limit.
Constant Summary collapse
- SAMPLE_KEY_TO_METRIC =
Maps the raw sample keys instrumentation writes (spec section 13) to the metric names practical_thresholds/fingerprint config uses (spec section 16.4). gc_* keys are deliberately left unmapped: GC activity is diagnostic-only and never drives a decision.
{ "duration_ns" => "duration", "sql_count" => "sql_count", "sql_duration_ns" => "sql_duration", "allocations" => "allocations" }.freeze
Class Method Summary collapse
- .compare_all(baseline_run, candidate_run, config) ⇒ Object
- .compare_one(id, baseline_workload, candidate_workload, config) ⇒ Object
- .incomparable_workload_result(id) ⇒ Object
- .index_by_id(run) ⇒ Object
- .metric_decisions(baseline_workload, candidate_workload, config) ⇒ Object
- .missing_workload_result(id, reason) ⇒ Object
- .sample_keys(baseline_workload, candidate_workload) ⇒ Object
- .samples_for(workload, sample_key) ⇒ Object
- .workload_decision(metrics) ⇒ Object
Class Method Details
.compare_all(baseline_run, candidate_run, config) ⇒ Object
27 28 29 30 31 32 33 34 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 27 def compare_all(baseline_run, candidate_run, config) baseline_by_id = index_by_id(baseline_run) candidate_by_id = index_by_id(candidate_run) (baseline_by_id.keys | candidate_by_id.keys).map do |id| compare_one(id, baseline_by_id[id], candidate_by_id[id], config) end end |
.compare_one(id, baseline_workload, candidate_workload, config) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 40 def compare_one(id, baseline_workload, candidate_workload, config) return missing_workload_result(id, "new_workload") unless baseline_workload return missing_workload_result(id, "removed_workload") unless candidate_workload definition_changed = baseline_workload["definition_hash"] != candidate_workload["definition_hash"] return incomparable_workload_result(id) if definition_changed metrics = metric_decisions(baseline_workload, candidate_workload, config) { "id" => id, "decision" => workload_decision(metrics), "metrics" => metrics, "diagnostics" => Diagnostics.for_workload(metrics) } end |
.incomparable_workload_result(id) ⇒ Object
61 62 63 64 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 61 def incomparable_workload_result(id) { "id" => id, "decision" => "incomparable", "metrics" => {}, "diagnostics" => ["Workload definition changed since the baseline run; comparison skipped."] } end |
.index_by_id(run) ⇒ Object
36 37 38 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 36 def index_by_id(run) run.fetch("workloads", []).to_h { |workload| [workload["id"], workload] } end |
.metric_decisions(baseline_workload, candidate_workload, config) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 66 def metric_decisions(baseline_workload, candidate_workload, config) sample_keys(baseline_workload, candidate_workload).each_with_object({}) do |sample_key, acc| metric = SAMPLE_KEY_TO_METRIC[sample_key] next unless metric baseline_samples = samples_for(baseline_workload, sample_key) candidate_samples = samples_for(candidate_workload, sample_key) next if baseline_samples.empty? || candidate_samples.empty? acc[metric] = MetricDecision.call(metric: metric, baseline_samples: baseline_samples, candidate_samples: candidate_samples, config: config) end end |
.missing_workload_result(id, reason) ⇒ Object
52 53 54 55 56 57 58 59 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 52 def missing_workload_result(id, reason) = if reason == "new_workload" "new workload with no prior baseline run" else "workload removed since the baseline run" end { "id" => id, "decision" => reason, "metrics" => {}, "diagnostics" => [] } end |
.sample_keys(baseline_workload, candidate_workload) ⇒ Object
80 81 82 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 80 def sample_keys(baseline_workload, candidate_workload) (baseline_workload.fetch("summary", {}).keys + candidate_workload.fetch("summary", {}).keys).uniq end |
.samples_for(workload, sample_key) ⇒ Object
84 85 86 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 84 def samples_for(workload, sample_key) workload.fetch("samples", []).filter_map { |sample| sample[sample_key] } end |
.workload_decision(metrics) ⇒ Object
88 89 90 91 92 93 94 95 |
# File 'lib/perfgate/comparison/workload_comparison.rb', line 88 def workload_decision(metrics) decisions = metrics.values.map { |m| m["decision"] } return "fail" if decisions.include?("fail") return "warn" if decisions.include?("warn") return "inconclusive" if decisions.include?("inconclusive") && decisions.all? { |d| d != "pass" } "pass" end |