Astro~/0.4
** Docs
** Astro * Docs
** /docs/reference/performance

Performance

Measured throughput and allocations for every layer, so you can size a link before building it.

Every frame protocol, both compressors, the Reed-Solomon, Viterbi, and BCH coders, the Proximity-1 synchronizer, the SDLS security layer, and the checksums are benchmarked. Run them:

make bench

The numbers below came from that suite. They are here so you can answer "will this keep up with my downlink?" without writing the benchmark yourself.

How to read these

goos: darwin   goarch: arm64   cpu: Apple M2 Pro

One machine, one architecture, single-threaded, warm cache, no I/O. Treat them as relative costs between layers, not as a promise about your hardware. The shape of the answer travels; the absolute figures do not.

MB/s counts the octets that went through the operation. Allocations matter as much as time on a flight-adjacent system, so they are in the table.

Figures are rounded to two significant figures, because they move by 10 to 15 percent between runs on the same machine. A difference of a few percent between two rows here means nothing; a factor of two means something.

The bottleneck is Reed-Solomon (Viterbi, on Proximity-1)

OperationThroughputAllocations
RS(255,223) encode33 MB/s3
RS(255,239) encode61 MB/s3
RS decode, no errors34 MB/s3
RS decode, 1 error7.7 MB/s8
RS decode, 8 errors7.1 MB/s8
RS decode, 16 errors7.1 MB/s9
Viterbi decode, 4096-octet frame0.73 MB/s3
Proximity-1 sync, clean stream350 MB/s57
Proximity-1 sync, degraded stream62 MB/s0

Four things to plan around.

Decoding costs about 4.8× more once it is actually correcting. A clean link decodes at about 34 MB/s and a link near the correction limit at about 7.1 MB/s. Size for the bad case, because the bad case is when you need the data.

The stronger code is nearly half the speed. RS(255,223) corrects 16 symbols at about 33 MB/s; RS(255,239) corrects 8 at about 61 MB/s. That is the trade, in numbers.

On a Proximity-1 link, Viterbi is the actual bottleneck, not Reed-Solomon. Decoding the rate-1/2, constraint-length-7 convolutional code of CCSDS 211.2-B-3 runs at 0.73 MB/s, about 10 times slower than RS decode even at its worst. pkg/pxsc was missing from make bench and its one benchmark reported no allocation figures, so this number was simply never in the picture before. "Reed-Solomon is the bottleneck" is true for a TM, AOS, or USLP downlink; a Proximity-1 link is bottlenecked by Viterbi instead.

Finding frame boundaries is cheap until the stream is bad. pkg/pxsc's synchronizer runs at about 350 MB/s when every PLTU's implied frame length is right the first time. On a stream seeded with false sync markers it drops to about 62 MB/s, because each false marker fails its CRC and sends the scan through every candidate frame length. That is a 5.6× cliff between a good pass and a noisy one, and it is worth sizing for, since a noisy pass is when the synchronizer matters. The fallback used to recompute a full CRC-32 per candidate; it now extends one incrementally, which is what keeps the degraded case at a constant factor rather than a quadratic one.

The time here is inherent Galois-field arithmetic rather than anything redundant, so it is unlikely to improve much — but that is only true of the time, not of the allocations. Berlekamp-Massey used to allocate a fresh scratch buffer on every non-zero discrepancy, which is why the 1/8/16-error rows above used to show 9, 23, and 40 allocations; they now show a flat 8, 8, and 9, because that buffer is allocated once and reused. Viterbi decode got the same kind of cleanup: allocations dropped from 14 per call to 3. Its time did not measurably change, because the trellis update dominates it, not allocation.

Everything else is far cheaper

OperationThroughputAllocations
CADU wrap8000 MB/s1
CADU wrap, randomized1000 MB/s2
TM frame encode310 MB/s2
TM frame decode300 MB/s2
TC frame encode280 MB/s3
TC frame decode300 MB/s2
AOS frame encode290 MB/s7
AOS frame decode300 MB/s3
USLP frame encode280 MB/s11
USLP frame decode300 MB/s3
CRC-16, 1115-octet frame310 MB/s0
CRC-32, 1115-octet frame310 MB/s0

Frame encoding and decoding sit around 300 MB/s across all four data link protocols, and that number is dominated by the CRC: a table-driven CRC-16 over the same 1115 octets runs at about the same rate. The framing itself is nearly free.

Header decoding alone is 3.6 ns for TM and 3.0 ns for AOS, with no allocations, so demultiplexing a stream by VCID before deciding what to keep costs almost nothing.

Packets

OperationThroughputAllocations
Encode, 256 octets4000 MB/s3
Encode, 4096 octets9000 MB/s3
Encode with CRC, 256 octets290 MB/s3
Decode, 256 octets4000 MB/s3
spp.PacketSizer0.59 ns0

The packet layer is not where your time goes, with one exception: WithErrorControl costs an order of magnitude. Encoding a 256-octet packet runs at thousands of MB/s without a CRC and a few hundred with one. The CRC is the whole cost, and it is the same CRC the frame layer already computes over everything. On a link where frames carry a FECF, a per-packet CRC buys you very little for 12× the packet encoding cost.

Compression

OperationThroughputAllocations
LDC compress, smooth ramp48 MB/s14
LDC compress, noise62 MB/s16
LDC decompress, smooth ramp48 MB/s269
LDC decompress, noise73 MB/s269
RHC compress, one cycle9.7 MB/s13
RHC decompress, one cycle33 MB/s7

LDC runs at roughly 50 to 70 MB/s, comfortably faster than the Reed-Solomon that will follow it, so compression is not the constraint in a downlink chain. Decompression allocates 269 times, which is worth knowing if you are processing an archive rather than a live pass.

RHC is measured per cycle over a small housekeeping vector, so its MB/s figure is dominated by per-cycle overhead rather than throughput. 13 allocations per compressed cycle is the number to watch on a spacecraft that runs it every second.

OperationThroughputAllocations
BCH encode69 MB/s1
BCH decode, clean68 MB/s1
BCH decode, with an error2.3 MB/s1
CLTU wrap70 MB/s2

BCH correction is 29× slower than the clean path, but an uplink is kilobits per second, so this never matters. It is listed for completeness.

SDLS security

Measured over a 1115-octet TM frame data field, the same frame size the tables above use, for the clause E1/E3/E4 AES-256-GCM baseline (authenticated encryption), GMAC (GCM's authentication-only companion), and the clause E2 AES-CMAC telecommand baseline (authentication-only):

OperationThroughputAllocations
ApplySecurity, AES-256-GCM1400 MB/s6
ApplySecurity, GMAC1400 MB/s7
ApplySecurity, AES-CMAC580 MB/s9
ProcessSecurity, AES-256-GCM1400 MB/s7
ProcessSecurity, GMAC1400 MB/s7
ProcessSecurity, AES-CMAC580 MB/s10

pkg/sdls had no benchmarks at all until now, and was absent from make bench, even though it runs on the same per-frame path as the Reed-Solomon and Viterbi coders above. All six numbers land comfortably above either coder, so SDLS is not what limits a protected downlink or Proximity-1 link; it was just never checked. AES-CMAC runs at a bit under half the speed of the AES-GCM paths here, which is worth knowing if you are choosing between the clause E2 and clause E1/E3/E4 baselines on throughput alone.

What is not measured

No end-to-end pipeline benchmark, no concurrent throughput, and nothing for pkg/sle, pkg/cfdp, pkg/bp, pkg/ltp, pkg/pus or pkg/xtce. Those are caller-pumped state machines and parsers whose cost depends far more on how you drive them than on the library, so a single number would mislead.

Things that will bite you

A 300 MB/s frame layer does not mean a 300 MB/s link. The chain is packet, frame, then Reed-Solomon (or, on Proximity-1, Viterbi), and the slowest stage sets the rate. On a downlink with RS(255,223) that is about 34 MB/s clean and about 7.1 MB/s while correcting; on a Proximity-1 link, Viterbi decode at 0.73 MB/s sets the rate instead.

These numbers are single-threaded. A Sender is not safe for concurrent use, and neither are the frame services, because a downlink is one ordered stream. Scaling means one pipeline per physical channel, not one per core.

Allocations are per operation, not per octet. Three allocations to encode a 4096-octet packet is cheap. Three allocations to encode a 16-octet packet, two orders of magnitude slower per octet, is the same three allocations doing much less work. Small packets are dominated by fixed cost.

Do not read MB/s on RHC as throughput. It compresses one fixed-length vector per cycle, so the figure reflects per-cycle overhead on a small input.

Reference