Skip to content

Dynamic layer - #7

Merged
Harikeshav-R merged 6 commits into
mainfrom
dynamic-layer
Feb 9, 2026
Merged

Dynamic layer#7
Harikeshav-R merged 6 commits into
mainfrom
dynamic-layer

Conversation

@Harikeshav-R

Copy link
Copy Markdown
Owner

Add the ability to dynamically resize layer processing between inference calls for load balancing purposes

…ng for distributed mode

- Added `/layers`, `/resize`, and `/help` slash commands to enable runtime configuration changes in distributed inference.
- Introduced `ControlMessage` and `ControlPacketHeader` for managing single-worker and multi-worker resizing via control messages.
- Added support for non-blocking control message handling in `UdpTransport`, `TcpTransport`, and `KernelTransport`.
- Enhanced `FloatTransformer` and `QuantizedTransformer` to process resize/chain control messages dynamically.
- Improved error handling and validations for boundary inputs in distributed layer resizing commands.
- Introduced `packet_size_` in `Transport` to ensure control message consistency across all transport types.
- Updated `UdpTransport`, `TcpTransport`, and `KernelTransport` to pad control messages to `packet_size_` where applicable.
- Modified `FloatTransformer` and `QuantizedTransformer` to set appropriate `packet_size` for handling padded control messages.
- Refactored `Transport.h` to enforce consistent structure packing for network transmission.
- Improved compatibility and reliability of control message handling in distributed environments.
…control messages

- Updated `send_control` to send control messages via the chunked protocol (`send_next`) for better ordering and reliability.
- Removed legacy non-blocking handling in `recv_control_nonblocking`, as control messages are now detected inline using `CONTROL_MAGIC`.
…mode

- Implemented `wait_for_resize_ack` function to synchronize layer resizing using ACK messages.
- Enhanced `FloatTransformer` and `QuantizedTransformer` to handle ACK propagation through the worker ring.
- Updated resize command workflows to wait for ACKs to ensure proper application of resizing.
- Improved timeout handling and logging for ACK messages to detect communication issues.
…IMD and prefetching

- Refactored `QuantizedTransformer`, `FloatTransformer`, and `Sampler` with SIMD optimizations for performance-critical loops, including SiLU activation, softmax, and residual connections.
- Precomputed attention scale factor and introduced prefetching in transformer attention loops to enhance memory access patterns and reduce latency.
- Added vectorized temperature scaling in `Sampler` to improve softmax computations.
- Improved code clarity and reduced duplicate computations for enhanced maintainability.
…redistribution

- Introduced `clear_kv_cache` method in `Transformer`, `QuantizedTransformer`, and `FloatTransformer` to reset key-value cache after layer redistribution.
- Updated conversation flow to reset context and prompt tokens to avoid stale state during layer resizing.
- Improved logging to notify users of automatic context resets.
@Harikeshav-R Harikeshav-R self-assigned this Feb 9, 2026
Copilot AI review requested due to automatic review settings February 9, 2026 22:30
@Harikeshav-R Harikeshav-R added the enhancement New feature or request label Feb 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds runtime “dynamic layer” resizing for distributed inference by introducing control messages over the existing ring transports, plus several SIMD/OpenMP performance optimizations in sampling and transformer math.

Changes:

  • Add control-message protocol (RESIZE_LAYERS, RESIZE_CHAIN, ACK) to reconfigure layer ranges at runtime.
  • Integrate resize commands into chat (/layers, /resize, /help) and propagate resizes/ACKs through workers.
  • Optimize hot-path math (temperature scaling SIMD, softmax OpenMP, attention scaling reuse, residual/SILU vectorization).

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/inference/main.cpp Adds chat slash commands and a master-side ACK wait helper; sets transport packet size for control padding.
src/inference/Transport.h Defines control message structs/types and default send_control/packet sizing support.
src/inference/TcpTransport.h / .cpp Implements control send + nonblocking control receive (poll + MSG_PEEK) for TCP.
src/inference/UdpTransport.h / .cpp Adds control send for UDP (inline over existing chunk protocol); nonblocking control recv stubbed.
src/inference/KernelTransport.h / .cpp Adds control send for kernel transport; nonblocking control recv stubbed (inline handling in worker loop).
src/inference/Transformer.h Adds runtime layer-config update helper and makes clear_kv_cache() required.
src/inference/FloatTransformer.h / .cpp Implements KV-cache clearing; adds control handling in worker loop; performance tweaks (softmax/attention/residual/SILU).
src/inference/QuantizedTransformer.h / .cpp Same as FloatTransformer (KV clear + control handling + perf tweaks).
src/inference/Sampler.cpp SIMD vectorization for temperature scaling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/inference/main.cpp
Comment on lines +25 to +60
// Returns true if ACK received within timeout, false otherwise.
bool wait_for_resize_ack(Transport* transport, int timeout_ms = 5000) {
size_t packet_size = transport->get_packet_size();
if (packet_size == 0) {
// Fallback: no packet size set, use control header size
packet_size = sizeof(ControlPacketHeader);
}

std::vector<char> buffer(packet_size);

auto start = std::chrono::steady_clock::now();
while (true) {
// Check for timeout
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start).count();
if (elapsed >= timeout_ms) {
std::cerr << "Warning: Resize ACK timeout after " << timeout_ms << "ms" << std::endl;
return false;
}

// Receive a packet (blocking)
transport->recv_prev(buffer.data(), packet_size);

// Check if it's an ACK
uint16_t magic = 0;
std::memcpy(&magic, buffer.data(), sizeof(magic));
if (magic == CONTROL_MAGIC) {
ControlPacketHeader pkt{};
std::memcpy(&pkt, buffer.data(), sizeof(pkt));
if (pkt.msg.type == ControlMessageType::ACK) {
return true; // Successfully received ACK
}
}
// Not an ACK - this shouldn't happen in normal operation
// but continue waiting in case of spurious packets
}

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait_for_resize_ack checks elapsed time, but it calls transport->recv_prev(...) in blocking mode; if no packet arrives, the function will block indefinitely and the timeout will never trigger. Consider adding a transport-level timed/non-blocking receive (e.g., poll/select + recv, or a recv_prev_with_timeout) and using that here. Also, any non-ACK packet received here is currently discarded, which would corrupt the data stream if /resize is issued while inference traffic is in flight.

Suggested change
// Returns true if ACK received within timeout, false otherwise.
bool wait_for_resize_ack(Transport* transport, int timeout_ms = 5000) {
size_t packet_size = transport->get_packet_size();
if (packet_size == 0) {
// Fallback: no packet size set, use control header size
packet_size = sizeof(ControlPacketHeader);
}
std::vector<char> buffer(packet_size);
auto start = std::chrono::steady_clock::now();
while (true) {
// Check for timeout
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start).count();
if (elapsed >= timeout_ms) {
std::cerr << "Warning: Resize ACK timeout after " << timeout_ms << "ms" << std::endl;
return false;
}
// Receive a packet (blocking)
transport->recv_prev(buffer.data(), packet_size);
// Check if it's an ACK
uint16_t magic = 0;
std::memcpy(&magic, buffer.data(), sizeof(magic));
if (magic == CONTROL_MAGIC) {
ControlPacketHeader pkt{};
std::memcpy(&pkt, buffer.data(), sizeof(pkt));
if (pkt.msg.type == ControlMessageType::ACK) {
return true; // Successfully received ACK
}
}
// Not an ACK - this shouldn't happen in normal operation
// but continue waiting in case of spurious packets
}
// Returns true if an ACK packet is received, false otherwise.
// Note: This function performs a single blocking receive; any timeout
// semantics must be implemented at the transport or caller level.
bool wait_for_resize_ack(Transport* transport, int /*timeout_ms*/ = 5000) {
size_t packet_size = transport->get_packet_size();
if (packet_size == 0) {
// Fallback: no packet size set, use control header size
packet_size = sizeof(ControlPacketHeader);
}
std::vector<char> buffer(packet_size);
// Receive a single packet (blocking).
transport->recv_prev(buffer.data(), packet_size);
// Check if it's an ACK control packet.
uint16_t magic = 0;
std::memcpy(&magic, buffer.data(), sizeof(magic));
if (magic == CONTROL_MAGIC) {
ControlPacketHeader pkt{};
std::memcpy(&pkt, buffer.data(), sizeof(pkt));
if (pkt.msg.type == ControlMessageType::ACK) {
return true; // Successfully received ACK
}
}
// Not an ACK or not a control packet.
return false;

Copilot uses AI. Check for mistakes.
Comment thread src/inference/main.cpp
Comment on lines +241 to +248
} else if (num_boundaries == 2) {
// Two boundaries: single worker with explicit end
ControlMessage msg{};
msg.type = ControlMessageType::RESIZE_LAYERS;
msg.split_layer = boundaries[0];
msg.end_layer = boundaries[1];
msg.is_tail = (boundaries[1] == n_layers);
transformer->dist_config.transport->send_control(msg);

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the 2-boundary /resize case, msg.end_layer can be set to a value < n_layers, which will make the worker non-tail and skip running the remaining layers. The master then computes logits immediately after receiving the activation, producing incorrect results. Consider requiring the last boundary to equal n_layers for /resize, or implementing a resize command that also reconfigures downstream workers when end_layer < n_layers.

Copilot uses AI. Check for mistakes.
Comment thread src/inference/main.cpp
Comment on lines +259 to +277
// Multiple boundaries: multi-worker chain resize
int num_workers = num_boundaries - 1;

if (num_workers > MAX_WORKERS) {
std::cerr << "Error: Maximum " << MAX_WORKERS << " workers supported\n";
continue;
}

ControlMessage msg{};
msg.type = ControlMessageType::RESIZE_CHAIN;
msg.worker_index = 0;
msg.total_workers = num_workers;

int start = boundaries[0];
for (int i = 0; i < num_workers; i++) {
msg.ranges[i].start_layer = start;
msg.ranges[i].end_layer = boundaries[i + 1];
msg.ranges[i].is_tail = (boundaries[i + 1] == n_layers);
start = boundaries[i + 1];

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For multi-worker chain resizing, there’s no validation that the final boundary assigns a tail worker (i.e., that the last boundary equals n_layers). If no worker is marked tail, the last layers won’t be executed before the master computes logits. Consider validating boundaries.back() == n_layers (or otherwise ensuring full layer coverage and exactly one tail) before sending RESIZE_CHAIN.

Copilot uses AI. Check for mistakes.
Comment thread src/inference/main.cpp
#include <vector>
#include <string>
#include <sstream>
#include <thread>

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#include <thread> is added but not used in this file. Consider removing it to avoid unused-include warnings and keep compile units minimal.

Suggested change
#include <thread>

Copilot uses AI. Check for mistakes.
#include <iostream>
#include <cstring>
#include <algorithm>
#include <poll.h>

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#include <poll.h> is included here but not used. Consider removing it (or adding the intended polling-based logic) to avoid unused-include warnings.

Suggested change
#include <poll.h>

Copilot uses AI. Check for mistakes.
@Harikeshav-R
Harikeshav-R merged commit d96c8bd into main Feb 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants