Skip to content

perf(core): add state_str() to UDP DPI enums, drop per-call heap allocs in Connection::state()#418

Closed
obchain wants to merge 1 commit into
domcyrus:mainfrom
obchain:perf/udp-dpi-state-static-str
Closed

perf(core): add state_str() to UDP DPI enums, drop per-call heap allocs in Connection::state()#418
obchain wants to merge 1 commit into
domcyrus:mainfrom
obchain:perf/udp-dpi-state-static-str

Conversation

@obchain

@obchain obchain commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Closes #417

What

Connection::state() is called every render frame for every visible connection. Five branches were building their return value with Cow::Owned(format!("PREFIX_{}", info.field)), allocating a String on the heap each time:

// before — 1 heap alloc per call for each of these protocols
ApplicationProtocol::Dhcp(info)    => Cow::Owned(format!("DHCP_{}",    info.message_type)),
ApplicationProtocol::Snmp(info)    => Cow::Owned(format!("SNMP_{}",    info.pdu_type)),
ApplicationProtocol::Ssdp(info)    => Cow::Owned(format!("SSDP_{}",    info.method)),
ApplicationProtocol::NetBios(info) => Cow::Owned(format!("NETBIOS_{}", info.service)),
ApplicationProtocol::Stun(info)    => Cow::Owned(format!("STUN_{}",    info.message_class)),

All five enums have a small, closed set of known variants. This PR adds state_str() methods that return the full prefixed string as a compile-time constant, then updates Connection::state() to use Cow::Borrowed instead:

// after — 0 heap allocs for known variants
ApplicationProtocol::Dhcp(info)    => info.message_type.state_str(),              // Cow<'static,str>
ApplicationProtocol::Snmp(info)    => Cow::Borrowed(info.pdu_type.state_str()),   // &'static str
ApplicationProtocol::Ssdp(info)    => Cow::Borrowed(info.method.state_str()),
ApplicationProtocol::NetBios(info) => Cow::Borrowed(info.service.state_str()),
ApplicationProtocol::Stun(info)    => Cow::Borrowed(info.message_class.state_str()),

New methods

Enum Return type Variants Example
DhcpMessageType Cow<'static, str> 8 static + Unknown(u8) "DHCP_DISCOVER"
SnmpPduType &'static str 9 "SNMP_GET"
SsdpMethod &'static str 3 "SSDP_M-SEARCH"
NetBiosService &'static str 2 "NETBIOS_NS"
StunMessageClass &'static str 4 "STUN_Request"

DhcpMessageType::Unknown(u8) retains a Cow::Owned allocation since the byte value is runtime data — all other variants are Cow::Borrowed.

Impact

For each frame with DHCP/SNMP/SSDP/NetBIOS/STUN connections visible: −1 heap alloc per connection per state() call. In a busy network with 50 such connections at 30 fps that is 1,500 allocations/second eliminated.

Tests

Five new unit tests:

  • dhcp_state_str_known_variants_are_borrowed — asserts Cow::Borrowed for all 8 known variants and Cow::Owned for Unknown(42)
  • snmp_state_str_matches_prefixed_display — each variant matches format!("SNMP_{}", variant)
  • ssdp_state_str_matches_prefixed_display
  • netbios_state_str_matches_prefixed_display
  • stun_state_str_matches_prefixed_display

Verification

cargo build --workspace            # clean
cargo test --workspace --lib       # 419 passed, 0 failed
cargo fmt --check                  # clean
cargo clippy --all-targets -- -D warnings  # clean

@domcyrus

Copy link
Copy Markdown
Owner

Thanks for the detailed write-up and tests. For Connection::state(), could you share a flamegraph or allocation profile from traffic with enough DHCP/SNMP/SSDP/NetBIOS/STUN connections to show this branch as a meaningful hot path? That would help distinguish this from a nice cleanup with limited real-world impact.

…cs in Connection::state()

Five branches in Connection::state() built their return value with
Cow::Owned(format!("PREFIX_{}", info.field)), allocating on the heap
every time state() was called — i.e. every render frame for each
DHCP, SNMP, SSDP, NetBIOS, or STUN connection.

All five enums have a finite, closed set of known variants whose
prefixed state strings are compile-time constants.  Add state_str()
methods that return those constants directly:

  DhcpMessageType::state_str() -> Cow<'static, str>
    Known variants: Cow::Borrowed("DHCP_DISCOVER") etc.
    Unknown(v):     Cow::Owned(format!("DHCP_UNKNOWN({})", v))

  SnmpPduType::state_str()    -> &'static str  (9 static variants)
  SsdpMethod::state_str()     -> &'static str  (3 static variants)
  NetBiosService::state_str() -> &'static str  (2 static variants)
  StunMessageClass::state_str() -> &'static str (4 static variants)

Connection::state() now calls these methods and wraps in
Cow::Borrowed where possible, eliminating the format! call entirely
for all known variants.

Five new tests verify that known variants produce the correct
prefixed strings and, for DhcpMessageType, that they are Borrowed;
Unknown(42) produces Owned("DHCP_UNKNOWN(42)").
@obchain obchain force-pushed the perf/udp-dpi-state-static-str branch from f5166ad to fd26c28 Compare June 29, 2026 07:45
@obchain

obchain commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

I profiled this under live traffic (samply, 60s). Connection::state() and the UDP DPI branches don't register as a hot path — negligible CPU — so this doesn't meet the perf bar in CONTRIBUTING.md. Closing with thanks. The profiling did surface a genuine snapshot-path cost, which I've written up in #437.

@obchain obchain closed this Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(core): eliminate per-call heap allocs in Connection::state() for UDP DPI protocols

2 participants