use crate::{
codec::{Dict, StrOrList, Wire},
error::{Error, Result},
msgpack::{Decoder, Encoder},
value::Value,
};
macro_rules! control_struct {
($(
$(#[$meta:meta])*
$name:ident {
$( $(#[$fmeta:meta])* $field:ident: $fty:ty $(= $fdefault:expr)? ),* $(,)?
}
)*) => {$(
wire_struct! {
$(#[$meta])*
#[derive(Debug, Clone, PartialEq)]
pub struct $name: array(stringify!($name)) {
pub rid: Option<StrOrList> = None,
pub http_worker_ipc: Option<String> = None,
$( $(#[$fmeta])* pub $field: $fty $(= $fdefault)? ),*
}
}
)*};
}
control_struct! {
FlushCacheReqInput {}
FlushCacheReqOutput {
success: bool,
}
PauseSchedulerReqInput {
mode: String = "abort".to_owned(),
}
PauseSchedulerReqOutput {
success: bool,
message: String = String::new(),
}
ResumeSchedulerReqInput {}
ResumeSchedulerReqOutput {
success: bool,
message: String = String::new(),
}
IsSchedulerPausedReqInput {}
IsSchedulerPausedReqOutput {
is_paused: bool,
}
UpdateWeightFromDiskReqInput {
model_path: String,
load_format: Option<String> = None,
weight_version: Option<String> = None,
flush_cache: bool = true,
}
UpdateWeightFromDiskReqOutput {
success: bool,
message: String,
num_paused_requests: Option<i64> = Some(0),
}
UpdateWeightsFromDistributedReqInput {
names: Vec<String>,
dtype_names: Vec<String>,
shapes: Vec<Vec<i64>>,
group_name: String = "weight_update_group".to_owned(),
flush_cache: bool = true,
weight_version: Option<String>,
}
UpdateWeightsFromDistributedReqOutput {
success: bool,
message: String,
}
UpdateWeightsFromTensorReqInput {
serialized_named_tensors: Vec<Value>,
load_format: Option<String>,
flush_cache: bool,
weight_version: Option<String> = None,
}
UpdateWeightsFromTensorReqOutput {
success: bool,
message: String,
}
InitWeightsUpdateGroupReqInput {
master_address: String,
master_port: i64,
rank_offset: i64,
world_size: i64,
group_name: String = "weight_update_group".to_owned(),
backend: String = "nccl".to_owned(),
}
InitWeightsUpdateGroupReqOutput {
success: bool,
message: String,
}
DestroyWeightsUpdateGroupReqInput {
group_name: String = "weight_update_group".to_owned(),
}
DestroyWeightsUpdateGroupReqOutput {
success: bool,
message: String,
}
UpdateWeightsFromMooncakeReqInput {
version: i64,
flush_cache: bool,
weight_version: Option<String>,
}
UpdateWeightsFromMooncakeReqOutput {
success: bool,
message: String,
}
RebalanceExpertsReqInput {}
RebalanceExpertsReqOutput {
success: bool,
message: String,
}
ReleaseMemoryOccupationReqInput {
tags: Option<Vec<String>> = None,
}
ReleaseMemoryOccupationReqOutput {
success: bool = true,
message: String = String::new(),
}
ResumeMemoryOccupationReqInput {
tags: Option<Vec<String>> = None,
}
ResumeMemoryOccupationReqOutput {
success: bool = true,
message: String = String::new(),
}
IsSleepingReqInput {}
IsSleepingReqOutput {
is_sleeping: bool,
}
GetInternalStateReq {}
GetInternalStateReqOutput {
internal_state: Dict<Value, Value>,
}
SetInternalStateReq {
server_args: Dict<Value, Value>,
}
SetInternalStateReqOutput {
updated: bool,
server_args: Dict<Value, Value>,
}
ProfileReq {
kind: i64,
output_dir: Option<String> = None,
start_step: Option<i64> = None,
num_steps: Option<i64> = None,
activities: Option<Vec<String>> = None,
profile_by_stage: bool = false,
with_stack: Option<bool> = None,
record_shapes: Option<bool> = None,
profile_id: Option<String> = None,
}
ProfileReqOutput {
success: bool,
message: String,
}
}
pub const PROFILE_START: i64 = 1;
pub const PROFILE_STOP: i64 = 2;
macro_rules! tagged_union {
(
$(#[$meta:meta])*
$vis:vis enum $name:ident { $( $(#[$vmeta:meta])* $variant:ident($ty:ident) ),* $(,)? }
) => {
$(#[$meta])*
$vis enum $name {
$( $(#[$vmeta])* $variant($ty) ),*
}
impl $name {
pub fn tag(&self) -> &'static str {
match self {
$( Self::$variant(_) => stringify!($ty) ),*
}
}
pub fn knows(tag: &str) -> bool {
matches!(tag, $( stringify!($ty) )|*)
}
}
impl Wire for $name {
fn encode(&self, encoder: &mut Encoder) {
match self {
$( Self::$variant(value) => value.encode(encoder) ),*
}
}
fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
match decoder.peek_tag()? {
$( stringify!($ty) => Ok(Self::$variant($ty::decode(decoder)?)), )*
other => Err(Error::Invalid(format!(
concat!("unknown ", stringify!($name), " {}"),
other
))),
}
}
}
};
}
tagged_union! {
#[derive(Debug, Clone, PartialEq)]
pub enum ControlRequest {
FlushCache(FlushCacheReqInput),
PauseScheduler(PauseSchedulerReqInput),
ResumeScheduler(ResumeSchedulerReqInput),
IsSchedulerPaused(IsSchedulerPausedReqInput),
UpdateWeightFromDisk(UpdateWeightFromDiskReqInput),
UpdateWeightsFromDistributed(UpdateWeightsFromDistributedReqInput),
UpdateWeightsFromTensor(UpdateWeightsFromTensorReqInput),
InitWeightsUpdateGroup(InitWeightsUpdateGroupReqInput),
DestroyWeightsUpdateGroup(DestroyWeightsUpdateGroupReqInput),
UpdateWeightsFromMooncake(UpdateWeightsFromMooncakeReqInput),
RebalanceExperts(RebalanceExpertsReqInput),
ReleaseMemoryOccupation(ReleaseMemoryOccupationReqInput),
ResumeMemoryOccupation(ResumeMemoryOccupationReqInput),
IsSleeping(IsSleepingReqInput),
GetInternalState(GetInternalStateReq),
SetInternalState(SetInternalStateReq),
Profile(ProfileReq),
}
}
tagged_union! {
#[derive(Debug, Clone, PartialEq)]
pub enum ControlOutput {
FlushCache(FlushCacheReqOutput),
PauseScheduler(PauseSchedulerReqOutput),
ResumeScheduler(ResumeSchedulerReqOutput),
IsSchedulerPaused(IsSchedulerPausedReqOutput),
UpdateWeightFromDisk(UpdateWeightFromDiskReqOutput),
UpdateWeightsFromDistributed(UpdateWeightsFromDistributedReqOutput),
UpdateWeightsFromTensor(UpdateWeightsFromTensorReqOutput),
InitWeightsUpdateGroup(InitWeightsUpdateGroupReqOutput),
DestroyWeightsUpdateGroup(DestroyWeightsUpdateGroupReqOutput),
UpdateWeightsFromMooncake(UpdateWeightsFromMooncakeReqOutput),
RebalanceExperts(RebalanceExpertsReqOutput),
ReleaseMemoryOccupation(ReleaseMemoryOccupationReqOutput),
ResumeMemoryOccupation(ResumeMemoryOccupationReqOutput),
IsSleeping(IsSleepingReqOutput),
GetInternalState(GetInternalStateReqOutput),
SetInternalState(SetInternalStateReqOutput),
Profile(ProfileReqOutput),
}
}
impl ControlRequest {
pub fn reply_tag(&self) -> &'static str {
match self {
Self::FlushCache(_) => "FlushCacheReqOutput",
Self::PauseScheduler(_) => "PauseSchedulerReqOutput",
Self::ResumeScheduler(_) => "ResumeSchedulerReqOutput",
Self::IsSchedulerPaused(_) => "IsSchedulerPausedReqOutput",
Self::UpdateWeightFromDisk(_) => "UpdateWeightFromDiskReqOutput",
Self::UpdateWeightsFromDistributed(_) => "UpdateWeightsFromDistributedReqOutput",
Self::UpdateWeightsFromTensor(_) => "UpdateWeightsFromTensorReqOutput",
Self::InitWeightsUpdateGroup(_) => "InitWeightsUpdateGroupReqOutput",
Self::DestroyWeightsUpdateGroup(_) => "DestroyWeightsUpdateGroupReqOutput",
Self::UpdateWeightsFromMooncake(_) => "UpdateWeightsFromMooncakeReqOutput",
Self::RebalanceExperts(_) => "RebalanceExpertsReqOutput",
Self::ReleaseMemoryOccupation(_) => "ReleaseMemoryOccupationReqOutput",
Self::ResumeMemoryOccupation(_) => "ResumeMemoryOccupationReqOutput",
Self::IsSleeping(_) => "IsSleepingReqOutput",
Self::GetInternalState(_) => "GetInternalStateReqOutput",
Self::SetInternalState(_) => "SetInternalStateReqOutput",
Self::Profile(_) => "ProfileReqOutput",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codec::{decode_frames, encode_frames};
#[test]
fn a_reply_tag_names_a_reply() {
let requests = [
ControlRequest::FlushCache(FlushCacheReqInput {
rid: None,
http_worker_ipc: None,
}),
ControlRequest::PauseScheduler(PauseSchedulerReqInput {
rid: None,
http_worker_ipc: None,
mode: "wait".to_owned(),
}),
];
for request in requests {
assert!(ControlOutput::knows(request.reply_tag()));
assert!(ControlRequest::knows(request.tag()));
let decoded: ControlRequest = decode_frames(&encode_frames(&request)).unwrap();
assert_eq!(decoded, request);
}
assert!(!ControlOutput::knows("BatchTokenIDOutSlim"));
}
}