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 +4 -4
- data/.github/workflows/benchmark.yml +0 -4
- data/.github/workflows/rake.yml +15 -18
- data/config/benchmarks/full-json.yml +2 -2
- data/config/benchmarks/full-toml.yml +2 -2
- data/config/benchmarks/full-xml.yml +2 -2
- data/config/benchmarks/full-yaml.yml +2 -2
- data/config/benchmarks/full.yml +2 -2
- data/config/benchmarks/short.yml +2 -2
- data/lib/serialbench/benchmark_runner.rb +12 -2
- data/lib/serialbench/cli/base_cli.rb +26 -0
- data/lib/serialbench/cli/benchmark_cli.rb +53 -205
- data/lib/serialbench/cli/environment_cli.rb +16 -47
- data/lib/serialbench/models/benchmark_config.rb +1 -1
- data/lib/serialbench/runners/base.rb +3 -4
- data/lib/serialbench/runners.rb +22 -0
- data/lib/serialbench/version.rb +1 -1
- data/lib/serialbench.rb +1 -0
- metadata +2 -2
- data/.github/workflows/windows-debug.yml +0 -171
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fe9e6d376c22b6c6326017435378977a38426eaeba84a1284dfa9f488f18d3bb
|
|
4
|
+
data.tar.gz: 2d11e9d26b9f0e6669502741bf1c151b0807ca18c54c79c1ac2f6ba19b66a2cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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'
|
data/.github/workflows/rake.yml
CHANGED
|
@@ -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: [
|
|
5
|
+
branches: [ main ]
|
|
8
6
|
tags: [ v* ]
|
|
9
|
-
paths-ignore:
|
|
10
|
-
- '.github/workflows/windows-debug.yml'
|
|
11
7
|
pull_request:
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
14
11
|
|
|
15
12
|
jobs:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
data/config/benchmarks/full.yml
CHANGED
data/config/benchmarks/short.yml
CHANGED
|
@@ -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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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[
|
|
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
|
-
|
|
27
|
-
|
|
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
|
data/lib/serialbench/version.rb
CHANGED
data/lib/serialbench.rb
CHANGED
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
|
+
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
|