Skip to content

Commit 78526ac

Browse files
mkschulzeclaude
andcommitted
diag(20.3): A/B test build for multi-peer CPU-spike regression
This is a DIAGNOSTIC build, not a shipping fix. Two suspect code paths are neutralized so we can confirm whether they are the regression source. Investigation tracked in .planning/debug/cpu-spikes-beta12-regression.md. ABTEST 1 (src/core/njclient.cpp): Revert DecodeMediaBuffer's SpscRing<DecodeChunk, N> from 256 back to 32. Confirms whether the 1 MB per-buffer × N peers × per-interval heap allocation introduced by 0e9cbae (in beta.20.1+) is the cause of the audible CPU spikes that grow with peer count. Side effect: re-introduces the original interval-overflow cutoff bug at high bitrates (decbuf_drops will climb in /rcmstats). ABTEST 2 (juce/JamWideJuceEditor.cpp): Stub the broadcastBeatHeartbeat() call from timerCallback. Confirms whether ~1.5 Hz JSON build + wsMutex_ acquisition + WebSocket send (introduced in beta.12 by 755257d) is the source of the baseline CPU bump users have reported since beta.12. Side effect: video companion sync indicator stops updating. How to use: - A/B compare against beta.20.2 under same load (4+ peers, 30+ min) - Watch audible-glitch cadence, Activity Monitor CPU% baseline, /rcmstats decbuf_drops - Each ABTEST can be toggled independently for symptom attribution (search for "=== ABTEST" markers in source) DO NOT ship as a normal beta. download.md still points to beta.20.2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2b3c93d commit 78526ac

4 files changed

Lines changed: 30 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
The 1.1 line is a complete JUCE rewrite (1.0 was CLAP/ImGui). Per-beta release notes for `1.1-beta.1` through `1.1-beta.20` are on the [GitHub Releases page](https://github.com/mkschulze/JamWide/releases) and are not duplicated here. Entries are tracked below starting with `1.1-beta.20.1`.
1111

12+
## [1.1.0-beta.20.3] - 2026-05-04 — DIAGNOSTIC BUILD
13+
14+
> **⚠ This is not a regular beta.** It is a diagnostic build for the multi-peer CPU-spike investigation tracked in `.planning/debug/cpu-spikes-beta12-regression.md`. Two suspect code paths are temporarily neutralized to confirm whether they are the regression source. Do **not** use this build for normal jamming — at high bitrates the original audio-cutoff bug that beta.20.1 fixed is intentionally re-introduced. Use beta.20.2 for normal use.
15+
16+
### Diagnostic changes (NOT shipping fixes)
17+
- **ABTEST 1**: `DecodeMediaBuffer`'s SPSC ring temporarily reverted from 256 → 32 chunks. Confirms whether per-peer-per-interval 1 MB heap allocation churn (introduced by beta.20.1's ring bump) is the cause of audible CPU spikes that grow with peer count. Side effect: original interval-overflow cutoff bug returns at high bitrates (≥192 kbps stereo on 12 s intervals); `decbuf_drops` will climb in `/rcmstats`.
18+
- **ABTEST 2**: `broadcastBeatHeartbeat` call in `JamWideJuceEditor::timerCallback` is stubbed. Confirms whether ~1.5 Hz JSON build + WebSocket send on the message thread is the source of the baseline CPU bump that started showing in beta.12. Side effect: video companion sync indicator stops updating; no other functional impact.
19+
20+
### Notes for testers
21+
- A/B compare baseline (beta.20.2) against this build under the same load (4+ peers, 30+ min session)
22+
- Watch for: (a) audible-glitch cadence change, (b) Activity Monitor CPU% baseline, (c) `decbuf_drops` counter via `/rcmstats`
23+
- Report findings to inform the proper fix (pool DecodeMediaBuffer + rate-limit/move heartbeat off message thread)
24+
1225
## [1.1.0-beta.20.2] - 2026-05-03
1326

1427
### Fixed

juce/JamWideJuceEditor.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,18 @@ void JamWideJuceEditor::timerCallback()
327327
beatBar.update(bpi, beat, iPos, iLen);
328328

329329
// Broadcast beat position to video companion page for sync indicator
330+
// === ABTEST 2 (cpu-spikes-beta12-regression) — heartbeat broadcast stubbed.
331+
// Hypothesis: ~1.5 Hz JSON build + wsMutex_ acquisition + WebSocket send
332+
// is the source of the beta-12-onward baseline-CPU bump that users have
333+
// reported. Diagnosis build only. To restore: uncomment the if-block.
334+
/*
330335
if (processorRef.videoCompanion && processorRef.videoCompanion->isActive())
331336
{
332337
int intervalCount = processorRef.uiSnapshot.interval_count.load(std::memory_order_relaxed);
333338
processorRef.videoCompanion->broadcastBeatHeartbeat(beat, bpi, intervalCount);
334339
}
340+
*/
341+
// === END ABTEST 2
335342

336343
// Update BeatBar BPM for label area display
337344
beatBar.setBpm(processorRef.uiSnapshot.bpm.load(std::memory_order_relaxed));

src/build_number.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#pragma once
2-
#define JAMWIDE_BUILD_NUMBER 313
2+
#define JAMWIDE_BUILD_NUMBER 314

src/core/njclient.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,15 @@ class DecodeMediaBuffer
354354
// codec needed. 256 × 4 KB = 1 MB gives 2× headroom over that worst case.
355355
// Memory cost: 1 MB per concurrent RemoteDownload; with 30-peer rooms that
356356
// is ~30 MB transient, acceptable.
357-
jamwide::SpscRing<jamwide::DecodeChunk, 256> m_chunks;
357+
// === ABTEST 1 (cpu-spikes-beta12-regression) — diagnostic revert of 0e9cbae.
358+
// Hypothesis: 1 MB-per-buffer × N peers × per-interval allocation churn is
359+
// the audible-glitch cause. WARNING: this re-introduces the original
360+
// interval-overflow cutoff bug at high bitrates. Diagnosis build only.
361+
// To restore production sizing: change 32 back to 256. The proper fix is
362+
// to keep capacity at 256 but heap-allocate the ring storage or pool the
363+
// DecodeMediaBuffer instances per (peer_slot, channel_idx).
364+
jamwide::SpscRing<jamwide::DecodeChunk, 32> m_chunks;
365+
// === END ABTEST 1
358366

359367
// Audio-thread-owned linear buffer — absorbs partial-chunk reads when the
360368
// codec asks for fewer bytes than CHUNK_BYTES at a time. Sized to 2x

0 commit comments

Comments
 (0)