serialbench 0.1.2 → 0.2.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 +294 -229
- data/.github/workflows/rake.yml +11 -0
- data/.github/workflows/windows-debug.yml +171 -0
- data/.gitignore +32 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +274 -0
- data/Gemfile +15 -1
- data/README.adoc +41 -0
- data/data/schemas/result.yml +29 -0
- data/docs/PLATFORM_VALIDATION_FIX.md +79 -0
- data/docs/SYCK_YAML_FIX.md +91 -0
- data/docs/WEBSITE_COMPLETION_PLAN.md +440 -0
- data/docs/WINDOWS_LIBXML_FIX.md +136 -0
- data/docs/WINDOWS_SETUP.md +122 -0
- data/lib/serialbench/benchmark_runner.rb +3 -3
- data/lib/serialbench/cli/benchmark_cli.rb +74 -1
- data/lib/serialbench/cli/environment_cli.rb +3 -3
- data/lib/serialbench/cli/resultset_cli.rb +112 -26
- data/lib/serialbench/cli/ruby_build_cli.rb +75 -88
- data/lib/serialbench/cli/validate_cli.rb +88 -0
- data/lib/serialbench/cli.rb +6 -2
- data/lib/serialbench/config_manager.rb +15 -26
- data/lib/serialbench/models/benchmark_config.rb +12 -0
- data/lib/serialbench/models/benchmark_result.rb +39 -3
- data/lib/serialbench/models/environment_config.rb +3 -2
- data/lib/serialbench/models/platform.rb +61 -6
- data/lib/serialbench/models/result.rb +28 -1
- data/lib/serialbench/models/result_set.rb +8 -0
- data/lib/serialbench/ruby_build_manager.rb +19 -23
- data/lib/serialbench/runners/asdf_runner.rb +1 -1
- data/lib/serialbench/runners/docker_runner.rb +2 -4
- data/lib/serialbench/runners/local_runner.rb +71 -0
- data/lib/serialbench/serializers/base_serializer.rb +1 -1
- data/lib/serialbench/serializers/json/rapidjson_serializer.rb +1 -5
- data/lib/serialbench/serializers/toml/base_toml_serializer.rb +0 -2
- data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +1 -1
- data/lib/serialbench/serializers/toml/tomlib_serializer.rb +1 -1
- data/lib/serialbench/serializers/xml/base_xml_serializer.rb +6 -1
- data/lib/serialbench/serializers/xml/leptris_serializer.rb +167 -0
- data/lib/serialbench/serializers/xml/libxml_serializer.rb +13 -8
- data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +11 -2
- data/lib/serialbench/serializers/xml/oga_serializer.rb +8 -8
- data/lib/serialbench/serializers/xml/ox_serializer.rb +2 -2
- data/lib/serialbench/serializers/xml/rexml_serializer.rb +3 -3
- data/lib/serialbench/serializers/yaml/base_yaml_serializer.rb +1 -3
- data/lib/serialbench/serializers/yaml/psych_serializer.rb +1 -5
- data/lib/serialbench/serializers/yaml/syck_serializer.rb +1 -1
- data/lib/serialbench/serializers.rb +5 -3
- data/lib/serialbench/site_generator.rb +234 -2
- data/lib/serialbench/templates/assets/css/format_based.css +1 -53
- data/lib/serialbench/templates/assets/css/themes.css +5 -4
- data/lib/serialbench/templates/assets/js/chart_helpers.js +44 -14
- data/lib/serialbench/templates/assets/js/dashboard.js +14 -15
- data/lib/serialbench/templates/format_based.liquid +480 -252
- data/lib/serialbench/version.rb +1 -1
- data/lib/serialbench/yaml_validator.rb +36 -0
- data/serialbench.gemspec +11 -2
- data/site/.gitignore +5 -0
- data/site/README.md +32 -0
- data/site/astro.config.mjs +12 -0
- data/site/package-lock.json +6160 -0
- data/site/package.json +22 -0
- data/site/public/favicon.svg +4 -0
- data/site/scripts/gen-sample-data.mjs +154 -0
- data/site/src/components/AvailabilityMatrix.astro +61 -0
- data/site/src/components/CalibratedLeaderboard.vue +134 -0
- data/site/src/components/CitationBox.vue +50 -0
- data/site/src/components/DashboardConsole.vue +193 -0
- data/site/src/components/FeaturesTable.astro +97 -0
- data/site/src/components/MemoryPanel.vue +44 -0
- data/site/src/components/OpsChart.vue +135 -0
- data/site/src/config.ts +18 -0
- data/site/src/layouts/Layout.astro +85 -0
- data/site/src/lib/channels.ts +24 -0
- data/site/src/lib/dashboard.ts +269 -0
- data/site/src/pages/index.astro +44 -0
- data/site/src/pages/library/[slug].astro +128 -0
- data/site/src/pages/methodology.astro +55 -0
- data/site/src/styles/global.css +103 -0
- data/site/tsconfig.json +5 -0
- metadata +58 -23
- data/.github/workflows/ci.yml +0 -74
- data/.github/workflows/docker.yml +0 -272
|
@@ -32,7 +32,6 @@ module Serialbench
|
|
|
32
32
|
say "\n📋 Recent Ruby versions available:", :white
|
|
33
33
|
recent_versions.each { |version| say " #{version}", :cyan }
|
|
34
34
|
end
|
|
35
|
-
|
|
36
35
|
rescue StandardError => e
|
|
37
36
|
say "❌ Failed to update Ruby-Build definitions: #{e.message}", :red
|
|
38
37
|
exit 1
|
|
@@ -52,42 +51,39 @@ module Serialbench
|
|
|
52
51
|
DESC
|
|
53
52
|
option :limit, type: :numeric, default: 50, desc: 'Maximum number of definitions to show'
|
|
54
53
|
def list(filter = nil)
|
|
55
|
-
|
|
56
|
-
definitions = RubyBuildManager.list_definitions(filter: filter)
|
|
57
|
-
|
|
58
|
-
if definitions.empty?
|
|
59
|
-
if filter
|
|
60
|
-
say "No Ruby-Build definitions found matching '#{filter}'", :yellow
|
|
61
|
-
else
|
|
62
|
-
say 'No Ruby-Build definitions found in cache', :yellow
|
|
63
|
-
say 'Update the cache first: serialbench ruby-build update', :white
|
|
64
|
-
end
|
|
65
|
-
return
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Limit results if there are many
|
|
69
|
-
limited_definitions = definitions.first(options[:limit])
|
|
54
|
+
definitions = RubyBuildManager.list_definitions(filter: filter)
|
|
70
55
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
say
|
|
56
|
+
if definitions.empty?
|
|
57
|
+
if filter
|
|
58
|
+
say "No Ruby-Build definitions found matching '#{filter}'", :yellow
|
|
59
|
+
else
|
|
60
|
+
say 'No Ruby-Build definitions found in cache', :yellow
|
|
61
|
+
say 'Update the cache first: serialbench ruby-build update', :white
|
|
76
62
|
end
|
|
63
|
+
return
|
|
64
|
+
end
|
|
77
65
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
say "\n... and #{remaining} more definitions", :yellow
|
|
81
|
-
say "Use --limit to show more results", :white
|
|
82
|
-
end
|
|
66
|
+
# Limit results if there are many
|
|
67
|
+
limited_definitions = definitions.first(options[:limit])
|
|
83
68
|
|
|
84
|
-
|
|
69
|
+
say "Ruby-Build Definitions#{filter ? " (filtered by '#{filter}')" : ''}:", :green
|
|
70
|
+
say '=' * 60, :green
|
|
85
71
|
|
|
86
|
-
|
|
87
|
-
say "
|
|
88
|
-
|
|
89
|
-
|
|
72
|
+
limited_definitions.each do |definition|
|
|
73
|
+
say " #{definition}", :cyan
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if definitions.length > options[:limit]
|
|
77
|
+
remaining = definitions.length - options[:limit]
|
|
78
|
+
say "\n... and #{remaining} more definitions", :yellow
|
|
79
|
+
say 'Use --limit to show more results', :white
|
|
90
80
|
end
|
|
81
|
+
|
|
82
|
+
say "\nTotal: #{definitions.length} definitions", :white
|
|
83
|
+
rescue StandardError => e
|
|
84
|
+
say "❌ Failed to list Ruby-Build definitions: #{e.message}", :red
|
|
85
|
+
say 'Try updating the cache: serialbench ruby-build update', :white
|
|
86
|
+
exit 1
|
|
91
87
|
end
|
|
92
88
|
|
|
93
89
|
desc 'show TAG', 'Show details for a specific Ruby-Build definition'
|
|
@@ -99,21 +95,18 @@ module Serialbench
|
|
|
99
95
|
serialbench ruby-build show 3.2.4
|
|
100
96
|
DESC
|
|
101
97
|
def show(tag)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
say 'Available definitions: serialbench ruby-build list', :white
|
|
115
|
-
exit 1
|
|
116
|
-
end
|
|
98
|
+
definition = RubyBuildManager.show_definition(tag)
|
|
99
|
+
|
|
100
|
+
say "Ruby-Build Definition: #{tag}", :green
|
|
101
|
+
say '=' * 40, :green
|
|
102
|
+
say "Tag: #{definition[:tag]}", :cyan
|
|
103
|
+
say "Available: #{definition[:available] ? '✅ Yes' : '❌ No'}", :cyan
|
|
104
|
+
say "Source: #{definition[:source]}", :cyan
|
|
105
|
+
say "Cache file: #{definition[:cache_file]}", :white
|
|
106
|
+
rescue StandardError => e
|
|
107
|
+
say "❌ #{e.message}", :red
|
|
108
|
+
say 'Available definitions: serialbench ruby-build list', :white
|
|
109
|
+
exit 1
|
|
117
110
|
end
|
|
118
111
|
|
|
119
112
|
desc 'validate TAG', 'Validate a Ruby-Build tag'
|
|
@@ -125,31 +118,28 @@ module Serialbench
|
|
|
125
118
|
serialbench ruby-build validate 3.2.4
|
|
126
119
|
DESC
|
|
127
120
|
def validate(tag)
|
|
128
|
-
|
|
129
|
-
valid = RubyBuildManager.validate_tag(tag)
|
|
130
|
-
|
|
131
|
-
if valid
|
|
132
|
-
say "✅ Ruby-Build tag '#{tag}' is valid", :green
|
|
133
|
-
else
|
|
134
|
-
say "❌ Ruby-Build tag '#{tag}' is not valid", :red
|
|
121
|
+
valid = RubyBuildManager.validate_tag(tag)
|
|
135
122
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
123
|
+
if valid
|
|
124
|
+
say "✅ Ruby-Build tag '#{tag}' is valid", :green
|
|
125
|
+
else
|
|
126
|
+
say "❌ Ruby-Build tag '#{tag}' is not valid", :red
|
|
139
127
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
end
|
|
128
|
+
# Suggest similar tags
|
|
129
|
+
definitions = RubyBuildManager.list_definitions
|
|
130
|
+
similar = definitions.select { |d| d.include?(tag.split('.').first(2).join('.')) }.first(5)
|
|
144
131
|
|
|
145
|
-
|
|
132
|
+
if similar.any?
|
|
133
|
+
say "\n💡 Similar available tags:", :yellow
|
|
134
|
+
similar.each { |s| say " #{s}", :cyan }
|
|
146
135
|
end
|
|
147
136
|
|
|
148
|
-
rescue StandardError => e
|
|
149
|
-
say "❌ Failed to validate tag: #{e.message}", :red
|
|
150
|
-
say 'Try updating the cache: serialbench ruby-build update', :white
|
|
151
137
|
exit 1
|
|
152
138
|
end
|
|
139
|
+
rescue StandardError => e
|
|
140
|
+
say "❌ Failed to validate tag: #{e.message}", :red
|
|
141
|
+
say 'Try updating the cache: serialbench ruby-build update', :white
|
|
142
|
+
exit 1
|
|
153
143
|
end
|
|
154
144
|
|
|
155
145
|
desc 'suggest', 'Suggest Ruby-Build tag for current Ruby version'
|
|
@@ -163,26 +153,23 @@ module Serialbench
|
|
|
163
153
|
serialbench ruby-build suggest
|
|
164
154
|
DESC
|
|
165
155
|
def suggest
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
suggested_tag = RubyBuildManager.suggest_current_ruby_tag
|
|
156
|
+
current_ruby = RUBY_VERSION
|
|
157
|
+
suggested_tag = RubyBuildManager.suggest_current_ruby_tag
|
|
169
158
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
# Validate the suggestion
|
|
174
|
-
if RubyBuildManager.validate_tag(suggested_tag)
|
|
175
|
-
say "✅ Suggested tag is valid", :green
|
|
176
|
-
else
|
|
177
|
-
say "⚠️ Suggested tag not found in ruby-build definitions", :yellow
|
|
178
|
-
say "You may need to update the cache or use a different tag", :white
|
|
179
|
-
end
|
|
159
|
+
say "Current Ruby version: #{current_ruby}", :cyan
|
|
160
|
+
say "Suggested ruby_build_tag: #{suggested_tag}", :green
|
|
180
161
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
say '
|
|
184
|
-
|
|
162
|
+
# Validate the suggestion
|
|
163
|
+
if RubyBuildManager.validate_tag(suggested_tag)
|
|
164
|
+
say '✅ Suggested tag is valid', :green
|
|
165
|
+
else
|
|
166
|
+
say '⚠️ Suggested tag not found in ruby-build definitions', :yellow
|
|
167
|
+
say 'You may need to update the cache or use a different tag', :white
|
|
185
168
|
end
|
|
169
|
+
rescue StandardError => e
|
|
170
|
+
say "❌ Failed to suggest tag: #{e.message}", :red
|
|
171
|
+
say 'Try updating the cache: serialbench ruby-build update', :white
|
|
172
|
+
exit 1
|
|
186
173
|
end
|
|
187
174
|
|
|
188
175
|
desc 'cache-info', 'Show information about the Ruby-Build definitions cache'
|
|
@@ -203,19 +190,19 @@ module Serialbench
|
|
|
203
190
|
say "Location: #{RubyBuildManager::CACHE_FILE}", :cyan
|
|
204
191
|
say "Definitions: #{definitions_count}", :cyan
|
|
205
192
|
say "Age: #{format_cache_age(cache_age)}", :cyan
|
|
206
|
-
say
|
|
193
|
+
say 'Status: ✅ Available', :green
|
|
207
194
|
|
|
208
195
|
if cache_age > 7 * 24 * 60 * 60 # 7 days
|
|
209
196
|
say "\n💡 Cache is older than 7 days, consider updating:", :yellow
|
|
210
|
-
say
|
|
197
|
+
say ' serialbench ruby-build update', :white
|
|
211
198
|
end
|
|
212
199
|
else
|
|
213
200
|
say 'Ruby-Build Cache Information:', :green
|
|
214
201
|
say '=' * 40, :green
|
|
215
202
|
say "Location: #{RubyBuildManager::CACHE_FILE}", :cyan
|
|
216
|
-
say
|
|
203
|
+
say 'Status: ❌ Not found', :red
|
|
217
204
|
say "\n📥 Update the cache first:", :yellow
|
|
218
|
-
say
|
|
205
|
+
say ' serialbench ruby-build update', :white
|
|
219
206
|
end
|
|
220
207
|
end
|
|
221
208
|
|
|
@@ -225,12 +212,12 @@ module Serialbench
|
|
|
225
212
|
days = (seconds / (24 * 60 * 60)).to_i
|
|
226
213
|
hours = ((seconds % (24 * 60 * 60)) / (60 * 60)).to_i
|
|
227
214
|
|
|
228
|
-
if days
|
|
215
|
+
if days.positive?
|
|
229
216
|
"#{days} day#{'s' if days != 1}, #{hours} hour#{'s' if hours != 1}"
|
|
230
|
-
elsif hours
|
|
217
|
+
elsif hours.positive?
|
|
231
218
|
"#{hours} hour#{'s' if hours != 1}"
|
|
232
219
|
else
|
|
233
|
-
|
|
220
|
+
'less than 1 hour'
|
|
234
221
|
end
|
|
235
222
|
end
|
|
236
223
|
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_cli'
|
|
4
|
+
require_relative '../yaml_validator'
|
|
5
|
+
|
|
6
|
+
module Serialbench
|
|
7
|
+
module Cli
|
|
8
|
+
# CLI for validating YAML files against schemas
|
|
9
|
+
class ValidateCli < BaseCli
|
|
10
|
+
desc 'result RESULT_FILE', 'Validate a benchmark result YAML file'
|
|
11
|
+
long_desc <<~DESC
|
|
12
|
+
Validate a benchmark result YAML file against its schema.
|
|
13
|
+
|
|
14
|
+
RESULT_FILE should be the path to a results.yaml file
|
|
15
|
+
|
|
16
|
+
Examples:
|
|
17
|
+
serialbench validate result results/runs/my-run/results.yaml
|
|
18
|
+
serialbench validate result test-artifacts/benchmark-results-ubuntu-latest-ruby-3.4/results.yaml
|
|
19
|
+
DESC
|
|
20
|
+
def result(file_path)
|
|
21
|
+
validate_file(file_path, 'result', 'Result')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc 'config BENCHMARK_CONFIG', 'Validate a benchmark configuration file'
|
|
25
|
+
long_desc <<~DESC
|
|
26
|
+
Validate a benchmark configuration file against its schema.
|
|
27
|
+
|
|
28
|
+
BENCHMARK_CONFIG should be the path to a benchmark config YAML file
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
serialbench validate config config/benchmarks/short.yml
|
|
32
|
+
serialbench validate config config/benchmarks/full.yml
|
|
33
|
+
DESC
|
|
34
|
+
def config(file_path)
|
|
35
|
+
validate_file(file_path, 'benchmark_config', 'Benchmark config')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc 'environment ENV_CONFIG', 'Validate an environment configuration file'
|
|
39
|
+
long_desc <<~DESC
|
|
40
|
+
Validate an environment configuration file against its schema.
|
|
41
|
+
|
|
42
|
+
ENV_CONFIG should be the path to an environment config YAML file
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
serialbench validate environment config/environments/local-dev.yml
|
|
46
|
+
serialbench validate environment config/environments/docker-ruby-3.4.yml
|
|
47
|
+
DESC
|
|
48
|
+
def environment(file_path)
|
|
49
|
+
validate_file(file_path, 'environment_config', 'Environment config')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
desc 'resultset RESULTSET_FILE', 'Validate a resultset YAML file'
|
|
53
|
+
long_desc <<~DESC
|
|
54
|
+
Validate a resultset YAML file against its schema.
|
|
55
|
+
|
|
56
|
+
RESULTSET_FILE should be the path to a resultset.yaml file
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
serialbench validate resultset results/sets/weekly-benchmark/resultset.yaml
|
|
60
|
+
serialbench validate resultset results/sets/comparison/resultset.yaml
|
|
61
|
+
DESC
|
|
62
|
+
def resultset(file_path)
|
|
63
|
+
validate_file(file_path, 'resultset', 'Resultset')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def validate_file(file_path, schema_name, friendly_name)
|
|
69
|
+
unless File.exist?(file_path)
|
|
70
|
+
say "❌ File not found: #{file_path}", :red
|
|
71
|
+
exit 1
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
say "📝 Validating #{friendly_name}: #{file_path}", :cyan
|
|
75
|
+
|
|
76
|
+
if Serialbench::YamlValidator.validate(file_path, schema_name)
|
|
77
|
+
say "✅ #{friendly_name} is valid", :green
|
|
78
|
+
else
|
|
79
|
+
say "❌ #{friendly_name} validation failed", :red
|
|
80
|
+
exit 1
|
|
81
|
+
end
|
|
82
|
+
rescue StandardError => e
|
|
83
|
+
say "❌ Error: #{e.message}", :red
|
|
84
|
+
exit 1
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/serialbench/cli.rb
CHANGED
|
@@ -6,6 +6,7 @@ require_relative 'cli/environment_cli'
|
|
|
6
6
|
require_relative 'cli/benchmark_cli'
|
|
7
7
|
require_relative 'cli/resultset_cli'
|
|
8
8
|
require_relative 'cli/ruby_build_cli'
|
|
9
|
+
require_relative 'cli/validate_cli'
|
|
9
10
|
|
|
10
11
|
module Serialbench
|
|
11
12
|
# Main CLI entry point for the new object-oriented command structure
|
|
@@ -22,6 +23,9 @@ module Serialbench
|
|
|
22
23
|
desc 'ruby_build SUBCOMMAND', 'Manage Ruby-Build definitions for validation'
|
|
23
24
|
subcommand 'ruby_build', Serialbench::Cli::RubyBuildCli
|
|
24
25
|
|
|
26
|
+
desc 'validate SUBCOMMAND', 'Validate YAML files against schemas'
|
|
27
|
+
subcommand 'validate', Serialbench::Cli::ValidateCli
|
|
28
|
+
|
|
25
29
|
desc 'version', 'Show Serialbench version'
|
|
26
30
|
def self.version
|
|
27
31
|
puts "Serialbench version #{Serialbench::VERSION}"
|
|
@@ -73,14 +77,14 @@ module Serialbench
|
|
|
73
77
|
end
|
|
74
78
|
|
|
75
79
|
# Handle unknown commands gracefully
|
|
76
|
-
def method_missing(method_name, *
|
|
80
|
+
def method_missing(method_name, *_args)
|
|
77
81
|
puts "Unknown command: #{method_name}"
|
|
78
82
|
puts ''
|
|
79
83
|
help
|
|
80
84
|
exit 1
|
|
81
85
|
end
|
|
82
86
|
|
|
83
|
-
def respond_to_missing?(
|
|
87
|
+
def respond_to_missing?(_method_name, _include_private = false)
|
|
84
88
|
false
|
|
85
89
|
end
|
|
86
90
|
end
|
|
@@ -39,16 +39,14 @@ module Serialbench
|
|
|
39
39
|
private
|
|
40
40
|
|
|
41
41
|
# Validate configuration against schema
|
|
42
|
-
def validate_config(config_data,
|
|
42
|
+
def validate_config(config_data, _config_path)
|
|
43
43
|
# For now, perform basic validation since we don't have a specific config schema validator
|
|
44
44
|
validate_basic_config(config_data)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
# Load the configuration schema
|
|
48
48
|
def load_schema
|
|
49
|
-
unless File.exist?(SCHEMA_PATH)
|
|
50
|
-
raise ConfigurationError, "Configuration schema not found: #{SCHEMA_PATH}"
|
|
51
|
-
end
|
|
49
|
+
raise ConfigurationError, "Configuration schema not found: #{SCHEMA_PATH}" unless File.exist?(SCHEMA_PATH)
|
|
52
50
|
|
|
53
51
|
begin
|
|
54
52
|
YAML.load_file(SCHEMA_PATH)
|
|
@@ -81,28 +79,22 @@ module Serialbench
|
|
|
81
79
|
|
|
82
80
|
# Validate Docker-specific configuration
|
|
83
81
|
def validate_docker_config(config)
|
|
84
|
-
unless config.image_variants && !config.image_variants.empty?
|
|
85
|
-
raise ConfigurationError, "Docker runtime requires 'image_variants' to be specified"
|
|
86
|
-
end
|
|
82
|
+
raise ConfigurationError, "Docker runtime requires 'image_variants' to be specified" unless config.image_variants && !config.image_variants.empty?
|
|
87
83
|
|
|
88
84
|
invalid_variants = config.image_variants - %w[slim alpine]
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
return if invalid_variants.empty?
|
|
86
|
+
|
|
87
|
+
raise ConfigurationError, "Invalid image variants: #{invalid_variants.join(', ')}. Valid variants: slim, alpine"
|
|
92
88
|
end
|
|
93
89
|
|
|
94
90
|
# Validate ASDF-specific configuration
|
|
95
91
|
def validate_asdf_config(config)
|
|
96
92
|
# Check if ASDF is available
|
|
97
|
-
unless command_available?('asdf')
|
|
98
|
-
raise ConfigurationError, "ASDF is not installed or not in PATH. Please install ASDF to use asdf runtime."
|
|
99
|
-
end
|
|
93
|
+
raise ConfigurationError, 'ASDF is not installed or not in PATH. Please install ASDF to use asdf runtime.' unless command_available?('asdf')
|
|
100
94
|
|
|
101
95
|
# Validate Ruby version format for ASDF (should include patch version)
|
|
102
96
|
config.ruby_versions.each do |version|
|
|
103
|
-
unless version.match?(/^\d+\.\d+\.\d+$/)
|
|
104
|
-
raise ConfigurationError, "ASDF runtime requires full version numbers (e.g., '3.2.8'), got: #{version}"
|
|
105
|
-
end
|
|
97
|
+
raise ConfigurationError, "ASDF runtime requires full version numbers (e.g., '3.2.8'), got: #{version}" unless version.match?(/^\d+\.\d+\.\d+$/)
|
|
106
98
|
end
|
|
107
99
|
end
|
|
108
100
|
|
|
@@ -111,25 +103,22 @@ module Serialbench
|
|
|
111
103
|
# Check required fields
|
|
112
104
|
required_fields = %w[runtime ruby_versions output_dir benchmark_config]
|
|
113
105
|
required_fields.each do |field|
|
|
114
|
-
unless config_data.key?(field)
|
|
115
|
-
raise ConfigurationError, "Missing required field: #{field}"
|
|
116
|
-
end
|
|
106
|
+
raise ConfigurationError, "Missing required field: #{field}" unless config_data.key?(field)
|
|
117
107
|
end
|
|
118
108
|
|
|
119
109
|
# Validate runtime
|
|
120
110
|
valid_runtimes = %w[docker asdf]
|
|
121
111
|
unless valid_runtimes.include?(config_data['runtime'])
|
|
122
|
-
raise ConfigurationError,
|
|
112
|
+
raise ConfigurationError,
|
|
113
|
+
"Invalid runtime: #{config_data['runtime']}. Valid runtimes: #{valid_runtimes.join(', ')}"
|
|
123
114
|
end
|
|
124
115
|
|
|
125
116
|
# Validate ruby_versions is an array
|
|
126
|
-
unless config_data['ruby_versions'].is_a?(Array)
|
|
127
|
-
raise ConfigurationError, "ruby_versions must be an array"
|
|
128
|
-
end
|
|
117
|
+
raise ConfigurationError, 'ruby_versions must be an array' unless config_data['ruby_versions'].is_a?(Array)
|
|
129
118
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
119
|
+
return unless config_data['ruby_versions'].empty?
|
|
120
|
+
|
|
121
|
+
raise ConfigurationError, 'ruby_versions cannot be empty'
|
|
133
122
|
end
|
|
134
123
|
|
|
135
124
|
# Check if a command is available in PATH
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'lutaml/model'
|
|
2
4
|
|
|
3
5
|
module Serialbench
|
|
@@ -51,6 +53,16 @@ module Serialbench
|
|
|
51
53
|
attribute :warmup, :integer, default: -> { 1 }
|
|
52
54
|
attribute :operations, :string, collection: true, values: %w[parse generate memory streaming]
|
|
53
55
|
|
|
56
|
+
key_value do
|
|
57
|
+
map 'name', to: :name
|
|
58
|
+
map 'description', to: :description
|
|
59
|
+
map 'data_sizes', to: :data_sizes
|
|
60
|
+
map 'formats', to: :formats
|
|
61
|
+
map 'iterations', to: :iterations
|
|
62
|
+
map 'warmup', to: :warmup
|
|
63
|
+
map 'operations', to: :operations
|
|
64
|
+
end
|
|
65
|
+
|
|
54
66
|
def to_file(file_path)
|
|
55
67
|
File.write(file_path, to_yaml)
|
|
56
68
|
end
|
|
@@ -8,16 +8,24 @@ module Serialbench
|
|
|
8
8
|
attribute :format, :string, values: %w[xml json yaml toml]
|
|
9
9
|
attribute :name, :string
|
|
10
10
|
attribute :version, :string
|
|
11
|
-
end
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
key_value do
|
|
13
|
+
map 'format', to: :format
|
|
14
|
+
map 'name', to: :name
|
|
15
|
+
map 'version', to: :version
|
|
16
|
+
end
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
class AdapterPerformance < Lutaml::Model::Serializable
|
|
18
20
|
attribute :adapter, :string
|
|
19
21
|
attribute :format, :string, values: %w[xml json yaml toml]
|
|
20
22
|
attribute :data_size, :string, values: %w[small medium large]
|
|
23
|
+
|
|
24
|
+
key_value do
|
|
25
|
+
map 'adapter', to: :adapter
|
|
26
|
+
map 'format', to: :format
|
|
27
|
+
map 'data_size', to: :data_size
|
|
28
|
+
end
|
|
21
29
|
end
|
|
22
30
|
|
|
23
31
|
class IterationPerformance < AdapterPerformance
|
|
@@ -25,6 +33,16 @@ module Serialbench
|
|
|
25
33
|
attribute :time_per_iteration, :float
|
|
26
34
|
attribute :iterations_per_second, :float
|
|
27
35
|
attribute :iterations_count, :integer
|
|
36
|
+
|
|
37
|
+
key_value do
|
|
38
|
+
map 'adapter', to: :adapter
|
|
39
|
+
map 'format', to: :format
|
|
40
|
+
map 'data_size', to: :data_size
|
|
41
|
+
map 'time_per_iterations', to: :time_per_iterations
|
|
42
|
+
map 'time_per_iteration', to: :time_per_iteration
|
|
43
|
+
map 'iterations_per_second', to: :iterations_per_second
|
|
44
|
+
map 'iterations_count', to: :iterations_count
|
|
45
|
+
end
|
|
28
46
|
end
|
|
29
47
|
|
|
30
48
|
class MemoryPerformance < AdapterPerformance
|
|
@@ -32,6 +50,16 @@ module Serialbench
|
|
|
32
50
|
attribute :total_retained, :integer
|
|
33
51
|
attribute :allocated_memory, :integer
|
|
34
52
|
attribute :retained_memory, :integer
|
|
53
|
+
|
|
54
|
+
key_value do
|
|
55
|
+
map 'adapter', to: :adapter
|
|
56
|
+
map 'format', to: :format
|
|
57
|
+
map 'data_size', to: :data_size
|
|
58
|
+
map 'total_allocated', to: :total_allocated
|
|
59
|
+
map 'total_retained', to: :total_retained
|
|
60
|
+
map 'allocated_memory', to: :allocated_memory
|
|
61
|
+
map 'retained_memory', to: :retained_memory
|
|
62
|
+
end
|
|
35
63
|
end
|
|
36
64
|
|
|
37
65
|
class BenchmarkResult < Lutaml::Model::Serializable
|
|
@@ -40,6 +68,14 @@ module Serialbench
|
|
|
40
68
|
attribute :generation, IterationPerformance, collection: true
|
|
41
69
|
attribute :memory, MemoryPerformance, collection: true
|
|
42
70
|
attribute :streaming, IterationPerformance, collection: true
|
|
71
|
+
|
|
72
|
+
key_value do
|
|
73
|
+
map 'serializers', to: :serializers
|
|
74
|
+
map 'parsing', to: :parsing
|
|
75
|
+
map 'generation', to: :generation
|
|
76
|
+
map 'memory', to: :memory
|
|
77
|
+
map 'streaming', to: :streaming
|
|
78
|
+
end
|
|
43
79
|
end
|
|
44
80
|
end
|
|
45
81
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'lutaml/model'
|
|
2
4
|
require_relative '../ruby_build_manager'
|
|
3
5
|
|
|
@@ -43,8 +45,7 @@ module Serialbench
|
|
|
43
45
|
attribute :name, :string
|
|
44
46
|
attribute :kind, :string
|
|
45
47
|
attribute :created_at, :string, default: -> { Time.now.utc.iso8601 }
|
|
46
|
-
attribute :ruby_build_tag, :string
|
|
47
|
-
RubyBuildManager.list_definitions
|
|
48
|
+
attribute :ruby_build_tag, :string
|
|
48
49
|
attribute :description, :string
|
|
49
50
|
attribute :docker, DockerEnvConfig
|
|
50
51
|
attribute :asdf, AsdfEnvConfig
|
|
@@ -15,17 +15,46 @@ module Serialbench
|
|
|
15
15
|
class Platform < Lutaml::Model::Serializable
|
|
16
16
|
attribute :platform_string, :string
|
|
17
17
|
attribute :kind, :string, default: -> { 'local' }
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# Fully qualified: lutaml-model 0.8+ instance-evals default
|
|
19
|
+
# lambdas, so bare detect_os/detect_arch (class methods) no
|
|
20
|
+
# longer resolve there.
|
|
21
|
+
attribute :os, :string, default: -> { Serialbench::Models::Platform.detect_os }
|
|
22
|
+
attribute :arch, :string, default: -> { Serialbench::Models::Platform.detect_arch }
|
|
20
23
|
attribute :ruby_version, :string, default: -> { RUBY_VERSION }
|
|
21
24
|
attribute :ruby_platform, :string, default: -> { RUBY_PLATFORM }
|
|
22
|
-
attribute :ruby_build_tag, :string
|
|
25
|
+
attribute :ruby_build_tag, :string
|
|
26
|
+
|
|
27
|
+
key_value do
|
|
28
|
+
map 'platform_string', to: :platform_string
|
|
29
|
+
map 'kind', to: :kind
|
|
30
|
+
map 'os', to: :os
|
|
31
|
+
map 'arch', to: :arch
|
|
32
|
+
map 'ruby_version', to: :ruby_version
|
|
33
|
+
map 'ruby_platform', to: :ruby_platform
|
|
34
|
+
map 'ruby_build_tag', to: :ruby_build_tag
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.current_local(ruby_version: nil)
|
|
38
|
+
version = ruby_version || RUBY_VERSION
|
|
39
|
+
|
|
40
|
+
# Check for GitHub Actions runner platform
|
|
41
|
+
github_platform = ENV['GITHUB_RUNNER_PLATFORM']
|
|
42
|
+
if github_platform
|
|
43
|
+
os, arch = parse_github_platform(github_platform)
|
|
44
|
+
platform_string = "#{github_platform}-ruby-#{version}"
|
|
45
|
+
else
|
|
46
|
+
os = detect_os
|
|
47
|
+
arch = detect_arch
|
|
48
|
+
platform_string = "local-#{version}"
|
|
49
|
+
end
|
|
23
50
|
|
|
24
|
-
def self.current_local
|
|
25
51
|
new(
|
|
26
|
-
platform_string:
|
|
52
|
+
platform_string: platform_string,
|
|
27
53
|
kind: 'local',
|
|
28
|
-
|
|
54
|
+
os: os,
|
|
55
|
+
arch: arch,
|
|
56
|
+
ruby_version: version,
|
|
57
|
+
ruby_build_tag: version
|
|
29
58
|
)
|
|
30
59
|
end
|
|
31
60
|
|
|
@@ -54,6 +83,32 @@ module Serialbench
|
|
|
54
83
|
'unknown'
|
|
55
84
|
end
|
|
56
85
|
end
|
|
86
|
+
|
|
87
|
+
def self.parse_github_platform(platform_name)
|
|
88
|
+
# Parse GitHub Actions runner platform names
|
|
89
|
+
# Examples: ubuntu-24.04, ubuntu-24.04-arm, macos-13, macos-15-intel,
|
|
90
|
+
# macos-14, macos-15, macos-26, windows-2022, windows-2025, windows-11-arm
|
|
91
|
+
|
|
92
|
+
case platform_name
|
|
93
|
+
when /^ubuntu.*-arm$/
|
|
94
|
+
['linux', 'arm64']
|
|
95
|
+
when /^ubuntu/
|
|
96
|
+
['linux', 'x86_64']
|
|
97
|
+
when /^macos-.*-intel$/
|
|
98
|
+
['macos', 'x86_64']
|
|
99
|
+
when /^macos-(13)$/
|
|
100
|
+
['macos', 'x86_64']
|
|
101
|
+
when /^macos-(14|15|26)$/
|
|
102
|
+
['macos', 'arm64']
|
|
103
|
+
when /^windows.*-arm$/
|
|
104
|
+
['windows', 'arm64']
|
|
105
|
+
when /^windows/
|
|
106
|
+
['windows', 'x86_64']
|
|
107
|
+
else
|
|
108
|
+
# Fallback to automatic detection
|
|
109
|
+
[detect_os, detect_arch]
|
|
110
|
+
end
|
|
111
|
+
end
|
|
57
112
|
end
|
|
58
113
|
end
|
|
59
114
|
end
|