serialbench 0.1.0 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/benchmark.yml +181 -30
- data/.github/workflows/ci.yml +3 -3
- data/.github/workflows/docker.yml +272 -0
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +25 -0
- data/Gemfile +6 -30
- data/README.adoc +381 -415
- data/Rakefile +0 -55
- data/config/benchmarks/full.yml +29 -0
- data/config/benchmarks/short.yml +26 -0
- data/config/environments/asdf-ruby-3.2.yml +8 -0
- data/config/environments/asdf-ruby-3.3.yml +8 -0
- data/config/environments/docker-ruby-3.0.yml +9 -0
- data/config/environments/docker-ruby-3.1.yml +9 -0
- data/config/environments/docker-ruby-3.2.yml +9 -0
- data/config/environments/docker-ruby-3.3.yml +9 -0
- data/config/environments/docker-ruby-3.4.yml +9 -0
- data/docker/Dockerfile.alpine +33 -0
- data/docker/Dockerfile.ubuntu +32 -0
- data/docker/README.md +214 -0
- data/exe/serialbench +1 -1
- data/lib/serialbench/benchmark_runner.rb +270 -350
- data/lib/serialbench/cli/base_cli.rb +51 -0
- data/lib/serialbench/cli/benchmark_cli.rb +380 -0
- data/lib/serialbench/cli/environment_cli.rb +181 -0
- data/lib/serialbench/cli/resultset_cli.rb +215 -0
- data/lib/serialbench/cli/ruby_build_cli.rb +238 -0
- data/lib/serialbench/cli.rb +59 -410
- data/lib/serialbench/config_manager.rb +140 -0
- data/lib/serialbench/models/benchmark_config.rb +63 -0
- data/lib/serialbench/models/benchmark_result.rb +45 -0
- data/lib/serialbench/models/environment_config.rb +71 -0
- data/lib/serialbench/models/platform.rb +59 -0
- data/lib/serialbench/models/result.rb +53 -0
- data/lib/serialbench/models/result_set.rb +71 -0
- data/lib/serialbench/models/result_store.rb +108 -0
- data/lib/serialbench/models.rb +54 -0
- data/lib/serialbench/ruby_build_manager.rb +153 -0
- data/lib/serialbench/runners/asdf_runner.rb +296 -0
- data/lib/serialbench/runners/base.rb +32 -0
- data/lib/serialbench/runners/docker_runner.rb +142 -0
- data/lib/serialbench/serializers/base_serializer.rb +8 -16
- data/lib/serialbench/serializers/json/base_json_serializer.rb +4 -4
- data/lib/serialbench/serializers/json/json_serializer.rb +0 -2
- data/lib/serialbench/serializers/json/oj_serializer.rb +0 -2
- data/lib/serialbench/serializers/json/rapidjson_serializer.rb +50 -0
- data/lib/serialbench/serializers/json/yajl_serializer.rb +6 -4
- data/lib/serialbench/serializers/toml/base_toml_serializer.rb +5 -3
- data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +0 -2
- data/lib/serialbench/serializers/toml/tomlib_serializer.rb +0 -2
- data/lib/serialbench/serializers/toml/tomlrb_serializer.rb +56 -0
- data/lib/serialbench/serializers/xml/base_xml_serializer.rb +4 -9
- data/lib/serialbench/serializers/xml/libxml_serializer.rb +0 -2
- data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +21 -5
- data/lib/serialbench/serializers/xml/oga_serializer.rb +0 -2
- data/lib/serialbench/serializers/xml/ox_serializer.rb +0 -2
- data/lib/serialbench/serializers/xml/rexml_serializer.rb +32 -4
- data/lib/serialbench/serializers/yaml/base_yaml_serializer.rb +59 -0
- data/lib/serialbench/serializers/yaml/psych_serializer.rb +54 -0
- data/lib/serialbench/serializers/yaml/syck_serializer.rb +102 -0
- data/lib/serialbench/serializers.rb +34 -6
- data/lib/serialbench/site_generator.rb +105 -0
- data/lib/serialbench/templates/assets/css/benchmark_report.css +535 -0
- data/lib/serialbench/templates/assets/css/format_based.css +526 -0
- data/lib/serialbench/templates/assets/css/themes.css +588 -0
- data/lib/serialbench/templates/assets/js/chart_helpers.js +381 -0
- data/lib/serialbench/templates/assets/js/dashboard.js +796 -0
- data/lib/serialbench/templates/assets/js/navigation.js +142 -0
- data/lib/serialbench/templates/base.liquid +49 -0
- data/lib/serialbench/templates/format_based.liquid +279 -0
- data/lib/serialbench/templates/partials/chart_section.liquid +4 -0
- data/lib/serialbench/version.rb +1 -1
- data/lib/serialbench.rb +2 -31
- data/serialbench.gemspec +28 -17
- metadata +192 -55
- data/lib/serialbench/chart_generator.rb +0 -821
- data/lib/serialbench/result_formatter.rb +0 -182
- data/lib/serialbench/result_merger.rb +0 -1201
- data/lib/serialbench/serializers/xml/base_parser.rb +0 -69
- data/lib/serialbench/serializers/xml/libxml_parser.rb +0 -98
- data/lib/serialbench/serializers/xml/nokogiri_parser.rb +0 -111
- data/lib/serialbench/serializers/xml/oga_parser.rb +0 -85
- data/lib/serialbench/serializers/xml/ox_parser.rb +0 -64
- 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
|
+
}
|