Commit Graph

17 Commits

Author SHA1 Message Date
Joseph Doherty
ba0d65317a Improve source XML docs and refresh profiling artifacts
This captures the iterative CommentChecker cleanup plus updated snapshot/report outputs used to validate and benchmark the latest JetStream and transport work.
2026-03-14 03:13:17 -04:00
Joseph Doherty
1d4b87e5f9 docs: refresh benchmark comparison with increased message counts
Increase message counts across all 14 benchmark test files to reduce
run-to-run variance (e.g. PubSub 16B: 10K→50K, FanOut: 10K→15K,
SinglePub: 100K→500K, JS tests: 5K→25K). Rewrite benchmarks_comparison.md
with fresh numbers from two-batch runs. Key changes: multi 4x4 reached
parity (1.01x), fan-out improved to 0.84x, TLS pub/sub shows 4.70x .NET
advantage, previous small-count anomalies corrected.
2026-03-13 17:52:03 -04:00
Joseph Doherty
0e5ce4ed9b perf: optimize fan-out serial path — pre-formatted MSG headers, non-atomic RR, linear pcd
Three optimizations making the serial fan-out path cheaper (fan-out 0.63x→0.70x,
multi pub/sub 0.65x→0.69x):

1. Pre-format MSG prefix ("MSG subject ") and suffix (" [reply] sizes\r\n") once
   per publish. New SendMessagePreformatted writes prefix+sid+suffix directly into
   _directBuf — zero encoding, pure memory copies. Only SID varies per delivery.

2. Replace queue-group round-robin Interlocked.Increment/Decrement with non-atomic
   uint QueueRoundRobin++ (safe: ProcessMessage runs single-threaded per connection).

3. Replace HashSet<INatsClient> pcd with ThreadStatic INatsClient[] + linear scan.
   O(n) but n≤16; faster than hash for small fan-out counts.
2026-03-13 16:23:18 -04:00
Joseph Doherty
23543b2ba8 Merge branch 'opt/js-async-file-publish'
JetStream async file publish optimization (~10% improvement):
- Cached state properties eliminate GetStateAsync on publish path
- Single stream lookup eliminates double FindBySubject
- Removed _messageIndexes dictionary from write path
- Hand-rolled UTF-8 pub-ack formatter for success path
- Exponential flush backoff matching Go server
- Lazy StoredMessage materialization (MessageMeta struct)

# Conflicts:
#	benchmarks_comparison.md
2026-03-13 15:37:11 -04:00
Joseph Doherty
82ab02a612 docs: refresh benchmark comparison after JS async publish optimization 2026-03-13 15:35:59 -04:00
Joseph Doherty
a62a25dcdf perf: optimize fan-out hot path and switch benchmarks to Release build
Round 9 optimizations targeting per-delivery overhead:
- Switch benchmark harness from Debug to Release build (biggest impact:
  durable fetch 0.42x→0.92x, request-reply to parity)
- Batch server-wide stats after fan-out loop (2 Interlocked per delivery → 2 per publish)
- Guard auto-unsub tracking with MaxMessages > 0 (skip Interlocked in common case)
- Cache SID as ASCII bytes on Subscription (avoid per-delivery encoding)
- Pre-encode subject bytes once before fan-out loop (avoid N encodings)
- Add 1-element subject string cache in ProcessPub (avoid repeated alloc)
- Remove Interlocked from SubList.Match stats counters (approximate is fine)
- Extract WriteMessageToBuffer helper for both string and span overloads
2026-03-13 15:30:02 -04:00
Joseph Doherty
86fd971510 docs: refresh benchmark comparison after round 8
Ordered consumer: 0.57x (signal-based wakeup + batch flush).
Cross-protocol MQTT: 1.20x (string.Create fast path + topic cache pre-warm).
2026-03-13 14:49:32 -04:00
Joseph Doherty
11e01b9026 perf: optimize MQTT cross-protocol path (0.30x → 0.78x Go)
Replace per-message async fire-and-forget with direct-buffer write loop
mirroring NatsClient pattern: SpinLock-guarded buffer append, double-
buffer swap, single WriteAsync per batch.

- MqttConnection: add _directBuf/_writeBuf + RunMqttWriteLoopAsync
- MqttConnection: add EnqueuePublishNoFlush (zero-alloc PUBLISH format)
- MqttPacketWriter: add WritePublishTo(Span<byte>) + MeasurePublish
- MqttTopicMapper: add NatsToMqttBytes with bounded ConcurrentDictionary
- MqttNatsClientAdapter: synchronous SendMessageNoFlush + SignalFlush
- Skip FlushAsync on plain TCP sockets (TCP auto-flushes)
2026-03-13 14:25:13 -04:00
Joseph Doherty
497aa227af docs: refresh benchmark comparison 2026-03-13 11:42:39 -04:00
Joseph Doherty
a470e0bcdb docs: refresh benchmark comparison 2026-03-13 11:39:54 -04:00
Joseph Doherty
fb0d31c615 docs: refresh benchmark comparison after SubList optimization 2026-03-13 10:18:52 -04:00
Joseph Doherty
a3b34fb16d docs: record parser hot-path allocation strategy 2026-03-13 10:08:20 -04:00
Joseph Doherty
0be321fa53 perf: batch flush signaling and fetch path optimizations (Round 6)
Implement Go's pcd (per-client deferred flush) pattern to reduce write-loop
wakeups during fan-out delivery, optimize ack reply string construction with
stack-based formatting, cache CompiledFilter on ConsumerHandle, and pool
fetch message lists. Durable consumer fetch improves from 0.60x to 0.74x Go.
2026-03-13 09:35:57 -04:00
Joseph Doherty
0a4e7a822f perf: eliminate per-message allocations in pub/sub hot path and coalesce outbound writes
Pub/sub 1:1 (16B) improved from 0.18x to 0.50x, fan-out from 0.18x to 0.44x,
and JetStream durable fetch from 0.13x to 0.64x vs Go. Key changes: replace
.ToArray() copy in SendMessage with pooled buffer handoff, batch multiple small
writes into single WriteAsync via 64KB coalesce buffer in write loop, and remove
profiling Stopwatch instrumentation from ProcessMessage/StreamManager hot paths.
2026-03-13 05:09:36 -04:00
Joseph Doherty
9e0df9b3d7 docs: add JetStream perf investigation notes and test status tracking
Add detailed analysis of the 1,200x JetStream file publish gap identifying
the bottleneck in the outbound write path (not FileStore). Add tests.md
tracking skipped/failing test status across Core and JetStream suites.
2026-03-13 03:20:43 -04:00
Joseph Doherty
4de691c9c5 perf: add FileStore buffered writes, O(1) state tracking, and eliminate redundant per-publish work
Implement Go-parity background flush loop (coalesce 16KB/8ms) in MsgBlock/FileStore,
replace O(n) GetStateAsync with incremental counters, skip PruneExpired/LoadAsync/
PrunePerSubject when not needed, and bypass RAFT for single-replica streams. Fix counter
tracking bugs in RemoveMsg/EraseMsg/TTL expiry and ObjectDisposedException races in
flush loop disposal. FileStore optimizations verified with 3112/3112 JetStream tests
passing; async publish benchmark remains at ~174 msg/s due to E2E protocol path bottleneck.
2026-03-13 03:11:11 -04:00
Joseph Doherty
37575dc41c feat: add benchmark test project for Go vs .NET server comparison
Side-by-side performance benchmarks using NATS.Client.Core against both
servers on ephemeral ports. Includes core pub/sub, request/reply latency,
and JetStream throughput tests with comparison output and
benchmarks_comparison.md results. Also fixes timestamp flakiness in
StoreInterfaceTests by using explicit timestamps.
2026-03-13 01:23:31 -04:00