From 4ebdfbf58b147d7cd31b3eafbe49749b94d06435 Mon Sep 17 00:00:00 2001 From: Michael Pham <61564344+Mikefly123@users.noreply.github.com> Date: Wed, 22 Jul 2026 21:50:06 -0700 Subject: [PATCH] fix(ram): carry fprime patch shrinking TlmPacketizer packetOffset to I16 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Carry patches/fprime-tlmpacketizer-i16-offset.patch, applied to lib/fprime by `make submodules` with a reverse-apply idempotency check (same pattern as the existing fprime-yamcs patch step). Also exclude patches/ from the trailing-whitespace and end-of-file pre-commit hooks: patch bytes must byte-match the upstream tree or `git apply` breaks. TlmPacketizer::TlmEntry stores FwSignedSizeType packetOffset[MAX_PACKETIZER_PACKETS] per channel — F Prime's 64-bit size-type migration leaked into a persistent dense channels x packets offset matrix. The offsets index into ComBuffers <= 256 B, so I16 is ample (keeps the -1 sentinel, supports offsets to 32 KiB; the range FW_ASSERT in setPacketList is tightened to the I16 max). 3 functional lines. Measured on this deployment (MAX_PACKETIZER_PACKETS=22, MAX_PACKETIZER_CHANNELS=202): - CdhCore::tlmSend bss: 60,480 -> 33,008 B (-27,472 B; reproduced in this build, nm 0x80f0) - malloc arena (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=-1): 173,272 -> 200,744 B - free heap at boot: 11,504 -> 38,976 B (3.4x; margin context in PR #467) Validation: fprime Svc/TlmPacketizer UT 12/12 pass (1 pre-existing skip); HWIL on v5e — stable boot, 49 channels decode sane, NO_OP and SEND_PKT pass, live sys_heap walk matches predicted numbers exactly. Upstream candidate for nasa/fprime; carried here until accepted. Co-Authored-By: Claude Fable 5 --- .pre-commit-config.yaml | 6 ++++ Makefile | 11 +++++++ patches/README.md | 18 +++++++++++ patches/fprime-tlmpacketizer-i16-offset.patch | 31 +++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 patches/fprime-tlmpacketizer-i16-offset.patch diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 988edf77..914cefe4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,13 @@ repos: rev: v5.0.0 hooks: - id: trailing-whitespace + # patches/*.patch are machine-generated diffs applied via `git apply`; + # their context/removed lines must byte-match the real upstream files, + # which can legitimately have trailing whitespace. Stripping it here + # silently breaks patch application. + exclude: ^patches/ - id: end-of-file-fixer + exclude: ^patches/ - id: check-yaml exclude: ^mkdocs\.yml$ - id: check-json diff --git a/Makefile b/Makefile index bb3e819f..df121c56 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,17 @@ help: ## Display this help. submodules: ## Initialize and update git submodules @git submodule foreach --recursive 'git checkout -- . && git clean -fd' || true @git submodule update --init --recursive + @echo "Applying fprime TlmPacketizer I16 packetOffset patch (upstream candidate)..." + @cd lib/fprime && \ + if git apply --check ../../patches/fprime-tlmpacketizer-i16-offset.patch 2>/dev/null; then \ + git apply ../../patches/fprime-tlmpacketizer-i16-offset.patch && \ + echo "✓ Applied TlmPacketizer I16 packetOffset patch"; \ + elif git apply --reverse --check ../../patches/fprime-tlmpacketizer-i16-offset.patch 2>/dev/null; then \ + echo "⚠ Patch already applied"; \ + else \ + echo "❌ Error: Unable to apply TlmPacketizer I16 patch. Run 'cd lib/fprime && git status' to check."; \ + exit 1; \ + fi export VIRTUAL_ENV ?= $(shell pwd)/fprime-venv .PHONY: fprime-venv diff --git a/patches/README.md b/patches/README.md index 09cbaf39..0a6402b6 100644 --- a/patches/README.md +++ b/patches/README.md @@ -2,6 +2,24 @@ This directory contains patches that are automatically applied to git submodules during the build process. +## fprime-tlmpacketizer-i16-offset.patch + +Shrinks `Svc::TlmPacketizer`'s per-channel `packetOffset` array from `FwSignedSizeType` +(64-bit) to `I16` in `lib/fprime`. The offset is a byte index into a ComBuffer-sized +packet (or the -1 "not in this packet" sentinel), so I16 is ample; the range `FW_ASSERT` +in `setPacketList` is tightened to the I16 max. + +**Why:** With this project's `MAX_PACKETIZER_CHANNELS=202` and `MAX_PACKETIZER_PACKETS=22`, +the dense channels×packets offset matrix dominates the component: the patch shrinks the +`tlmSend` instance from 60,480 to 33,008 B of BSS (−27,472 B), which flows 1:1 into the +libc malloc arena (free-at-boot measured 11,504 → 38,976 B on a v5e board). + +**Status:** Upstream candidate for nasa/fprime; carried here until accepted. + +**Application:** Applied automatically by `make submodules` with a reverse-apply +idempotency check. As with the other fprime patches, `lib/fprime` will show as modified — +do not commit the submodule pointer. + ## fprime-gds-version.patch This patch updates the `fprime-gds` version requirement in `lib/fprime/requirements.txt` from 4.1.0 to 4.1.1a2. diff --git a/patches/fprime-tlmpacketizer-i16-offset.patch b/patches/fprime-tlmpacketizer-i16-offset.patch new file mode 100644 index 00000000..440da005 --- /dev/null +++ b/patches/fprime-tlmpacketizer-i16-offset.patch @@ -0,0 +1,31 @@ +diff --git a/Svc/TlmPacketizer/TlmPacketizer.cpp b/Svc/TlmPacketizer/TlmPacketizer.cpp +index 89af22e1d..ba1c68555 100644 +--- a/Svc/TlmPacketizer/TlmPacketizer.cpp ++++ b/Svc/TlmPacketizer/TlmPacketizer.cpp +@@ -89,10 +89,10 @@ void TlmPacketizer::setPacketList(const TlmPacketizerPacketList& packetList, + entry.ignored = false; + entry.channelSize = packetList.list[pktEntry]->list[tlmEntry].size; + // the offset into the buffer will be the current packet length +- // the offset must fit within FwSignedSizeType to allow for negative values +- FW_ASSERT(packetLen <= static_cast(std::numeric_limits::max()), ++ // the offset must fit within I16 to allow for the -1 sentinel value ++ FW_ASSERT(packetLen <= static_cast(std::numeric_limits::max()), + static_cast(packetLen)); +- entry.packetOffset[pktEntry] = static_cast(packetLen); ++ entry.packetOffset[pktEntry] = static_cast(packetLen); + + packetLen += entry.channelSize; + +diff --git a/Svc/TlmPacketizer/TlmPacketizer.hpp b/Svc/TlmPacketizer/TlmPacketizer.hpp +index 7f80d76d2..ffb58fc5d 100644 +--- a/Svc/TlmPacketizer/TlmPacketizer.hpp ++++ b/Svc/TlmPacketizer/TlmPacketizer.hpp +@@ -172,7 +172,7 @@ class TlmPacketizer final : public TlmPacketizerComponentBase, public Fw::ParamE + FwChanIdType id; //!< telemetry id stored in slot + // Offsets into packet buffers. + // -1 means that channel is not in that packet +- FwSignedSizeType packetOffset[MAX_PACKETIZER_PACKETS]; ++ I16 packetOffset[MAX_PACKETIZER_PACKETS]; + FwSizeType channelSize; //!< max serialized size of the channel in bytes + bool ignored; //!< ignored channel id + bool hasValue; //!< if the entry has received a value at least once