leptris 1.9.107.0 → 1.9.107.1
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/CHANGELOG.md +19 -0
- data/TODO.restructure/22-sax-drain-bulk-strip.md +28 -0
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/sax/recorder.rb +11 -7
- 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: 859b03f81870e25ede0d7b9f05ac20d4013506220a69614dc7ea82d9db27b371
|
|
4
|
+
data.tar.gz: e3eb2b0658fb4698717e61a5a8a70b3195e0f229137b3035abf59f32096c0ab0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 179b50450680923f7bb71c1079e3226559d04a754ce0892765fd2bcbdbb4d3b7506d88dda7a8f58bd2f4148c6266248d0fe84ff5efd63485b14a047e6835aa1b
|
|
7
|
+
data.tar.gz: 5a4653e79904ec197c7775e08cd11478d2dc2638a2d28a52b4b901f6cb93745793cd4748bcd397cf92b051349865d5b16741f52e2cb86866c0d3ae129cf4af50
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ All notable changes to Leptris will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.107.1] - 2026-09-08
|
|
9
|
+
|
|
10
|
+
### Improved
|
|
11
|
+
|
|
12
|
+
- **SAX drain: bulk kind strip** (TODO.restructure/22 — the moxml
|
|
13
|
+
0.77-0.93x row): the recorder's dispatch loop read the event
|
|
14
|
+
kind with a `get_uint8` per EVENT (a memory crossing for every
|
|
15
|
+
record, dispatched or not); the strip now reads in ONE bulk
|
|
16
|
+
`get_bytes` + ONE `unpack` per drain via the memoized
|
|
17
|
+
per-count template — kind codes 0..10 unpack to immediate
|
|
18
|
+
Fixnums, so the change strictly removes ~count FFI crossings
|
|
19
|
+
with zero new allocations. Allocation profile (load-independent
|
|
20
|
+
measurement) is far ahead either way: text-only 32,381 vs
|
|
21
|
+
Nokogiri's 400,061 allocs/parse (12x fewer); all-events 112,440
|
|
22
|
+
vs 400,034 (3.6x fewer) — the remaining gap is pure per-event
|
|
23
|
+
CPU, which this addresses. Timing verification gated on a clean
|
|
24
|
+
host window (bench staged; the shared machine sat at load
|
|
25
|
+
40-400 today).
|
|
26
|
+
|
|
8
27
|
## [1.9.107.0] - 2026-09-08
|
|
9
28
|
|
|
10
29
|
### Changed
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# 22 — SAX drain: bulk kind strip (the 0.77-0.93x row)
|
|
2
|
+
|
|
3
|
+
Status: CODE DONE — timing verification gated on a clean window
|
|
4
|
+
|
|
5
|
+
The moxml table shows SAX at 0.77-0.93x Nokogiri (it fully won at
|
|
6
|
+
the 1.9.40-era battery). Investigation under load-404 conditions
|
|
7
|
+
(timing unusable; allocation profiling is load-independent):
|
|
8
|
+
|
|
9
|
+
- **Allocations are NOT the gap** — measured GC-stat deltas:
|
|
10
|
+
text-only 32,381 vs Nokogiri's 400,061 allocs/parse (12x fewer);
|
|
11
|
+
all-events 112,440 vs 400,034 (3.6x fewer).
|
|
12
|
+
- **The time cost was per-event FFI crossings in the drain**: the
|
|
13
|
+
kind strip was read with a `get_uint8` per EVENT (all events,
|
|
14
|
+
dispatched or not — a memory crossing each) after the
|
|
15
|
+
whole-record-unpack was retired for its 2.25M-Integer profile.
|
|
16
|
+
- **Fix**: the kind strip reads in ONE `get_bytes` + ONE `unpack`
|
|
17
|
+
per drain through the already-defined memoized
|
|
18
|
+
`KIND_TEMPLATE_FOR` — kind codes 0..10 unpack to IMMEDIATE
|
|
19
|
+
Fixnums (zero allocation), so this strictly removes ~count FFI
|
|
20
|
+
crossings per drain with no new allocations. Per-dispatched-event
|
|
21
|
+
field reads (2-3 `get_uint32`) remain.
|
|
22
|
+
|
|
23
|
+
- [x] Bulk strip restored; SAX suite green; allocation profile
|
|
24
|
+
re-verified (32k/112k vs 400k/400k).
|
|
25
|
+
- [ ] **Timing verification** (the actual 0.77-0.93x row): bench
|
|
26
|
+
staged at /tmp/bench_sax.rb — requires load < 20 (the host
|
|
27
|
+
has been at 40-400). Gate: text-only and all-events SAX at
|
|
28
|
+
parity or better vs Nokogiri on the raw binding.
|
data/lib/leptris/version.rb
CHANGED
|
@@ -159,16 +159,20 @@ class Leptris::XML::SAX::Recorder
|
|
|
159
159
|
@handle, len_ptr)
|
|
160
160
|
arena = arena_ptr.read_bytes(len_ptr.read_uint64)
|
|
161
161
|
count = count_ptr.read_uint64
|
|
162
|
-
# Kind
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
162
|
+
# Kind strip in ONE bulk read + ONE unpack per drain: the
|
|
163
|
+
# per-count template reads the first byte of each record,
|
|
164
|
+
# skipping the stride (KIND_TEMPLATE_FOR is memoized per
|
|
165
|
+
# count). Kind codes are 0..10 — unpack yields immediate
|
|
166
|
+
# Fixnums, so the strip allocates nothing. This replaces a
|
|
167
|
+
# get_uint8 crossing per EVENT (all events, dispatched or
|
|
168
|
+
# not) with one memory read per drain — the SAX gap to
|
|
169
|
+
# Nokogiri's per-event C callback lives exactly here.
|
|
170
|
+
kinds = records_ptr.get_bytes(0, count * RECORD_STRIDE)
|
|
171
|
+
.unpack(KIND_TEMPLATE_FOR[count])
|
|
167
172
|
one_arg_start = dispatched[:start_element] == :one_arg
|
|
168
173
|
i = 0
|
|
169
174
|
while i < count
|
|
170
|
-
|
|
171
|
-
kind = KIND_BY_CODE[code]
|
|
175
|
+
kind = kinds[i] && KIND_BY_CODE[kinds[i]]
|
|
172
176
|
if kind && dispatched[kind]
|
|
173
177
|
base = i * RECORD_STRIDE
|
|
174
178
|
case kind
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: leptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.9.107.
|
|
4
|
+
version: 1.9.107.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -90,6 +90,7 @@ files:
|
|
|
90
90
|
- TODO.restructure/19-gitignore-hygiene.md
|
|
91
91
|
- TODO.restructure/20-utf8proc-enablement.md
|
|
92
92
|
- TODO.restructure/21-typeddata-variant-prototype.md
|
|
93
|
+
- TODO.restructure/22-sax-drain-bulk-strip.md
|
|
93
94
|
- docs/adr/0001-lockstep-mirror.md
|
|
94
95
|
- docs/adr/0002-utf8-at-the-seam.md
|
|
95
96
|
- docs/adr/0003-readonly-memoization-pattern.md
|