serialbench 0.4.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: e90d8b6ebc8deebf308b1e02214b978597d0d2a9699c3845ebf6405953d733b7
4
- data.tar.gz: 4cc9e46139f7054919657d66fd26ed6b40430856e0bdd317f2677451bc1bf715
3
+ metadata.gz: fe9e6d376c22b6c6326017435378977a38426eaeba84a1284dfa9f488f18d3bb
4
+ data.tar.gz: 2d11e9d26b9f0e6669502741bf1c151b0807ca18c54c79c1ac2f6ba19b66a2cb
5
5
  SHA512:
6
- metadata.gz: 38652e0714893c8ed9590fe1a7ef29c9c6e94cdbdcb0104d9190d12bad1c95f8635680b904d66b9edda72f55f7c037ce5e18894bf5fb66d5b88db21ba2dcaa3d
7
- data.tar.gz: 728e8ee7c92138afdfd722cfb93ef7463c22e7d1c8882e5d83507dba7861637addd659e489df21c91a80a45680fc532eb0898f9ffed9ce48402a604962b73c85
6
+ metadata.gz: aa8cb879628d4b55671da1f54104f550f29c067af9e59471799728ed813ba2c428cb45457d6d90460e4ea5f9481a41c072c9a11e1237e37c4f407e3fd15e9854
7
+ data.tar.gz: a1cd5baddbca54dcc8ada57b3d5a3de4f566ad2a93cacb83281dbb7f16d44955827af1726f1027badb64a0e3a9f650121040430b04f9fd4edcb4e413e206cc3a
@@ -3,11 +3,7 @@ name: benchmark-weekly
3
3
  on:
4
4
  push:
5
5
  branches: [main]
6
- paths-ignore:
7
- - '.github/workflows/windows-debug.yml'
8
6
  pull_request:
9
- paths-ignore:
10
- - '.github/workflows/windows-debug.yml'
11
7
  schedule:
12
8
  # Run benchmarks weekly on Sundays at 2 AM UTC
13
9
  - cron: '0 2 * * 0'
@@ -1,26 +1,23 @@
1
- # Auto-generated by Cimas: Do not edit it manually!
2
- # See https://github.com/metanorma/cimas
3
1
  name: rake
4
2
 
5
3
  on:
6
4
  push:
7
- branches: [ master, main ]
5
+ branches: [ main ]
8
6
  tags: [ v* ]
9
- paths-ignore:
10
- - '.github/workflows/windows-debug.yml'
11
7
  pull_request:
12
- paths-ignore:
13
- - '.github/workflows/windows-debug.yml'
8
+
9
+ permissions:
10
+ contents: read
14
11
 
15
12
  jobs:
16
- rake:
17
- uses: metanorma/ci/.github/workflows/generic-rake.yml@main
18
- with:
19
- before-setup-ruby: |
20
- vcpkg install libxml2:x64-windows 2>&1 || true
21
- vcpkg integrate install 2>&1 || true
22
- mkdir -p .bundle 2>&1 || true
23
- echo "---" > .bundle/config 2>&1 || true
24
- echo 'BUNDLE_BUILD__LIBXML___RUBY: "--with-xml2-dir=C:/vcpkg/installed/x64-windows --with-xml2-include=C:/vcpkg/installed/x64-windows/include/libxml2 --with-xml2-lib=C:/vcpkg/installed/x64-windows/lib"' >> .bundle/config 2>&1 || true
25
- secrets:
26
- pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
13
+ rspec:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: '3.4'
21
+ bundler-cache: true
22
+
23
+ - run: bundle exec rspec --format progress
@@ -17,8 +17,8 @@ iterations:
17
17
  large: 1
18
18
 
19
19
  operations:
20
- - parse
21
- - generate
20
+ - parsing
21
+ - generation
22
22
  - streaming
23
23
  - memory
24
24
 
@@ -17,8 +17,8 @@ iterations:
17
17
  large: 1
18
18
 
19
19
  operations:
20
- - parse
21
- - generate
20
+ - parsing
21
+ - generation
22
22
  - streaming
23
23
  - memory
24
24
 
@@ -17,8 +17,8 @@ iterations:
17
17
  large: 1
18
18
 
19
19
  operations:
20
- - parse
21
- - generate
20
+ - parsing
21
+ - generation
22
22
  - streaming
23
23
  - xpath
24
24
  - memory
@@ -17,8 +17,8 @@ iterations:
17
17
  large: 1
18
18
 
19
19
  operations:
20
- - parse
21
- - generate
20
+ - parsing
21
+ - generation
22
22
  - streaming
23
23
  - memory
24
24
 
@@ -25,8 +25,8 @@ iterations:
25
25
  large: 1
26
26
 
27
27
  operations:
28
- - parse
29
- - generate
28
+ - parsing
29
+ - generation
30
30
  - streaming
31
31
  - xpath
32
32
  - memory
@@ -19,8 +19,8 @@ iterations:
19
19
  large: 1
20
20
 
21
21
  operations:
22
- - parse
23
- - generate
22
+ - parsing
23
+ - generation
24
24
  - streaming
25
25
 
26
26
  warmup: 2
@@ -21,6 +21,7 @@ module Serialbench
21
21
  @serializers = Serializers.available
22
22
  @test_data = {}
23
23
  @results = []
24
+ validate_operations!
24
25
  load_test_data
25
26
  end
26
27
 
@@ -45,11 +46,13 @@ module Serialbench
45
46
  puts "Test data sizes: #{@test_data.keys.join(', ')}"
46
47
  puts
47
48
 
49
+ selected = @benchmark_config.operations
50
+ selected = OPERATIONS.keys + ['memory'] if selected.nil? || selected.empty?
48
51
  results = {}
49
52
  OPERATIONS.each do |name, handler|
50
- results[name.to_sym] = run_benchmark_type(name, name, &handler)
53
+ results[name.to_sym] = selected.include?(name) ? run_benchmark_type(name, name, &handler) : []
51
54
  end
52
- results[:memory] = run_memory_benchmarks
55
+ results[:memory] = selected.include?('memory') ? run_memory_benchmarks : []
53
56
 
54
57
  Models::BenchmarkResult.new(
55
58
  serializers: Serializers.information,
@@ -165,6 +168,13 @@ module Serialbench
165
168
  end
166
169
  end
167
170
 
171
+ def validate_operations!
172
+ unknown = (@benchmark_config.operations || []) - (OPERATIONS.keys + ['memory'])
173
+ return if unknown.empty?
174
+
175
+ raise ArgumentError, "unknown operations #{unknown.inspect}; expected: #{OPERATIONS.keys.join(', ')}, memory"
176
+ end
177
+
168
178
  def load_test_data
169
179
  @test_data = TestData.load(@benchmark_config)
170
180
  end
@@ -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,79 +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
- say "Generate site: serialbench benchmark build-site #{result_dir}", :white
288
- rescue StandardError => e
289
- say "❌ Local benchmark failed: #{e.message}", :red
290
- say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
291
- raise e
292
- end
293
-
294
- def execute_docker_benchmark(environment, config, benchmark_config_path)
295
- say '🐳 Executing Docker benchmark', :green
296
-
297
- require_relative '../runners/docker_runner'
298
-
299
- environment_config_path = "config/environments/#{environment.name}.yml"
300
- runner = Runners::DockerRunner.new(environment, environment_config_path)
301
-
302
- # Create results directory
303
- result_dir = "results/runs/#{environment.name}-results"
304
- FileUtils.mkdir_p(result_dir)
305
-
306
- # Run benchmark
307
- runner.run_benchmark(config, benchmark_config_path, result_dir)
308
-
309
- say '✅ Docker benchmark completed successfully!', :green
310
- say "Results saved to: #{result_dir}", :cyan
311
- say "Generate site: serialbench benchmark build-site #{result_dir}", :white
312
- rescue StandardError => e
313
- say "❌ Docker benchmark failed: #{e.message}", :red
314
- say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
315
- raise e
316
- end
317
-
318
283
  def show_execute_usage_and_exit
319
284
  say '❌ Error: Environment and config file arguments are required.', :red
320
285
  say ''
@@ -331,123 +296,6 @@ module Serialbench
331
296
  exit 1
332
297
  end
333
298
 
334
- def load_environment_config(environment_config_path)
335
- unless File.exist?(environment_config_path)
336
- say "❌ Environment not found: #{environment_config_path}", :red
337
- exit 1
338
- end
339
-
340
- Models::EnvironmentConfig.from_file(environment_config_path)
341
- rescue StandardError => e
342
- say "❌ Failed to load environment: #{e.message}", :red
343
- say "Environment file: #{environment_config_path}", :white
344
- exit 1
345
- end
346
-
347
- def load_benchmark_config(benchmark_config_path)
348
- unless File.exist?(benchmark_config_path)
349
- say "❌ Benchmark config not found: #{benchmark_config_path}", :red
350
- exit 1
351
- end
352
-
353
- Models::BenchmarkConfig.from_file(benchmark_config_path)
354
- rescue StandardError => e
355
- say "❌ Failed to load benchmark config: #{e.message}", :red
356
- say "Benchmark config file: #{benchmark_config_path}", :white
357
- exit 1
358
- end
359
-
360
- # def execute_local_benchmark(environment, config, benchmark_config_path)
361
- # say '🏠 Executing local benchmark', :green
362
-
363
- # # Create benchmark runner with config
364
- # runner_options = {
365
- # formats: (config['formats'] || %w[xml json yaml toml]).map(&:to_sym),
366
- # iterations: config['iterations'] || 10,
367
- # warmup: config['warmup'] || 3,
368
- # config: config
369
- # }
370
-
371
- # runner = Serialbench::BenchmarkRunner.new(**runner_options)
372
-
373
- # # Run benchmarks
374
- # say "Running benchmarks with #{runner_options[:iterations]} iterations...", :white
375
- # results = runner.run_all_benchmarks
376
-
377
- # # Create platform-specific directory name using environment's ruby_build_tag
378
- # require_relative '../models/platform'
379
- # platform = Serialbench::Models::Platform.current_local
380
- # platform_string = "local-#{platform.os}-#{platform.arch}-ruby-#{environment['ruby_build_tag']}"
381
-
382
- # # Create results directory
383
- # result_dir = "results/runs/#{environment['name']}"
384
- # FileUtils.mkdir_p(result_dir)
385
-
386
- # # Save results to single YAML file with platform and metadata merged in
387
- # results_file = File.join(result_dir, 'results.yaml')
388
- # full_results = {
389
- # 'platform' => {
390
- # 'platform_string' => platform_string,
391
- # 'os' => platform.os,
392
- # 'arch' => platform.arch
393
- # },
394
- # 'metadata' => {
395
- # 'environment_name' => environment['name'],
396
- # 'benchmark_config' => benchmark_config_path,
397
- # 'created_at' => Time.now.iso8601,
398
- # 'tags' => ['local', platform.os, platform.arch, "ruby-#{environment['ruby_build_tag']}"]
399
- # },
400
- # 'environment' => {
401
- # 'name' => environment['name'],
402
- # 'type' => environment.kind,
403
- # 'ruby_build_tag' => environment['ruby_build_tag'],
404
- # 'created_at' => Time.now.iso8601
405
- # },
406
- # 'config' => {
407
- # 'benchmark_config' => benchmark_config_path,
408
- # 'formats' => config['formats'],
409
- # 'iterations' => config['iterations'],
410
- # 'data_sizes' => config['data_sizes']
411
- # },
412
- # 'results' => results
413
- # }
414
-
415
- # File.write(results_file, full_results.to_yaml)
416
-
417
- # say '✅ Local benchmark completed successfully!', :green
418
- # say "Results saved to: #{result_dir}", :cyan
419
- # say "Generate site: serialbench benchmark build-site #{result_dir}", :white
420
- # rescue StandardError => e
421
- # say "❌ Local benchmark failed: #{e.message}", :red
422
- # say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
423
- # raise e
424
- # end
425
-
426
- def execute_asdf_benchmark(environment, _config, benchmark_config_path)
427
- say '🔧 Executing ASDF benchmark', :green
428
-
429
- # Use the ASDF runner to execute the benchmark
430
- require_relative '../asdf_runner'
431
-
432
- # Create a config object that AsdfRunner expects
433
- asdf_config = environment.merge({
434
- 'benchmark_config' => benchmark_config_path
435
- })
436
-
437
- runner = Serialbench::AsdfRunner.new(asdf_config)
438
-
439
- say "Installing Ruby #{environment['ruby_build_tag']} via ASDF...", :white
440
- runner.prepare
441
- runner.benchmark
442
-
443
- say '✅ ASDF benchmark completed successfully!', :green
444
- say "Results saved to: results/runs/#{environment['name']}", :cyan
445
- say "Generate site: serialbench benchmark build-site results/runs/#{environment['name']}", :white
446
- rescue StandardError => e
447
- say "❌ ASDF benchmark failed: #{e.message}", :red
448
- say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
449
- raise e
450
- end
451
299
  end
452
300
  end
453
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
@@ -51,7 +51,7 @@ module Serialbench
51
51
  attribute :formats, :string, collection: true, values: %w[xml json yaml toml]
52
52
  attribute :iterations, BenchmarkIteration
53
53
  attribute :warmup, :integer, default: -> { 1 }
54
- attribute :operations, :string, collection: true, values: %w[parse generate memory streaming]
54
+ attribute :operations, :string, collection: true, values: %w[parsing generation xpath streaming memory]
55
55
 
56
56
  key_value do
57
57
  map 'name', to: :name
@@ -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.4.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.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
@@ -260,7 +260,6 @@ files:
260
260
  - ".github/workflows/benchmark.yml"
261
261
  - ".github/workflows/rake.yml"
262
262
  - ".github/workflows/release.yml"
263
- - ".github/workflows/windows-debug.yml"
264
263
  - ".gitignore"
265
264
  - ".rspec"
266
265
  - ".rubocop.yml"
@@ -309,6 +308,7 @@ files:
309
308
  - lib/serialbench/models/result.rb
310
309
  - lib/serialbench/models/result_store.rb
311
310
  - lib/serialbench/ruby_build_manager.rb
311
+ - lib/serialbench/runners.rb
312
312
  - lib/serialbench/runners/asdf_runner.rb
313
313
  - lib/serialbench/runners/base.rb
314
314
  - lib/serialbench/runners/docker_runner.rb
@@ -1,171 +0,0 @@
1
- name: Windows Debug
2
-
3
- on:
4
- push:
5
- branches: [ master, main ]
6
- paths:
7
- - '.github/workflows/windows-debug.yml'
8
- pull_request:
9
- paths:
10
- - '.github/workflows/windows-debug.yml'
11
- workflow_dispatch:
12
-
13
- jobs:
14
- test-libxml2-install:
15
- runs-on: windows-latest
16
- strategy:
17
- fail-fast: false
18
- matrix:
19
- ruby: ['3.1', '3.4']
20
- method: ['vcpkg', 'msys2', 'direct']
21
-
22
- name: Test ${{ matrix.method }} on Ruby ${{ matrix.ruby }}
23
-
24
- steps:
25
- - uses: actions/checkout@v4
26
-
27
- - name: Set up Ruby
28
- uses: ruby/setup-ruby@v1
29
- with:
30
- ruby-version: ${{ matrix.ruby }}
31
-
32
- - name: Install via vcpkg
33
- if: matrix.method == 'vcpkg'
34
- shell: powershell
35
- run: |
36
- Write-Host "Installing libxml2 via vcpkg..."
37
- vcpkg install libxml2:x64-windows
38
- vcpkg integrate install
39
-
40
- # Find the libxml2 installation
41
- $vcpkgRoot = "C:\vcpkg"
42
- $libxml2Path = Join-Path $vcpkgRoot "installed\x64-windows"
43
-
44
- Write-Host "libxml2 installed at: $libxml2Path"
45
-
46
- # Set environment variables
47
- echo "LIBXML2_INCLUDE=$libxml2Path\include" >> $env:GITHUB_ENV
48
- echo "LIBXML2_LIB=$libxml2Path\lib" >> $env:GITHUB_ENV
49
- echo "PKG_CONFIG_PATH=$libxml2Path\lib\pkgconfig" >> $env:GITHUB_ENV
50
-
51
- # Add to PATH
52
- $currentPath = [Environment]::GetEnvironmentVariable("PATH", "Process")
53
- $newPath = "$libxml2Path\bin;$currentPath"
54
- echo "$newPath" >> $env:GITHUB_PATH
55
-
56
- # Verify installation
57
- Get-ChildItem -Path $libxml2Path -Recurse | Where-Object { $_.Name -like "*libxml*" } | Select-Object FullName
58
-
59
- - name: Install via msys2
60
- if: matrix.method == 'msys2'
61
- shell: powershell
62
- run: |
63
- Write-Host "Installing libxml2 via msys2..."
64
- choco install -y msys2
65
-
66
- # Initialize msys2 and install libxml2
67
- C:\tools\msys64\usr\bin\bash -lc "pacman -Syu --noconfirm"
68
- C:\tools\msys64\usr\bin\bash -lc "pacman -S --noconfirm mingw-w64-x86_64-libxml2 mingw-w64-x86_64-pkg-config"
69
-
70
- # Set environment variables
71
- $msys2Root = "C:\tools\msys64\mingw64"
72
- echo "LIBXML2_INCLUDE=$msys2Root\include\libxml2" >> $env:GITHUB_ENV
73
- echo "LIBXML2_LIB=$msys2Root\lib" >> $env:GITHUB_ENV
74
- echo "PKG_CONFIG_PATH=$msys2Root\lib\pkgconfig" >> $env:GITHUB_ENV
75
-
76
- # Add to PATH
77
- echo "$msys2Root\bin" >> $env:GITHUB_PATH
78
-
79
- # Verify installation
80
- Get-ChildItem -Path $msys2Root -Recurse | Where-Object { $_.Name -like "*libxml*" } | Select-Object FullName
81
-
82
- - name: Install via direct download
83
- if: matrix.method == 'direct'
84
- shell: powershell
85
- run: |
86
- Write-Host "Installing libxml2 via direct download..."
87
-
88
- # Download pre-built binaries from gnome.org
89
- $downloadDir = "$env:TEMP\libxml2"
90
- New-Item -ItemType Directory -Force -Path $downloadDir
91
-
92
- # Download libxml2 and dependencies
93
- $libxml2Url = "https://download.gnome.org/binaries/win64/libxml2/2.9/libxml2-2.9.14-x64_dll.zip"
94
- $zlibUrl = "https://download.gnome.org/binaries/win64/dependencies/zlib-1.2.13-x64_dll.zip"
95
- $iconvUrl = "https://download.gnome.org/binaries/win64/dependencies/libiconv-1.17-x64_dll.zip"
96
-
97
- Invoke-WebRequest -Uri $libxml2Url -OutFile "$downloadDir\libxml2.zip"
98
- Invoke-WebRequest -Uri $zlibUrl -OutFile "$downloadDir\zlib.zip"
99
- Invoke-WebRequest -Uri $iconvUrl -OutFile "$downloadDir\iconv.zip"
100
-
101
- # Extract archives
102
- Expand-Archive -Path "$downloadDir\libxml2.zip" -DestinationPath "C:\libxml2" -Force
103
- Expand-Archive -Path "$downloadDir\zlib.zip" -DestinationPath "C:\libxml2" -Force
104
- Expand-Archive -Path "$downloadDir\iconv.zip" -DestinationPath "C:\libxml2" -Force
105
-
106
- # Set environment variables
107
- echo "LIBXML2_INCLUDE=C:\libxml2\include" >> $env:GITHUB_ENV
108
- echo "LIBXML2_LIB=C:\libxml2\lib" >> $env:GITHUB_ENV
109
-
110
- # Add to PATH
111
- echo "C:\libxml2\bin" >> $env:GITHUB_PATH
112
-
113
- # Verify installation
114
- Get-ChildItem -Path "C:\libxml2" -Recurse | Where-Object { $_.Name -like "*libxml*" } | Select-Object FullName
115
-
116
- - name: Verify pkg-config
117
- shell: powershell
118
- run: |
119
- Write-Host "Checking for pkg-config..."
120
- try {
121
- $pkgConfigPath = Get-Command pkg-config -ErrorAction Stop
122
- Write-Host "pkg-config found at: $($pkgConfigPath.Source)"
123
- pkg-config --version
124
- } catch {
125
- Write-Host "pkg-config not found, installing pkgconfiglite..."
126
- choco install -y pkgconfiglite
127
- pkg-config --version
128
- }
129
-
130
- # Try to find libxml2 via pkg-config
131
- Write-Host "`nSearching for libxml-2.0.pc..."
132
- if ($env:PKG_CONFIG_PATH) {
133
- Write-Host "PKG_CONFIG_PATH: $env:PKG_CONFIG_PATH"
134
- pkg-config --list-all | Select-String libxml
135
- }
136
-
137
- - name: Install bundler
138
- run: gem install bundler
139
-
140
- - name: Try to install libxml-ruby gem
141
- shell: powershell
142
- continue-on-error: true
143
- run: |
144
- Write-Host "Attempting to install libxml-ruby..."
145
-
146
- # Set additional environment variables for gem installation
147
- if ($env:LIBXML2_INCLUDE) {
148
- $env:CFLAGS = "-I$env:LIBXML2_INCLUDE"
149
- $env:CPPFLAGS = "-I$env:LIBXML2_INCLUDE"
150
- }
151
- if ($env:LIBXML2_LIB) {
152
- $env:LDFLAGS = "-L$env:LIBXML2_LIB"
153
- }
154
-
155
- gem install libxml-ruby --verbose
156
-
157
- - name: Report results
158
- if: always()
159
- shell: powershell
160
- run: |
161
- Write-Host "`n=== Installation Method: ${{ matrix.method }} ==="
162
- Write-Host "Ruby Version: ${{ matrix.ruby }}"
163
- Write-Host "`nEnvironment Variables:"
164
- Write-Host "LIBXML2_INCLUDE: $env:LIBXML2_INCLUDE"
165
- Write-Host "LIBXML2_LIB: $env:LIBXML2_LIB"
166
- Write-Host "PKG_CONFIG_PATH: $env:PKG_CONFIG_PATH"
167
- Write-Host "`nPATH:"
168
- $env:PATH -split ';' | ForEach-Object { Write-Host " $_" }
169
-
170
- Write-Host "`nChecking for libxml2 files..."
171
- Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue -Include libxml2.dll,libxml2.lib,xml2-config.h 2>$null | Select-Object FullName