Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
e54d0b1
feat(shmem): CPU proxy for IBGDA operations on Pensando AINIC
Aug 3, 2026
5d8813a
feat(shmem): integrate CPU proxy into MORI SHMEM layer
Aug 3, 2026
e04802b
fix(ionic): expose ibv_qp/ibv_cq handles for CPU proxy thread
Aug 3, 2026
ff9ece2
test: cross-NIC DMA capability test for multi-rail approach
Aug 3, 2026
efa6e45
feat: send-side routing — multi-rail QPs + lkey override
Aug 3, 2026
51d2607
wip: send-side routing — per-NIC MR + rkey exchange
Aug 3, 2026
924f285
fix: QP index mapping for proxy — use epIndex-indexed array
Aug 3, 2026
50759a7
wip: save progress — need to debug SIGSEGV in proxy EP test
Aug 3, 2026
102db5e
debug: found SIGSEGV crash location — line 345 in setup()
Aug 3, 2026
e61a4c4
fix: skip parent domain creation in proxy mode to avoid GPU corruption
Aug 3, 2026
62fcf6b
fix: use posix_memalign for proxy ring + document JIT cache invalidation
Aug 3, 2026
3572353
wip: re-enable proxy thread + plain QP + parent domain skip
Aug 3, 2026
dcdd2cd
fix: move per-NIC MR to symmetric_memory + skip 0-QP thread + narrow …
Aug 3, 2026
9bf0280
fix: lazy CQ poll + hipHostRegister for GPU-accessible ring
Aug 3, 2026
49b5d3c
feat: SEND_WITH_IMM atomic emulation + agreed-rail QP mapping + TC fix
Aug 4, 2026
31af7e7
fix: uncached VRAM + PCIe read fence for data/signal ordering
Aug 4, 2026
b4eed72
fix: increase recv WR count to 512 per proxy QP
Aug 4, 2026
3e4fea3
debug: add trace for uncached symmetric memory allocation path
Aug 4, 2026
a3a59b4
fix: conditional hipSetDevice in proxy thread
Aug 4, 2026
9b769e3
cleanup: simplify hipSetDevice in proxy MainLoop
Aug 4, 2026
016a329
fix: replace SEND_WITH_IMM with RDMA_WRITE for signal delivery
Aug 4, 2026
c50ce8e
feat: hybrid signal delivery — RDMA_WRITE for data signals, SEND_WITH…
Aug 4, 2026
e4fbddf
fix: increase proxy ring size to 8192 for large token counts
Aug 4, 2026
a18fd17
fix: increase proxy ring to 64K slots for bench-scale token counts
Aug 4, 2026
db3a42c
fix: remove FENCE from PROXY_SIGNAL_WRITE to unblock bench at scale
Aug 4, 2026
9243d69
cleanup: remove debug logging from proxy thread
Aug 4, 2026
4b235d1
cleanup: remove all debug fprintf from proxy infrastructure
Aug 4, 2026
bdbbb64
fix: remove orphaned fprintf arguments from sed cleanup
Aug 4, 2026
003cbab
cleanup: remove MoRI-RAIL debug prints from context.cpp
Aug 4, 2026
fba19f7
fix: only do per-NIC MR registration for the heap, not sub-allocations
Aug 4, 2026
21da9b6
debug: add minimal traces for vLLM init hang diagnosis
Aug 4, 2026
47770c2
fix: skip redundant MR registration + Allgather for heap sub-allocations
Aug 4, 2026
76e5162
feat: per-NIC proxy threads + targeted quiet for 3.4x dispatch speedup
Aug 5, 2026
e1622ce
v5: Full kernel separation — GpuStates clean, separate ProxyGpuState
Aug 12, 2026
46c069a
v5: Fix proxy dispatch for Warp/Block scope — root cause of AINIC hang
Aug 12, 2026
8eec84b
v5: Remove debug traces from init.cpp and runtime.cpp
Aug 12, 2026
a841a66
v5: Gate application layer proxy changes behind env var
Aug 12, 2026
49c405d
v5: Consolidate env var to MORI_EP_OVER_RDMA only
Aug 12, 2026
82870eb
v5: Revert shmem_ibgda_kernels.hpp to main — no proxy changes needed
Aug 12, 2026
0e7968e
v5: Minimal shmem_device_api.hpp — keep original macros, add one guar…
Aug 12, 2026
1fb0510
v5: Simplify proxy guard to just #ifdef MORI_PROXY_ENABLED
Aug 12, 2026
9cc3949
v6: Use TransportType::PROXY — native dispatch framework
Aug 12, 2026
bc08dfc
v6: Gate proxy dispatch branches with #ifdef MORI_PROXY_ENABLED
Aug 12, 2026
f329260
v6: Fix template specialization signatures and long/unsigned long redefs
Aug 12, 2026
236673b
v6: Remove address-based overloads, fix duplicate GetGlobalProxyStatePtr
Aug 12, 2026
3e98858
v6: Add address-based and signal stubs for all kernel templates
Aug 12, 2026
7947482
refactor: consolidate MORI_EP_OVER_RDMA env var checks
Aug 12, 2026
e1fc7dc
cleanup: move shmem_proxy_state.hpp include to top of internal.hpp
Aug 12, 2026
f3027ee
feat: add ProxyGpuStates as subclass of GpuStates
Aug 12, 2026
0cc49b9
cleanup: remove tp8-1p1d-bench skill file
Aug 12, 2026
b79a125
refactor: use ProxyGpuStates as single gpuStates in ShmemStates
Aug 12, 2026
cfd8cdc
refactor: single-symbol copy with size gated on proxy active
Aug 12, 2026
55caf81
refactor: use Context::IsProxyEnabled() for copy size gate
Aug 12, 2026
485dda6
cleanup: tidy internal.hpp — remove proxy_state include, move forward…
Aug 12, 2026
602833e
refactor: move proxyThreads to init.cpp file-local, use IsProxyEnabled()
Aug 12, 2026
bd0064a
cleanup: use inherited ProxyGpuStates in shmem.hpp weak symbol
Aug 12, 2026
e6d4e88
cleanup: delete shmem_proxy_state.hpp, fix shmem.hpp two-symbol approach
Aug 12, 2026
7082cb2
refactor: align ProxyGpuStates name, move extern + getter to internal…
Aug 12, 2026
5a3963a
fix: restore assert(false) fallthrough in dispatch macros
Aug 12, 2026
f29f4f0
fix: restore separate GpuStates + ProxyGpuStates in ShmemStates
Aug 12, 2026
5564238
rename: proxyGpuState → proxyGpuStates in ShmemStates
Aug 12, 2026
b9c02da
fix: update init.cpp and runtime.cpp for standalone ProxyGpuStates
Aug 12, 2026
433d1e4
cleanup: remove ProxyGpuStates.active field
Aug 12, 2026
bb8e8b1
refactor: use proxyEnabled directly in context.cpp, clean if/else paths
Aug 12, 2026
8ecc796
fix: remove unnecessary (int) cast to match main
Aug 12, 2026
933f8c5
refactor: clean if/else separation in BuildAndConnectInitialEndpoints
Aug 12, 2026
5f76d30
refactor: add GetRailContext() helper, deduplicate agreed-rail formula
Aug 12, 2026
c5e2806
cleanup: symmetric_memory.cpp — remove debug fprintf, use IsProxyEnab…
Aug 12, 2026
7547d18
refactor: keep main's MR registration untouched, single proxy if block
Aug 12, 2026
c8b8196
refactor: optimize proxy sub-allocation path, keep native untouched
Aug 12, 2026
ef8c6ac
refactor: cache proxyEnabled in IonicDeviceContext constructor
Aug 12, 2026
397aaed
cleanup: remove dead duplicate proxy QP block in ionic.cpp
Aug 12, 2026
aa7e241
fix: restore commented-out cqPool.insert from main
Aug 12, 2026
c267827
fix: reorder cqPool/qpPool insert before ibv handle expose
Aug 12, 2026
4b06cbe
cleanup: remove ibvHandle expose from native IBGDA path
Aug 12, 2026
0b19f69
cleanup: deduplicate MORI_DEFINE_GPU_STATES macro
Aug 12, 2026
3634247
fix: add VMM heap support to proxy PutMemNbi and PutSizeImmNbi
Aug 12, 2026
e469c21
fix: rename PROXY_STATE_MAX_NICS → PROXY_MAX_NICS in init.cpp
Aug 12, 2026
60a7674
debug: add traces for hang diagnosis
Aug 12, 2026
d72e52c
debug: add more traces for hang diagnosis (iteration 3)
Aug 12, 2026
555b69e
debug: add proxy thread traces for perf diagnosis
Aug 12, 2026
02d4209
debug: add thread count trace
Aug 12, 2026
3171441
fix: gate Warp/Block proxy kernels on lane 0 / thread 0
Aug 12, 2026
9ed32f2
Revert "fix: gate Warp/Block proxy kernels on lane 0 / thread 0"
Aug 12, 2026
90d8b7b
debug: add proxy thread ops counter on shutdown
Aug 12, 2026
546155b
fix: gate Warp/Block proxy kernels on lane 0 / thread 0
Aug 12, 2026
7e010ad
perf: symmetric agreed-rail formula for even NIC distribution
Aug 13, 2026
13bf51d
Revert "perf: symmetric agreed-rail formula for even NIC distribution"
Aug 13, 2026
13e308a
cleanup: remove all debug traces for v7 release
Aug 13, 2026
6cb8f76
fix: remove orphaned fprintf arguments in init.cpp
Aug 13, 2026
efb1fb2
investigation: add proxy fields to GpuStates (v3 style)
Aug 13, 2026
ae3ee1c
investigation: use GpuStates proxy fields from shmem_proxy_kernels
Aug 13, 2026
c925208
cleanup: remove unused useProxy field from GpuStates
Aug 13, 2026
96556e5
cleanup: remove ProxyGpuStates entirely — proxy state lives in GpuStates
Aug 13, 2026
c1638e3
test: add 8-byte padding before proxyRings to match ae3ee1c2 layout
Aug 13, 2026
6a379ba
cleanup: revert runtime.cpp whitespace to match main
Aug 13, 2026
a688cc0
cleanup: remove debug tools from PR
Aug 13, 2026
bd2fbfa
cleanup: remove stale compile tests
Aug 13, 2026
750ba3e
feat: CX7 proxy QP support — port ionic proxy pattern to mlx5
Aug 13, 2026
b7eb51e
fix: use RdmaDeviceVendorId::Mellanox (not Mlx5)
Aug 13, 2026
48c14da
debug: add traces for CX7 proxy combine hang
Aug 13, 2026
683dfe9
debug: trace op type and post count per 1000 ops
Aug 13, 2026
b203b0a
debug: add heartbeat trace to proxy thread — shows pending/head/next …
Aug 13, 2026
653fb88
debug: trace RECV handler — target addr, value, byte_len
Aug 13, 2026
ab19c0a
debug: trace ALL recv CQEs including opcode/status/byte_len
Aug 13, 2026
0bad02d
debug: trace recv_buf/recv_count on recv CQE, remove heartbeat
Aug 13, 2026
d00973d
fix: use native RDMA atomics on CX7, SEND_WITH_IMM on ionic
Aug 13, 2026
ca6f985
restore original comments in BuildAndConnectInitialEndpoints
Aug 13, 2026
a65ed24
cleanup: merge duplicate IsProxyEnabled blocks, restore comments
Aug 13, 2026
b7d8b14
cleanup: remove all debug traces from proxy_thread.cpp and init.cpp
Aug 13, 2026
189a45f
add: Broadcom bnxt proxy RDMA support for EP
Aug 20, 2026
9c4c3dc
fix: skip BnxtDvApi check when proxy mode enabled
Aug 21, 2026
9ae6ebd
fix: skip DV API check for all providers when proxy enabled
Aug 21, 2026
a571258
Merge pull request #12 from itej89/feat/ep-rdma-sharing-bnxt
itej89 Aug 21, 2026
32f8129
fix: use hipHostGetDevicePointer for proxy ring GPU pointers (#13)
itej89 Aug 21, 2026
4902eb0
add proxy mode log line for RDMA init verification
Aug 26, 2026
fb190f0
refactor: route proxy through IBVerbsDeviceContext (#14)
itej89 Aug 27, 2026
228e68b
fix: remove proxy code from bnxt DV provider (#15)
itej89 Aug 27, 2026
4c77d8c
fix: remove proxy code from bnxt DV provider (#16)
itej89 Aug 27, 2026
1efe5e9
fix: add _tunable_defines() to _hipcc_device_bc for Triton/FlyDSL (#17)
itej89 Aug 27, 2026
b008bf2
fix: restore rdmaRegister guard and guard heapRkeys_ memcpy in proxy …
itej89 Aug 27, 2026
b8a5d7f
fix: check wc.status before opcode, use MORI logger in proxy (#19)
itej89 Aug 27, 2026
0a1deda
rename: MORI_EP_OVER_RDMA → MORI_ENABLE_HOST_PROXY (#20)
itej89 Aug 27, 2026
7d04f1a
fix: remove MORI_EP_OVER_RDMA fallback completely
Aug 28, 2026
645f5ed
fix: log error on null atomic target address in proxy DrainCq
Aug 28, 2026
8b60e6a
fix: use MORI_APP_ERROR for proxy transport logs
Aug 28, 2026
de983fb
fix: write atomic fetch result back to ring slot for native atomics
Aug 28, 2026
d9bc81f
fix: replace x86 asm with portable std::atomic_thread_fence (#21)
itej89 Aug 28, 2026
ac2a6b6
fix: stage inline data in ProxyCmd for PROXY_RDMA_WRITE_INLINE (#22)
itej89 Aug 28, 2026
ebf8bf8
fix: validate atomic target addr against heap range in proxy DrainCq …
itej89 Aug 28, 2026
3bca0d4
trial2: atomic fetch round-trip over SEND_WITH_IMM emulation (#25)
itej89 Aug 29, 2026
7d16bd4
Merge upstream/main into feat/ep-rdma-sharing
Aug 29, 2026
1781fa1
style: fix clang-format and license headers for pre-commit CI
Aug 29, 2026
700751a
fix: tag atomic-fetch reply WR with sentinel wr_id to prevent slot 0 …
itej89 Aug 31, 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
2 changes: 1 addition & 1 deletion include/mori/application/application_device_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ namespace application {
/* Transport Types */
/* ---------------------------------------------------------------------------------------------- */

enum TransportType { RDMA = 0, P2P = 1, SDMA = 2 };
enum TransportType { RDMA = 0, P2P = 1, SDMA = 2, PROXY = 3 };

// Atomic internal buffer configuration. Defined here (device-safe) rather than in
// the host transport/rdma/rdma.hpp so device kernels (e.g. shmem_ibgda_kernels) can
Expand Down
14 changes: 14 additions & 0 deletions include/mori/application/context/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,16 @@ class Context {

RdmaContext* GetRdmaContext() const { return rdmaContext.get(); }
RdmaDeviceContext* GetRdmaDeviceContext() const { return rdmaDeviceContext.get(); }
const std::vector<std::unique_ptr<RdmaDeviceContext>>& GetAllRdmaDeviceContexts() const {
return allRdmaDeviceContexts;
}
bool RdmaTransportEnabled() const { return GetRdmaDeviceContext() != nullptr; }
RdmaDeviceContext* GetRailContext(int peerRank) const {
const int nCtx = static_cast<int>(allRdmaDeviceContexts.size());
int peerLocalGpu = peerRank % nCtx;
int agreedRail = std::max(LocalRankInNode(), peerLocalGpu) % nCtx;
return allRdmaDeviceContexts[agreedRail].get();
}

// Check if P2P connection is possible with a peer (same node)
bool CanUseP2P(int destRank) const;
Expand All @@ -112,6 +121,7 @@ class Context {
// in a test function after the workers had already been spawned.
bool IsSdmaEnabled() const { return sdmaEnabled; }
bool IsP2PDisabled() const { return p2pDisabled; }
bool IsProxyEnabled() const { return proxyEnabled; }
bool IsRailOnly() const { return railOnly; }

// Returns the initial RDMA endpoint set. Empty until BuildInitialEndpoints()
Expand Down Expand Up @@ -187,6 +197,7 @@ class Context {
int numQpPerPe{4};
bool sdmaEnabled{false};
bool p2pDisabled{false};
bool proxyEnabled{false};
bool railOnly{false};
std::string myHostname;
std::vector<PeerInfo> peerInfos;
Expand All @@ -195,6 +206,9 @@ class Context {

std::unique_ptr<RdmaContext> rdmaContext{nullptr};
std::unique_ptr<RdmaDeviceContext> rdmaDeviceContext{nullptr};
// One context per available RDMA device/port, indexed by NIC index (0..numNics-1).
// QP-to-NIC mapping is via the agreed-rail formula, not a direct index.
std::vector<std::unique_ptr<RdmaDeviceContext>> allRdmaDeviceContexts;

std::vector<RdmaEndpoint> rdmaEps;
bool initialEndpointsBuilt{false};
Expand Down
11 changes: 11 additions & 0 deletions include/mori/application/memory/symmetric_memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ class SymmMemManager {
SymmMemObjPtr GetVMMHeapObj() const { return vmmHeapObj; }
size_t GetVMMChunkSize() const { return vmmChunkSize; }

// Per-NIC keys for send-side routing (proxy mode).
// perNicLkeys[nic] = lkey for MY buffer registered on nic's PD.
// perNicPeerRkeys[nic][peer] = rkey for peer's buffer registered on nic's PD.
std::vector<uint32_t> perNicLkeys;
std::vector<std::vector<uint32_t>> perNicPeerRkeys;

// Cached heap rkeys — sub-allocations reuse these instead of doing
// redundant ibv_reg_mr + Allgather for each shmem_malloc.
uint32_t heapLkey_{0};
std::vector<uint32_t> heapRkeys_;

// Common Utilities
SymmMemObjPtr Get(void* localPtr) const;
HeapVAManager* GetHeapVAManager() const { return heapVAManager.get(); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,19 @@ class IBVerbsDeviceContext : public RdmaDeviceContext {
uint32_t qpId = 0) override;
bool DestroyRdmaEndpointNoThrow(const RdmaEndpoint&) noexcept override;

struct ProxyRecvInfo {
void* buf;
uint32_t lkey;
uint32_t count;
};
ProxyRecvInfo GetProxyRecvInfo(uint32_t qpn) const;

private:
mutable std::mutex poolMu;
std::unordered_map<void*, ibv_cq*> cqPool;
std::unordered_map<uint32_t, ibv_qp*> qpPool;
std::vector<ibv_comp_channel*> compChPool;
std::unordered_map<uint32_t, ProxyRecvInfo> proxyRecvInfo;
};

class IBVerbsDevice : public RdmaDevice {
Expand Down
3 changes: 3 additions & 0 deletions include/mori/core/transport/rdma/ibverbs_handle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ struct IBVerbsHandle {
ibv_cq* cq{nullptr};
ibv_srq* srq{nullptr};
ibv_comp_channel* compCh{nullptr};
void* recvBuf{nullptr};
uint32_t recvLkey{0};
uint32_t recvCount{0};
};

} // namespace core
Expand Down
212 changes: 212 additions & 0 deletions include/mori/core/transport/rdma/proxy/proxy_device_primitives.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
// Copyright © Advanced Micro Devices, Inc. All rights reserved.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Copyright © Advanced Micro Devices, Inc. All rights reserved.
// MIT License
#pragma once

#include "mori/core/transport/rdma/proxy/proxy_types.hpp"

#ifdef __HIPCC__

namespace mori {
namespace core {

// Returns sequence number (monotonically increasing). Mask with PROXY_RING_MASK for slot index.
inline __device__ uint32_t ProxyReserveSlot(volatile ProxyRing* ring) {
return __hip_atomic_fetch_add((uint32_t*)&ring->gpu_head, 1u, __ATOMIC_RELAXED,
__HIP_MEMORY_SCOPE_AGENT);
}

inline __device__ void ProxyWaitSlotFree(volatile ProxyRing* ring, uint32_t slot) {
int spins = 0;
while (true) {
uint32_t st = __hip_atomic_load((uint32_t*)&ring->cmds[slot].status, __ATOMIC_RELAXED,
__HIP_MEMORY_SCOPE_SYSTEM);
if (st == PROXY_FREE || st == PROXY_COMPLETED) break;
if (++spins % 100000 == 0) __builtin_amdgcn_s_sleep(1);
}
}

inline __device__ void ProxyWaitSlotCompleted(volatile ProxyRing* ring, uint32_t slot) {
while (true) {
uint32_t st = __hip_atomic_load((uint32_t*)&ring->cmds[slot].status, __ATOMIC_RELAXED,
__HIP_MEMORY_SCOPE_SYSTEM);
if (st == PROXY_COMPLETED || st == PROXY_ERROR) break;
__builtin_amdgcn_s_sleep(1);
}
}

inline __device__ uint32_t ProxyPostWrite(volatile ProxyRing* ring, uint32_t qp_idx,
uint64_t src_addr, uint32_t lkey, uint64_t dst_addr,
uint32_t rkey, uint32_t length) {
uint32_t seq = ProxyReserveSlot(ring);
uint32_t slot = seq & PROXY_RING_MASK;
ProxyWaitSlotFree(ring, slot);

ring->cmds[slot].op = PROXY_RDMA_WRITE;
ring->cmds[slot].qp_idx = qp_idx;
ring->cmds[slot].src_addr = src_addr;
ring->cmds[slot].dst_addr = dst_addr;
ring->cmds[slot].length = length;
ring->cmds[slot].lkey = lkey;
ring->cmds[slot].rkey = rkey;
ring->cmds[slot].flags = 1;

__threadfence_system();
ring->cmds[slot].status = PROXY_PENDING;
return seq;
}

inline __device__ uint32_t ProxyPostWriteInline(volatile ProxyRing* ring, uint32_t qp_idx,
const void* src, uint32_t lkey, uint64_t dst_addr,
uint32_t rkey, uint32_t length) {
uint32_t seq = ProxyReserveSlot(ring);
uint32_t slot = seq & PROXY_RING_MASK;
ProxyWaitSlotFree(ring, slot);

ring->cmds[slot].op = PROXY_RDMA_WRITE_INLINE;
ring->cmds[slot].qp_idx = qp_idx;
ring->cmds[slot].dst_addr = dst_addr;
ring->cmds[slot].length = length;
ring->cmds[slot].lkey = lkey;
ring->cmds[slot].rkey = rkey;
ring->cmds[slot].flags = 1;

if (src != nullptr && length > 0 && length <= PROXY_MAX_INLINE_DATA) {
const uint64_t* s64 = reinterpret_cast<const uint64_t*>(src);
volatile uint64_t* d64 = reinterpret_cast<volatile uint64_t*>(ring->cmds[slot].inline_data);
for (uint32_t i = 0; i < (length + 7) / 8; i++) d64[i] = s64[i];
ring->cmds[slot].inline_tag = PROXY_INLINE_SCALAR_WRITE;
ring->cmds[slot].inline_len = length;
} else {
ring->cmds[slot].inline_tag = PROXY_INLINE_NONE;
ring->cmds[slot].inline_len = 0;
}

__threadfence_system();
ring->cmds[slot].status = PROXY_PENDING;
return seq;
}

inline __device__ uint32_t ProxyPostAtomicNonFetch(volatile ProxyRing* ring, uint32_t qp_idx,
uint64_t dst_addr, uint32_t rkey,
uint64_t add_value, uint32_t lkey,
uint64_t ibuf_addr) {
uint32_t seq = ProxyReserveSlot(ring);
uint32_t slot = seq & PROXY_RING_MASK;
ProxyWaitSlotFree(ring, slot);

ring->cmds[slot].op = PROXY_ATOMIC_FETCH_ADD;
ring->cmds[slot].qp_idx = qp_idx;
ring->cmds[slot].src_addr = ibuf_addr;
ring->cmds[slot].dst_addr = dst_addr;
ring->cmds[slot].length = 8;
ring->cmds[slot].lkey = lkey;
ring->cmds[slot].rkey = rkey;
ring->cmds[slot].atomic_arg = add_value;
ring->cmds[slot].flags = PROXY_FLAGS_DEFAULT;

__threadfence_system();
ring->cmds[slot].status = PROXY_PENDING;
return seq;
}

// Signal write: RDMA_WRITE of value to remote addr on the SAME NIC path
// as the preceding data write. Used for signals paired with data
// (ShmemPutMemNbiSignalThread) to ensure PCIe write ordering.
inline __device__ uint32_t ProxyPostSignalWrite(volatile ProxyRing* ring, uint32_t qp_idx,
uint64_t dst_addr, uint32_t rkey, uint64_t value,
uint32_t lkey, uint64_t ibuf_addr) {
uint32_t seq = ProxyReserveSlot(ring);
uint32_t slot = seq & PROXY_RING_MASK;
ProxyWaitSlotFree(ring, slot);

ring->cmds[slot].op = PROXY_SIGNAL_WRITE;
ring->cmds[slot].qp_idx = qp_idx;
ring->cmds[slot].src_addr = ibuf_addr;
ring->cmds[slot].dst_addr = dst_addr;
ring->cmds[slot].length = 8;
ring->cmds[slot].lkey = lkey;
ring->cmds[slot].rkey = rkey;
ring->cmds[slot].atomic_arg = value;
ring->cmds[slot].flags = 1;

__threadfence_system();
ring->cmds[slot].status = PROXY_PENDING;
return seq;
}

inline __device__ uint64_t ProxyPostAtomicFetch(volatile ProxyRing* ring, uint32_t qp_idx,
uint64_t dst_addr, uint32_t rkey,
uint64_t add_value, uint32_t lkey,
uint64_t ibuf_addr) {
uint32_t seq = ProxyReserveSlot(ring);
uint32_t slot = seq & PROXY_RING_MASK;
ProxyWaitSlotFree(ring, slot);

ring->cmds[slot].op = PROXY_ATOMIC_FETCH_ADD;
ring->cmds[slot].qp_idx = qp_idx;
ring->cmds[slot].src_addr = ibuf_addr;
ring->cmds[slot].dst_addr = dst_addr;
ring->cmds[slot].length = 8;
ring->cmds[slot].lkey = lkey;
ring->cmds[slot].rkey = rkey;
ring->cmds[slot].atomic_arg = add_value;
ring->cmds[slot].flags = PROXY_FLAGS_FETCH_REQUIRED;
// Store slot index in inline_data so the remote can send it back in the reply
*reinterpret_cast<volatile uint64_t*>(&ring->cmds[slot].inline_data[0]) =
static_cast<uint64_t>(slot);
ring->cmds[slot].result = 0;

__threadfence_system();
ring->cmds[slot].status = PROXY_PENDING;

ProxyWaitSlotCompleted(ring, slot);
return ring->cmds[slot].result;
Comment on lines +183 to +184

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do atomic fetch operations always return 0? Is this the expected?

}

// Wait for all ops from [first_seq, first_seq + count) to complete.
// When count > PROXY_RING_SIZE, slots were reused during submission.
// ProxyWaitSlotFree already ensured earlier slots completed before reuse,
// so we only need to wait for the tail — the last PROXY_RING_SIZE slots.
inline __device__ void ProxyQuiet(volatile ProxyRing* ring, uint32_t first_seq, uint32_t count) {
if (count == 0) return;
uint32_t start = first_seq;
if (count > PROXY_RING_SIZE) {
start = first_seq + count - PROXY_RING_SIZE;
}
uint32_t end = first_seq + count;
for (uint32_t seq = start; seq < end; seq++) {
uint32_t slot = seq & PROXY_RING_MASK;
ProxyWaitSlotCompleted(ring, slot);
}
}

// Range variant for multi-warp callers that know the exact range.
inline __device__ void ProxyQuietRange(volatile ProxyRing* ring, uint32_t from, uint32_t to) {
ProxyQuiet(ring, from, to - from);
}

} // namespace core
} // namespace mori

#endif // __HIPCC__
86 changes: 86 additions & 0 deletions include/mori/core/transport/rdma/proxy/proxy_thread.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright © Advanced Micro Devices, Inc. All rights reserved.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Copyright © Advanced Micro Devices, Inc. All rights reserved.
// MIT License
#pragma once

#if !defined(__HIPCC__) && !defined(__CUDACC__)

#include <infiniband/verbs.h>
#include <pthread.h>

#include <atomic>
#include <vector>

#include "mori/core/transport/rdma/proxy/proxy_types.hpp"

namespace mori {
namespace core {

struct InlineBuf {
uint64_t data[4];
};

struct ProxyQpHandle {
ibv_qp* qp{nullptr};
ibv_cq* cq{nullptr};
uint32_t lkey_override{0};
uint32_t rkey_override{0};
void* recv_buf{nullptr};
uint32_t recv_lkey{0};
uint32_t recv_count{0};
bool use_native_atomics{false};
};

class ProxyThread {
public:
ProxyThread() = default;
~ProxyThread();

void Init(ProxyRing* ring, std::vector<ProxyQpHandle> qps, int gpuId = 0, uintptr_t heapBase = 0,
uintptr_t heapEnd = 0);
void Start();
void Shutdown();

private:
static void* ThreadFunc(void* arg);
void MainLoop();
void DrainCq(ProxyQpHandle& qph);
bool BuildWr(volatile ProxyCmd* cmd, ProxyQpHandle& qph, ibv_send_wr& wr, ibv_sge& sge,
uint32_t slot_id, InlineBuf& ibuf);

ProxyRing* ring_{nullptr};
std::vector<ProxyQpHandle> qps_;
pthread_t thread_{};
std::atomic<bool> running_{false};
uint32_t next_slot_{0};
uint64_t ops_posted_{0};
uint64_t ops_completed_{0};
int gpu_id_{0};
uintptr_t heap_base_{0};
uintptr_t heap_end_{0};
};

} // namespace core
} // namespace mori

#endif // !defined(__HIPCC__) && !defined(__CUDACC__)
Loading
Loading