mirror of
https://github.com/esphome/esphome.git
synced 2026-09-15 17:18:40 +00:00
[api] Add out-of-line write_raw_ wrappers calling write_raw_inline_
Hot paths use write_raw_inline_ (ALWAYS_INLINE fast path). Cold paths (handshake, error handling) use write_raw_ which is an out-of-line wrapper that calls write_raw_inline_ — same logic, no code duplication, but the compiler won't expand the fast path at each cold call site.
This commit is contained in:
@@ -112,6 +112,14 @@ APIError APIFrameHelper::drain_overflow_and_handle_errors_() {
|
||||
return APIError::OK;
|
||||
}
|
||||
|
||||
// Out-of-line wrappers — same logic as write_raw_inline_ but not force-inlined.
|
||||
// Used by cold callers (handshake, error handling) to avoid code bloat.
|
||||
APIError APIFrameHelper::write_raw_(const void *data, uint16_t len) { return this->write_raw_inline_(data, len); }
|
||||
|
||||
APIError APIFrameHelper::write_raw_(const struct iovec *iov, int iovcnt, uint16_t total_write_len) {
|
||||
return this->write_raw_inline_(iov, iovcnt, total_write_len);
|
||||
}
|
||||
|
||||
// Single-buffer slow path: wraps data in iovec and delegates to the iovec slow path.
|
||||
APIError APIFrameHelper::write_raw_slow_(const void *data, uint16_t len, ssize_t sent) {
|
||||
struct iovec iov = {const_cast<void *>(data), len};
|
||||
|
||||
@@ -190,9 +190,14 @@ class APIFrameHelper {
|
||||
// Returns OK for transient errors (WOULD_BLOCK), SOCKET_WRITE_FAILED for hard errors.
|
||||
APIError drain_overflow_and_handle_errors_();
|
||||
|
||||
// Write a single contiguous buffer to the socket (inlined fast path)
|
||||
inline APIError ESPHOME_ALWAYS_INLINE write_raw_(const void *data, uint16_t len) {
|
||||
// Fast path: no overflow backlog and full write succeeds
|
||||
// Out-of-line write methods — used by cold paths (handshake, error handling)
|
||||
APIError write_raw_(const void *data, uint16_t len);
|
||||
APIError write_raw_(const struct iovec *iov, int iovcnt, uint16_t total_write_len);
|
||||
|
||||
// Inlined write methods — used by hot paths (write_protobuf_packet, write_protobuf_messages)
|
||||
// These inline the fast path (overflow empty + full write) and tail-call the out-of-line
|
||||
// slow path only on failure/partial write.
|
||||
inline APIError ESPHOME_ALWAYS_INLINE write_raw_inline_(const void *data, uint16_t len) {
|
||||
ssize_t sent = -1;
|
||||
if (this->overflow_buf_.empty()) [[likely]] {
|
||||
sent = this->socket_->write(data, len);
|
||||
@@ -201,9 +206,8 @@ class APIFrameHelper {
|
||||
}
|
||||
return this->write_raw_slow_(data, len, sent);
|
||||
}
|
||||
// Write multiple iovec buffers to the socket (inlined fast path)
|
||||
inline APIError ESPHOME_ALWAYS_INLINE write_raw_(const struct iovec *iov, int iovcnt, uint16_t total_write_len) {
|
||||
// Fast path: no overflow backlog and full writev succeeds
|
||||
inline APIError ESPHOME_ALWAYS_INLINE write_raw_inline_(const struct iovec *iov, int iovcnt,
|
||||
uint16_t total_write_len) {
|
||||
ssize_t sent = -1;
|
||||
if (this->overflow_buf_.empty()) [[likely]] {
|
||||
sent = this->socket_->writev(iov, iovcnt);
|
||||
@@ -212,7 +216,9 @@ class APIFrameHelper {
|
||||
}
|
||||
return this->write_raw_slow_(iov, iovcnt, total_write_len, sent);
|
||||
}
|
||||
// Slow paths (out-of-line): handle partial writes, errors, overflow buffering
|
||||
|
||||
private:
|
||||
// Slow path: handle partial writes, errors, overflow buffering
|
||||
APIError write_raw_slow_(const void *data, uint16_t len, ssize_t sent);
|
||||
APIError write_raw_slow_(const struct iovec *iov, int iovcnt, uint16_t total_write_len, ssize_t sent);
|
||||
|
||||
|
||||
@@ -504,7 +504,7 @@ APIError APINoiseFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuff
|
||||
aerr = this->encrypt_noise_message_(buf_start, msg, iov);
|
||||
if (aerr != APIError::OK)
|
||||
return aerr;
|
||||
return this->write_raw_(iov.iov_base, static_cast<uint16_t>(iov.iov_len));
|
||||
return this->write_raw_inline_(iov.iov_base, static_cast<uint16_t>(iov.iov_len));
|
||||
}
|
||||
|
||||
APIError APINoiseFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffer, std::span<const MessageInfo> messages) {
|
||||
@@ -530,7 +530,7 @@ APIError APINoiseFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffer, s
|
||||
total_write_len += iov.iov_len;
|
||||
}
|
||||
|
||||
return this->write_raw_(iovs.data(), iovs.size(), total_write_len);
|
||||
return this->write_raw_inline_(iovs.data(), iovs.size(), total_write_len);
|
||||
}
|
||||
|
||||
APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) {
|
||||
@@ -540,16 +540,15 @@ APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) {
|
||||
header[2] = (uint8_t) len;
|
||||
|
||||
if (len == 0) {
|
||||
return this->write_raw_slow_(header, 3, -1);
|
||||
return this->write_raw_(header, 3);
|
||||
}
|
||||
// Handshake path — use iovec slow path directly to avoid inlining write_raw_ fast path
|
||||
struct iovec iov[2];
|
||||
iov[0].iov_base = header;
|
||||
iov[0].iov_len = 3;
|
||||
iov[1].iov_base = const_cast<uint8_t *>(data);
|
||||
iov[1].iov_len = len;
|
||||
|
||||
return this->write_raw_slow_(iov, 2, 3 + len, -1);
|
||||
return this->write_raw_(iov, 2, 3 + len);
|
||||
}
|
||||
|
||||
/** Initiate the data structures for the handshake.
|
||||
|
||||
@@ -219,11 +219,11 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) {
|
||||
"Bad indicator byte";
|
||||
char msg[INDICATOR_MSG_SIZE];
|
||||
memcpy_P(msg, MSG_PROGMEM, INDICATOR_MSG_SIZE);
|
||||
this->write_raw_slow_(msg, INDICATOR_MSG_SIZE, -1);
|
||||
this->write_raw_(msg, INDICATOR_MSG_SIZE);
|
||||
#else
|
||||
static const char MSG[] = "\x00"
|
||||
"Bad indicator byte";
|
||||
this->write_raw_slow_(MSG, INDICATOR_MSG_SIZE, -1);
|
||||
this->write_raw_(MSG, INDICATOR_MSG_SIZE);
|
||||
#endif
|
||||
}
|
||||
return aerr;
|
||||
@@ -292,7 +292,7 @@ APIError APIPlaintextFrameHelper::write_protobuf_packet(uint8_t type, ProtoWrite
|
||||
uint8_t *msg_start = write_plaintext_header(buffer_data, msg, frame_header_padding_);
|
||||
uint8_t msg_header_len = static_cast<uint8_t>(buffer_data + frame_header_padding_ - msg_start);
|
||||
uint16_t msg_len = static_cast<uint16_t>(msg_header_len + msg.payload_size);
|
||||
return this->write_raw_(msg_start, msg_len);
|
||||
return this->write_raw_inline_(msg_start, msg_len);
|
||||
}
|
||||
|
||||
APIError APIPlaintextFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffer,
|
||||
@@ -318,7 +318,7 @@ APIError APIPlaintextFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffe
|
||||
total_write_len += msg_len;
|
||||
}
|
||||
|
||||
return this->write_raw_(iovs.data(), iovs.size(), total_write_len);
|
||||
return this->write_raw_inline_(iovs.data(), iovs.size(), total_write_len);
|
||||
}
|
||||
|
||||
} // namespace esphome::api
|
||||
|
||||
Reference in New Issue
Block a user