Repository navigation
feat: add reusable LedFx application performance tools - #8
Merged
Merged
Conversation
shauneccles
added a commit
to LedFx/LedFx
that referenced
this pull request
Oct 5, 2026
LedFx delegates packet encoding and sending to `ledfx-senders` while retaining application-owned serial, TCP and DTLS sessions where required. It skips visualization preparation when no browser subscribes, preserves configured preview cadence, and reduces repeated allocation/conversion work in the effect pipeline. - Uses canonical public senders for E1.31, DDP, Art-Net, OPC, OSC and Nanoleaf, plus native vendor encoding and RGB gathering. Application RGB frames remain NumPy arrays. - Preserves transactional sender replacement, DNS generation checks, rollback and ownership locks, including current-main's Art-Net render/configuration deadlock regression. OSC configuration validation uses the public constructor and closes its temporary probe. - Keeps independent wire, lifecycle, destination-update, complete-write and numerical regression tests. Reusable application benchmarks live in [LedFx/ledfx-tools](https://github.com/LedFx/ledfx-tools); protocol microbenchmarks and native releases remain in [ledfx-senders](https://github.com/LedFx/ledfx-senders). The dependency requires `ledfx-senders>=0.3.0,<0.4.0`, locks [published 0.3.1](https://github.com/LedFx/ledfx-senders/releases/tag/v0.3.1), and uses wheels; uv is configured not to build it from source. The lock refresh changes no unrelated dependency. This delivery is based directly on current main (`a5ec8278`), preserves its shared-release CI, and adds no application Rust build, CI workflow, temporary sender facade, benchmark archive or development report. The existing measurement campaign compared main `a5ec8278` with cleanup `091ac8b9`: 50,000 RGB pixels, CPython 3.12.14, NumPy 2.5.3, standard asyncio, the same independent native loopback receiver, and three randomized adjacent pairs per workload. Each trial used two seconds warmup and eight seconds measured. Render pacing was bypassed while Rainbow's effect update cadence remained about 60 Hz. | Preview workload | Before render FPS | After render FPS | Median paired ratio | Pair range | | --- | ---: | ---: | ---: | ---: | | No subscriber; preview pacing bypassed | 496 | 1,148 | 2.376× | 2.215–2.425× | | Full preview; preview pacing bypassed | 681 | 719 | 1.023× | 1.009–1.103× | | Full preview; normal 60 Hz preview limit | 1,040 | 1,101 | 1.060× | 0.980–1.127× | These are whole-application results. The large no-subscriber gain is substantially explained by skipping unused preview preparation and does not establish a sender-only speedup. The small full-preview differences overlap plausible host variation. Individual-row FPS medians differ from the medians of paired ratios. Render/DDP throughput includes repeated images; both preview modes deliver about 59 changed RGB images per second. Local loopback stress results do not establish physical LED latency or LAN/Wi-Fi capacity, and zero malformed DDP packets does not mean zero incomplete frames. Final validation used the real PyPI 0.3.1 CPython 3.12 wheel in a frozen locked environment. Its hash matches PyPI and the lockfile, and all 19 installed sender package payloads match the wheel, including the native extension. Canonical public `Frame`, all seven sender exports, and E1.31 `ChannelLayout` imports were verified. The complete application suite passed **3,337 tests and 29 subtests**, with one skip; **116 focused CLI, sender, lifecycle and E1.31 tests** passed after the review fixes. The E1.31 blocked-import fixture supplies the same NumPy frame type as the application, retains exact wire assertions and explicitly runs its child from the repository root. All configured hooks passed, including Ruff lint/format, isolated locked strict Pyrefly, ClassVar audit, actionlint and zizmor. Strict Pyrefly reports zero errors with seven existing suppressions in the standard CI dependency set. The optional Hue extra exposes five existing typing errors and remains separate from this cleanup. Review fixes preserve active sender sequences and pixel buffers across unchanged DNS resolution, retain the active frame when destinations change, and propagate the actual tray startup/shutdown status across pystray's setup thread using a bounded join. These fixes have focused regressions and passed the complete suite at `c6a6ba5a`. Hosted validation for the preceding `9303fc1c` head: [CI 37281836408](https://github.com/LedFx/LedFx/actions/runs/37281836408) passed Linux tests on Python 3.11–3.14, Windows tests, macOS smoke tests, wheel/sdist checks, all frozen builds and both Docker architectures. Hosted checks for the updated head must pass independently before merge. This PR incorporates or replaces all production changes from #2059, #2060, #2061 and #2062. Close that obsolete stack as superseded after this PR merges; no additional patch or rebase of those branches is needed. Reusable performance tooling remains in [ledfx-tools #8](LedFx/ledfx-tools#8). Follow-up packet-wrapper cleanup, vendor lifecycle/frame ownership work and preview subscription filtering/early frame coalescing are separate post-merge changes. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Performance** * Improved effect rendering, color conversion, and visualization updates, including smoother handling of large matrices. * **Device Output** * Updated network device integrations for Art-Net, DDP, E1.31, OPC, OSC, UDP, Nanoleaf, and other supported devices. * Improved sender replacement and address-resolution handling to help maintain output during configuration changes. * Fixed OpenRGB transfers to ensure complete frames are sent. * **Reliability** * Improved application startup and shutdown behavior, including tray startup and CI smoke tests. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The LedFx performance spikes accumulated application benchmarks and experiment results in the application tree. This adds a reusable external
ledfx_performancepackage for measuring explicit LedFx checkouts and environments, so the production application can consume sender wheels without carrying profiling scripts or native build tooling.The package provides whole-app effect runs, synthetic audio and media fixtures, independent DDP and websocket output checks, Python 3.15 sampling reports, and randomized adjacent before/after comparisons. Runs retain provenance, failed trials and process logs outside application source; deadlines and owned process cleanup bound each experiment. README examples document pacing, receiver limits and interpretation of results. Derived performance code retains LedFx's GPL license alongside the existing tools' MIT license.
Validation: 27 tests pass; Ruff lint/format, strict Pyrefly and actionlint pass. A real uncapped before/after full-preview pair passed, along with synthetic-DSP Melt & Sparkle and generated-GIF smoke runs. The dedicated quality workflow also supports manual runs.