Module: Polyrun::Benchmark::Profile
- Defined in:
- lib/polyrun/benchmark/profile.rb
Overview
Records benchmark output during performance specs and writes profile artifacts. Set POLYRUN_BENCH=1 to echo lines to stdout. JSON sidecar enables report-benchmark exports.
Constant Summary collapse
- STORAGE_KEY =
:polyrun_benchmark_profile_storage
Class Method Summary collapse
- .commit_sha(repository_root: default_repository_root) ⇒ Object
- .current_section_storage ⇒ Object
- .default_repository_root ⇒ Object
- .detect_section_title(line) ⇒ Object
- .export_extension(format) ⇒ Object
- .export_formats ⇒ Object
- .export_sidecars!(data, json_path) ⇒ Object
- .format_metric_line(metric) ⇒ Object
- .git_command(command, repository_root:) ⇒ Object
- .lines_storage ⇒ Object
- .log(message = "") ⇒ Object
- .metrics_storage ⇒ Object
- .output_path(repository_root: default_repository_root, extension: "log", commit_sha: nil, working_tree_clean: nil, timestamp: nil) ⇒ Object
- .profile_header(meta) ⇒ Object
- .profile_meta(repository_root: default_repository_root) ⇒ Object
- .record_metric!(name:, value:, unit: "seconds", section: nil) ⇒ Object
- .reset! ⇒ Object
- .snapshot ⇒ Object
- .storage ⇒ Object
- .timestamp ⇒ Object
- .verbose? ⇒ Boolean
- .working_tree_clean?(repository_root: default_repository_root) ⇒ Boolean
- .write!(repository_root: default_repository_root) ⇒ Object
Class Method Details
.commit_sha(repository_root: default_repository_root) ⇒ Object
127 128 129 |
# File 'lib/polyrun/benchmark/profile.rb', line 127 def commit_sha(repository_root: default_repository_root) git_command("git rev-parse HEAD", repository_root: repository_root) || "unknown" end |
.current_section_storage ⇒ Object
182 183 184 |
# File 'lib/polyrun/benchmark/profile.rb', line 182 def current_section_storage storage["current_section"] end |
.default_repository_root ⇒ Object
186 187 188 |
# File 'lib/polyrun/benchmark/profile.rb', line 186 def default_repository_root Dir.pwd end |
.detect_section_title(line) ⇒ Object
148 149 150 151 152 153 154 155 |
# File 'lib/polyrun/benchmark/profile.rb', line 148 def detect_section_title(line) return unless line.is_a?(String) return if line.strip.empty? return if line.start_with?("#") return unless line.end_with?(":") line.strip.delete_suffix(":") end |
.export_extension(format) ⇒ Object
81 82 83 84 85 86 87 |
# File 'lib/polyrun/benchmark/profile.rb', line 81 def export_extension(format) case format.to_s.downcase when "markdown", "md" then "md" when "text", "console", "txt" then "txt" else format.to_s.downcase end end |
.export_formats ⇒ Object
74 75 76 77 78 79 |
# File 'lib/polyrun/benchmark/profile.rb', line 74 def export_formats raw = ENV["POLYRUN_BENCH_FORMATS"] return [] if raw.nil? || raw.to_s.strip.empty? raw.split(",").map(&:strip).reject(&:empty?) end |
.export_sidecars!(data, json_path) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/polyrun/benchmark/profile.rb', line 62 def export_sidecars!(data, json_path) formats = export_formats return if formats.empty? require_relative "report" base = json_path.sub(/\.json\z/, "") formats.each do |format| path = "#{base}.#{export_extension(format)}" File.write(path, Report.render(data, format: format)) end end |
.format_metric_line(metric) ⇒ Object
157 158 159 160 161 162 |
# File 'lib/polyrun/benchmark/profile.rb', line 157 def format_metric_line(metric) value = metric["value"] unit = metric["unit"] suffix = (unit == "seconds") ? "s" : " #{unit}" format(" %s: %s%s", metric["name"], value, suffix) end |
.git_command(command, repository_root:) ⇒ Object
139 140 141 142 143 144 145 146 |
# File 'lib/polyrun/benchmark/profile.rb', line 139 def git_command(command, repository_root:) stdout, status = Open3.capture2(command, chdir: repository_root) return nil unless status.success? stdout.strip rescue nil end |
.lines_storage ⇒ Object
174 175 176 |
# File 'lib/polyrun/benchmark/profile.rb', line 174 def lines_storage storage["lines"] end |
.log(message = "") ⇒ Object
18 19 20 21 22 23 24 25 |
# File 'lib/polyrun/benchmark/profile.rb', line 18 def log( = "") line = .to_s lines_storage << line section = detect_section_title(line) || current_section_storage.first current_section_storage[0] = section if detect_section_title(line) $stdout.puts(line) if verbose? && !line.empty? line end |
.metrics_storage ⇒ Object
178 179 180 |
# File 'lib/polyrun/benchmark/profile.rb', line 178 def metrics_storage storage["metrics"] end |
.output_path(repository_root: default_repository_root, extension: "log", commit_sha: nil, working_tree_clean: nil, timestamp: nil) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/polyrun/benchmark/profile.rb', line 93 def output_path(repository_root: default_repository_root, extension: "log", commit_sha: nil, working_tree_clean: nil, timestamp: nil) commit_identifier = commit_sha || self.commit_sha(repository_root: repository_root) clean_tree = working_tree_clean.nil? ? working_tree_clean?(repository_root: repository_root) : working_tree_clean filename = if clean_tree "profile_#{commit_identifier}.#{extension}" else recorded_at = || self. "profile_#{commit_identifier}_#{recorded_at}.#{extension}" end File.join(repository_root, "tmp", "benchmarks", filename) end |
.profile_header(meta) ⇒ Object
116 117 118 119 120 121 122 123 124 125 |
# File 'lib/polyrun/benchmark/profile.rb', line 116 def profile_header() [ "# Benchmark profile", "# commit: #{["commit"]}", "# recorded_at: #{["recorded_at"]}", "# working_tree_clean: #{["working_tree_clean"]}", "# ruby: #{["ruby"]}", "" ].join("\n") end |
.profile_meta(repository_root: default_repository_root) ⇒ Object
106 107 108 109 110 111 112 113 114 |
# File 'lib/polyrun/benchmark/profile.rb', line 106 def (repository_root: default_repository_root) { "commit" => commit_sha(repository_root: repository_root), "recorded_at" => Time.now.utc.iso8601, "working_tree_clean" => working_tree_clean?(repository_root: repository_root), "ruby" => RUBY_VERSION, "polyrun_version" => Polyrun::VERSION } end |
.record_metric!(name:, value:, unit: "seconds", section: nil) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/polyrun/benchmark/profile.rb', line 27 def record_metric!(name:, value:, unit: "seconds", section: nil) section_name = section || current_section_storage.first metric = { "section" => section_name.to_s, "name" => name.to_s, "value" => value, "unit" => unit.to_s } metrics_storage << metric log(format_metric_line(metric)) metric end |
.reset! ⇒ Object
12 13 14 15 16 |
# File 'lib/polyrun/benchmark/profile.rb', line 12 def reset! lines_storage.clear metrics_storage.clear current_section_storage.replace(["default"]) end |
.snapshot ⇒ Object
40 41 42 43 44 45 46 |
# File 'lib/polyrun/benchmark/profile.rb', line 40 def snapshot { "meta" => , "lines" => lines_storage.dup, "metrics" => metrics_storage.dup } end |
.storage ⇒ Object
166 167 168 169 170 171 172 |
# File 'lib/polyrun/benchmark/profile.rb', line 166 def storage Thread.current[STORAGE_KEY] ||= { "lines" => [], "metrics" => [], "current_section" => ["default"] } end |
.timestamp ⇒ Object
135 136 137 |
# File 'lib/polyrun/benchmark/profile.rb', line 135 def Time.now.utc.strftime("%Y%m%d%H%M%S") end |
.verbose? ⇒ Boolean
89 90 91 |
# File 'lib/polyrun/benchmark/profile.rb', line 89 def verbose? %w[1 true yes].include?(ENV["POLYRUN_BENCH"]&.to_s&.downcase) end |
.working_tree_clean?(repository_root: default_repository_root) ⇒ Boolean
131 132 133 |
# File 'lib/polyrun/benchmark/profile.rb', line 131 def working_tree_clean?(repository_root: default_repository_root) git_command("git status --porcelain", repository_root: repository_root).to_s.empty? end |
.write!(repository_root: default_repository_root) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/polyrun/benchmark/profile.rb', line 48 def write!(repository_root: default_repository_root) data = snapshot return if data["lines"].empty? && data["metrics"].empty? log_path = output_path(repository_root: repository_root, extension: "log") json_path = output_path(repository_root: repository_root, extension: "json") FileUtils.mkdir_p(File.dirname(log_path)) File.write(log_path, profile_header(data["meta"]) + data["lines"].join("\n") + "\n") File.write(json_path, JSON.pretty_generate(data)) export_sidecars!(data, json_path) $stdout.puts("\nBenchmark profile written to #{log_path}") if verbose? log_path end |