0. 前言
uccl 的官方 pr 内,看了一下 closed 的 关于 nixl 的 pr 有 37 个。
- backend API 设计:#186, #212, #755
- NIXL 语义补齐:#357, #428, #750, #779
- vLLM 连接器适配:#409
- 多网络传输实现:#385, #521, #560, #571, #577, #597, #638, #677, #730, #593
- 其他乱七八糟平台、cicd、安装全都是 pr。。。。。。。。 核心改动就是在uccl_engine.cc,uccl_engine.h这俩文件内。
1. nixl UCCL backend api
nixlBackendEngine 内的 virtual 虚函基本上都有对应的 uccl 实现。具体 uccl 自己实现了下面的:
// src/plugins/uccl/uccl_backend.h
class nixlUcclEngine : public nixlBackendEngine {
public:
bool supportsRemote() const { return true; }
bool supportsLocal() const { return false; }
bool supportsNotif() const { return true; }
nixl_mem_list_t getSupportedMems() const;
nixl_status_t getPublicData(const nixlBackendMD *meta, std::string &str) const;
nixl_status_t getConnInfo(std::string &str) const;
nixl_status_t loadRemoteConnInfo(const std::string &remote_agent, const std::string &remote_conn_info);
nixl_status_t connect(const std::string &remote_agent) override;
nixl_status_t disconnect(const std::string &remote_agent);
nixl_status_t registerMem(const nixlBlobDesc &mem, const nixl_mem_t &nixl_mem, nixlBackendMD *&out);
nixl_status_t deregisterMem(nixlBackendMD *meta);
nixl_status_t loadLocalMD(...);
nixl_status_t loadRemoteMD(...);
nixl_status_t prepXfer(...);
nixl_status_t postXfer(...);
nixl_status_t checkXfer(...);
nixl_status_t releaseReqH(...);
nixl_status_t getNotifs(notif_list_t ¬if_list);
nixl_status_t genNotif(const std::string &remote_agent, const std::string &msg) const override;
private:
startListener();
...
}2. uccl 侧 northbound
| uccl 侧 northbound | |
|---|---|
| supportsRemote() | 底层支持:uccl_engine_get_metadata()、uccl_engine_connect()、uccl_engine_accept()、uccl_engine_prepare_fifo()、uccl_engine_read_vector()、uccl_engine_write_vector() |
| supportsNotif() | 底层支持:uccl_engine_start_listener()、uccl_engine_get_notifs()、uccl_engine_send_notif() |
| supportsLocal() | fasle |
| supportsProgTh() | \ |
| getSupportedMems() | uccl_engine_reg() |
| nixlUcclEngine() 自己本身的构造函数 | uccl_engine_create(),(ps:这里 mooncake 也有自己的createTransferEngine()实现), 启一个后台线程 startListener(),持续做 accept。 |
| ~nixlUcclEngine() | 调uccl_engine_stop_accept() 让阻塞中的 accept 退出,destroy 所有 MR,所有 conn 以及 engine。 |
| startListener() | 循环调用uccl_engine_accept() 接受远端连接,对每个新连接调用 uccl_engine_start_listener(),让通知收发通道工作起来。 然后把连接放进 connected_agents_ |
| getConnInfo() | 对应**uccl_engine_get_metadata()**,把 endpoint 的 unified metadata 变成字符串形式,最终生成类似 ip:port?gpu 的连接串 |
| loadRemoteConnInfo() | 拿到 NIXL 传下来的 ip/port/gpu_dix 后用**uccl_engine_connect()*建链,建完调用ccl_engine_start_listener(),然后把 remote_agent → uccl_conn_t 记到 connected_agents_。 |
| connect() | \ |
| disconnect() | uccl_engine_conn_destroy() |
| registerMem() | uccl_engine_reg()/uccl_engine_prepare_fifo()/uccl_engine_mr_destroy() |
| deregisterMem() | uccl_engine_mr_destroy() |
| getPublicData | \ |
| loadLocalMD | \ |
| loadRemoteMD | \ |
| unloadMD | \ |
| prepXfer() | 从前面的connected_agents_ 拿到对应的 uccl_conn_t* ,然后创建 nixlUcclReqH,然后需要我们自己实现一个deserialize 去还原fifo 的格式(char→struct),然后uccl_engine_update_fifo去patch前面 enqueue 的fifo |
| postXfer() 单边 | 走uccl_engine_read_vector()或者uccl_engine_write_vector()读写数据,返回当前的 transfer_id 写到nixlUcclReqH。 |
| checkXfer() 双边 | 从nixlUcclReqH 拿出当前要等的 transfer id, 调用uccl_engine_xfer_status 去轮询,如果需要 notif 的话就要多一个 uccl_engine_send_notify |
| releaseReqH() | \ |
| getNotifs() | uccl_engine_get_notifs(),把 uccl 的完成翻译 给nixl |
| genNotif() | 独立的函数,调用 uccl_engine_send_notif |
3. UCCL 与 Flagcx 不同之处
uccl 现在的 post 内 NIXL_READ/NIXL_WRITE都是调用的自己uccl_engine_read_vector()和uccl_engine_write_vector()的单边数据传输。然后uccl notfy的控制面用的 tcp/oob/socket 都是双边控制。
flagcx 内如果走双边数据面,那我们就得双边控制面。