serialbench 0.1.1 → 0.1.2

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/benchmark.yml +13 -5
  3. data/.github/workflows/docker.yml +35 -9
  4. data/.github/workflows/rake.yml +15 -0
  5. data/Gemfile +2 -1
  6. data/README.adoc +267 -1129
  7. data/Rakefile +0 -55
  8. data/config/benchmarks/full.yml +29 -0
  9. data/config/benchmarks/short.yml +26 -0
  10. data/config/environments/asdf-ruby-3.2.yml +8 -0
  11. data/config/environments/asdf-ruby-3.3.yml +8 -0
  12. data/config/environments/docker-ruby-3.0.yml +9 -0
  13. data/config/environments/docker-ruby-3.1.yml +9 -0
  14. data/config/environments/docker-ruby-3.2.yml +9 -0
  15. data/config/environments/docker-ruby-3.3.yml +9 -0
  16. data/config/environments/docker-ruby-3.4.yml +9 -0
  17. data/docker/Dockerfile.alpine +33 -0
  18. data/docker/{Dockerfile.benchmark → Dockerfile.ubuntu} +4 -3
  19. data/docker/README.md +2 -2
  20. data/exe/serialbench +1 -1
  21. data/lib/serialbench/benchmark_runner.rb +261 -423
  22. data/lib/serialbench/cli/base_cli.rb +51 -0
  23. data/lib/serialbench/cli/benchmark_cli.rb +380 -0
  24. data/lib/serialbench/cli/environment_cli.rb +181 -0
  25. data/lib/serialbench/cli/resultset_cli.rb +215 -0
  26. data/lib/serialbench/cli/ruby_build_cli.rb +238 -0
  27. data/lib/serialbench/cli.rb +58 -601
  28. data/lib/serialbench/config_manager.rb +140 -0
  29. data/lib/serialbench/models/benchmark_config.rb +63 -0
  30. data/lib/serialbench/models/benchmark_result.rb +45 -0
  31. data/lib/serialbench/models/environment_config.rb +71 -0
  32. data/lib/serialbench/models/platform.rb +59 -0
  33. data/lib/serialbench/models/result.rb +53 -0
  34. data/lib/serialbench/models/result_set.rb +71 -0
  35. data/lib/serialbench/models/result_store.rb +108 -0
  36. data/lib/serialbench/models.rb +54 -0
  37. data/lib/serialbench/ruby_build_manager.rb +153 -0
  38. data/lib/serialbench/runners/asdf_runner.rb +296 -0
  39. data/lib/serialbench/runners/base.rb +32 -0
  40. data/lib/serialbench/runners/docker_runner.rb +142 -0
  41. data/lib/serialbench/serializers/base_serializer.rb +8 -16
  42. data/lib/serialbench/serializers/json/base_json_serializer.rb +4 -4
  43. data/lib/serialbench/serializers/json/json_serializer.rb +0 -2
  44. data/lib/serialbench/serializers/json/oj_serializer.rb +0 -2
  45. data/lib/serialbench/serializers/json/yajl_serializer.rb +0 -2
  46. data/lib/serialbench/serializers/toml/base_toml_serializer.rb +5 -3
  47. data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +0 -2
  48. data/lib/serialbench/serializers/toml/tomlib_serializer.rb +0 -2
  49. data/lib/serialbench/serializers/toml/tomlrb_serializer.rb +56 -0
  50. data/lib/serialbench/serializers/xml/base_xml_serializer.rb +4 -9
  51. data/lib/serialbench/serializers/xml/libxml_serializer.rb +0 -2
  52. data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +0 -2
  53. data/lib/serialbench/serializers/xml/oga_serializer.rb +0 -2
  54. data/lib/serialbench/serializers/xml/ox_serializer.rb +0 -2
  55. data/lib/serialbench/serializers/xml/rexml_serializer.rb +0 -2
  56. data/lib/serialbench/serializers/yaml/base_yaml_serializer.rb +5 -1
  57. data/lib/serialbench/serializers/yaml/syck_serializer.rb +59 -22
  58. data/lib/serialbench/serializers.rb +23 -6
  59. data/lib/serialbench/site_generator.rb +105 -0
  60. data/lib/serialbench/templates/assets/css/benchmark_report.css +535 -0
  61. data/lib/serialbench/templates/assets/css/format_based.css +526 -0
  62. data/lib/serialbench/templates/assets/css/themes.css +588 -0
  63. data/lib/serialbench/templates/assets/js/chart_helpers.js +381 -0
  64. data/lib/serialbench/templates/assets/js/dashboard.js +796 -0
  65. data/lib/serialbench/templates/assets/js/navigation.js +142 -0
  66. data/lib/serialbench/templates/base.liquid +49 -0
  67. data/lib/serialbench/templates/format_based.liquid +279 -0
  68. data/lib/serialbench/templates/partials/chart_section.liquid +4 -0
  69. data/lib/serialbench/version.rb +1 -1
  70. data/lib/serialbench.rb +2 -31
  71. data/serialbench.gemspec +4 -1
  72. metadata +86 -16
  73. data/config/ci.yml +0 -22
  74. data/config/full.yml +0 -30
  75. data/docker/run-benchmarks.sh +0 -356
  76. data/lib/serialbench/chart_generator.rb +0 -821
  77. data/lib/serialbench/result_formatter.rb +0 -182
  78. data/lib/serialbench/result_merger.rb +0 -1201
  79. data/lib/serialbench/serializers/xml/base_parser.rb +0 -69
  80. data/lib/serialbench/serializers/xml/libxml_parser.rb +0 -98
  81. data/lib/serialbench/serializers/xml/nokogiri_parser.rb +0 -111
  82. data/lib/serialbench/serializers/xml/oga_parser.rb +0 -85
  83. data/lib/serialbench/serializers/xml/ox_parser.rb +0 -64
  84. data/lib/serialbench/serializers/xml/rexml_parser.rb +0 -129
@@ -0,0 +1,381 @@
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
+ const colors = [
176
+ '#6366f1', '#8b5cf6', '#06b6d4', '#10b981', '#f59e0b',
177
+ '#ef4444', '#ec4899', '#84cc16', '#f97316', '#6b7280'
178
+ ];
179
+
180
+ const datasets = serializers.map((serializer, index) => {
181
+ const serializerData = data[serializer];
182
+ console.log(`🔍 Processing serializer ${serializer}:`, serializerData);
183
+
184
+ const values = environments.map(env => {
185
+ const value = serializerData[env]?.iterations_per_second || 0;
186
+ console.log(` 📊 ${env}: ${value}`);
187
+ return value;
188
+ });
189
+
190
+ console.log(`📊 Values for ${serializer}:`, values);
191
+
192
+ return {
193
+ label: serializer,
194
+ data: values,
195
+ backgroundColor: colors[index % colors.length],
196
+ borderColor: colors[index % colors.length],
197
+ borderWidth: 2,
198
+ borderRadius: 4,
199
+ borderSkipped: false,
200
+ };
201
+ });
202
+
203
+ // Convert environment names to readable Ruby versions
204
+ const labels = environments.map(env => {
205
+ const match = env.match(/(\d+_\d+_\d+)/);
206
+ return match ? `Ruby ${match[1].replace(/_/g, '.')}` : env;
207
+ });
208
+
209
+ console.log(`🏷️ Chart labels:`, labels);
210
+ console.log(`📊 Chart datasets:`, datasets);
211
+
212
+ try {
213
+ const chartConfig = {
214
+ type: 'bar',
215
+ data: {
216
+ labels: labels,
217
+ datasets: datasets
218
+ },
219
+ options: {
220
+ responsive: true,
221
+ maintainAspectRatio: false,
222
+ plugins: {
223
+ title: {
224
+ display: true,
225
+ text: title,
226
+ font: { size: 16, weight: 'bold' },
227
+ color: '#374151'
228
+ },
229
+ legend: {
230
+ position: 'top',
231
+ labels: {
232
+ usePointStyle: true,
233
+ padding: 20,
234
+ font: { size: 12 }
235
+ }
236
+ }
237
+ },
238
+ scales: {
239
+ y: {
240
+ beginAtZero: true,
241
+ title: {
242
+ display: true,
243
+ text: 'Iterations per Second',
244
+ font: { size: 12, weight: 'bold' }
245
+ },
246
+ grid: {
247
+ color: '#f3f4f6'
248
+ }
249
+ },
250
+ x: {
251
+ title: {
252
+ display: true,
253
+ text: 'Ruby Versions',
254
+ font: { size: 12, weight: 'bold' }
255
+ },
256
+ grid: {
257
+ display: false
258
+ }
259
+ }
260
+ }
261
+ }
262
+ };
263
+
264
+ console.log(`🎯 Creating chart with config:`, chartConfig);
265
+ const chart = new Chart(ctx, chartConfig);
266
+ console.log(`✅ Chart created successfully:`, chart);
267
+ console.log(`✅ Successfully created performance chart: ${canvasId}`);
268
+ } catch (error) {
269
+ console.error(`❌ Error creating performance chart ${canvasId}:`, error);
270
+ console.error(`❌ Error stack:`, error.stack);
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Create a memory chart for multi-version comparison
276
+ */
277
+ function createMemoryChart(canvasId, title, data, environments) {
278
+ if (!isChartJsLoaded()) {
279
+ console.error('Chart.js is not loaded');
280
+ return;
281
+ }
282
+
283
+ const canvas = document.getElementById(canvasId);
284
+ if (!canvas) {
285
+ console.warn(`Canvas element with id '${canvasId}' not found`);
286
+ return;
287
+ }
288
+
289
+ const ctx = canvas.getContext('2d');
290
+
291
+ const serializers = Object.keys(data);
292
+ if (serializers.length === 0) {
293
+ console.warn(`No data available for memory chart: ${canvasId}`);
294
+ return;
295
+ }
296
+
297
+ const colors = [
298
+ '#6366f1', '#8b5cf6', '#06b6d4', '#10b981', '#f59e0b',
299
+ '#ef4444', '#ec4899', '#84cc16', '#f97316', '#6b7280'
300
+ ];
301
+
302
+ const datasets = serializers.map((serializer, index) => {
303
+ const serializerData = data[serializer];
304
+ const values = environments.map(env => {
305
+ const envData = serializerData[env];
306
+ return envData ? (envData.allocated_memory / 1024 / 1024) : 0; // Convert to MB
307
+ });
308
+
309
+ return {
310
+ label: serializer,
311
+ data: values,
312
+ backgroundColor: colors[index % colors.length],
313
+ borderColor: colors[index % colors.length],
314
+ borderWidth: 2,
315
+ borderRadius: 4,
316
+ borderSkipped: false,
317
+ };
318
+ });
319
+
320
+ // Convert environment names to readable Ruby versions
321
+ const labels = environments.map(env => {
322
+ const match = env.match(/(\d+_\d+_\d+)/);
323
+ return match ? `Ruby ${match[1].replace(/_/g, '.')}` : env;
324
+ });
325
+
326
+ try {
327
+ new Chart(ctx, {
328
+ type: 'bar',
329
+ data: {
330
+ labels: labels,
331
+ datasets: datasets
332
+ },
333
+ options: {
334
+ responsive: true,
335
+ maintainAspectRatio: false,
336
+ plugins: {
337
+ title: {
338
+ display: true,
339
+ text: title,
340
+ font: { size: 16, weight: 'bold' },
341
+ color: '#374151'
342
+ },
343
+ legend: {
344
+ position: 'top',
345
+ labels: {
346
+ usePointStyle: true,
347
+ padding: 20,
348
+ font: { size: 12 }
349
+ }
350
+ }
351
+ },
352
+ scales: {
353
+ y: {
354
+ beginAtZero: true,
355
+ title: {
356
+ display: true,
357
+ text: 'Memory Usage (MB)',
358
+ font: { size: 12, weight: 'bold' }
359
+ },
360
+ grid: {
361
+ color: '#f3f4f6'
362
+ }
363
+ },
364
+ x: {
365
+ title: {
366
+ display: true,
367
+ text: 'Ruby Versions',
368
+ font: { size: 12, weight: 'bold' }
369
+ },
370
+ grid: {
371
+ display: false
372
+ }
373
+ }
374
+ }
375
+ }
376
+ });
377
+ console.log(`Successfully created memory chart: ${canvasId}`);
378
+ } catch (error) {
379
+ console.error(`Error creating memory chart ${canvasId}:`, error);
380
+ }
381
+ }