serialbench 0.1.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 +7 -0
- data/.github/workflows/benchmark.yml +125 -0
- data/.github/workflows/ci.yml +74 -0
- data/.rspec +4 -0
- data/Gemfile +34 -0
- data/README.adoc +592 -0
- data/Rakefile +63 -0
- data/exe/serialbench +6 -0
- data/lib/serialbench/benchmark_runner.rb +540 -0
- data/lib/serialbench/chart_generator.rb +821 -0
- data/lib/serialbench/cli.rb +438 -0
- data/lib/serialbench/memory_profiler.rb +31 -0
- data/lib/serialbench/result_formatter.rb +182 -0
- data/lib/serialbench/result_merger.rb +1201 -0
- data/lib/serialbench/serializers/base_serializer.rb +63 -0
- data/lib/serialbench/serializers/json/base_json_serializer.rb +67 -0
- data/lib/serialbench/serializers/json/json_serializer.rb +58 -0
- data/lib/serialbench/serializers/json/oj_serializer.rb +102 -0
- data/lib/serialbench/serializers/json/yajl_serializer.rb +67 -0
- data/lib/serialbench/serializers/toml/base_toml_serializer.rb +76 -0
- data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +55 -0
- data/lib/serialbench/serializers/toml/tomlib_serializer.rb +50 -0
- data/lib/serialbench/serializers/xml/base_parser.rb +69 -0
- data/lib/serialbench/serializers/xml/base_xml_serializer.rb +71 -0
- data/lib/serialbench/serializers/xml/libxml_parser.rb +98 -0
- data/lib/serialbench/serializers/xml/libxml_serializer.rb +127 -0
- data/lib/serialbench/serializers/xml/nokogiri_parser.rb +111 -0
- data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +118 -0
- data/lib/serialbench/serializers/xml/oga_parser.rb +85 -0
- data/lib/serialbench/serializers/xml/oga_serializer.rb +125 -0
- data/lib/serialbench/serializers/xml/ox_parser.rb +64 -0
- data/lib/serialbench/serializers/xml/ox_serializer.rb +88 -0
- data/lib/serialbench/serializers/xml/rexml_parser.rb +129 -0
- data/lib/serialbench/serializers/xml/rexml_serializer.rb +121 -0
- data/lib/serialbench/serializers.rb +62 -0
- data/lib/serialbench/version.rb +5 -0
- data/lib/serialbench.rb +42 -0
- data/serialbench.gemspec +51 -0
- metadata +239 -0
data/README.adoc
ADDED
@@ -0,0 +1,592 @@
|
|
1
|
+
= Serialbench: Comprehensive serialization benchmarking suite for Ruby
|
2
|
+
|
3
|
+
image:https://img.shields.io/gem/v/serialbench.svg["Gem Version", link="https://rubygems.org/gems/serialbench"]
|
4
|
+
image:https://github.com/example/serialbench/actions/workflows/rake.yml/badge.svg["Build Status", link="https://github.com/example/serialbench/actions/workflows/rake.yml"]
|
5
|
+
image:https://img.shields.io/github/issues-pr-raw/example/serialbench.svg["Pull Requests", link="https://github.com/example/serialbench/pulls"]
|
6
|
+
image:https://img.shields.io/github/commits-since/example/serialbench/latest.svg["Commits since latest",link="https://github.com/example/serialbench/releases"]
|
7
|
+
|
8
|
+
== Purpose
|
9
|
+
|
10
|
+
Serialbench is a comprehensive benchmarking suite that evaluates the performance of popular Ruby serialization libraries across multiple formats and dimensions including parsing speed, generation speed, memory usage, and feature completeness.
|
11
|
+
|
12
|
+
This tool helps developers make informed decisions when choosing serialization libraries for their Ruby applications by providing detailed performance comparisons and analysis across XML, JSON, and TOML formats.
|
13
|
+
|
14
|
+
=== Tested XML libraries
|
15
|
+
|
16
|
+
==== Core XML Libraries
|
17
|
+
* **Ox** - High-performance XML parser optimized for speed and low memory usage
|
18
|
+
* **Nokogiri** - Feature-rich XML/HTML parser with XPath support and comprehensive DOM manipulation
|
19
|
+
* **LibXML** - Ruby bindings for the libxml2 C library with excellent performance characteristics
|
20
|
+
* **Oga** - Pure Ruby XML parser with XPath support and streaming capabilities
|
21
|
+
* **REXML** - Ruby's built-in XML parser with streaming support (reference implementation)
|
22
|
+
|
23
|
+
==== Additional Format Support
|
24
|
+
* **JSON** - Ruby's built-in JSON parser (for comparison baseline)
|
25
|
+
* **Oj** - High-performance JSON parser with streaming support (for comparison baseline)
|
26
|
+
* **YAJL** - Yet Another JSON Library with streaming support (for comparison baseline)
|
27
|
+
* **TOML-RB** - Ruby TOML parser (for comparison baseline)
|
28
|
+
* **Tomlib** - Fast TOML parser (for comparison baseline)
|
29
|
+
|
30
|
+
== Installation
|
31
|
+
|
32
|
+
Add this line to your application's Gemfile:
|
33
|
+
|
34
|
+
[source,ruby]
|
35
|
+
----
|
36
|
+
gem 'serialbench'
|
37
|
+
----
|
38
|
+
|
39
|
+
And then execute:
|
40
|
+
|
41
|
+
[source,shell]
|
42
|
+
----
|
43
|
+
$ bundle install
|
44
|
+
----
|
45
|
+
|
46
|
+
Or install it yourself as:
|
47
|
+
|
48
|
+
[source,shell]
|
49
|
+
----
|
50
|
+
$ gem install serialbench
|
51
|
+
----
|
52
|
+
|
53
|
+
=== XML library dependencies
|
54
|
+
|
55
|
+
To run benchmarks for all supported XML libraries, install the following gems:
|
56
|
+
|
57
|
+
[source,shell]
|
58
|
+
----
|
59
|
+
# Core XML libraries
|
60
|
+
$ gem install ox nokogiri libxml-ruby oga
|
61
|
+
|
62
|
+
# Additional format libraries (for comparison)
|
63
|
+
$ gem install oj toml-rb
|
64
|
+
|
65
|
+
# Memory profiling support
|
66
|
+
$ gem install memory_profiler
|
67
|
+
----
|
68
|
+
|
69
|
+
NOTE: REXML and JSON are included with Ruby and require no additional installation.
|
70
|
+
|
71
|
+
=== Library-specific installation notes
|
72
|
+
|
73
|
+
==== Ox
|
74
|
+
High-performance C extension requiring compilation:
|
75
|
+
[source,shell]
|
76
|
+
----
|
77
|
+
$ gem install ox
|
78
|
+
----
|
79
|
+
|
80
|
+
==== Nokogiri
|
81
|
+
May require system dependencies on some platforms:
|
82
|
+
[source,shell]
|
83
|
+
----
|
84
|
+
# macOS with Homebrew
|
85
|
+
$ brew install libxml2 libxslt
|
86
|
+
$ gem install nokogiri
|
87
|
+
|
88
|
+
# Ubuntu/Debian
|
89
|
+
$ sudo apt-get install libxml2-dev libxslt1-dev
|
90
|
+
$ gem install nokogiri
|
91
|
+
----
|
92
|
+
|
93
|
+
==== LibXML
|
94
|
+
Ruby bindings for libxml2:
|
95
|
+
[source,shell]
|
96
|
+
----
|
97
|
+
# macOS with Homebrew
|
98
|
+
$ brew install libxml2
|
99
|
+
$ gem install libxml-ruby
|
100
|
+
|
101
|
+
# Ubuntu/Debian
|
102
|
+
$ sudo apt-get install libxml2-dev
|
103
|
+
$ gem install libxml-ruby
|
104
|
+
----
|
105
|
+
|
106
|
+
==== Oga
|
107
|
+
Pure Ruby implementation with no system dependencies:
|
108
|
+
[source,shell]
|
109
|
+
----
|
110
|
+
$ gem install oga
|
111
|
+
----
|
112
|
+
|
113
|
+
== Usage
|
114
|
+
|
115
|
+
=== Command line interface
|
116
|
+
|
117
|
+
Run the complete XML benchmark suite:
|
118
|
+
|
119
|
+
[source,shell]
|
120
|
+
----
|
121
|
+
$ serialbench benchmark
|
122
|
+
----
|
123
|
+
|
124
|
+
Run XML-only benchmarks:
|
125
|
+
|
126
|
+
[source,shell]
|
127
|
+
----
|
128
|
+
$ serialbench benchmark --formats xml
|
129
|
+
----
|
130
|
+
|
131
|
+
Run benchmarks with comparison formats:
|
132
|
+
|
133
|
+
[source,shell]
|
134
|
+
----
|
135
|
+
$ serialbench benchmark --formats xml json
|
136
|
+
$ serialbench benchmark --formats xml json toml
|
137
|
+
----
|
138
|
+
|
139
|
+
Run only DOM parsing benchmarks:
|
140
|
+
|
141
|
+
[source,shell]
|
142
|
+
----
|
143
|
+
$ serialbench benchmark --parsing-only
|
144
|
+
----
|
145
|
+
|
146
|
+
Run only XML generation benchmarks:
|
147
|
+
|
148
|
+
[source,shell]
|
149
|
+
----
|
150
|
+
$ serialbench benchmark --generation-only
|
151
|
+
----
|
152
|
+
|
153
|
+
Run only streaming/SAX parsing benchmarks:
|
154
|
+
|
155
|
+
[source,shell]
|
156
|
+
----
|
157
|
+
$ serialbench benchmark --streaming-only
|
158
|
+
----
|
159
|
+
|
160
|
+
Output results in JSON format only:
|
161
|
+
|
162
|
+
[source,shell]
|
163
|
+
----
|
164
|
+
$ serialbench benchmark --output-format json
|
165
|
+
----
|
166
|
+
|
167
|
+
List available XML parsers:
|
168
|
+
|
169
|
+
[source,shell]
|
170
|
+
----
|
171
|
+
$ serialbench list
|
172
|
+
$ serialbench list --format xml
|
173
|
+
----
|
174
|
+
|
175
|
+
Show help information:
|
176
|
+
|
177
|
+
[source,shell]
|
178
|
+
----
|
179
|
+
$ serialbench help
|
180
|
+
$ serialbench help benchmark
|
181
|
+
----
|
182
|
+
|
183
|
+
Show version:
|
184
|
+
|
185
|
+
[source,shell]
|
186
|
+
----
|
187
|
+
$ serialbench version
|
188
|
+
----
|
189
|
+
|
190
|
+
=== XML-specific benchmark options
|
191
|
+
|
192
|
+
Run benchmarks for specific XML libraries only:
|
193
|
+
|
194
|
+
[source,shell]
|
195
|
+
----
|
196
|
+
$ serialbench benchmark --formats xml --parsers ox,nokogiri
|
197
|
+
$ serialbench benchmark --formats xml --parsers rexml,oga
|
198
|
+
----
|
199
|
+
|
200
|
+
Run memory-intensive benchmarks:
|
201
|
+
|
202
|
+
[source,shell]
|
203
|
+
----
|
204
|
+
$ serialbench benchmark --formats xml --memory-profiling
|
205
|
+
----
|
206
|
+
|
207
|
+
Generate detailed XML processing reports:
|
208
|
+
|
209
|
+
[source,shell]
|
210
|
+
----
|
211
|
+
$ serialbench benchmark --formats xml --detailed-reports
|
212
|
+
----
|
213
|
+
|
214
|
+
=== Multi-Ruby Version Comparison
|
215
|
+
|
216
|
+
Merge benchmark results from multiple Ruby versions:
|
217
|
+
|
218
|
+
[source,shell]
|
219
|
+
----
|
220
|
+
$ serialbench merge_results ruby-3.0/results ruby-3.1/results ruby-3.2/results merged_output/
|
221
|
+
----
|
222
|
+
|
223
|
+
Generate GitHub Pages HTML from multiple benchmark runs:
|
224
|
+
|
225
|
+
[source,shell]
|
226
|
+
----
|
227
|
+
$ serialbench github_pages ruby-3.0/results ruby-3.1/results ruby-3.2/results docs/
|
228
|
+
----
|
229
|
+
|
230
|
+
This creates an interactive HTML report with:
|
231
|
+
|
232
|
+
* **Multi-version charts**: Compare performance across Ruby versions
|
233
|
+
* **Interactive navigation**: Switch between parsing, generation, streaming, and memory usage
|
234
|
+
* **Environment details**: Ruby versions, platforms, and serializer versions
|
235
|
+
* **GitHub Pages ready**: Deploy directly to GitHub Pages for public sharing
|
236
|
+
|
237
|
+
=== Programmatic usage
|
238
|
+
|
239
|
+
==== Basic benchmark execution
|
240
|
+
|
241
|
+
[source,ruby]
|
242
|
+
----
|
243
|
+
require 'serialbench'
|
244
|
+
|
245
|
+
# Run all benchmarks for all formats
|
246
|
+
results = Serialbench.run_benchmarks
|
247
|
+
|
248
|
+
# Run benchmarks for specific formats
|
249
|
+
results = Serialbench.run_benchmarks(formats: [:xml, :json])
|
250
|
+
|
251
|
+
# Generate comprehensive reports
|
252
|
+
report_files = Serialbench.generate_reports(results)
|
253
|
+
|
254
|
+
puts "HTML report: #{report_files[:html]}"
|
255
|
+
puts "Charts generated: #{report_files[:charts].length}"
|
256
|
+
----
|
257
|
+
|
258
|
+
==== Custom benchmark configuration
|
259
|
+
|
260
|
+
[source,ruby]
|
261
|
+
----
|
262
|
+
require 'serialbench'
|
263
|
+
|
264
|
+
# Create a custom benchmark runner
|
265
|
+
runner = Serialbench::BenchmarkRunner.new(formats: [:json, :xml])
|
266
|
+
|
267
|
+
# Run specific benchmark categories
|
268
|
+
parsing_results = runner.run_parsing_benchmarks
|
269
|
+
generation_results = runner.run_generation_benchmarks
|
270
|
+
memory_results = runner.run_memory_benchmarks
|
271
|
+
|
272
|
+
# Format and display results
|
273
|
+
formatter = Serialbench::ResultFormatter.new(runner.results)
|
274
|
+
puts formatter.summary
|
275
|
+
----
|
276
|
+
|
277
|
+
==== Individual serializer testing
|
278
|
+
|
279
|
+
[source,ruby]
|
280
|
+
----
|
281
|
+
require 'serialbench'
|
282
|
+
|
283
|
+
# Test a specific JSON serializer
|
284
|
+
oj_serializer = Serialbench::Serializers::Json::OjSerializer.new
|
285
|
+
|
286
|
+
if oj_serializer.available?
|
287
|
+
json_content = '{"users": [{"name": "Alice", "age": 30}]}'
|
288
|
+
|
289
|
+
# Parse JSON
|
290
|
+
data = oj_serializer.parse(json_content)
|
291
|
+
|
292
|
+
# Generate JSON
|
293
|
+
json_output = oj_serializer.generate(data, pretty: true)
|
294
|
+
|
295
|
+
# Stream parsing (if supported)
|
296
|
+
if oj_serializer.supports_streaming?
|
297
|
+
oj_serializer.stream_parse(json_content) do |event, data|
|
298
|
+
puts "Event: #{event}, Data: #{data}"
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
puts "Serializer: #{oj_serializer.name}"
|
303
|
+
puts "Version: #{oj_serializer.version}"
|
304
|
+
puts "Format: #{oj_serializer.format}"
|
305
|
+
puts "Features: #{oj_serializer.features}"
|
306
|
+
end
|
307
|
+
----
|
308
|
+
|
309
|
+
==== Check available serializers
|
310
|
+
|
311
|
+
[source,ruby]
|
312
|
+
----
|
313
|
+
require 'serialbench'
|
314
|
+
|
315
|
+
# List all available serializers
|
316
|
+
Serialbench.available_serializers.each do |serializer_class|
|
317
|
+
serializer = serializer_class.new
|
318
|
+
puts "#{serializer.format}: #{serializer.name} v#{serializer.version}"
|
319
|
+
end
|
320
|
+
|
321
|
+
# List serializers for specific format
|
322
|
+
Serialbench.available_serializers(:json).each do |serializer_class|
|
323
|
+
serializer = serializer_class.new
|
324
|
+
puts "JSON: #{serializer.name} v#{serializer.version}"
|
325
|
+
end
|
326
|
+
----
|
327
|
+
|
328
|
+
== Benchmark categories
|
329
|
+
|
330
|
+
=== Parsing performance
|
331
|
+
|
332
|
+
Measures the time required to parse serialized data into Ruby objects.
|
333
|
+
|
334
|
+
* **Small files**: ~1KB configuration-style documents
|
335
|
+
* **Medium files**: ~1MB API responses with 1,000 records
|
336
|
+
* **Large files**: ~10MB data exports with 10,000 records
|
337
|
+
|
338
|
+
=== Generation performance
|
339
|
+
|
340
|
+
Tests how quickly libraries can convert Ruby objects into serialized strings.
|
341
|
+
|
342
|
+
=== Streaming performance
|
343
|
+
|
344
|
+
Evaluates streaming event-based parsing performance for libraries that support it, which processes data sequentially and is memory-efficient for large files.
|
345
|
+
|
346
|
+
=== Memory usage analysis
|
347
|
+
|
348
|
+
Profiles memory allocation and retention during serialization operations using the `memory_profiler` gem.
|
349
|
+
|
350
|
+
== Output and reports
|
351
|
+
|
352
|
+
=== Generated files
|
353
|
+
|
354
|
+
Running benchmarks creates the following output structure:
|
355
|
+
|
356
|
+
[source]
|
357
|
+
----
|
358
|
+
results/
|
359
|
+
├── reports/
|
360
|
+
│ ├── benchmark_report.html # Main HTML report
|
361
|
+
│ └── benchmark_report.adoc # AsciiDoc source
|
362
|
+
├── charts/
|
363
|
+
│ ├── parsing_performance.svg
|
364
|
+
│ ├── generation_performance.svg
|
365
|
+
│ ├── streaming_performance.svg
|
366
|
+
│ ├── memory_usage_comparison.svg
|
367
|
+
│ └── format_comparison.svg
|
368
|
+
├── data/
|
369
|
+
│ ├── results.json # Raw benchmark data
|
370
|
+
│ └── results.csv # CSV export
|
371
|
+
└── assets/
|
372
|
+
└── css/
|
373
|
+
└── benchmark_report.css # Report styling
|
374
|
+
----
|
375
|
+
|
376
|
+
=== Report features
|
377
|
+
|
378
|
+
* **Multi-format comparison**: Compare XML, JSON, and TOML performance
|
379
|
+
* **Interactive charts**: SVG-based performance visualizations
|
380
|
+
* **Comparative analysis**: Side-by-side library comparisons
|
381
|
+
* **Performance rankings**: Fastest to slowest for each category
|
382
|
+
* **Memory profiling**: Detailed memory allocation analysis
|
383
|
+
* **Feature matrix**: Capability comparison across libraries
|
384
|
+
* **Recommendations**: Use-case specific library suggestions
|
385
|
+
* **Environment details**: Ruby version, platform, and library versions
|
386
|
+
|
387
|
+
=== Sample output
|
388
|
+
|
389
|
+
[source]
|
390
|
+
----
|
391
|
+
Serialbench - Comprehensive Serialization Performance Tests
|
392
|
+
===========================================================
|
393
|
+
Environment: Ruby 3.3.2 on arm64-darwin23
|
394
|
+
Timestamp: 2024-01-15T10:30:00Z
|
395
|
+
|
396
|
+
Available serializers: rexml, json, oj, toml-rb
|
397
|
+
Test formats: xml, json, toml
|
398
|
+
Test data sizes: small, medium, large
|
399
|
+
|
400
|
+
Parsing Performance:
|
401
|
+
Small files:
|
402
|
+
JSON/oj: 0.08ms
|
403
|
+
JSON/json: 0.12ms
|
404
|
+
XML/rexml: 0.45ms
|
405
|
+
TOML/toml-rb: 0.52ms
|
406
|
+
|
407
|
+
Medium files:
|
408
|
+
JSON/oj: 8.23ms
|
409
|
+
JSON/json: 12.67ms
|
410
|
+
XML/rexml: 28.45ms
|
411
|
+
TOML/toml-rb: 35.21ms
|
412
|
+
----
|
413
|
+
|
414
|
+
== Methodology
|
415
|
+
|
416
|
+
=== Performance measurement
|
417
|
+
|
418
|
+
* Each test runs multiple iterations with warmup iterations
|
419
|
+
* Memory profiling uses 10 iterations to reduce noise
|
420
|
+
* Results show average performance across all iterations
|
421
|
+
* Benchmarks use Ruby's `Benchmark.realtime` for precise timing
|
422
|
+
|
423
|
+
=== Test data
|
424
|
+
|
425
|
+
==== Synthetic datasets
|
426
|
+
|
427
|
+
The benchmark suite uses carefully crafted synthetic data that represents common real-world scenarios:
|
428
|
+
|
429
|
+
* **Configuration files**: Small, nested structures typical of application settings
|
430
|
+
* **API responses**: Medium-sized documents with repeated record structures
|
431
|
+
* **Data exports**: Large documents with extensive hierarchical data
|
432
|
+
|
433
|
+
==== Multi-format consistency
|
434
|
+
|
435
|
+
* Equivalent data structures across XML, JSON, and TOML formats
|
436
|
+
* Consistent complexity and nesting levels
|
437
|
+
* Representative of real-world usage patterns
|
438
|
+
|
439
|
+
=== Statistical considerations
|
440
|
+
|
441
|
+
* Multiple iterations reduce timing variance
|
442
|
+
* Warmup iterations eliminate JIT compilation effects
|
443
|
+
* Memory measurements account for garbage collection
|
444
|
+
* Results include both absolute and relative performance metrics
|
445
|
+
|
446
|
+
== Library comparison matrix
|
447
|
+
|
448
|
+
[cols="1,1,1,1,1,1,1"]
|
449
|
+
|===
|
450
|
+
|Format |Library |Parsing |Generation |Streaming |Memory |Features
|
451
|
+
|
452
|
+
|XML |REXML |⭐⭐ |⭐⭐ |⭐⭐⭐ |⭐⭐ |Built-in
|
453
|
+
|XML |Ox |⭐⭐⭐⭐⭐ |⭐⭐⭐⭐⭐ |⭐⭐⭐⭐ |⭐⭐⭐⭐⭐ |High-performance
|
454
|
+
|XML |Nokogiri |⭐⭐⭐⭐ |⭐⭐⭐⭐ |⭐⭐⭐⭐ |⭐⭐⭐⭐ |Feature-rich
|
455
|
+
|XML |LibXML |⭐⭐⭐⭐⭐ |⭐⭐⭐⭐ |⭐⭐⭐⭐ |⭐⭐⭐⭐⭐ |High-performance
|
456
|
+
|XML |Oga |⭐⭐ |⭐⭐ |⭐⭐⭐ |⭐⭐ |Pure Ruby
|
457
|
+
|JSON |JSON |⭐⭐⭐ |⭐⭐⭐ |❌ |⭐⭐⭐ |Built-in
|
458
|
+
|JSON |Oj |⭐⭐⭐⭐⭐ |⭐⭐⭐⭐⭐ |⭐⭐⭐⭐ |⭐⭐⭐⭐⭐ |High-performance
|
459
|
+
|JSON |YAJL |⭐⭐⭐⭐ |⭐⭐⭐ |⭐⭐⭐⭐ |⭐⭐⭐⭐ |Streaming
|
460
|
+
|TOML |TOML-RB |⭐⭐⭐ |⭐⭐⭐ |❌ |⭐⭐⭐ |Standard
|
461
|
+
|TOML |Tomlib |⭐⭐⭐⭐⭐ |⭐⭐⭐⭐ |❌ |⭐⭐⭐⭐⭐ |High-performance
|
462
|
+
|===
|
463
|
+
|
464
|
+
_Performance ratings: ⭐⭐⭐⭐⭐ Excellent, ⭐⭐⭐⭐ Good, ⭐⭐⭐ Average, ⭐⭐ Below average, ⭐ Poor, ❌ Not supported_
|
465
|
+
|
466
|
+
== Recommendations
|
467
|
+
|
468
|
+
=== For high-performance JSON applications
|
469
|
+
|
470
|
+
**Oj** is recommended for applications where JSON parsing/generation speed is critical. It consistently outperforms the built-in JSON library.
|
471
|
+
|
472
|
+
=== For configuration files
|
473
|
+
|
474
|
+
**TOML** provides human-readable configuration with good parsing performance. **JSON** is faster but less readable for configuration.
|
475
|
+
|
476
|
+
=== For data interchange
|
477
|
+
|
478
|
+
**JSON** offers the best balance of performance, compatibility, and tooling support across different systems.
|
479
|
+
|
480
|
+
=== For document processing
|
481
|
+
|
482
|
+
**XML** with **REXML** provides built-in support, though performance is lower than JSON alternatives.
|
483
|
+
|
484
|
+
=== For memory-constrained environments
|
485
|
+
|
486
|
+
**Oj** demonstrates superior memory efficiency. For large file processing, streaming approaches are recommended where available.
|
487
|
+
|
488
|
+
=== For minimal dependencies
|
489
|
+
|
490
|
+
**JSON** and **REXML** are included with Ruby and require no additional gems, making them suitable for environments with strict dependency constraints.
|
491
|
+
|
492
|
+
== Development
|
493
|
+
|
494
|
+
=== Running tests
|
495
|
+
|
496
|
+
[source,shell]
|
497
|
+
----
|
498
|
+
$ bundle exec rake
|
499
|
+
$ bundle exec rspec
|
500
|
+
----
|
501
|
+
|
502
|
+
=== Contributing
|
503
|
+
|
504
|
+
1. Fork the repository
|
505
|
+
2. Create your feature branch (`git checkout -b feature/my-new-feature`)
|
506
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
507
|
+
4. Push to the branch (`git push origin feature/my-new-feature`)
|
508
|
+
5. Create a new Pull Request
|
509
|
+
|
510
|
+
=== Adding new serializers
|
511
|
+
|
512
|
+
To add support for additional serialization libraries:
|
513
|
+
|
514
|
+
1. Create a new serializer class in `lib/serialbench/serializers/{format}/`
|
515
|
+
2. Inherit from the appropriate base class (`BaseXmlSerializer`, `BaseJsonSerializer`, etc.)
|
516
|
+
3. Implement the required methods: `parse`, `generate`, `name`, `version`
|
517
|
+
4. Add the serializer to the registry in `lib/serialbench/serializers.rb`
|
518
|
+
5. Update documentation and tests
|
519
|
+
|
520
|
+
==== Example: Adding a new JSON serializer
|
521
|
+
|
522
|
+
[source,ruby]
|
523
|
+
----
|
524
|
+
# lib/serialbench/serializers/json/yajl_serializer.rb
|
525
|
+
class YajlSerializer < BaseJsonSerializer
|
526
|
+
def available?
|
527
|
+
require_library('yajl')
|
528
|
+
end
|
529
|
+
|
530
|
+
def name
|
531
|
+
'yajl'
|
532
|
+
end
|
533
|
+
|
534
|
+
def version
|
535
|
+
require 'yajl'
|
536
|
+
Yajl::VERSION
|
537
|
+
end
|
538
|
+
|
539
|
+
def parse(json_string)
|
540
|
+
require 'yajl'
|
541
|
+
Yajl::Parser.parse(json_string)
|
542
|
+
end
|
543
|
+
|
544
|
+
def generate(object, options = {})
|
545
|
+
require 'yajl'
|
546
|
+
Yajl::Encoder.encode(object)
|
547
|
+
end
|
548
|
+
end
|
549
|
+
----
|
550
|
+
|
551
|
+
== Architecture
|
552
|
+
|
553
|
+
=== Serializer hierarchy
|
554
|
+
|
555
|
+
[source]
|
556
|
+
----
|
557
|
+
BaseSerializer
|
558
|
+
├── BaseXmlSerializer
|
559
|
+
│ └── RexmlSerializer
|
560
|
+
├── BaseJsonSerializer
|
561
|
+
│ ├── JsonSerializer
|
562
|
+
│ └── OjSerializer
|
563
|
+
└── BaseTomlSerializer
|
564
|
+
└── TomlRbSerializer
|
565
|
+
----
|
566
|
+
|
567
|
+
=== Key components
|
568
|
+
|
569
|
+
* **Serializers**: Individual library implementations
|
570
|
+
* **BenchmarkRunner**: Orchestrates benchmark execution
|
571
|
+
* **ResultFormatter**: Formats and displays results
|
572
|
+
* **ReportGenerator**: Creates HTML/AsciiDoc reports
|
573
|
+
* **ChartGenerator**: Creates performance visualizations
|
574
|
+
* **MemoryProfiler**: Analyzes memory usage patterns
|
575
|
+
|
576
|
+
== Research and references
|
577
|
+
|
578
|
+
This benchmarking suite was developed based on research from:
|
579
|
+
|
580
|
+
* https://www.ohler.com/dev/xml_with_ruby/xml_with_ruby.html[XML with Ruby performance analysis]
|
581
|
+
* https://gist.github.com/danneu/3977120[Ruby XML parser comparison]
|
582
|
+
* https://gist.github.com/adilosa/d4277dc1c683da91990515352ffe5420[XML parsing benchmarks]
|
583
|
+
|
584
|
+
== Copyright
|
585
|
+
|
586
|
+
This gem is developed, maintained and funded by
|
587
|
+
https://www.ribose.com[Ribose Inc.]
|
588
|
+
|
589
|
+
== License
|
590
|
+
|
591
|
+
The gem is available as open source under the terms of the
|
592
|
+
https://opensource.org/licenses/BSD-2-Clause[2-Clause BSD License].
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
desc 'Run benchmarks'
|
9
|
+
task :benchmark do
|
10
|
+
require_relative 'lib/serialbench'
|
11
|
+
|
12
|
+
puts 'Running XML benchmarks...'
|
13
|
+
results = Serialbench.run_benchmarks
|
14
|
+
|
15
|
+
puts "\nGenerating reports..."
|
16
|
+
report_files = Serialbench.generate_reports(results)
|
17
|
+
|
18
|
+
puts "\nBenchmark complete!"
|
19
|
+
puts 'Reports generated:'
|
20
|
+
puts " HTML: #{report_files[:html]}"
|
21
|
+
puts " AsciiDoc: #{report_files[:asciidoc]}"
|
22
|
+
puts " Charts: #{report_files[:charts].length} SVG files"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Install all XML library dependencies'
|
26
|
+
task :install_deps do
|
27
|
+
gems = %w[ox nokogiri libxml-ruby oga memory_profiler]
|
28
|
+
|
29
|
+
puts 'Installing XML library dependencies...'
|
30
|
+
gems.each do |gem_name|
|
31
|
+
puts "Installing #{gem_name}..."
|
32
|
+
system("gem install #{gem_name}")
|
33
|
+
rescue StandardError => e
|
34
|
+
puts "Warning: Failed to install #{gem_name}: #{e.message}"
|
35
|
+
end
|
36
|
+
puts 'Done!'
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'Check which XML libraries are available'
|
40
|
+
task :check_libs do
|
41
|
+
require_relative 'lib/serialbench'
|
42
|
+
|
43
|
+
runner = Serialbench::BenchmarkRunner.new
|
44
|
+
|
45
|
+
puts 'XML Library Availability Check'
|
46
|
+
puts '=' * 40
|
47
|
+
|
48
|
+
runner.parsers.each do |parser|
|
49
|
+
status = parser.available? ? '✓ Available' : '✗ Not available'
|
50
|
+
version = parser.available? ? " (#{parser.version})" : ''
|
51
|
+
puts "#{parser.name.ljust(15)} #{status}#{version}"
|
52
|
+
end
|
53
|
+
|
54
|
+
puts "\nMemory profiler: #{Serialbench::MemoryProfiler.available? ? '✓ Available' : '✗ Not available'}"
|
55
|
+
end
|
56
|
+
|
57
|
+
desc 'Clean generated files'
|
58
|
+
task :clean do
|
59
|
+
FileUtils.rm_rf('results')
|
60
|
+
puts 'Cleaned generated files'
|
61
|
+
end
|
62
|
+
|
63
|
+
task default: :spec
|