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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64e0e821d66fb8c8d25debf605648a6d533f432e0882f1a7cecf58b2e2a19e52
4
- data.tar.gz: 70bb6cf535b69d0ae0c470459f183d6420e87db4a8bef12c89152f1d739c793b
3
+ metadata.gz: 859b03f81870e25ede0d7b9f05ac20d4013506220a69614dc7ea82d9db27b371
4
+ data.tar.gz: e3eb2b0658fb4698717e61a5a8a70b3195e0f229137b3035abf59f32096c0ab0
5
5
  SHA512:
6
- metadata.gz: eadc86a700848a3a0980d0e2af292ded87619a4bd958a0ea897a310c35caf00dfca7d4c1a997e1760d48d18872cb84458440601bc437a120131e6f4344a614b0
7
- data.tar.gz: 9d6a4fbc7dc3b88e96c896a4b55d10583b9764979a4d7f8eb3d0a51be3422d870f758a805c566529e85c94c2bcd7512b5715479e4d1e04295ce1936ff78599ab
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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.107.0"
4
+ VERSION = "1.9.107.1"
5
5
  end
@@ -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 is the first byte of each record read it off the C
163
- # pointer. The previous path copied every record into Ruby
164
- # and unpacked a Fixnum array just for the kind strip
165
- # (2.25M Integers on a single-feed drain); one get_uint8 per
166
- # event replaces both.
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
- code = records_ptr.get_uint8(i * RECORD_STRIDE)
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.0
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