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
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Serialbench
4
- module Parsers
5
- class BaseParser
6
- attr_reader :name, :version
7
-
8
- def initialize
9
- @name = self.class.name.split('::').last.gsub('Parser', '').downcase
10
- @version = detect_version
11
- end
12
-
13
- # Parse XML string into document object
14
- def parse_dom(xml_string)
15
- raise NotImplementedError, 'Subclasses must implement parse_dom'
16
- end
17
-
18
- # Parse XML with SAX-style streaming
19
- def parse_sax(xml_string, handler = nil)
20
- raise NotImplementedError, 'Subclasses must implement parse_sax'
21
- end
22
-
23
- # Generate XML string from document object
24
- def generate_xml(document, options = {})
25
- raise NotImplementedError, 'Subclasses must implement generate_xml'
26
- end
27
-
28
- # Check if library is available
29
- def available?
30
- require library_require_name
31
- true
32
- rescue LoadError
33
- false
34
- end
35
-
36
- # Get library features
37
- def features
38
- {
39
- xpath: supports_xpath?,
40
- namespaces: supports_namespaces?,
41
- validation: supports_validation?,
42
- streaming: supports_streaming?
43
- }
44
- end
45
-
46
- def supports_streaming?
47
- false
48
- end
49
-
50
- protected
51
-
52
- def detect_version
53
- 'unknown'
54
- end
55
-
56
- def supports_xpath?
57
- false
58
- end
59
-
60
- def supports_namespaces?
61
- true
62
- end
63
-
64
- def supports_validation?
65
- false
66
- end
67
- end
68
- end
69
- end
@@ -1,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base_parser'
4
-
5
- module Serialbench
6
- module Parsers
7
- class LibxmlParser < BaseParser
8
- def parse_dom(xml_string)
9
- require 'libxml'
10
- LibXML::XML::Document.string(xml_string)
11
- end
12
-
13
- def parse_sax(xml_string, handler = nil)
14
- require 'libxml'
15
- handler ||= LibxmlSaxHandler.new
16
- parser = LibXML::XML::SaxParser.string(xml_string)
17
- parser.callbacks = handler
18
- parser.parse
19
- handler
20
- end
21
-
22
- def generate_xml(document, options = {})
23
- require 'libxml'
24
- document.to_s
25
- end
26
-
27
- def supports_streaming?
28
- true
29
- end
30
-
31
- # SAX handler for LibXML
32
- class LibxmlSaxHandler
33
- attr_reader :elements_processed, :text_nodes_processed
34
-
35
- def initialize
36
- @elements_processed = 0
37
- @text_nodes_processed = 0
38
- # Include LibXML callbacks if available
39
- return unless defined?(::LibXML)
40
-
41
- return if self.class.ancestors.include?(::LibXML::XML::SaxParser::Callbacks)
42
-
43
- self.class.send(:include,
44
- ::LibXML::XML::SaxParser::Callbacks)
45
- end
46
-
47
- def on_start_document
48
- # Document processing started
49
- end
50
-
51
- def on_end_document
52
- # Document processing complete
53
- end
54
-
55
- def on_start_element(element, attributes)
56
- @elements_processed += 1
57
- end
58
-
59
- def on_characters(chars)
60
- @text_nodes_processed += 1 unless chars.strip.empty?
61
- end
62
-
63
- def on_end_element(element)
64
- # Element processing complete
65
- end
66
-
67
- def on_error(msg)
68
- # Handle parsing errors
69
- end
70
- end
71
-
72
- protected
73
-
74
- def library_require_name
75
- 'libxml'
76
- end
77
-
78
- def detect_version
79
- require 'libxml'
80
- LibXML::XML::VERSION
81
- rescue LoadError
82
- 'not available'
83
- end
84
-
85
- def supports_xpath?
86
- true
87
- end
88
-
89
- def supports_namespaces?
90
- true
91
- end
92
-
93
- def supports_validation?
94
- true
95
- end
96
- end
97
- end
98
- end
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base_parser'
4
-
5
- module Serialbench
6
- module Parsers
7
- class NokogiriParser < BaseParser
8
- def parse_dom(xml_string)
9
- require 'nokogiri'
10
- Nokogiri::XML(xml_string)
11
- end
12
-
13
- def parse_sax(xml_string, handler = nil)
14
- require 'nokogiri'
15
- handler ||= NokogiriSaxHandler.new
16
- parser = Nokogiri::XML::SAX::Parser.new(handler)
17
- parser.parse(xml_string)
18
- handler
19
- end
20
-
21
- def generate_xml(document, options = {})
22
- require 'nokogiri'
23
- indent = options.fetch(:indent, 0)
24
- if indent > 0
25
- document.to_xml(indent: indent)
26
- else
27
- document.to_xml
28
- end
29
- end
30
-
31
- def supports_streaming?
32
- true
33
- end
34
-
35
- # SAX handler for Nokogiri
36
- class NokogiriSaxHandler < (defined?(::Nokogiri) ? ::Nokogiri::XML::SAX::Document : Object)
37
- attr_reader :elements_processed, :text_nodes_processed
38
-
39
- def initialize
40
- @elements_processed = 0
41
- @text_nodes_processed = 0
42
- end
43
-
44
- def start_document
45
- # Document processing started
46
- end
47
-
48
- def end_document
49
- # Document processing complete
50
- end
51
-
52
- def start_element(name, attrs = [])
53
- @elements_processed += 1
54
- end
55
-
56
- def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = [])
57
- @elements_processed += 1
58
- end
59
-
60
- def characters(string)
61
- @text_nodes_processed += 1 unless string.strip.empty?
62
- end
63
-
64
- def end_element(name)
65
- # Element processing complete
66
- end
67
-
68
- def end_element_namespace(name, prefix = nil, uri = nil)
69
- # Element processing complete
70
- end
71
-
72
- def error(message)
73
- # Handle parsing errors
74
- end
75
-
76
- def warning(message)
77
- # Handle parsing warnings
78
- end
79
-
80
- def xmldecl(version, encoding, standalone)
81
- # Handle XML declaration
82
- end
83
- end
84
-
85
- protected
86
-
87
- def library_require_name
88
- 'nokogiri'
89
- end
90
-
91
- def detect_version
92
- require 'nokogiri'
93
- Nokogiri::VERSION
94
- rescue LoadError
95
- 'not available'
96
- end
97
-
98
- def supports_xpath?
99
- true
100
- end
101
-
102
- def supports_namespaces?
103
- true
104
- end
105
-
106
- def supports_validation?
107
- true
108
- end
109
- end
110
- end
111
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base_parser'
4
-
5
- module Serialbench
6
- module Parsers
7
- class OgaParser < BaseParser
8
- def parse_dom(xml_string)
9
- require 'oga'
10
- Oga.parse_xml(xml_string)
11
- end
12
-
13
- def parse_sax(xml_string, handler = nil)
14
- require 'oga'
15
- handler ||= DefaultSaxHandler.new
16
- Oga.sax_parse_xml(xml_string, handler)
17
- handler
18
- end
19
-
20
- def generate_xml(document, options = {})
21
- require 'oga'
22
- document.to_xml
23
- end
24
-
25
- def supports_streaming?
26
- true
27
- end
28
-
29
- protected
30
-
31
- def library_require_name
32
- 'oga'
33
- end
34
-
35
- def detect_version
36
- require 'oga'
37
- Oga::VERSION
38
- rescue LoadError
39
- 'not available'
40
- end
41
-
42
- def supports_xpath?
43
- true
44
- end
45
-
46
- def supports_namespaces?
47
- true
48
- end
49
-
50
- def supports_validation?
51
- false
52
- end
53
-
54
- # Default SAX handler for Oga
55
- class DefaultSaxHandler
56
- attr_reader :elements_processed, :text_nodes_processed
57
-
58
- def initialize
59
- @elements_processed = 0
60
- @text_nodes_processed = 0
61
- end
62
-
63
- def on_element(namespace, name, attributes = {})
64
- @elements_processed += 1
65
- end
66
-
67
- def on_text(text)
68
- @text_nodes_processed += 1 unless text.strip.empty?
69
- end
70
-
71
- def on_cdata(text)
72
- @text_nodes_processed += 1 unless text.strip.empty?
73
- end
74
-
75
- def on_comment(text)
76
- # Handle comments
77
- end
78
-
79
- def on_processing_instruction(name, text)
80
- # Handle processing instructions
81
- end
82
- end
83
- end
84
- end
85
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base_parser'
4
-
5
- module Serialbench
6
- module Parsers
7
- class OxParser < BaseParser
8
- def parse_dom(xml_string)
9
- require 'ox'
10
- Ox.parse(xml_string)
11
- end
12
-
13
- def parse_sax(xml_string, handler = nil)
14
- require 'ox'
15
- require 'stringio'
16
- handler ||= OxSaxHandler.new
17
- Ox.sax_parse(handler, StringIO.new(xml_string))
18
- handler
19
- end
20
-
21
- def generate_xml(document, options = {})
22
- require 'ox'
23
- indent = options.fetch(:indent, 0)
24
- Ox.dump(document, indent: indent)
25
- end
26
-
27
- def supports_streaming?
28
- true
29
- end
30
-
31
- # SAX handler for Ox
32
- class OxSaxHandler < (defined?(::Ox) ? ::Ox::Sax : Object)
33
- attr_reader :elements_processed, :text_nodes_processed
34
-
35
- def initialize
36
- @elements_processed = 0
37
- @text_nodes_processed = 0
38
- end
39
-
40
- def start_element(name)
41
- @elements_processed += 1
42
- end
43
-
44
- def end_element(name)
45
- # Process end element
46
- end
47
-
48
- def text(value)
49
- @text_nodes_processed += 1 unless value.strip.empty?
50
- end
51
-
52
- def attr(name, value)
53
- # Process attribute
54
- end
55
- end
56
-
57
- protected
58
-
59
- def library_require_name
60
- 'ox'
61
- end
62
- end
63
- end
64
- end
@@ -1,129 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base_parser'
4
-
5
- module Serialbench
6
- module Parsers
7
- class RexmlParser < BaseParser
8
- def parse_dom(xml_string)
9
- require 'rexml/document'
10
- REXML::Document.new(xml_string)
11
- end
12
-
13
- def parse_sax(xml_string, handler = nil)
14
- require 'rexml/parsers/sax2parser'
15
- handler ||= DefaultSaxHandler.new
16
- parser = REXML::Parsers::SAX2Parser.new(xml_string)
17
- parser.listen(handler)
18
- parser.parse
19
- handler
20
- rescue LoadError
21
- # Fallback if SAX2 is not available
22
- require 'rexml/document'
23
- doc = REXML::Document.new(xml_string)
24
- handler ||= DefaultSaxHandler.new
25
- # Simulate SAX events by walking the document
26
- doc.root.each_recursive do |element|
27
- if element.is_a?(REXML::Element)
28
- handler.start_element(nil, element.name, element.name, element.attributes)
29
- handler.end_element(nil, element.name, element.name)
30
- elsif element.is_a?(REXML::Text)
31
- handler.characters(element.to_s)
32
- end
33
- end
34
- handler
35
- end
36
-
37
- def generate_xml(document, options = {})
38
- require 'rexml/document'
39
- indent = options.fetch(:indent, 0)
40
- output = String.new
41
- if indent > 0
42
- document.write(output, indent)
43
- else
44
- document.write(output)
45
- end
46
- output
47
- end
48
-
49
- def supports_streaming?
50
- true
51
- end
52
-
53
- protected
54
-
55
- def library_require_name
56
- 'rexml/document'
57
- end
58
-
59
- def detect_version
60
- require 'rexml/rexml'
61
- REXML::VERSION
62
- rescue LoadError, NameError
63
- 'built-in'
64
- end
65
-
66
- def supports_xpath?
67
- true
68
- end
69
-
70
- def supports_namespaces?
71
- true
72
- end
73
-
74
- def supports_validation?
75
- false
76
- end
77
- end
78
-
79
- # Default SAX handler for REXML - only define if REXML SAX is available
80
- begin
81
- require 'rexml/sax2listener'
82
-
83
- class DefaultSaxHandler
84
- include ::REXML::SAX2Listener
85
-
86
- attr_reader :elements_processed, :text_nodes_processed
87
-
88
- def initialize
89
- @elements_processed = 0
90
- @text_nodes_processed = 0
91
- end
92
-
93
- def start_element(uri, localname, qname, attributes)
94
- @elements_processed += 1
95
- end
96
-
97
- def characters(text)
98
- @text_nodes_processed += 1 unless text.strip.empty?
99
- end
100
-
101
- def end_element(uri, localname, qname)
102
- # Element processing complete
103
- end
104
- end
105
- rescue LoadError
106
- # SAX2Listener not available, define a simple handler
107
- class DefaultSaxHandler
108
- attr_reader :elements_processed, :text_nodes_processed
109
-
110
- def initialize
111
- @elements_processed = 0
112
- @text_nodes_processed = 0
113
- end
114
-
115
- def start_element(uri, localname, qname, attributes)
116
- @elements_processed += 1
117
- end
118
-
119
- def characters(text)
120
- @text_nodes_processed += 1 unless text.strip.empty?
121
- end
122
-
123
- def end_element(uri, localname, qname)
124
- # Element processing complete
125
- end
126
- end
127
- end
128
- end
129
- end