serialbench 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7267d278bec24e38ca217bfbf164c10411f03b4fb333295f05c617c56f91a8b8
4
- data.tar.gz: fcf4034a75ee9615197e2fd0cd3e7b63a795c7f3f0b1ba2c3b1cd0170babecb6
3
+ metadata.gz: fe9e6d376c22b6c6326017435378977a38426eaeba84a1284dfa9f488f18d3bb
4
+ data.tar.gz: 2d11e9d26b9f0e6669502741bf1c151b0807ca18c54c79c1ac2f6ba19b66a2cb
5
5
  SHA512:
6
- metadata.gz: 4acd59cfc6d0b8d47d1d09172ea2f034063633ba5435fccc2fcfbd35ec11d96d41080210d84d149423979b3e14873cf3833512d36917515dfdb0ccdb698dfc1f
7
- data.tar.gz: a913c26df13272e009996925fc6dd4789f74c6f968d27cd02da6155b71f1026d03e8bc2bb1cef1ba400ca19170b3c5a7f0d04ab125658ebf8a54c14551c5607b
6
+ metadata.gz: aa8cb879628d4b55671da1f54104f550f29c067af9e59471799728ed813ba2c428cb45457d6d90460e4ea5f9481a41c072c9a11e1237e37c4f407e3fd15e9854
7
+ data.tar.gz: a1cd5baddbca54dcc8ada57b3d5a3de4f566ad2a93cacb83281dbb7f16d44955827af1726f1027badb64a0e3a9f650121040430b04f9fd4edcb4e413e206cc3a
@@ -46,6 +46,32 @@ module Serialbench
46
46
  def generate_timestamp
47
47
  Time.now.utc.strftime('%Y%m%d_%H%M%S')
48
48
  end
49
+
50
+ def load_environment_config(environment_config_path)
51
+ unless File.exist?(environment_config_path)
52
+ say "❌ Environment not found: #{environment_config_path}", :red
53
+ exit 1
54
+ end
55
+
56
+ require_relative '../models/environment_config'
57
+ Models::EnvironmentConfig.from_yaml(IO.read(environment_config_path))
58
+ rescue StandardError => e
59
+ say "❌ Failed to load environment config: #{e.message}", :red
60
+ exit 1
61
+ end
62
+
63
+ def load_benchmark_config(benchmark_config_path)
64
+ unless File.exist?(benchmark_config_path)
65
+ say "❌ Benchmark configuration file not found: #{benchmark_config_path}", :red
66
+ exit 1
67
+ end
68
+
69
+ require_relative '../models/benchmark_config'
70
+ Models::BenchmarkConfig.from_yaml(IO.read(benchmark_config_path))
71
+ rescue StandardError => e
72
+ say "❌ Failed to load benchmark config: #{e.message}", :red
73
+ exit 1
74
+ end
49
75
  end
50
76
  end
51
77
  end
@@ -76,22 +76,60 @@ module Serialbench
76
76
  say "Environment: #{environment.name} (#{environment.kind})", :cyan
77
77
  say "Configuration: #{benchmark_config_path}", :cyan
78
78
 
79
- begin
80
- # Execute benchmark based on environment type
81
- case environment.kind
82
- when 'local'
83
- execute_local_benchmark(environment, config, benchmark_config_path)
84
- when 'docker'
85
- execute_docker_benchmark(environment, config, benchmark_config_path)
86
- when 'asdf'
87
- execute_asdf_benchmark(environment, config, benchmark_config_path)
88
- else
89
- raise "Unsupported environment type: #{environment.kind}"
90
- end
91
- rescue StandardError => e
92
- say "❌ Error executing benchmark run: #{e.message}", :red
93
- exit 1
79
+ result_dir = "results/runs/#{environment.name}-results"
80
+ FileUtils.mkdir_p(result_dir)
81
+
82
+ Runners.for(environment, environment_config_path)
83
+ .run_benchmark(config, benchmark_config_path, result_dir)
84
+
85
+ say '✅ Benchmark completed successfully!', :green
86
+ say "Results saved to: #{result_dir}", :cyan
87
+ rescue StandardError => e
88
+ say "❌ Error executing benchmark run: #{e.message}", :red
89
+ exit 1
90
+ end
91
+
92
+ desc 'create [NAME]', 'Generate a run configuration file'
93
+ long_desc <<~DESC
94
+ Generate a configuration file for a benchmark run.
95
+
96
+ NAME is optional - if not provided, a timestamped name will be generated.
97
+
98
+ Examples:
99
+ serialbench benchmark create # Creates config with timestamp
100
+ serialbench benchmark create my-benchmark # Creates config/runs/my-benchmark.yml
101
+ DESC
102
+ option :formats, type: :array, default: %w[xml json yaml toml],
103
+ desc: 'Formats to benchmark (xml, json, yaml, toml)'
104
+ option :warmup, type: :numeric, default: 3,
105
+ desc: 'Number of warmup iterations'
106
+ option :data_sizes, type: :array, default: %w[small medium large],
107
+ desc: 'Data sizes to test (small, medium, large)'
108
+ def create(name = nil)
109
+ raise 'Run name cannot be empty' if name&.strip&.empty?
110
+
111
+ validate_name(name)
112
+
113
+ config_dir = 'config/runs'
114
+ FileUtils.mkdir_p(config_dir)
115
+
116
+ benchmark_config_path = File.join(config_dir, "#{name}.yml")
117
+
118
+ if File.exist?(benchmark_config_path)
119
+ say "Configuration file already exists: #{benchmark_config_path}", :yellow
120
+ return unless yes?('Overwrite existing file? (y/n)')
94
121
  end
122
+
123
+ benchmark_config = Models::BenchmarkConfig.new(
124
+ formats: options[:formats],
125
+ warmup: options[:warmup],
126
+ data_sizes: options[:data_sizes]
127
+ )
128
+
129
+ benchmark_config.to_file(benchmark_config_path)
130
+
131
+ say "✅ Generated run configuration: #{benchmark_config_path}", :green
132
+ say 'Edit the file to customize benchmark settings', :cyan
95
133
  end
96
134
 
97
135
  desc '_docker_execute ENVIRONMENT_CONFIG_PATH BENCHMARK_CONFIG_PATH', '(Private) Execute a benchmark run'
@@ -242,77 +280,6 @@ module Serialbench
242
280
 
243
281
  private
244
282
 
245
- def execute_local_benchmark(environment, config, benchmark_config_path)
246
- say '🏠 Executing local benchmark', :green
247
-
248
- runner = Serialbench::BenchmarkRunner.new(
249
- environment_config: environment,
250
- benchmark_config: config
251
- )
252
-
253
- # Run benchmarks
254
- results = runner.run_all_benchmarks
255
-
256
- platform = Serialbench::Models::Platform.current_local
257
-
258
- metadata = Models::RunMetadata.new(
259
- benchmark_config_path: benchmark_config_path,
260
- environment_config_path: "config/environments/#{environment.name}.yml",
261
- tags: [
262
- 'local',
263
- platform.os,
264
- platform.arch,
265
- "ruby-#{environment.ruby_build_tag}"
266
- ]
267
- )
268
-
269
- # Create results directory
270
- result_dir = "results/runs/#{environment.name}-results"
271
- FileUtils.mkdir_p(result_dir)
272
-
273
- # Save results to single YAML file with platform and metadata merged in
274
- results_model = Models::Result.new(
275
- platform: platform,
276
- metadata: metadata,
277
- environment_config: environment,
278
- benchmark_config: config,
279
- benchmark_result: results
280
- )
281
-
282
- results_file = File.join(result_dir, 'results.yaml')
283
- results_model.to_file(results_file)
284
-
285
- say '✅ Local benchmark completed successfully!', :green
286
- say "Results saved to: #{result_dir}", :cyan
287
- rescue StandardError => e
288
- say "❌ Local benchmark failed: #{e.message}", :red
289
- say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
290
- raise e
291
- end
292
-
293
- def execute_docker_benchmark(environment, config, benchmark_config_path)
294
- say '🐳 Executing Docker benchmark', :green
295
-
296
- require_relative '../runners/docker_runner'
297
-
298
- environment_config_path = "config/environments/#{environment.name}.yml"
299
- runner = Runners::DockerRunner.new(environment, environment_config_path)
300
-
301
- # Create results directory
302
- result_dir = "results/runs/#{environment.name}-results"
303
- FileUtils.mkdir_p(result_dir)
304
-
305
- # Run benchmark
306
- runner.run_benchmark(config, benchmark_config_path, result_dir)
307
-
308
- say '✅ Docker benchmark completed successfully!', :green
309
- say "Results saved to: #{result_dir}", :cyan
310
- rescue StandardError => e
311
- say "❌ Docker benchmark failed: #{e.message}", :red
312
- say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
313
- raise e
314
- end
315
-
316
283
  def show_execute_usage_and_exit
317
284
  say '❌ Error: Environment and config file arguments are required.', :red
318
285
  say ''
@@ -329,52 +296,6 @@ module Serialbench
329
296
  exit 1
330
297
  end
331
298
 
332
- def load_environment_config(environment_config_path)
333
- unless File.exist?(environment_config_path)
334
- say "❌ Environment not found: #{environment_config_path}", :red
335
- exit 1
336
- end
337
-
338
- Models::EnvironmentConfig.from_file(environment_config_path)
339
- rescue StandardError => e
340
- say "❌ Failed to load environment: #{e.message}", :red
341
- say "Environment file: #{environment_config_path}", :white
342
- exit 1
343
- end
344
-
345
- def load_benchmark_config(benchmark_config_path)
346
- unless File.exist?(benchmark_config_path)
347
- say "❌ Benchmark config not found: #{benchmark_config_path}", :red
348
- exit 1
349
- end
350
-
351
- Models::BenchmarkConfig.from_file(benchmark_config_path)
352
- rescue StandardError => e
353
- say "❌ Failed to load benchmark config: #{e.message}", :red
354
- say "Benchmark config file: #{benchmark_config_path}", :white
355
- exit 1
356
- end
357
-
358
- def execute_asdf_benchmark(environment, config, benchmark_config_path)
359
- say '🔧 Executing ASDF benchmark', :green
360
-
361
- require_relative '../runners/asdf_runner'
362
-
363
- environment_config_path = "config/environments/#{environment.name}.yml"
364
- runner = Runners::AsdfRunner.new(environment, environment_config_path)
365
-
366
- result_dir = "results/runs/#{environment.name}-results"
367
- FileUtils.mkdir_p(result_dir)
368
-
369
- runner.run_benchmark(config, benchmark_config_path, result_dir)
370
-
371
- say '✅ ASDF benchmark completed successfully!', :green
372
- say "Results saved to: #{result_dir}", :cyan
373
- rescue StandardError => e
374
- say "❌ ASDF benchmark failed: #{e.message}", :red
375
- say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
376
- raise e
377
- end
378
299
  end
379
300
  end
380
301
  end
@@ -30,7 +30,7 @@ module Serialbench
30
30
  desc: 'Default Docker image for docker environments'
31
31
  option :dockerfile, type: :string, default: 'Dockerfile', desc: 'Default Dockerfile for docker environments'
32
32
  def new(name, kind, ruby_build_tag)
33
- validate_environment_name!(name)
33
+ validate_name(name)
34
34
 
35
35
  config_path = File.join(options[:dir], "#{name}.yml")
36
36
 
@@ -39,15 +39,15 @@ module Serialbench
39
39
  return unless yes?('Overwrite existing environment? (y/n)')
40
40
  end
41
41
 
42
- FileUtils.mkdir_p('config/environments')
42
+ FileUtils.mkdir_p(options[:dir])
43
43
 
44
44
  kind_config = case kind
45
45
  when 'docker'
46
- raise unless options[:docker_image] && options[:dockerfile]
46
+ raise ArgumentError, '--docker_image and --dockerfile are required for docker environments' unless options[:docker_image] && options[:dockerfile]
47
47
 
48
48
  Models::EnvironmentConfig.new(
49
49
  name: name,
50
- type: kind,
50
+ kind: kind,
51
51
  ruby_build_tag: ruby_build_tag,
52
52
  docker: Models::DockerEnvConfig.new(
53
53
  image: options[:docker_image],
@@ -58,19 +58,25 @@ module Serialbench
58
58
  when 'asdf'
59
59
  Models::EnvironmentConfig.new(
60
60
  name: name,
61
- type: kind,
61
+ kind: kind,
62
62
  ruby_build_tag: ruby_build_tag,
63
63
  asdf: Models::AsdfEnvConfig.new(auto_install: true),
64
64
  description: "ASDF environment for Ruby #{ruby_build_tag} benchmarks"
65
65
  )
66
+ when 'local'
67
+ Models::EnvironmentConfig.new(
68
+ name: name,
69
+ kind: kind,
70
+ ruby_build_tag: ruby_build_tag,
71
+ description: "Local environment for Ruby #{ruby_build_tag} benchmarks"
72
+ )
73
+ else
74
+ raise ArgumentError, "unknown environment kind: #{kind} (expected local, docker, or asdf)"
66
75
  end
67
76
  File.write(config_path, kind_config.to_yaml)
68
77
 
69
78
  say "✅ Created environment template: #{config_path}", :green
70
79
 
71
- # Show ruby-build tag suggestion for local environments
72
- show_ruby_build_suggestion if kind == 'local'
73
-
74
80
  say ''
75
81
  say 'Next steps:', :white
76
82
  say "1. Edit #{config_path} to confirm/change configuration", :cyan
@@ -99,7 +105,7 @@ module Serialbench
99
105
  FileUtils.mkdir_p(result_dir)
100
106
  say "Results will be saved to: #{result_dir}", :cyan
101
107
 
102
- runner = create_environment_runner(environment_config, environment_path)
108
+ runner = Runners.for(environment_config, environment_path)
103
109
  runner.run_benchmark(benchmark_config, benchmark_config_path, result_dir)
104
110
 
105
111
  say '✅ Benchmark completed successfully!', :green
@@ -125,7 +131,7 @@ module Serialbench
125
131
 
126
132
  say "🔧 Preparing environment '#{environment_config.name}'...", :green
127
133
 
128
- runner = create_environment_runner(environment_config, environment_config_path)
134
+ runner = Runners.for(environment_config, environment_config_path)
129
135
  runner.prepare
130
136
 
131
137
  say '✅ Environment prepared successfully!', :green
@@ -137,45 +143,8 @@ module Serialbench
137
143
 
138
144
  private
139
145
 
140
- def load_benchmark_config(benchmark_config_path)
141
- unless File.exist?(benchmark_config_path)
142
- say "❌ Benchmark configuration file not found: #{benchmark_config_path}", :red
143
- exit 1
144
- end
145
146
 
146
- Models::BenchmarkConfig.from_yaml(IO.read(benchmark_config_path))
147
- rescue StandardError => e
148
- say "❌ Failed to load benchmark config: #{e.message}", :red
149
- exit 1
150
- end
151
147
 
152
- def load_environment_config(environment_config_path)
153
- unless File.exist?(environment_config_path)
154
- say "❌ Environment not found: #{environment_config_path}", :red
155
- exit 1
156
- end
157
-
158
- Models::EnvironmentConfig.from_yaml(IO.read(environment_config_path))
159
- rescue StandardError => e
160
- say "❌ Failed to load environment config: #{e.message}", :red
161
- exit 1
162
- end
163
-
164
- def create_environment_runner(environment_config, environment_config_path)
165
- case environment_config.kind
166
- when 'docker'
167
- require_relative '../runners/docker_runner'
168
- Runners::DockerRunner.new(environment_config, environment_config_path)
169
- when 'asdf'
170
- require_relative '../runners/asdf_runner'
171
- Runners::AsdfRunner.new(environment_config, environment_config_path)
172
- when 'local'
173
- require_relative '../runners/local_runner'
174
- Runners::LocalRunner.new(environment_config, environment_config_path)
175
- else
176
- raise "Unknown environment type: #{environment_config.kind}"
177
- end
178
- end
179
148
  end
180
149
  end
181
150
  end
@@ -7,8 +7,8 @@ require 'open3'
7
7
  require 'stringio'
8
8
 
9
9
  module Serialbench
10
- # Handles ASDF-based benchmark execution
11
10
  module Runners
11
+ # Runner protocol: prepare, then run_benchmark(config, config_path, result_dir)
12
12
  class Base
13
13
  def initialize(environment_config, environment_config_path)
14
14
  @environment_config = environment_config
@@ -23,9 +23,8 @@ module Serialbench
23
23
  raise NotImplementedError, 'Subclasses must implement the prepare method'
24
24
  end
25
25
 
26
- # Run benchmark
27
- def benchmark
28
- raise NotImplementedError, 'Subclasses must implement the benchmark method'
26
+ def run_benchmark(benchmark_config, benchmark_config_path, result_dir)
27
+ raise NotImplementedError, 'Subclasses must implement the run_benchmark method'
29
28
  end
30
29
  end
31
30
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'runners/base'
4
+ require_relative 'runners/local_runner'
5
+ require_relative 'runners/docker_runner'
6
+ require_relative 'runners/asdf_runner'
7
+
8
+ module Serialbench
9
+ # Executes benchmarks in an environment: local, docker, or asdf.
10
+ module Runners
11
+ def self.for(environment_config, environment_config_path)
12
+ runner_class = case environment_config.kind
13
+ when 'local' then LocalRunner
14
+ when 'docker' then DockerRunner
15
+ when 'asdf' then AsdfRunner
16
+ else raise ArgumentError, "unknown environment kind: #{environment_config.kind}"
17
+ end
18
+
19
+ runner_class.new(environment_config, environment_config_path)
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Serialbench
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
data/lib/serialbench.rb CHANGED
@@ -9,6 +9,7 @@ require_relative 'serialbench/models'
9
9
 
10
10
  module Serialbench
11
11
  autoload :TestData, 'serialbench/test_data'
12
+ autoload :Runners, 'serialbench/runners'
12
13
 
13
14
  class Error < StandardError; end
14
15
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serialbench
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
@@ -308,6 +308,7 @@ files:
308
308
  - lib/serialbench/models/result.rb
309
309
  - lib/serialbench/models/result_store.rb
310
310
  - lib/serialbench/ruby_build_manager.rb
311
+ - lib/serialbench/runners.rb
311
312
  - lib/serialbench/runners/asdf_runner.rb
312
313
  - lib/serialbench/runners/base.rb
313
314
  - lib/serialbench/runners/docker_runner.rb