Module: Perfgate::Comparison::Diagnostics

Defined in:
lib/perfgate/comparison/diagnostics.rb

Overview

Simple, deterministic diagnostic rules (spec 20.3). These exist to point a reader at a likely explanation for a regression, never to claim a source-code root cause: "SQL query count increased by 5" is a fact about the sample data, not a guess about which line of code changed.

Class Method Summary collapse

Class Method Details

.allocations_rule(metrics) ⇒ Object



48
49
50
51
52
53
# File 'lib/perfgate/comparison/diagnostics.rb', line 48

def allocations_rule(metrics)
  metric = metrics["allocations"]
  return nil unless regressed?(metric)

  "Allocations increased by #{metric["change_percent"]}%."
end

.duration_without_resource_change_rule(metrics) ⇒ Object



55
56
57
58
59
60
61
62
# File 'lib/perfgate/comparison/diagnostics.rb', line 55

def duration_without_resource_change_rule(metrics)
  return nil unless regressed?(metrics["duration"])

  resource_metrics = metrics.values_at("sql_count", "sql_duration", "allocations").compact
  return nil if resource_metrics.empty? || resource_metrics.any? { |metric| metric["decision"] != "pass" }

  "Duration increased while SQL and allocation metrics remained stable."
end

.environment_changed_rules(compatibility) ⇒ Object



23
24
25
26
27
28
29
# File 'lib/perfgate/comparison/diagnostics.rb', line 23

def environment_changed_rules(compatibility)
  return [] if compatibility["status"] == "compatible"

  compatibility.fetch("differences", []).map do |difference|
    "Environment changed: #{difference["field"]} (#{difference["severity"]})."
  end
end

.for_workload(metrics) ⇒ Object



13
14
15
16
17
18
19
20
21
# File 'lib/perfgate/comparison/diagnostics.rb', line 13

def for_workload(metrics)
  [
    sql_count_rule(metrics),
    sql_duration_without_count_rule(metrics),
    allocations_rule(metrics),
    duration_without_resource_change_rule(metrics),
    *noise_rules(metrics)
  ].compact
end

.noise_rules(metrics) ⇒ Object



64
65
66
67
# File 'lib/perfgate/comparison/diagnostics.rb', line 64

def noise_rules(metrics)
  metrics.select { |_name, metric| metric["noisy"] }
         .map { |name, _metric| "Sample variability is high for #{name}; treat this decision with caution." }
end

.regressed?(metric_result) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/perfgate/comparison/diagnostics.rb', line 31

def regressed?(metric_result)
  metric_result && metric_result["decision"] != "pass" && (metric_result["absolute_change"] || 0).positive?
end

.sql_count_rule(metrics) ⇒ Object



35
36
37
38
39
40
# File 'lib/perfgate/comparison/diagnostics.rb', line 35

def sql_count_rule(metrics)
  metric = metrics["sql_count"]
  return nil unless regressed?(metric)

  "SQL query count increased by #{metric["absolute_change"].to_i}."
end

.sql_duration_without_count_rule(metrics) ⇒ Object



42
43
44
45
46
# File 'lib/perfgate/comparison/diagnostics.rb', line 42

def sql_duration_without_count_rule(metrics)
  return nil unless regressed?(metrics["sql_duration"]) && !regressed?(metrics["sql_count"])

  "SQL duration increased without a corresponding increase in query count."
end