serialbench 0.1.1 → 0.1.3

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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/benchmark.yml +273 -220
  3. data/.github/workflows/rake.yml +26 -0
  4. data/.github/workflows/windows-debug.yml +171 -0
  5. data/.gitignore +32 -0
  6. data/.rubocop.yml +1 -0
  7. data/.rubocop_todo.yml +274 -0
  8. data/Gemfile +14 -1
  9. data/README.adoc +292 -1118
  10. data/Rakefile +0 -55
  11. data/config/benchmarks/full.yml +29 -0
  12. data/config/benchmarks/short.yml +26 -0
  13. data/config/environments/asdf-ruby-3.2.yml +8 -0
  14. data/config/environments/asdf-ruby-3.3.yml +8 -0
  15. data/config/environments/docker-ruby-3.0.yml +9 -0
  16. data/config/environments/docker-ruby-3.1.yml +9 -0
  17. data/config/environments/docker-ruby-3.2.yml +9 -0
  18. data/config/environments/docker-ruby-3.3.yml +9 -0
  19. data/config/environments/docker-ruby-3.4.yml +9 -0
  20. data/data/schemas/result.yml +29 -0
  21. data/docker/Dockerfile.alpine +33 -0
  22. data/docker/{Dockerfile.benchmark → Dockerfile.ubuntu} +4 -3
  23. data/docker/README.md +2 -2
  24. data/docs/PLATFORM_VALIDATION_FIX.md +79 -0
  25. data/docs/SYCK_YAML_FIX.md +91 -0
  26. data/docs/WEBSITE_COMPLETION_PLAN.md +440 -0
  27. data/docs/WINDOWS_LIBXML_FIX.md +136 -0
  28. data/docs/WINDOWS_SETUP.md +122 -0
  29. data/exe/serialbench +1 -1
  30. data/lib/serialbench/benchmark_runner.rb +261 -423
  31. data/lib/serialbench/cli/base_cli.rb +51 -0
  32. data/lib/serialbench/cli/benchmark_cli.rb +453 -0
  33. data/lib/serialbench/cli/environment_cli.rb +181 -0
  34. data/lib/serialbench/cli/resultset_cli.rb +261 -0
  35. data/lib/serialbench/cli/ruby_build_cli.rb +225 -0
  36. data/lib/serialbench/cli/validate_cli.rb +88 -0
  37. data/lib/serialbench/cli.rb +61 -600
  38. data/lib/serialbench/config_manager.rb +129 -0
  39. data/lib/serialbench/models/benchmark_config.rb +75 -0
  40. data/lib/serialbench/models/benchmark_result.rb +81 -0
  41. data/lib/serialbench/models/environment_config.rb +72 -0
  42. data/lib/serialbench/models/platform.rb +111 -0
  43. data/lib/serialbench/models/result.rb +80 -0
  44. data/lib/serialbench/models/result_set.rb +79 -0
  45. data/lib/serialbench/models/result_store.rb +108 -0
  46. data/lib/serialbench/models.rb +54 -0
  47. data/lib/serialbench/ruby_build_manager.rb +149 -0
  48. data/lib/serialbench/runners/asdf_runner.rb +296 -0
  49. data/lib/serialbench/runners/base.rb +32 -0
  50. data/lib/serialbench/runners/docker_runner.rb +140 -0
  51. data/lib/serialbench/runners/local_runner.rb +71 -0
  52. data/lib/serialbench/serializers/base_serializer.rb +9 -17
  53. data/lib/serialbench/serializers/json/base_json_serializer.rb +4 -4
  54. data/lib/serialbench/serializers/json/json_serializer.rb +0 -2
  55. data/lib/serialbench/serializers/json/oj_serializer.rb +0 -2
  56. data/lib/serialbench/serializers/json/rapidjson_serializer.rb +1 -1
  57. data/lib/serialbench/serializers/json/yajl_serializer.rb +0 -2
  58. data/lib/serialbench/serializers/toml/base_toml_serializer.rb +5 -5
  59. data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +1 -3
  60. data/lib/serialbench/serializers/toml/tomlib_serializer.rb +1 -3
  61. data/lib/serialbench/serializers/toml/tomlrb_serializer.rb +56 -0
  62. data/lib/serialbench/serializers/xml/base_xml_serializer.rb +4 -9
  63. data/lib/serialbench/serializers/xml/libxml_serializer.rb +4 -10
  64. data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +2 -4
  65. data/lib/serialbench/serializers/xml/oga_serializer.rb +4 -10
  66. data/lib/serialbench/serializers/xml/ox_serializer.rb +2 -4
  67. data/lib/serialbench/serializers/xml/rexml_serializer.rb +3 -5
  68. data/lib/serialbench/serializers/yaml/base_yaml_serializer.rb +5 -1
  69. data/lib/serialbench/serializers/yaml/psych_serializer.rb +1 -1
  70. data/lib/serialbench/serializers/yaml/syck_serializer.rb +60 -23
  71. data/lib/serialbench/serializers.rb +23 -6
  72. data/lib/serialbench/site_generator.rb +283 -0
  73. data/lib/serialbench/templates/assets/css/benchmark_report.css +535 -0
  74. data/lib/serialbench/templates/assets/css/format_based.css +474 -0
  75. data/lib/serialbench/templates/assets/css/themes.css +589 -0
  76. data/lib/serialbench/templates/assets/js/chart_helpers.js +411 -0
  77. data/lib/serialbench/templates/assets/js/dashboard.js +795 -0
  78. data/lib/serialbench/templates/assets/js/navigation.js +142 -0
  79. data/lib/serialbench/templates/base.liquid +49 -0
  80. data/lib/serialbench/templates/format_based.liquid +507 -0
  81. data/lib/serialbench/templates/partials/chart_section.liquid +4 -0
  82. data/lib/serialbench/version.rb +1 -1
  83. data/lib/serialbench/yaml_validator.rb +36 -0
  84. data/lib/serialbench.rb +2 -31
  85. data/serialbench.gemspec +15 -3
  86. metadata +106 -25
  87. data/.github/workflows/ci.yml +0 -74
  88. data/.github/workflows/docker.yml +0 -246
  89. data/config/ci.yml +0 -22
  90. data/config/full.yml +0 -30
  91. data/docker/run-benchmarks.sh +0 -356
  92. data/lib/serialbench/chart_generator.rb +0 -821
  93. data/lib/serialbench/result_formatter.rb +0 -182
  94. data/lib/serialbench/result_merger.rb +0 -1201
  95. data/lib/serialbench/serializers/xml/base_parser.rb +0 -69
  96. data/lib/serialbench/serializers/xml/libxml_parser.rb +0 -98
  97. data/lib/serialbench/serializers/xml/nokogiri_parser.rb +0 -111
  98. data/lib/serialbench/serializers/xml/oga_parser.rb +0 -85
  99. data/lib/serialbench/serializers/xml/ox_parser.rb +0 -64
  100. data/lib/serialbench/serializers/xml/rexml_parser.rb +0 -129
@@ -0,0 +1,411 @@
1
+ // Chart.js helper functions for Serialbench reports
2
+
3
+ /**
4
+ * Check if Chart.js is loaded
5
+ */
6
+ function isChartJsLoaded() {
7
+ return typeof Chart !== 'undefined';
8
+ }
9
+
10
+ /**
11
+ * Create a performance chart for single benchmark results
12
+ */
13
+ function createSinglePerformanceChart(canvasId, title, data, metric) {
14
+ if (!isChartJsLoaded()) {
15
+ console.error('Chart.js is not loaded');
16
+ return;
17
+ }
18
+
19
+ const canvas = document.getElementById(canvasId);
20
+ if (!canvas) {
21
+ console.warn(`Canvas element with id '${canvasId}' not found`);
22
+ return;
23
+ }
24
+
25
+ const ctx = canvas.getContext('2d');
26
+
27
+ const serializers = Object.keys(data);
28
+ const values = serializers.map(serializer => {
29
+ const serializerData = data[serializer];
30
+ return serializerData[metric] || 0;
31
+ });
32
+
33
+ const colors = serializers.map((_, index) => `hsl(${index * 60}, 70%, 50%)`);
34
+
35
+ try {
36
+ new Chart(ctx, {
37
+ type: 'bar',
38
+ data: {
39
+ labels: serializers,
40
+ datasets: [{
41
+ label: metric === 'iterations_per_second' ? 'Operations/Second' : 'Time (ms)',
42
+ data: values,
43
+ backgroundColor: colors,
44
+ borderColor: colors.map(color => color.replace('50%', '40%')),
45
+ borderWidth: 1
46
+ }]
47
+ },
48
+ options: {
49
+ responsive: true,
50
+ plugins: {
51
+ title: {
52
+ display: true,
53
+ text: title
54
+ },
55
+ legend: {
56
+ display: false
57
+ }
58
+ },
59
+ scales: {
60
+ y: {
61
+ beginAtZero: true,
62
+ title: {
63
+ display: true,
64
+ text: metric === 'iterations_per_second' ? 'Operations/Second' : 'Time (ms)'
65
+ }
66
+ }
67
+ }
68
+ }
69
+ });
70
+ console.log(`Successfully created chart: ${canvasId}`);
71
+ } catch (error) {
72
+ console.error(`Error creating chart ${canvasId}:`, error);
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Create a memory chart for single benchmark results
78
+ */
79
+ function createSingleMemoryChart(canvasId, title, data) {
80
+ if (!isChartJsLoaded()) {
81
+ console.error('Chart.js is not loaded');
82
+ return;
83
+ }
84
+
85
+ const canvas = document.getElementById(canvasId);
86
+ if (!canvas) {
87
+ console.warn(`Canvas element with id '${canvasId}' not found`);
88
+ return;
89
+ }
90
+
91
+ const ctx = canvas.getContext('2d');
92
+
93
+ const serializers = Object.keys(data);
94
+ const values = serializers.map(serializer => {
95
+ const serializerData = data[serializer];
96
+ return serializerData.allocated_memory ? (serializerData.allocated_memory / 1024 / 1024) : 0;
97
+ });
98
+
99
+ const colors = serializers.map((_, index) => `hsl(${index * 60}, 70%, 50%)`);
100
+
101
+ try {
102
+ new Chart(ctx, {
103
+ type: 'bar',
104
+ data: {
105
+ labels: serializers,
106
+ datasets: [{
107
+ label: 'Memory Usage (MB)',
108
+ data: values,
109
+ backgroundColor: colors,
110
+ borderColor: colors.map(color => color.replace('50%', '40%')),
111
+ borderWidth: 1
112
+ }]
113
+ },
114
+ options: {
115
+ responsive: true,
116
+ plugins: {
117
+ title: {
118
+ display: true,
119
+ text: title
120
+ },
121
+ legend: {
122
+ display: false
123
+ }
124
+ },
125
+ scales: {
126
+ y: {
127
+ beginAtZero: true,
128
+ title: {
129
+ display: true,
130
+ text: 'Memory Usage (MB)'
131
+ }
132
+ }
133
+ }
134
+ }
135
+ });
136
+ console.log(`Successfully created memory chart: ${canvasId}`);
137
+ } catch (error) {
138
+ console.error(`Error creating memory chart ${canvasId}:`, error);
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Create a performance chart for multi-version comparison
144
+ */
145
+ function createPerformanceChart(canvasId, title, data, metric, environments) {
146
+ console.log(`🎨 createPerformanceChart called for ${canvasId}`);
147
+ console.log(`📊 Chart.js available:`, typeof Chart !== 'undefined');
148
+ console.log(`📊 Chart.js object:`, Chart);
149
+
150
+ if (!isChartJsLoaded()) {
151
+ console.error('❌ Chart.js is not loaded');
152
+ return;
153
+ }
154
+
155
+ const canvas = document.getElementById(canvasId);
156
+ if (!canvas) {
157
+ console.warn(`⚠️ Canvas element with id '${canvasId}' not found`);
158
+ return;
159
+ }
160
+
161
+ console.log(`✅ Canvas found:`, canvas);
162
+ const ctx = canvas.getContext('2d');
163
+ console.log(`✅ Context obtained:`, ctx);
164
+
165
+ const serializers = Object.keys(data);
166
+ if (serializers.length === 0) {
167
+ console.warn(`⚠️ No data available for chart: ${canvasId}`);
168
+ return;
169
+ }
170
+
171
+ console.log(`📈 Serializers:`, serializers);
172
+ console.log(`🌍 Environments:`, environments);
173
+ console.log(`📊 Raw data:`, data);
174
+
175
+ // Get theme-aware colors
176
+ const isDarkMode = document.documentElement.getAttribute('data-theme') === 'dark';
177
+ const textColor = getComputedStyle(document.documentElement).getPropertyValue('--text-primary').trim() || (isDarkMode ? '#F8FAFC' : '#0F172A');
178
+ const gridColor = getComputedStyle(document.documentElement).getPropertyValue('--border-primary').trim() || (isDarkMode ? '#475569' : '#E2E8F0');
179
+
180
+ // High contrast color palette
181
+ const colors = [
182
+ '#F97316', '#3B82F6', '#10B981', '#EF4444', '#8B5CF6',
183
+ '#F59E0B', '#EC4899', '#06B6D4', '#84CC16', '#6366F1'
184
+ ];
185
+
186
+ const datasets = serializers.map((serializer, index) => {
187
+ const serializerData = data[serializer];
188
+ console.log(`🔍 Processing serializer ${serializer}:`, serializerData);
189
+
190
+ const values = environments.map(env => {
191
+ const value = serializerData[env]?.iterations_per_second || 0;
192
+ console.log(` 📊 ${env}: ${value}`);
193
+ return value;
194
+ });
195
+
196
+ console.log(`📊 Values for ${serializer}:`, values);
197
+
198
+ return {
199
+ label: serializer,
200
+ data: values,
201
+ backgroundColor: colors[index % colors.length],
202
+ borderColor: colors[index % colors.length],
203
+ borderWidth: 2,
204
+ borderRadius: 4,
205
+ borderSkipped: false,
206
+ };
207
+ });
208
+
209
+ // Convert environment names to readable Ruby versions
210
+ const labels = environments.map(env => {
211
+ const match = env.match(/(\d+_\d+_\d+)/);
212
+ return match ? `Ruby ${match[1].replace(/_/g, '.')}` : env;
213
+ });
214
+
215
+ console.log(`🏷️ Chart labels:`, labels);
216
+ console.log(`📊 Chart datasets:`, datasets);
217
+
218
+ try {
219
+ const chartConfig = {
220
+ type: 'bar',
221
+ data: {
222
+ labels: labels,
223
+ datasets: datasets
224
+ },
225
+ options: {
226
+ responsive: true,
227
+ maintainAspectRatio: false,
228
+ plugins: {
229
+ title: {
230
+ display: true,
231
+ text: title,
232
+ font: { size: 16, weight: 'bold' },
233
+ color: textColor
234
+ },
235
+ legend: {
236
+ position: 'top',
237
+ labels: {
238
+ usePointStyle: true,
239
+ padding: 20,
240
+ font: { size: 12 },
241
+ color: textColor
242
+ }
243
+ }
244
+ },
245
+ scales: {
246
+ y: {
247
+ beginAtZero: true,
248
+ title: {
249
+ display: true,
250
+ text: 'Iterations per Second',
251
+ font: { size: 12, weight: 'bold' },
252
+ color: textColor
253
+ },
254
+ ticks: {
255
+ color: textColor
256
+ },
257
+ grid: {
258
+ color: gridColor
259
+ }
260
+ },
261
+ x: {
262
+ title: {
263
+ display: true,
264
+ text: 'Ruby Versions',
265
+ font: { size: 12, weight: 'bold' },
266
+ color: textColor
267
+ },
268
+ ticks: {
269
+ color: textColor
270
+ },
271
+ grid: {
272
+ display: false
273
+ }
274
+ }
275
+ }
276
+ }
277
+ };
278
+
279
+ console.log(`🎯 Creating chart with config:`, chartConfig);
280
+ const chart = new Chart(ctx, chartConfig);
281
+ console.log(`✅ Chart created successfully:`, chart);
282
+ console.log(`✅ Successfully created performance chart: ${canvasId}`);
283
+ } catch (error) {
284
+ console.error(`❌ Error creating performance chart ${canvasId}:`, error);
285
+ console.error(`❌ Error stack:`, error.stack);
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Create a memory chart for multi-version comparison
291
+ */
292
+ function createMemoryChart(canvasId, title, data, environments) {
293
+ if (!isChartJsLoaded()) {
294
+ console.error('Chart.js is not loaded');
295
+ return;
296
+ }
297
+
298
+ const canvas = document.getElementById(canvasId);
299
+ if (!canvas) {
300
+ console.warn(`Canvas element with id '${canvasId}' not found`);
301
+ return;
302
+ }
303
+
304
+ const ctx = canvas.getContext('2d');
305
+
306
+ const serializers = Object.keys(data);
307
+ if (serializers.length === 0) {
308
+ console.warn(`No data available for memory chart: ${canvasId}`);
309
+ return;
310
+ }
311
+
312
+ // Get theme-aware colors
313
+ const isDarkMode = document.documentElement.getAttribute('data-theme') === 'dark';
314
+ const textColor = getComputedStyle(document.documentElement).getPropertyValue('--text-primary').trim() || (isDarkMode ? '#F8FAFC' : '#0F172A');
315
+ const gridColor = getComputedStyle(document.documentElement).getPropertyValue('--border-primary').trim() || (isDarkMode ? '#475569' : '#E2E8F0');
316
+
317
+ // High contrast color palette
318
+ const colors = [
319
+ '#F97316', '#3B82F6', '#10B981', '#EF4444', '#8B5CF6',
320
+ '#F59E0B', '#EC4899', '#06B6D4', '#84CC16', '#6366F1'
321
+ ];
322
+
323
+ const datasets = serializers.map((serializer, index) => {
324
+ const serializerData = data[serializer];
325
+ const values = environments.map(env => {
326
+ const envData = serializerData[env];
327
+ return envData ? (envData.allocated_memory / 1024 / 1024) : 0; // Convert to MB
328
+ });
329
+
330
+ return {
331
+ label: serializer,
332
+ data: values,
333
+ backgroundColor: colors[index % colors.length],
334
+ borderColor: colors[index % colors.length],
335
+ borderWidth: 2,
336
+ borderRadius: 4,
337
+ borderSkipped: false,
338
+ };
339
+ });
340
+
341
+ // Convert environment names to readable Ruby versions
342
+ const labels = environments.map(env => {
343
+ const match = env.match(/(\d+_\d+_\d+)/);
344
+ return match ? `Ruby ${match[1].replace(/_/g, '.')}` : env;
345
+ });
346
+
347
+ try {
348
+ new Chart(ctx, {
349
+ type: 'bar',
350
+ data: {
351
+ labels: labels,
352
+ datasets: datasets
353
+ },
354
+ options: {
355
+ responsive: true,
356
+ maintainAspectRatio: false,
357
+ plugins: {
358
+ title: {
359
+ display: true,
360
+ text: title,
361
+ font: { size: 16, weight: 'bold' },
362
+ color: textColor
363
+ },
364
+ legend: {
365
+ position: 'top',
366
+ labels: {
367
+ usePointStyle: true,
368
+ padding: 20,
369
+ font: { size: 12 },
370
+ color: textColor
371
+ }
372
+ }
373
+ },
374
+ scales: {
375
+ y: {
376
+ beginAtZero: true,
377
+ title: {
378
+ display: true,
379
+ text: 'Memory Usage (MB)',
380
+ font: { size: 12, weight: 'bold' },
381
+ color: textColor
382
+ },
383
+ ticks: {
384
+ color: textColor
385
+ },
386
+ grid: {
387
+ color: gridColor
388
+ }
389
+ },
390
+ x: {
391
+ title: {
392
+ display: true,
393
+ text: 'Ruby Versions',
394
+ font: { size: 12, weight: 'bold' },
395
+ color: textColor
396
+ },
397
+ ticks: {
398
+ color: textColor
399
+ },
400
+ grid: {
401
+ display: false
402
+ }
403
+ }
404
+ }
405
+ }
406
+ });
407
+ console.log(`Successfully created memory chart: ${canvasId}`);
408
+ } catch (error) {
409
+ console.error(`Error creating memory chart ${canvasId}:`, error);
410
+ }
411
+ }