Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
96ef304
runtime/realm: MVP attempt to develop a static subgraph
rohany Jan 19, 2026
d4f7f95
runtime/realm: small optimizations
rohany Dec 6, 2024
0899959
src/realm: fixup for previous commit, make execute_task public
rohany Jan 19, 2026
e50fef4
runtime/realm: support interpolations for tasks in static schedule
rohany Jan 19, 2026
d7c51b0
runtime/realm: add arrival support to static subgraph implementation
rohany Jan 19, 2026
5fdb088
runtime/realm: support external preconditions in subgraph replay
rohany Jan 19, 2026
ff218c7
runtime/realm: fix bug in external precondition triggering
rohany Dec 9, 2024
d055c09
runtime/realm: hack to support preloading task funcptrs
rohany Jan 19, 2026
dc01512
Revert "runtime/realm: hack to support preloading task funcptrs"
rohany Jan 19, 2026
70baf63
runtime/realm: support for deferred subgraph execution
rohany Jan 19, 2026
577b639
runtime/realm: fix typo in subgraph instantiation
rohany Dec 12, 2024
764593b
runtime/realm: stop using the slow merge_events(set<>) API
rohany Dec 12, 2024
2f7b68c
runtime/realm: switch to fresh precondition array for each instantiation
rohany Jan 19, 2026
e889e8c
runtime/realm: more cleanup for deferred subgraph instantiations
rohany Jan 19, 2026
1b7abae
runtime/realm: initial progress towards supporting GPUs in subgraphs
rohany Jan 20, 2026
9629b82
runtime/realm: bugfixes
rohany Jan 20, 2026
2af8510
src/realm/cuda: use dedicated gpu workers
rohany Jan 20, 2026
53ea72e
src/realm/cuda: actually record into the cuda event
rohany Jan 20, 2026
7037bfe
runtime/realm: cleanup before merge
rohany Jan 20, 2026
69561be
runtime/realm: small cleanup
rohany Jan 20, 2026
4fe7c4e
runtime/realm: switch to a dynamic queue in subgraph replay
rohany Jan 20, 2026
b1d2ff3
runtime/realm: bugfixes+cleanup
rohany Jan 20, 2026
1d065fb
runtime/realm: support a static and dynamic partition of the subgraph
rohany Jan 20, 2026
b1ab28a
runtime/realm: add support for external postconditions
rohany Dec 24, 2024
068011d
runtime/realm: small cleanup of subgraph replays
rohany Jan 20, 2026
ee6dd57
runtime/realm: optimize copies in subgraph replays
rohany Jan 20, 2026
de77e35
runtime/realm: hack to run copies on application processors
rohany Jan 20, 2026
24e1818
src/realm/transfer: small cleanup to xd resetting
rohany Jan 20, 2026
05a8faf
runtime/realm: more progress towards copy fast paths
rohany Jan 20, 2026
66e4cc9
runtime/realm: bugfixes for asynchronous subgraph operations
rohany Jan 20, 2026
d6b3d00
runtime/realm: hoist subgraph cuda copy functions for other xds
rohany Jan 20, 2026
28db5ae
src/realm/transfer: remove unnecessary cast
rohany Jan 20, 2026
829af48
src/realm/cuda: fix typo
rohany Jan 20, 2026
9bcff2b
runtime,test: QOL cleanup and some bugfixes
rohany Jan 20, 2026
77b3407
runtime/realm: update comments
rohany Jan 20, 2026
2f2ca25
test/realm: test some more interesting kinds of copies
rohany Jan 20, 2026
1ea684c
runtime/realm: flatten some nested data structures post compilation
rohany Jan 20, 2026
96f1d15
runtime/realm: initial support for copies that use multiple xd's
rohany Jan 20, 2026
0353d98
runtime/realm: first round of bugfixes for multiple xd's per copy
rohany Jan 20, 2026
9bf60c0
runtime/realm: be more precise about when copies respect async
rohany Jan 20, 2026
7dad19a
runtime/realm: clean up some comments
rohany Jan 20, 2026
ef2fea0
runtime/realm: always implicitly order subgraph executions
rohany Jan 20, 2026
b074c94
tests: fix missing event chain in test
rohany Jan 20, 2026
1f44fdb
test/realm: improve stencil subgraph test
rohany Jan 8, 2025
16c5cb1
test/realm: add anti-dependencies to stencil app
Jan 8, 2025
01270c9
test/realm: add sanity check on problem size
Jan 8, 2025
27144fb
tests: update the stencil subgraph application with GPU support
rohany Jan 20, 2026
f0efebe
src/realm/cuda: delete streams in channels in the right place
rohany Jan 20, 2026
e9fcfd4
runtime/realm: fix async op checking bug, order subgraph deletions
rohany Jan 15, 2025
27175b5
runtime/realm,test/realm: initial profiling support for subgraphs
rohany Jan 20, 2026
18c643e
runtime/realm: more bugfixes for subgraph profiling
rohany Jan 20, 2026
73f20d6
src/realm/cuda: fix subgraph GPU profiling bug
rohany Jan 20, 2026
ca19d9e
runtime/realm: small cleanup for subgraph profiling
rohany Jan 20, 2026
b5129ca
runtime/realm: fix bugs around completion profiling of GPU tasks
rohany Jan 20, 2026
f501726
runtime/realm: ensure subgraphs can't finish before gpu profile repor…
rohany Jan 20, 2026
0bf6a56
runtime/realm: fix race in subgraph profiling scheduling
rohany Jan 20, 2025
6fda083
runtime/realm: move subgraph deletions off critical path
rohany Jan 20, 2026
8b17050
runtime/realm: shut down the subgraph reaping background worker
rohany Jan 20, 2026
34dc927
runtime/realm: make subgraph deletion capture instantiation cleanups
rohany Jan 20, 2026
4c3557e
runtime/realm: some progress towards shaking out races in miniaero
rohany Jan 20, 2026
b3b4321
runtime/realm: fix nasty race in async copies in subgraph instantiations
rohany Jan 25, 2025
49ce9a8
runtime/realm: fix merge fallout
rohany Jan 27, 2025
697fe68
runtime/realm: initial support for indirection copies in subgraphs
rohany Jan 20, 2026
f35ad33
runtime/realm: refactor copy indirection resource management
rohany Jan 20, 2026
7edfa6f
runtime/realm: more copy indirection refactoring
rohany Jan 20, 2026
b96399e
runtime/realm: fix typo
rohany Jan 29, 2025
f2c8d40
runtime/realm: send copies with IBs to the dynamic subgraph partition
rohany Jan 20, 2026
6b9e0e6
runtime/realm: plan and execute copies with IBs in the static subgraph
rohany Jan 20, 2026
c0e9fb5
runtime/realm: some bugfixes for ib alloc replays
rohany Jan 20, 2026
1213d5d
src/realm/transfer: properly reset more XD iterators
rohany Jan 31, 2025
4d4085a
runtime/realm: avoid an new in ib allocations
rohany Jan 31, 2025
878f462
Revert "runtime/realm: avoid an new in ib allocations"
rohany Jan 31, 2025
c3ce767
runtime/realm: update comment
rohany Jan 20, 2026
4bdc028
runtime/realm: initial pass at supporting remote XDs in subgraph replays
rohany Jan 20, 2026
339630c
runtime/realm: first round of bugfixes for remote copy planning
rohany Jan 20, 2026
a2654d2
src: add missing CMakeLists.txt change
rohany Jan 20, 2026
4e71ff1
src: add missing cuda_internal.h change
rohany Jan 20, 2026
9d6c19f
runtime/realm: more bugfixes for remotely planned copies
rohany Jan 20, 2026
3a48825
runtime/realm: use remote completions instead explicit responses
rohany Jan 20, 2026
fb70f4b
runtime/realm: clean up comments
rohany Jan 20, 2026
6cd115d
runtime/realm: fix potential race in starting external precondition e…
rohany Feb 6, 2025
298cbfd
runtime/realm: add some nvtx annotations for subgraph profiling
rohany Jan 20, 2026
ccb663b
runtime/realm: fix nvtx params
rohany Jan 20, 2026
cef6519
src/realm/transfer: fix macro
rohany Jan 20, 2026
8781a57
runtime/realm: fix macro
rohany Feb 7, 2025
ee7d22a
runtime/realm: fix macro
rohany Jan 20, 2026
35222b5
runtime/realm: special case event waits within subgraph executions
rohany Jan 20, 2026
30e2d0f
runtime/realm: make the subgraph scheduler spin/yield customizable
rohany Jan 20, 2026
0078e86
runtime/realm: make subgraph barrier arrivals happen on trigger
rohany Jan 20, 2026
015ca13
runtime/realm: fix sneaky race introduced by barrier fix
rohany Jan 20, 2026
a0ab59e
Merge branch 'main' into subgraph-compilation-prototype
rohany Jan 21, 2026
b6cdee6
src/realm: clean up build warning fallout
rohany Jan 21, 2026
20f95c3
src/realm: add a few comments to help guide review
rohany Jan 28, 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
248 changes: 241 additions & 7 deletions src/realm/cuda/cuda_internal.cc

Large diffs are not rendered by default.

65 changes: 52 additions & 13 deletions src/realm/cuda/cuda_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,6 @@ namespace Realm {
GPUProcessor *proc = nullptr; // TODO(cperry): delete me
};

// an interface for receiving completion notification for a GPU operation
// (right now, just copies)
class GPUCompletionNotification {
public:
virtual ~GPUCompletionNotification(void) {}

virtual void request_completed(void) = 0;
};

class GPUWorkFence : public Realm::Operation::AsyncWorkItem {
public:
GPUWorkFence(GPU *gpu, Realm::Operation *op);
Expand Down Expand Up @@ -258,7 +249,7 @@ namespace Realm {
void add_notification(GPUCompletionNotification *notification);
void add_event(CUevent event, GPUWorkFence *fence,
GPUCompletionNotification *notification = NULL,
GPUWorkStart *start = NULL);
GPUWorkStart *start = NULL, bool return_event = true);
void wait_on_streams(const std::set<GPUStream *> &other_streams);

// atomically checks rate limit counters and returns true if 'bytes'
Expand All @@ -280,6 +271,7 @@ namespace Realm {
Mutex mutex;
struct PendingEvent {
CUevent event;
bool return_event = true;
GPUWorkFence *fence;
GPUWorkStart *start;
GPUCompletionNotification *notification;
Expand Down Expand Up @@ -345,6 +337,7 @@ namespace Realm {

CUevent get_event(bool external = false);
void return_event(CUevent e, bool external = false);
void return_events(CUevent* events, size_t num_events);

protected:
Mutex mutex;
Expand Down Expand Up @@ -545,6 +538,14 @@ namespace Realm {

virtual void shutdown(void);

virtual void push_subgraph_replay_context() override;
virtual void pop_subgraph_replay_context() override;

virtual void push_subgraph_task_replay_context(SubgraphOperationProfilingInfo* prof) override;
virtual void pop_subgraph_task_replay_context(void** token, void* trigger, SubgraphOperationProfilingInfo* prof) override;
virtual void sync_task_async_effect(void* token) override;
virtual void return_subgraph_async_tokens(const std::vector<void*>& tokens) override;

protected:
virtual void execute_task(Processor::TaskFuncID func_id,
const ByteArrayRef &task_args);
Expand Down Expand Up @@ -773,6 +774,18 @@ namespace Realm {
size_t width_in_bytes, height, depth;
};

// Utility methods for asynchronous XferDes objects to
// interact with subgraphs. Must be called from within
// a CUDA context.

// Synchronize with any previous subgraph work launched on the given stream.
void sync_subgraph_incoming_deps(ProcSubgraphReplayState* all_proc_states, unsigned index, GPUStream* stream);
// Add a GPUCompletionNotification to the given stream, which tracks
// when work launched by a transfer is done.
void add_transfer_completion_notification(ProcSubgraphReplayState* all_proc_states, GPUStream* stream, GPUStream* depstream, GPUCompletionNotification* completion);
// Notify the subgraph that the control side of GPU subgraph operation has completed.
void notify_subgraph_control_completion(ProcSubgraphReplayState* all_proc_states, unsigned subgraph_index, unsigned xd_index, GPUStream* depstream);

class GPUChannel;

class GPUXferDes : public XferDes {
Expand All @@ -785,6 +798,10 @@ namespace Realm {

bool progress_xd(GPUChannel *channel, TimeLimit work_until);

bool launches_async_work_locally() override { return true; }
void on_subgraph_control_completion() override;
LocalTaskProcessor* get_async_event_proc() override;

private:
std::vector<GPU *> src_gpus, dst_gpus;
std::vector<bool> dst_is_ipc;
Expand All @@ -802,6 +819,10 @@ namespace Realm {
long get_requests(Request **requests, long nr);
bool progress_xd(GPUIndirectChannel *channel, TimeLimit work_until);

bool launches_async_work_locally() override { return true; }
void on_subgraph_control_completion() override;
LocalTaskProcessor* get_async_event_proc() override;

protected:
std::vector<GPU *> src_gpus, dst_gpus;
std::vector<bool> dst_is_ipc;
Expand All @@ -811,7 +832,6 @@ namespace Realm {
: public SingleXDQChannel<GPUIndirectChannel, GPUIndirectXferDes> {
public:
GPUIndirectChannel(GPU *_src_gpu, XferDesKind _kind, BackgroundWorkManager *bgwork);
~GPUIndirectChannel();

// multi-threading of cuda copies for a given device is disabled by
// default (can be re-enabled with -cuda:mtdma 1)
Expand Down Expand Up @@ -841,10 +861,12 @@ namespace Realm {

long submit(Request **requests, long nr);
GPU *get_gpu() const { return src_gpu; }
void shutdown() override;

protected:
friend class GPUIndirectXferDes;
GPU *src_gpu;
GPUStream* subgraph_stream;
};

class GPUIndirectRemoteChannelInfo : public SimpleRemoteChannelInfo {
Expand Down Expand Up @@ -887,7 +909,6 @@ namespace Realm {
class GPUChannel : public SingleXDQChannel<GPUChannel, GPUXferDes> {
public:
GPUChannel(GPU *_src_gpu, XferDesKind _kind, BackgroundWorkManager *bgwork);
~GPUChannel();

// multi-threading of cuda copies for a given device is disabled by
// default (can be re-enabled with -cuda:mtdma 1)
Expand All @@ -903,10 +924,13 @@ namespace Realm {

long submit(Request **requests, long nr);
GPU *get_gpu() const { return src_gpu; }
void shutdown() override;

private:
friend class GPUXferDes;
GPU *src_gpu;
// std::deque<Request*> pending_copies;
// Stream to manage interaction with potential subgraph replays.
GPUStream* subgraph_stream;
};

class GPUfillChannel;
Expand All @@ -918,12 +942,19 @@ namespace Realm {
const std::vector<XferDesPortInfo> &outputs_info, int _priority,
const void *_fill_data, size_t _fill_size, size_t _fill_total);

void reset(const std::vector<off_t>& ib_offsets) override;

long get_requests(Request **requests, long nr);

bool progress_xd(GPUfillChannel *channel, TimeLimit work_until);

bool launches_async_work_locally() override { return true; }
void on_subgraph_control_completion() override;
LocalTaskProcessor* get_async_event_proc() override;

protected:
size_t reduced_fill_size;
size_t fill_total;
};

class GPUfillChannel : public SingleXDQChannel<GPUfillChannel, GPUfillXferDes> {
Expand All @@ -942,11 +973,13 @@ namespace Realm {
size_t fill_total);

long submit(Request **requests, long nr);
void shutdown() override;

protected:
friend class GPUfillXferDes;

GPU *gpu;
GPUStream* subgraph_stream;
};

class GPUreduceChannel;
Expand All @@ -962,6 +995,10 @@ namespace Realm {

bool progress_xd(GPUreduceChannel *channel, TimeLimit work_until);

bool launches_async_work_locally() override { return true; }
void on_subgraph_control_completion() override;
LocalTaskProcessor* get_async_event_proc() override;

protected:
XferDesRedopInfo redop_info;
const ReductionOpUntyped *redop;
Expand Down Expand Up @@ -992,11 +1029,13 @@ namespace Realm {
size_t fill_total) override;

long submit(Request **requests, long nr) override;
void shutdown() override;

protected:
friend class GPUreduceXferDes;

GPU *gpu;
GPUStream* subgraph_stream;
};

class GPUreduceRemoteChannelInfo : public SimpleRemoteChannelInfo {
Expand Down
110 changes: 103 additions & 7 deletions src/realm/cuda/cuda_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ namespace Realm {

void GPUStream::add_event(CUevent event, GPUWorkFence *fence,
GPUCompletionNotification *notification,
GPUWorkStart *start)
GPUWorkStart *start, bool return_event)
{
bool add_to_worker = false;
{
Expand All @@ -245,6 +245,7 @@ namespace Realm {
e.fence = fence;
e.start = start;
e.notification = notification;
e.return_event = return_event;

pending_events.push_back(e);
}
Expand Down Expand Up @@ -320,14 +321,15 @@ namespace Realm {
log_stream.debug() << "CUDA event " << event << " triggered on stream " << stream
<< " (GPU " << gpu << ")";

// give event back to GPU for reuse
gpu->event_pool.return_event(event);

// this event has triggered, so figure out the fence/notification to trigger
// and also peek at the next event
GPUWorkFence *fence = 0;
GPUWorkStart *start = 0;
GPUCompletionNotification *notification = 0;
bool return_event = false;
// The logic below may change the value stored in
// `event`, so save it before manipulating the queue.
CUevent event_to_return = event;

{
AutoLock<> al(mutex);
Expand All @@ -337,6 +339,7 @@ namespace Realm {
fence = e.fence;
start = e.start;
notification = e.notification;
return_event = e.return_event;
pending_events.pop_front();

if(pending_events.empty()) {
Expand All @@ -346,6 +349,10 @@ namespace Realm {
event = pending_events.front().event;
}

if (return_event) {
gpu->event_pool.return_event(event_to_return);
}

if(start) {
start->mark_gpu_work_start();
}
Expand Down Expand Up @@ -585,6 +592,16 @@ namespace Realm {
available_events[current_size++] = e;
}

void GPUEventPool::return_events(CUevent* events, size_t num_events) {
AutoLock<> al(mutex);

assert(current_size < total_size);

for (size_t i = 0; i < num_events; i++) {
available_events[current_size++] = events[i];
}
}

////////////////////////////////////////////////////////////////////////
//
// class ContextSynchronizer
Expand Down Expand Up @@ -990,9 +1007,9 @@ namespace Realm {
}
}
params.set_num_cores(1);
params.set_alu_usage(params.CORE_USAGE_SHARED);
params.set_fpu_usage(params.CORE_USAGE_SHARED);
params.set_ldst_usage(params.CORE_USAGE_SHARED);
params.set_alu_usage(params.CORE_USAGE_EXCLUSIVE);
params.set_fpu_usage(params.CORE_USAGE_EXCLUSIVE);
params.set_ldst_usage(params.CORE_USAGE_EXCLUSIVE);
params.set_max_stack_size(_stack_size);

std::string name = stringbuilder() << "GPU proc " << _me;
Expand All @@ -1013,6 +1030,85 @@ namespace Realm {

GPUProcessor::~GPUProcessor(void) { delete core_rsrv; }

void GPUProcessor::push_subgraph_replay_context() {
gpu->push_context();
}

void GPUProcessor::pop_subgraph_replay_context() {
gpu->pop_context();
}

void GPUProcessor::push_subgraph_task_replay_context(SubgraphOperationProfilingInfo* prof) {
// TODO (rohany): A good chunk of this is ripped from the
// GPUContextManager...
assert(ThreadLocal::current_gpu_stream == nullptr);
GPUStream *s = gpu->get_next_task_stream();
ThreadLocal::current_gpu_stream = s;
assert(!ThreadLocal::created_gpu_streams);

// a task can force context sync on task completion either on or off during
// execution, so use -1 as a "no preference" value
ThreadLocal::context_sync_required = -1;

// Push profiling information, if necessary. This completion operation
// will set just the GPU start timeline.
if (prof && prof->wants_gpu_timeline) {
auto e = gpu->event_pool.get_event();
CHECK_CU(CUDA_DRIVER_FNPTR(cuEventRecord)(e, s->get_stream()));
auto completion = new GPUProfInfoTrigger(prof, true /* start */);
s->add_event(e, nullptr, completion, nullptr, true /* return_event */);
}
}

void GPUProcessor::pop_subgraph_task_replay_context(void** token, void* trigger, SubgraphOperationProfilingInfo* prof) {
GPUStream *s = ThreadLocal::current_gpu_stream;
assert(!ThreadLocal::created_gpu_streams);

assert(!gpu->module->config->cfg_task_legacy_sync);
assert(ThreadLocal::context_sync_required == 0);

// Again, handle post-task GPU timeline information. This must happen
// before we enqueue the trigger, otherwise the profiling information
// may not get recorded by the time the subgraph finishes and it is
// sent out during subgraph cleanup. It has to handle several different
// kinds of profiling requests on operation finish.
if (prof && (prof->wants_gpu_timeline || prof->wants_timeline || prof->wants_fevent)) {
auto e = gpu->event_pool.get_event();
CHECK_CU(CUDA_DRIVER_FNPTR(cuEventRecord)(e, s->get_stream()));
auto completion = new GPUProfInfoTrigger(prof, false /* start */);
s->add_event(e, nullptr, completion, nullptr, true /* return_event */);
}

// Record an event for the completion of kernels launched by the task.
auto e = gpu->event_pool.get_event();
// Return the event to the caller. The caller is responsible
// for cleaning up this
*(CUevent_st**)(token) = e;
// Actually record the event.
CHECK_CU(CUDA_DRIVER_FNPTR(cuEventRecord)(e, s->get_stream()));

// Enqueue a poller for the completion of the launched kernels.
if (trigger) {
auto completion = static_cast<GPUCompletionNotification*>(trigger);
// The subgraph cleanup will be responsible for cleaning up
// and returning events to the pool.
s->add_event(e, nullptr, completion, nullptr, false /* return_event */);
}

ThreadLocal::current_gpu_stream = nullptr;
}

void GPUProcessor::sync_task_async_effect(void *token) {
// The GPUProcessor will only ever return CUevent_st* to the scheduler.
CUevent_st* e = (CUevent_st*)(token);
GPUStream *s = ThreadLocal::current_gpu_stream;
CHECK_CU(CUDA_DRIVER_FNPTR(cuStreamWaitEvent)(s->get_stream(), e, 0));
}

void GPUProcessor::return_subgraph_async_tokens(const std::vector<void*>& tokens) {
gpu->event_pool.return_events((CUevent_st**)tokens.data(), tokens.size());
}

GPUStream *GPU::find_stream(CUstream stream) const
{
for(std::vector<GPUStream *>::const_iterator it = task_streams.begin();
Expand Down
10 changes: 10 additions & 0 deletions src/realm/cuda/cuda_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ namespace Realm {
class GPUZCMemory;
class GPUReplHeapListener;

// TODO (rohany): Moving this out of the CUDA module (for now).
// an interface for receiving completion notification for a GPU operation
// (right now, just copies)
class GPUCompletionNotification {
public:
virtual ~GPUCompletionNotification(void) {}

virtual void request_completed(void) = 0;
};

class CudaModuleConfig : public ModuleConfig {
friend class CudaModule;

Expand Down
Loading
Loading