serialbench 0.10.0 → 0.12.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 +4 -4
- data/.github/workflows/benchmark.yml +9 -15
- data/Gemfile +3 -6
- data/config/benchmarks/full-xml.yml +1 -0
- data/lib/serialbench/benchmark_runner.rb +35 -1
- data/lib/serialbench/models/benchmark_config.rb +1 -1
- data/lib/serialbench/models/benchmark_result.rb +2 -0
- data/lib/serialbench/serializers/xml/base_xml_serializer.rb +4 -0
- data/lib/serialbench/serializers/xml/leptris_serializer.rb +1 -1
- data/lib/serialbench/serializers/xml/saxon_serializer.rb +72 -0
- data/lib/serialbench/serializers.rb +3 -1
- data/lib/serialbench/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fb1d328cda41b77014e07bcca03086cf860a81a9f02c8863918e37d41ab1e201
|
|
4
|
+
data.tar.gz: 889ba7216bdc343cf5886f2fdaf6257452633161cd291c66e54823caa4cfbb7d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 64d0c977c7efffaa614ac03425eae1cf5c3e83d44f06bc2ba98da8b03671644887ec8813d8c506987e6d0f0ce74424af5bf74bf025ad9a09303f7d57a0c3ffa4
|
|
7
|
+
data.tar.gz: 4db8775576b87ff4eb268f063e323527f5f639d3c65c55f12f02078d7772ff552dc67578f048179a7c17d0a33a08058527959f96f2b0403595ce349c4bb9c79c
|
|
@@ -116,27 +116,21 @@ jobs:
|
|
|
116
116
|
- name: Install gems
|
|
117
117
|
run: bundle install
|
|
118
118
|
|
|
119
|
+
- name: Fetch Saxon-HE (XSLT 2.0/3.0 comparison)
|
|
120
|
+
run: |
|
|
121
|
+
mkdir -p vendor
|
|
122
|
+
curl -sL -o vendor/saxonhe.jar "https://repo1.maven.org/maven2/net/sf/saxon/Saxon-HE/12.10/Saxon-HE-12.10.jar"
|
|
123
|
+
curl -sL -o vendor/xmlresolver.jar "https://repo1.maven.org/maven2/org/xmlresolver/xmlresolver/5.2.2/xmlresolver-5.2.2.jar"
|
|
124
|
+
echo "SAXON_JAR=$PWD/vendor/saxonhe.jar" >> "$GITHUB_ENV"
|
|
125
|
+
echo "XMLRESOLVER_JAR=$PWD/vendor/xmlresolver.jar" >> "$GITHUB_ENV"
|
|
126
|
+
shell: bash
|
|
127
|
+
|
|
119
128
|
- name: Load canonical fixtures
|
|
120
129
|
run: |
|
|
121
130
|
git clone --depth 1 https://github.com/serialbench/fixtures.git test_data
|
|
122
131
|
(cd test_data && sha256sum -c SHA256SUMS) || (cd test_data && shasum -a 256 -c SHA256SUMS)
|
|
123
132
|
shell: bash
|
|
124
133
|
|
|
125
|
-
- name: Point teptris at its vendored DLL (Windows)
|
|
126
|
-
if: startsWith(matrix.platform, 'windows-')
|
|
127
|
-
shell: bash
|
|
128
|
-
run: |
|
|
129
|
-
# teptris 0.1.0's mingw gem vendors the library as teptris.dll but
|
|
130
|
-
# its FFI loader searches libteptris.dll; TEPTRIS_LIB_PATH (the
|
|
131
|
-
# loader's first candidate) bridges until the ext-based gem ships.
|
|
132
|
-
DLL=$(bundle exec ruby -e "print File.join(Gem::Specification.find_by_name('teptris').gem_dir, 'lib', 'teptris.dll')" 2>/dev/null || true)
|
|
133
|
-
if [ -n "$DLL" ] && [ -f "$DLL" ]; then
|
|
134
|
-
echo "TEPTRIS_LIB_PATH=$DLL" >> "$GITHUB_ENV"
|
|
135
|
-
echo "TEPTRIS_LIB_PATH=$DLL"
|
|
136
|
-
else
|
|
137
|
-
echo "no vendored teptris.dll found — teptris stays unavailable on this leg"
|
|
138
|
-
fi
|
|
139
|
-
|
|
140
134
|
- name: Create environment config
|
|
141
135
|
run: |
|
|
142
136
|
mkdir -p config/environments
|
data/Gemfile
CHANGED
|
@@ -12,12 +12,9 @@ unless Gem.win_platform? && RUBY_PLATFORM.include?('aarch64')
|
|
|
12
12
|
gem 'libxml-ruby'
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
gem 'leptris', '1.9.
|
|
16
|
-
gem 'yeptris', '0.
|
|
17
|
-
|
|
18
|
-
# path (loads only under exactly Ruby 3.3.12 at hostedtoolcache) and ships no
|
|
19
|
-
# mingw gems. Bump when the ext links portably and windows variants exist.
|
|
20
|
-
gem 'teptris', '0.1.0'
|
|
15
|
+
gem 'leptris', '1.9.193.4' # html5 conformance campaign + memchr tokenizer perf
|
|
16
|
+
gem 'yeptris', '0.6.5.4' # compiled plan walk; dump round-trip fixed (plain keys)
|
|
17
|
+
gem 'teptris', '0.2.36' # full platform matrix incl. mingw - windows coverage unblocked
|
|
21
18
|
gem 'benchmark' # Removed from stdlib in Ruby 4.0
|
|
22
19
|
gem 'base64' # Required for Ruby 3.4+
|
|
23
20
|
gem 'lutaml-model', '~> 0.7'
|
|
@@ -142,10 +142,39 @@ _DEFAULT_XSLT_STYLESHEET = <<'XSL'.freeze
|
|
|
142
142
|
</xsl:stylesheet>
|
|
143
143
|
XSL
|
|
144
144
|
|
|
145
|
+
_DEFAULT_XSLT30_STYLESHEET = <<'XSL30'.freeze
|
|
146
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
147
|
+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
148
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
149
|
+
exclude-result-prefixes="xs"
|
|
150
|
+
version="3.0">
|
|
151
|
+
<xsl:output method="xml" indent="yes"/>
|
|
152
|
+
<xsl:template match="/">
|
|
153
|
+
<report30>
|
|
154
|
+
<xsl:iterate select="//user | //record | //database | //cache">
|
|
155
|
+
<xsl:param name="labels" as="xs:string*" select="()"/>
|
|
156
|
+
<xsl:on-completion>
|
|
157
|
+
<joined><xsl:value-of select="string-join($labels, ', ')"/></joined>
|
|
158
|
+
<count><xsl:value-of select="count($labels)"/></count>
|
|
159
|
+
</xsl:on-completion>
|
|
160
|
+
<xsl:variable name="label" select="string((name, data/field1, ttl)[1])"/>
|
|
161
|
+
<xsl:if test="$label != ''">
|
|
162
|
+
<row kind="{local-name()}" label="{upper-case($label)}"/>
|
|
163
|
+
</xsl:if>
|
|
164
|
+
<xsl:next-iteration>
|
|
165
|
+
<xsl:with-param name="labels" select="if ($label != '') then ($labels, $label) else $labels"/>
|
|
166
|
+
</xsl:next-iteration>
|
|
167
|
+
</xsl:iterate>
|
|
168
|
+
</report30>
|
|
169
|
+
</xsl:template>
|
|
170
|
+
</xsl:stylesheet>
|
|
171
|
+
XSL30
|
|
172
|
+
|
|
145
173
|
XPATH_QUERIES = ['//book', "//book[@id='101']", '//book[price > 30]/title'].freeze
|
|
146
174
|
XQUERY_EXPRESSIONS = ['count(//user | //record)', "//record[@id='101']/data/field1", '//user[profile/age > 40]/name'].freeze
|
|
147
175
|
RNG_SCHEMA = File.expand_path('test_data/schema.rng', Dir.pwd).then { |p| File.exist?(p) ? File.read(p) : _DEFAULT_RNG_SCHEMA }
|
|
148
176
|
XSLT_STYLESHEET = File.expand_path('test_data/transform.xsl', Dir.pwd).then { |p| File.exist?(p) ? File.read(p) : _DEFAULT_XSLT_STYLESHEET }
|
|
177
|
+
XSLT30_STYLESHEET = File.expand_path('test_data/transform30.xsl', Dir.pwd).then { |p| File.exist?(p) ? File.read(p) : _DEFAULT_XSLT30_STYLESHEET }
|
|
149
178
|
|
|
150
179
|
OPERATIONS = {
|
|
151
180
|
'parsing' => ->(s, data) { s.parse(data) },
|
|
@@ -158,7 +187,8 @@ XSL
|
|
|
158
187
|
doc = s.parse(data)
|
|
159
188
|
XQUERY_EXPRESSIONS.each { |x| s.xquery_eval(doc, x) }
|
|
160
189
|
},
|
|
161
|
-
'xslt' => ->(s, data) { s.
|
|
190
|
+
'xslt' => ->(s, data) { s.xslt_apply(data, XSLT_STYLESHEET) },
|
|
191
|
+
'xslt30' => ->(s, data) { s.xslt_apply(data, XSLT30_STYLESHEET) },
|
|
162
192
|
'validation' => ->(s, data) { s.validate(s.parse(data), RNG_SCHEMA) },
|
|
163
193
|
'streaming' => ->(s, data) { s.stream_parse(data) { |_event, _data| } },
|
|
164
194
|
}.freeze
|
|
@@ -280,6 +310,8 @@ XSL
|
|
|
280
310
|
serializers = Serializers.for_format(format)
|
|
281
311
|
|
|
282
312
|
case type_name
|
|
313
|
+
when 'parsing', 'memory'
|
|
314
|
+
serializers.select { |s| s.supports?(:parse) }
|
|
283
315
|
when 'generation'
|
|
284
316
|
serializers.select { |s| s.supports?(:generate) }
|
|
285
317
|
when 'streaming'
|
|
@@ -292,6 +324,8 @@ XSL
|
|
|
292
324
|
serializers.select { |s| s.supports?(:xslt) }
|
|
293
325
|
when 'validation'
|
|
294
326
|
serializers.select { |s| s.supports?(:validation) }
|
|
327
|
+
when 'xslt30'
|
|
328
|
+
serializers.select { |s| s.supports?(:xslt30) }
|
|
295
329
|
else
|
|
296
330
|
serializers
|
|
297
331
|
end
|
|
@@ -51,7 +51,7 @@ module Serialbench
|
|
|
51
51
|
attribute :formats, :string, collection: true, values: %w[xml html json yaml toml]
|
|
52
52
|
attribute :iterations, BenchmarkIteration
|
|
53
53
|
attribute :warmup, :integer, default: -> { 1 }
|
|
54
|
-
attribute :operations, :string, collection: true, values: %w[parsing generation xpath xquery xslt validation streaming memory]
|
|
54
|
+
attribute :operations, :string, collection: true, values: %w[parsing generation xpath xquery xslt xslt30 validation streaming memory]
|
|
55
55
|
|
|
56
56
|
key_value do
|
|
57
57
|
map 'name', to: :name
|
|
@@ -73,6 +73,7 @@ module Serialbench
|
|
|
73
73
|
attribute :xpath, IterationPerformance, collection: true
|
|
74
74
|
attribute :xquery, IterationPerformance, collection: true
|
|
75
75
|
attribute :xslt, IterationPerformance, collection: true
|
|
76
|
+
attribute :xslt30, IterationPerformance, collection: true
|
|
76
77
|
attribute :validation, IterationPerformance, collection: true
|
|
77
78
|
|
|
78
79
|
key_value do
|
|
@@ -84,6 +85,7 @@ module Serialbench
|
|
|
84
85
|
map 'xpath', to: :xpath
|
|
85
86
|
map 'xquery', to: :xquery
|
|
86
87
|
map 'xslt', to: :xslt
|
|
88
|
+
map 'xslt30', to: :xslt30
|
|
87
89
|
map 'validation', to: :validation
|
|
88
90
|
end
|
|
89
91
|
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_xml_serializer'
|
|
4
|
+
require 'open3'
|
|
5
|
+
require 'tmpdir'
|
|
6
|
+
|
|
7
|
+
module Serialbench
|
|
8
|
+
module Serializers
|
|
9
|
+
module Xml
|
|
10
|
+
# Saxon-HE via its Java CLI: the reference XSLT 2.0/3.0 engine.
|
|
11
|
+
# Cold-process semantics: every iteration is a full JVM + compile +
|
|
12
|
+
# transform, so ips is comparable to leptris only end-to-end, never
|
|
13
|
+
# per-transform — features record cold_process: true.
|
|
14
|
+
class SaxonSerializer < BaseXmlSerializer
|
|
15
|
+
def name
|
|
16
|
+
'saxon-he'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def capabilities
|
|
20
|
+
Set.new(%i[xslt xslt30])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def features
|
|
24
|
+
{ 'xslt_version' => '3.0', 'cold_process' => true }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def classpath
|
|
28
|
+
jars = [ENV['SAXON_JAR'], ENV['XMLRESOLVER_JAR']].compact
|
|
29
|
+
jars.empty? ? nil : jars.join(File::PATH_SEPARATOR)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def xslt_apply(source_xml, stylesheet)
|
|
33
|
+
Dir.mktmpdir('saxonbench') do |dir|
|
|
34
|
+
src = File.join(dir, 's.xml')
|
|
35
|
+
xsl = File.join(dir, 's.xsl')
|
|
36
|
+
File.write(src, source_xml)
|
|
37
|
+
File.write(xsl, stylesheet)
|
|
38
|
+
out, _err, _st = Open3.capture3('java', '-cp', classpath, 'net.sf.saxon.Transform',
|
|
39
|
+
"-xsl:#{xsl}", "-s:#{src}")
|
|
40
|
+
raise Error, "saxon transform failed: #{out}#{_err}"[0, 200] unless _st.success?
|
|
41
|
+
|
|
42
|
+
out
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def available?
|
|
47
|
+
return @available if defined?(@available)
|
|
48
|
+
|
|
49
|
+
@available = begin
|
|
50
|
+
cp = classpath
|
|
51
|
+
raise LoadError, 'SAXON_JAR / XMLRESOLVER_JAR not set' unless cp
|
|
52
|
+
|
|
53
|
+
out, _err, st = Open3.capture3('java', '-cp', cp, 'net.sf.saxon.Version')
|
|
54
|
+
raise LoadError, 'java failed' unless st.success?
|
|
55
|
+
|
|
56
|
+
true
|
|
57
|
+
rescue StandardError, LoadError => e
|
|
58
|
+
warn "#{name} unavailable: #{e.class}: #{e.message}"
|
|
59
|
+
false
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def version
|
|
64
|
+
return 'unknown' unless available?
|
|
65
|
+
|
|
66
|
+
out, = Open3.capture3('java', '-cp', classpath, 'net.sf.saxon.Version')
|
|
67
|
+
out[/Saxon-HE (\S+)/, 1] || out.strip[0, 40]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -11,6 +11,7 @@ require_relative 'serializers/xml/nokogiri_serializer'
|
|
|
11
11
|
require_relative 'serializers/xml/oga_serializer'
|
|
12
12
|
require_relative 'serializers/xml/libxml_serializer'
|
|
13
13
|
require_relative 'serializers/xml/leptris_serializer'
|
|
14
|
+
require_relative 'serializers/xml/saxon_serializer'
|
|
14
15
|
|
|
15
16
|
# HTML Serializers
|
|
16
17
|
require_relative 'serializers/html/base_html_serializer'
|
|
@@ -49,7 +50,8 @@ module Serialbench
|
|
|
49
50
|
Xml::NokogiriSerializer,
|
|
50
51
|
Xml::OgaSerializer,
|
|
51
52
|
Xml::LibxmlSerializer,
|
|
52
|
-
Xml::LeptrisSerializer
|
|
53
|
+
Xml::LeptrisSerializer,
|
|
54
|
+
Xml::SaxonSerializer
|
|
53
55
|
],
|
|
54
56
|
json: [
|
|
55
57
|
Json::JsonSerializer,
|
data/lib/serialbench/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: serialbench
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
@@ -346,6 +346,7 @@ files:
|
|
|
346
346
|
- lib/serialbench/serializers/xml/oga_serializer.rb
|
|
347
347
|
- lib/serialbench/serializers/xml/ox_serializer.rb
|
|
348
348
|
- lib/serialbench/serializers/xml/rexml_serializer.rb
|
|
349
|
+
- lib/serialbench/serializers/xml/saxon_serializer.rb
|
|
349
350
|
- lib/serialbench/serializers/yaml/base_yaml_serializer.rb
|
|
350
351
|
- lib/serialbench/serializers/yaml/psych_serializer.rb
|
|
351
352
|
- lib/serialbench/serializers/yaml/syck_serializer.rb
|