Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
d1a7237
docs: design no-IMEX DeepEP transport
cursoragent Jul 23, 2026
6d8ae26
docs: plan no-IMEX DeepEP support
cursoragent Jul 23, 2026
785aadf
fix: pass default CUDA graph pool
cursoragent Jul 23, 2026
7ed212d
test: cover cross-process VMM IPC
cursoragent Jul 23, 2026
c7fd766
fix: support cross-process VMM IPC
cursoragent Jul 23, 2026
ccda6c5
test: cover DeepEP transport configuration
cursoragent Jul 23, 2026
4287591
feat: configure DeepEP transport in TOML
cursoragent Jul 23, 2026
d6165b7
test: cover archived DeepEP transport profiles
cursoragent Jul 23, 2026
d74f290
feat: validate archived DeepEP transport
cursoragent Jul 23, 2026
b0234e5
test: cover DeepEP transport engine hooks
cursoragent Jul 23, 2026
60477ff
test: preserve vLLM first-save profiling
cursoragent Jul 23, 2026
db3555c
feat: apply DeepEP transport in engine hooks
cursoragent Jul 23, 2026
d816458
style: format DeepEP hook changes
cursoragent Jul 23, 2026
efc8728
test: preserve vLLM first-save metadata
cursoragent Jul 23, 2026
69efcd0
fix: preserve vLLM first-save metadata
cursoragent Jul 23, 2026
694f22f
test: cover no-IMEX experimental recipes
cursoragent Jul 23, 2026
2ec7250
test: cover no-IMEX recipe documentation
cursoragent Jul 23, 2026
f743855
docs: add no-IMEX DeepEP recipes
cursoragent Jul 23, 2026
0a5d36b
test: cover modern SGLang attention metadata API
cursoragent Jul 23, 2026
4c30d5e
fix: support modern SGLang attention metadata API
cursoragent Jul 23, 2026
f48ef04
test: cover vLLM NVSHMEM host auto-detection
cursoragent Jul 23, 2026
384017d
fix: detect installed NVSHMEM host library for vLLM
cursoragent Jul 23, 2026
8a4a0bd
test: cover CUDA graph dependency edge metadata
cursoragent Jul 24, 2026
721f783
test: link edge metadata helper to CUDA driver
cursoragent Jul 24, 2026
d81340e
fix: preserve CUDA graph dependency edge metadata
cursoragent Jul 24, 2026
52ca812
test: use canonical graph archive names
cursoragent Jul 24, 2026
d98f9b3
test: compare edge replay output on CPU
cursoragent Jul 24, 2026
aa6a920
test: isolate legacy parallel graph fixture
cursoragent Jul 24, 2026
60ac2a6
style: format edge metadata CUDA helper
cursoragent Jul 24, 2026
fc173a3
test: cover mixed CUDA graph edge metadata
cursoragent Jul 24, 2026
f7f27a4
fix: batch CUDA dependencies by edge metadata
cursoragent Jul 24, 2026
622e49b
style: format dependency batching helper
cursoragent Jul 24, 2026
550b9d5
test: cover SGLang LOAD logits shard pre-copy
cursoragent Jul 24, 2026
7c8323a
fix: pre-copy SGLang LOAD local logits shard
cursoragent Jul 24, 2026
5cf1906
test: cover SGLang regular TP logits shard pre-copy
cursoragent Jul 24, 2026
c39b595
test: complete regular TP pre-copy coverage
cursoragent Jul 24, 2026
b2d4079
fix: pre-copy SGLang regular TP local shard
cursoragent Jul 24, 2026
3e32b73
test: complete fake SGLang gather modules
cursoragent Jul 24, 2026
67e2db3
test: cover optional SGLang gather APIs
cursoragent Jul 24, 2026
b4e6345
fix: tolerate optional SGLang gather APIs
cursoragent Jul 24, 2026
3973756
test: cover final no-IMEX review regressions
cursoragent Jul 24, 2026
7517509
fix: delegate unsupported SGLang regular-TP gather layouts
cursoragent Jul 24, 2026
6cde904
fix: validate VMM IPC chunk-import range before interior pointer
cursoragent Jul 24, 2026
750368e
chore: harden experimental recipes and pin deterministic defaults
cursoragent Jul 24, 2026
743d2f3
docs: document binary dependency record widths and compatibility
cursoragent Jul 24, 2026
3bc1d1f
test: scope VMM IPC regression to invalid-range rejection
cursoragent Jul 24, 2026
af38a6a
test: cover cached-chunk, stale-generation, and deepep-mode rereview …
cursoragent Jul 24, 2026
9f619c1
fix: validate cached VMM IPC chunk carve against actual mapping
cursoragent Jul 24, 2026
7dd065b
fix: verify chunk generation against live export before fd transfer
cursoragent Jul 24, 2026
1b59dbe
test: run cross-process VMM IPC regressions across two GPUs
cursoragent Jul 24, 2026
632df90
feat: accept documented DEEPEP_MODE override in SGLang recipe
cursoragent Jul 24, 2026
dea454b
test: assert SGLang hook doc lists _patch_attn_tp_logits_gather
cursoragent Jul 24, 2026
ec2687f
docs: document _patch_attn_tp_logits_gather in SGLang hook surface
cursoragent Jul 24, 2026
287eb14
test: assert DeepEP dispatch routing instead of printing
cursoragent Jul 24, 2026
bb32d60
test: encode DeepEP dispatch payloads exactly in bfloat16
cursoragent Jul 24, 2026
184bc76
test: race two importer threads on a peer chunk's first open
cursoragent Jul 24, 2026
8acb26d
test: exercise the VMM IPC insertion-race loser path under contention
cursoragent Jul 24, 2026
0093e38
fix: factor VMM IPC chunk-request validator for both cache paths
cursoragent Jul 24, 2026
02af2b2
test: assert exact DeepEP dispatch delivery per expert
cursoragent Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 72 additions & 6 deletions csrc/BinaryGraphIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,46 @@

namespace foundry {

namespace {

bool validate_binary_layout(const uint8_t* data, size_t file_size,
const binary_format::FileHeader& header) {
namespace bf = binary_format;

if (header.num_sections != bf::SECTION_COUNT) {
return false;
}

const uint64_t directory_size =
static_cast<uint64_t>(header.num_sections) * sizeof(bf::SectionEntry);
if (directory_size > file_size - sizeof(bf::FileHeader)) {
return false;
}

const auto* sections = reinterpret_cast<const bf::SectionEntry*>(data + sizeof(bf::FileHeader));
for (uint32_t i = 0; i < header.num_sections; ++i) {
const auto& section = sections[i];
if (section.section_type != i || section.offset > file_size ||
section.size > file_size - section.offset) {
return false;
}
}

const uint64_t legacy_dependency_size =
static_cast<uint64_t>(header.num_dependencies) * sizeof(bf::LegacyBinDependency);
const uint64_t dependency_size =
static_cast<uint64_t>(header.num_dependencies) * sizeof(bf::BinDependency);
const uint64_t stored_dependency_size = sections[bf::SECTION_DEPENDENCY_TABLE].size;
const bool has_dependencies = (header.flags & bf::FLAG_HAS_DEPENDENCIES) != 0;
if (has_dependencies != (header.num_dependencies != 0)) {
return false;
}
return stored_dependency_size == legacy_dependency_size ||
stored_dependency_size == dependency_size;
}

} // namespace

void CUDAGraph::save_binary(const std::string& bin_path, const boost::json::object& root) {
namespace json = boost::json;
namespace bf = binary_format;
Expand Down Expand Up @@ -270,7 +310,19 @@ void CUDAGraph::save_binary(const std::string& bin_path, const boost::json::obje
deps.reserve(deps_array.size());
for (const auto& dep_val : deps_array) {
const json::object& d = dep_val.as_object();
deps.push_back({d.at("from").to_number<uint32_t>(), d.at("to").to_number<uint32_t>()});
bf::BinDependency dep = {};
dep.from_id = d.at("from").to_number<uint32_t>();
dep.to_id = d.at("to").to_number<uint32_t>();
if (d.contains("from_port")) {
dep.from_port = static_cast<uint8_t>(d.at("from_port").to_number<unsigned int>());
}
if (d.contains("to_port")) {
dep.to_port = static_cast<uint8_t>(d.at("to_port").to_number<unsigned int>());
}
if (d.contains("type")) {
dep.type = static_cast<uint8_t>(d.at("type").to_number<unsigned int>());
}
deps.push_back(dep);
}

// ---- Generators ----
Expand Down Expand Up @@ -397,7 +449,7 @@ boost::json::value read_and_parse_binary_graph(const std::string& bin_path) {
if (file_size < sizeof(bf::FileHeader))
return json::value{};
const bf::FileHeader& header = *reinterpret_cast<const bf::FileHeader*>(data);
if (!bf::validate_header(header))
if (!bf::validate_header(header) || !validate_binary_layout(data, file_size, header))
return json::value{};

// Read section directory
Expand Down Expand Up @@ -653,13 +705,26 @@ boost::json::value read_and_parse_binary_graph(const std::string& bin_path) {
// Dependencies
if (header.flags & bf::FLAG_HAS_DEPENDENCIES) {
auto [dep_data, dep_size] = section(bf::SECTION_DEPENDENCY_TABLE);
const bf::BinDependency* deps = reinterpret_cast<const bf::BinDependency*>(dep_data);
const size_t dependency_entry_size = dep_size / header.num_dependencies;
const bool has_edge_data = dependency_entry_size == sizeof(bf::BinDependency);
json::array deps_array;
deps_array.reserve(header.num_dependencies);
for (uint32_t i = 0; i < header.num_dependencies; i++) {
const uint8_t* record = dep_data + i * dependency_entry_size;
const auto* legacy = reinterpret_cast<const bf::LegacyBinDependency*>(record);
json::object d;
d["from"] = deps[i].from_id;
d["to"] = deps[i].to_id;
d["from"] = legacy->from_id;
d["to"] = legacy->to_id;
if (has_edge_data) {
const auto* dep = reinterpret_cast<const bf::BinDependency*>(record);
d["from_port"] = static_cast<unsigned int>(dep->from_port);
d["to_port"] = static_cast<unsigned int>(dep->to_port);
d["type"] = static_cast<unsigned int>(dep->type);
} else {
d["from_port"] = 0;
d["to_port"] = 0;
d["type"] = 0;
}
deps_array.push_back(d);
}
root["dependencies"] = std::move(deps_array);
Expand Down Expand Up @@ -725,7 +790,8 @@ BinaryGraphFile read_binary_graph_file(const std::string& bin_path) {
in.close();

memcpy(&result.header, result.data.data(), sizeof(bf::FileHeader));
if (!bf::validate_header(result.header)) {
if (!bf::validate_header(result.header) ||
!validate_binary_layout(result.data.data(), file_size, result.header)) {
result.data.clear();
return result;
}
Expand Down
89 changes: 81 additions & 8 deletions csrc/CUDAGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <cstddef>
#include <cstring>
#include <iostream>
#include <map>
#include <tuple>
#include <unordered_map>
#include <cuda.h>
#include <fstream>
Expand Down Expand Up @@ -127,6 +129,47 @@ MempoolId_t torch_graph_pool_handle(bool is_user_created = true) {

} // namespace

CUresult add_graph_dependencies(CUgraph graph, const std::vector<CUgraphNode>& from_nodes,
const std::vector<CUgraphNode>& to_nodes,
const std::vector<CUgraphEdgeData>& edge_data) {
TORCH_INTERNAL_ASSERT(from_nodes.size() == to_nodes.size());
TORCH_INTERNAL_ASSERT(from_nodes.size() == edge_data.size());

struct DependencyBatch {
std::vector<CUgraphNode> from_nodes;
std::vector<CUgraphNode> to_nodes;
std::vector<CUgraphEdgeData> edge_data;
};
using EdgeDataKey = std::tuple<unsigned char, unsigned char, unsigned char>;
std::map<EdgeDataKey, DependencyBatch> batches;

// CUDA 13.0 silently normalizes non-default entries when one call mixes edge annotations.
// Group identical annotations so each driver call remains lossless without adding edges singly.
for (size_t index = 0; index < edge_data.size(); ++index) {
const auto& data = edge_data[index];
auto& batch = batches[{data.from_port, data.to_port, data.type}];
batch.from_nodes.push_back(from_nodes[index]);
batch.to_nodes.push_back(to_nodes[index]);
batch.edge_data.push_back(data);
}

for (auto& [key, batch] : batches) {
(void)key;
#if (defined(CUDA_VERSION) && CUDA_VERSION >= 13000)
CUresult result = cuGraphAddDependencies(graph, batch.from_nodes.data(), batch.to_nodes.data(),
batch.edge_data.data(), batch.edge_data.size());
#else
CUresult result =
cuGraphAddDependencies_v2(graph, batch.from_nodes.data(), batch.to_nodes.data(),
batch.edge_data.data(), batch.edge_data.size());
#endif
if (result != CUDA_SUCCESS) {
return result;
}
}
return CUDA_SUCCESS;
}

static bool _cuda_graphs_debug = false;

static CUDAGeneratorStateRegistry global_generator_state_registry;
Expand Down Expand Up @@ -934,6 +977,7 @@ void CUDAGraph::analyze_captured_graph() {
GraphDependency dep;
dep.from_index = from_it->second;
dep.to_index = to_it->second;
dep.edge_data = edges[i];
graph_dependencies.push_back(dep);
}
}
Expand Down Expand Up @@ -1335,7 +1379,8 @@ void CUDAGraph::save(const std::string& json_path, const OutputTensors& output_t
nodes_array.push_back(node_obj);
}

// Compute topology key = node types + cluster dim values per kernel node.
// Compute topology key = node types + cluster dim values per kernel node +
// dependency endpoints and edge data.
// cuGraphExecUpdate does NOT propagate kernel node attribute changes
// (set via cuGraphKernelNodeSetAttribute) to the CUgraphExec — only
// CUDA_KERNEL_NODE_PARAMS fields are updated. This means cluster dim
Expand Down Expand Up @@ -1381,6 +1426,22 @@ void CUDAGraph::save(const std::string& json_path, const OutputTensors& output_t
}
}
}

std::vector<GraphDependency> sorted_dependencies = graph_dependencies;
std::sort(sorted_dependencies.begin(), sorted_dependencies.end(),
[](const GraphDependency& lhs, const GraphDependency& rhs) {
return std::make_tuple(lhs.from_index, lhs.to_index, lhs.edge_data.from_port,
lhs.edge_data.to_port, lhs.edge_data.type) <
std::make_tuple(rhs.from_index, rhs.to_index, rhs.edge_data.from_port,
rhs.edge_data.to_port, rhs.edge_data.type);
});
topology_key += "|D";
for (const auto& dep : sorted_dependencies) {
topology_key += ";" + std::to_string(dep.from_index) + ">" + std::to_string(dep.to_index) +
":" + std::to_string(static_cast<int>(dep.edge_data.from_port)) + ":" +
std::to_string(static_cast<int>(dep.edge_data.to_port)) + ":" +
std::to_string(static_cast<int>(dep.edge_data.type));
}
root["topology_key"] = topology_key;
}

Expand Down Expand Up @@ -1447,6 +1508,9 @@ void CUDAGraph::save(const std::string& json_path, const OutputTensors& output_t
json::object dep_obj;
dep_obj["from"] = dep.from_index;
dep_obj["to"] = dep.to_index;
dep_obj["from_port"] = static_cast<int>(dep.edge_data.from_port);
dep_obj["to_port"] = static_cast<int>(dep.edge_data.to_port);
dep_obj["type"] = static_cast<int>(dep.edge_data.type);
deps_array.push_back(dep_obj);
}
root["dependencies"] = deps_array;
Expand Down Expand Up @@ -2031,25 +2095,34 @@ GraphLoadResult CUDAGraph::load(const std::string& json_path, MempoolId_t pool)
if (!deps_array.empty()) {
std::vector<CUgraphNode> from_nodes;
std::vector<CUgraphNode> to_nodes;
std::vector<CUgraphEdgeData> edge_data;
from_nodes.reserve(deps_array.size());
to_nodes.reserve(deps_array.size());
edge_data.reserve(deps_array.size());

for (const auto& dep_val : deps_array) {
const json::object& dep_obj = dep_val.as_object();
int from_id = dep_obj.at("from").to_number<int>();
int to_id = dep_obj.at("to").to_number<int>();
CUgraphEdgeData data{};
if (dep_obj.contains("from_port")) {
data.from_port = static_cast<decltype(data.from_port)>(
dep_obj.at("from_port").to_number<unsigned int>());
}
if (dep_obj.contains("to_port")) {
data.to_port =
static_cast<decltype(data.to_port)>(dep_obj.at("to_port").to_number<unsigned int>());
}
if (dep_obj.contains("type")) {
data.type = static_cast<decltype(data.type)>(dep_obj.at("type").to_number<unsigned int>());
}

from_nodes.push_back(id_to_node[from_id]);
to_nodes.push_back(id_to_node[to_id]);
edge_data.push_back(data);
}

#if (defined(CUDA_VERSION) && CUDA_VERSION >= 13000)
CUresult dep_result = cuGraphAddDependencies(cuGraph, from_nodes.data(), to_nodes.data(),
nullptr, deps_array.size());
#else
CUresult dep_result = cuGraphAddDependencies_v2(cuGraph, from_nodes.data(), to_nodes.data(),
nullptr, deps_array.size());
#endif
CUresult dep_result = add_graph_dependencies(cuGraph, from_nodes, to_nodes, edge_data);
if (dep_result != CUDA_SUCCESS) {
fprintf(stderr, "[foundry LOAD ERROR] cuGraphAddDependencies FAILED with error %d\n",
dep_result);
Expand Down
23 changes: 16 additions & 7 deletions csrc/CUDAGraphParallel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,22 +776,31 @@ GraphLoadResult CUDAGraph::build_graph_from_parsed(ParsedGraphData&& parsed, CUc
if (!deps_array.empty()) {
std::vector<CUgraphNode> from_nodes;
std::vector<CUgraphNode> to_nodes;
std::vector<CUgraphEdgeData> edge_data;
from_nodes.reserve(deps_array.size());
to_nodes.reserve(deps_array.size());
edge_data.reserve(deps_array.size());

for (const auto& dep_val : deps_array) {
const json::object& dep_obj = dep_val.as_object();
from_nodes.push_back(id_to_node[dep_obj.at("from").to_number<int>()]);
to_nodes.push_back(id_to_node[dep_obj.at("to").to_number<int>()]);
CUgraphEdgeData data{};
if (dep_obj.contains("from_port")) {
data.from_port = static_cast<decltype(data.from_port)>(
dep_obj.at("from_port").to_number<unsigned int>());
}
if (dep_obj.contains("to_port")) {
data.to_port =
static_cast<decltype(data.to_port)>(dep_obj.at("to_port").to_number<unsigned int>());
}
if (dep_obj.contains("type")) {
data.type = static_cast<decltype(data.type)>(dep_obj.at("type").to_number<unsigned int>());
}
edge_data.push_back(data);
}

#if (defined(CUDA_VERSION) && CUDA_VERSION >= 13000)
CUresult dep_result = cuGraphAddDependencies(cuGraph, from_nodes.data(), to_nodes.data(),
nullptr, deps_array.size());
#else
CUresult dep_result = cuGraphAddDependencies_v2(cuGraph, from_nodes.data(), to_nodes.data(),
nullptr, deps_array.size());
#endif
CUresult dep_result = add_graph_dependencies(cuGraph, from_nodes, to_nodes, edge_data);
if (dep_result != CUDA_SUCCESS) {
fprintf(stderr, "[foundry LOAD ERROR] cuGraphAddDependencies FAILED with error %d\n",
dep_result);
Expand Down
Loading