/home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/physics/integration/map_completion.hh Source File#

DiFfRG: /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/physics/integration/map_completion.hh Source File
DiFfRG
Discretization Framework for functional Renormalization Group flows
map_completion.hh
Go to the documentation of this file.
1#pragma once
2
3// DiFfRG
6
7// std
8#include <cstring>
9#include <exception>
10#include <functional>
11#include <type_traits>
12#include <utility>
13#include <vector>
14
15namespace DiFfRG
16{
17 namespace internal
18 {
26 inline constexpr bool has_device_backend = !std::is_same_v<typename GPU_exec::memory_space, CPU_memory>;
27 } // namespace internal
28
62 {
63 public:
64 struct PendingCopy {
65 void *dst;
66 const void *src;
67 size_t bytes;
68 };
69
73 static void record(void *dst, const void *src, const size_t bytes)
74 {
75 pending().push_back(PendingCopy{dst, src, bytes});
76 }
77
96 static void record_work(std::function<void()> job) { deferred_work().push_back(std::move(job)); }
97
108 static void flush()
109 {
110 // Host work first, and *before* the fence: the device is still chewing through whatever was
111 // launched inside the scope, so this is the window in which host kernels are free. Drained
112 // through a local so that a job which itself queues work cannot invalidate the iteration.
113 auto &w = deferred_work();
114 while (!w.empty()) {
115 std::vector<std::function<void()>> batch;
116 batch.swap(w);
117 for (auto &job : batch)
118 job();
119 }
120
121 Kokkos::fence("DiFfRG::MapCompletion::flush");
122 auto &p = pending();
123 for (const auto &c : p)
124 std::memcpy(c.dst, c.src, c.bytes);
125 p.clear();
127 }
128
134 static void discard(const char *reason)
135 {
136 // Dropped without running: the destinations may already be gone, and an unrun job is exactly
137 // as abandoned as an unlanded copy.
138 deferred_work().clear();
139 pending().clear();
141 }
142
149 static bool has_pending(const void *src)
150 {
151 for (const auto &c : pending())
152 if (c.src == src) return true;
153 return false;
154 }
155
159 static bool deferral_enabled() { return deferral(); }
160 static void set_deferral(const bool enabled)
161 {
162 deferral() = enabled;
163 // The scheduler splits a map that is flushed on return more aggressively than one inside a
164 // batch, because the ranks it leaves out have nothing else to pick up. See
165 // MapScheduler::set_batched().
167 }
168
169 private:
170 static std::vector<PendingCopy> &pending()
171 {
172 static std::vector<PendingCopy> p;
173 return p;
174 }
175 static std::vector<std::function<void()>> &deferred_work()
176 {
177 static std::vector<std::function<void()>> w;
178 return w;
179 }
180 static bool &deferral()
181 {
182 static bool enabled = false;
183 return enabled;
184 }
185 };
186
190 inline void flush_maps() { MapCompletion::flush(); }
191
219 {
220 public:
223 {
225 // Leaving via an exception means this rank abandons the batch while the others are still
226 // filling theirs. Running the collective here would deadlock; poisoning the scheduler turns
227 // the next flush into a diagnosable abort instead. Under MPI an exception thrown out of a
228 // flow block is not recoverable anyway -- the ranks have already diverged.
229 if (std::uncaught_exceptions() > 0) {
230 MapCompletion::discard("an exception was thrown inside a DeferredMaps scope");
231 return;
232 }
234 }
235 DeferredMaps(const DeferredMaps &) = delete;
237 };
238} // namespace DiFfRG
Scope in which map() results are landed lazily instead of one blocking copy per call.
Definition map_completion.hh:219
DeferredMaps & operator=(const DeferredMaps &)=delete
~DeferredMaps()
Definition map_completion.hh:222
DeferredMaps()
Definition map_completion.hh:221
DeferredMaps(const DeferredMaps &)=delete
Deferred landing of QuadratureIntegrator::map() results in host memory.
Definition map_completion.hh:62
static void set_deferral(const bool enabled)
Definition map_completion.hh:160
static bool deferral_enabled()
Whether the caller has opened a DeferredMaps scope.
Definition map_completion.hh:159
static std::vector< std::function< void()> > & deferred_work()
Definition map_completion.hh:175
static std::vector< PendingCopy > & pending()
Definition map_completion.hh:170
static void record(void *dst, const void *src, const size_t bytes)
Register a device->host result that still has to be copied from staging into dst.
Definition map_completion.hh:73
static bool has_pending(const void *src)
Whether src already has an unlanded result queued.
Definition map_completion.hh:149
static void discard(const char *reason)
Drop every pending copy without performing it, and abandon the MPI plan.
Definition map_completion.hh:134
static void flush()
Fence, land every pending map result, then exchange slices between MPI ranks.
Definition map_completion.hh:108
static bool & deferral()
Definition map_completion.hh:180
static void record_work(std::function< void()> job)
Queue a host-side map() to be run at flush time instead of now.
Definition map_completion.hh:96
void set_batched(const bool batched)
Tell the scheduler whether the caller has a deferral scope open.
Definition map_scheduler.hh:272
static MapScheduler & instance()
void poison(const char *reason)
void complete()
Exchange every slice registered since the last completion.
constexpr bool has_device_backend
Whether the default execution space is a real device.
Definition map_completion.hh:26
Definition complex_math.hh:10
void flush_maps()
Land all outstanding map() results. See MapCompletion.
Definition map_completion.hh:190
Definition map_completion.hh:64
size_t bytes
Definition map_completion.hh:67
const void * src
Definition map_completion.hh:66
void * dst
Definition map_completion.hh:65