1#ifndef SRC_APPS_CHEM_EXCHANGEOPERATOR_H_
2#define SRC_APPS_CHEM_EXCHANGEOPERATOR_H_
32 const long granularity_level) {
34 const long nsw = std::max<long>(1, nsubworld);
35 const long level = std::max<long>(1, granularity_level);
36 return std::min<long>(level * nsw,
long(n));
46 const long granularity_level) {
47 std::vector<Batch_1D> out;
48 if (n == 0)
return out;
50 const long bs_floor = long(n) / nbatch;
51 const long rem = long(n) - bs_floor * nbatch;
53 for (
long b = 0;
b < nbatch; ++
b) {
54 const long sz = bs_floor + (
b < rem ? 1 : 0);
55 out.emplace_back(begin, begin + sz);
78inline std::vector<std::pair<Batch_1D, Batch_1D>>
82 std::vector<std::pair<Batch_1D, Batch_1D>> out;
83 out.reserve(columns.size() * rows.size());
84 for (
const auto&
c : columns)
85 for (
const auto& r : rows) out.emplace_back(
c, r);
95template<
typename T, std::
size_t NDIM>
98 if (
a.size() !=
b.size())
return false;
99 for (std::size_t i = 0; i <
a.size(); ++i)
111inline std::map<std::pair<long,long>,
long>
113 std::map<std::pair<long,long>,
long> owner;
114 if (ncolumn <= 0 or nrow <= 0 or nworker <= 0)
return owner;
115 for (
long c = 0;
c < ncolumn; ++
c)
116 for (
long r = 0; r < nrow; ++r) owner[{
c, r}] =
c % nworker;
125 const long a = std::max(i, j),
b = std::min(i, j);
126 return a * (
a + 1) / 2 +
b;
147inline std::map<std::pair<long,long>,
long>
149 std::map<std::pair<long,long>,
long> owner;
150 if (n <= 0 or M <= 0)
return owner;
151 auto eligible = [n](
long i,
long j,
long t) ->
bool {
152 if (i == j)
return (i % n) == t;
153 return ((i % n) == t) or ((j % n) == t);
156 const std::size_t ntask = std::size_t(M) * std::size_t(M + 1) / 2;
157 std::vector<std::pair<long,long>> tasks;
158 tasks.reserve(ntask);
159 for (
long i = 0; i < M; ++i)
160 for (
long j = 0; j <= i; ++j)
161 tasks.emplace_back(i, j);
163 std::vector<std::vector<std::pair<long,long>>> T(n);
170 std::vector<char> taken(ntask, 0);
171 std::vector<std::size_t> cursor(n, 0);
172 std::size_t placed = 0;
173 long t = 0, misses = 0;
174 while (placed < ntask and misses < n) {
175 std::size_t&
c = cursor[t];
176 while (
c < ntask and (taken[
c] or not eligible(tasks[
c].first, tasks[
c].second, t))) ++
c;
179 T[t].push_back(tasks[
c]);
189 for (std::size_t idx = 0; idx < ntask; ++idx)
190 if (not taken[idx]) T[tasks[idx].first % n].push_back(tasks[idx]);
193 for (
long iter = 0; iter < 10000; ++iter) {
194 long big = 0,
small = 0;
195 for (
long p = 1;
p < n; ++
p) {
196 if (
long(T[
p].size()) > long(T[big].size())) big =
p;
197 if (
long(T[
p].size()) < long(T[
small].size()))
small =
p;
199 if (
long(T[big].size()) - long(T[
small].size()) <= 1)
break;
201 std::vector<long> order(n);
202 for (
long p = 0;
p < n; ++
p) order[
p] =
p;
203 std::sort(order.begin(), order.end(),
204 [&T](
long a,
long b){ return T[a].size() > T[b].size(); });
205 for (
long bi = 0; bi < n and not moved; ++bi) {
206 for (
long si = n - 1; si > bi and not moved; --si) {
207 const long bt = order[bi], st = order[si];
208 if (
long(T[bt].size()) -
long(T[st].size()) <= 1)
continue;
209 for (
long idx = 0; idx < long(T[bt].size()); ++idx) {
210 const auto& tk = T[bt][idx];
211 if (tk.first == tk.second)
continue;
212 if (not eligible(tk.first, tk.second, st))
continue;
214 T[bt].erase(T[bt].begin() + idx);
220 if (not moved)
break;
223 for (
long p = 0;
p < n; ++
p)
224 for (
const auto& tk : T[
p])
241inline std::map<std::pair<long,long>,
long>
243 std::map<std::pair<long,long>,
long> owner;
244 if (n <= 0 or M <= 0)
return owner;
245 auto C = [&](
long i,
long j) ->
double {
246 const long t =
exchange_sym_tri(i, j);
return (t <
long(cost.size())) ? cost[t] : 0.0;
248 std::vector<double>
load(n, 0.0);
250 for (
long i = 0; i < M; ++i) {
const long r = i % n;
load[r] +=
C(i,i); owner[{i,i}] = r; }
252 std::vector<std::pair<long,long>> off;
253 off.reserve(std::size_t(M) * std::size_t(M > 0 ? M - 1 : 0) / 2);
254 for (
long i = 0; i < M; ++i)
for (
long j = 0; j < i; ++j) off.emplace_back(i, j);
255 std::sort(off.begin(), off.end(), [&](
const std::pair<long,long>&
A,
const std::pair<long,long>&
B){
256 const double ca = C(A.first,A.second), cb = C(B.first,B.second);
257 return (ca != cb) ? (ca > cb) : (A < B);
259 for (
const auto& [i,j] : off) {
260 const long ri = i % n, rj = j % n;
261 const long r = (ri == rj) ? ri : (
load[ri] <=
load[rj] ? ri : rj);
262 owner[{i,j}] = r;
load[r] +=
C(i,j);
265 for (
long pass = 0; pass < 50; ++pass) {
266 long hot = 0;
for (
long p = 1;
p < n; ++
p)
if (
load[
p] >
load[hot]) hot =
p;
267 bool improved =
false;
268 for (
const auto& [i,j] : off) {
269 auto it = owner.find({i,j});
270 if (it->second != hot)
continue;
271 const long ri = i % n, rj = j % n;
272 if (ri == rj)
continue;
273 const long other = (hot == ri) ? rj : ri;
274 const double c =
C(i,j);
276 load[hot] -=
c;
load[other] +=
c; it->second = other; improved =
true;
279 if (not improved)
break;
318 if (tier == 2)
waited =
true;
324 static const bool on = (std::getenv(
"MAD_EXCH_TASK_PROFILE") !=
nullptr);
335 static const bool on = (std::getenv(
"MAD_EXCH_FORCE_GENERAL") !=
nullptr);
345 static std::ofstream os;
346 if (not os.is_open()) {
347 os.open(
"exch_taskprof.r" + std::to_string(
p.universe_rank) +
".jsonl", std::ios::app);
348 if (not os.is_open())
return;
350 os <<
"{\"task\":" <<
p.task_id
351 <<
",\"rank\":" <<
p.universe_rank
352 <<
",\"subworld\":" <<
p.subworld_id
353 <<
",\"subworld_nrank\":" <<
p.subworld_nrank
354 <<
",\"thresh\":" <<
p.thresh
356 <<
",\"diagonal\":" << (
p.diagonal ?
"true" :
"false")
357 <<
",\"row\":[" <<
p.row_begin <<
"," <<
p.row_end <<
"]"
358 <<
",\"col\":[" <<
p.col_begin <<
"," <<
p.col_end <<
"]"
359 <<
",\"wall_start\":" <<
p.wall_start
360 <<
",\"wall\":" << (
p.wall_end -
p.wall_start)
361 <<
",\"wait_for_data\":" <<
p.wait_for_data_wall
362 <<
",\"compute_wall\":" <<
p.compute_wall
363 <<
",\"compute_cpu\":" <<
p.compute_cpu
364 <<
",\"compute_components_wall\":{"
365 <<
"\"mul1\":" <<
p.mul1_wall <<
",\"apply\":" <<
p.apply_wall
366 <<
",\"mul2\":" <<
p.mul2_wall <<
",\"truncate\":" <<
p.truncate_wall
367 <<
",\"other\":" << (
p.compute_wall -
p.mul1_wall -
p.apply_wall
368 -
p.mul2_wall -
p.truncate_wall)
370 <<
",\"operand_source\":" <<
p.operand_source
371 <<
",\"waited\":" << (
p.waited ?
"true" :
"false")
372 <<
",\"peak_rss_gb\":" <<
p.peak_rss_gb
385 const std::vector<double>& cost) {
386 if (M <= 0 or cost.empty())
return;
388 std::snprintf(
name,
sizeof(
name),
"Ccall%03ld_k%ld.csv", call_index,
k);
389 std::ofstream os(
name);
390 if (not os.is_open())
return;
391 os <<
"# call=" << call_index <<
" k=" <<
k <<
" M=" << M <<
"\n";
393 for (
long i = 0; i < M; ++i)
394 for (
long j = 0; j <= i; ++j) {
395 const long t = i * (i + 1) / 2 + j;
396 if (t <
long(cost.size())) os << i <<
"," << j <<
"," << cost[t] <<
"\n";
414template<
typename T, std::
size_t NDIM>
416 std::size_t
k = 0x5a17ull;
425 std::size_t
k = std::size_t(salt);
442template<
typename keyT,
typename dataT>
450 for (
const auto& s :
slots_)
if (s.key == key)
return true;
456 for (
auto it =
slots_.begin(); it !=
slots_.end(); ++it) {
457 if (it->key == key) {
459 return &
slots_.front().data;
472 if (not it->pinned) {
slots_.erase(it);
break; }
475 return slots_.front().data;
485 for (
const auto& s :
slots_)
if (not s.pinned) ++
c;
500template <
typename T, std::
size_t NDIM>
505 template <
typename Archive>
515template <
typename T, std::
size_t NDIM>
528 dests_ = std::move(dests);
533 for (
const auto& r : recs) {
537 "exchange finalize: a chunk names a destination this rank has not "
538 "been given, so its reducer targets were never set");
539 typename implT::dcT::accessor acc;
540 dests_[r.f]->get_coeffs().insert(acc, r.key);
541 acc->second.template gaxpy_inplace<T, T>(T(1.0), r.node,
beta_);
561template <
typename T, std::
size_t NDIM>
567 const std::size_t chunk_entries) {
571 std::vector<implT*> dests(dest_vec.size(),
nullptr);
572 for (std::size_t
f = 0;
f < dest_vec.size(); ++
f)
577 std::map<ProcessID, std::vector<recT>> buckets;
578 const std::size_t nf = std::min(src_vec.size(), dest_vec.size());
579 for (std::size_t
f = 0;
f < nf; ++
f) {
580 auto simpl = src_vec[
f].get_impl();
581 auto dimpl = dest_vec[
f].get_impl();
582 if (not simpl or not dimpl)
continue;
583 const implT& dref = *dimpl;
584 for (
auto it = simpl->get_coeffs().begin(); it != simpl->get_coeffs().end(); ++it) {
585 const ProcessID owner = dref.get_coeffs().owner(it->first);
586 std::vector<recT>&
b = buckets[owner];
587 b.push_back(recT{
f, it->first, it->second});
588 if (
b.size() >= chunk_entries) {
594 for (
auto& kv : buckets)
595 if (not kv.second.empty())
600template<
typename T, std::
size_t NDIM>
615 MacroTaskExchangeSimple::reset_batch_cache_counters();
620 double t1 = double(mul1_timer) * 0.001;
621 double t2 = double(apply_timer) * 0.001;
622 double t3 = double(mul2_timer) * 0.001;
626 double resident = double(MacroTaskExchangeSimple::batch_cache_hits());
627 double fetched = double(MacroTaskExchangeSimple::batch_cache_misses());
628 double ahead = double(MacroTaskExchangeSimple::batch_prefetch_hits());
639 j[
"total"] = elapsed_time;
640 j[
"batch_cache_hits"] = long(resident);
641 j[
"batch_cache_misses"] = long(fetched);
642 j[
"batch_prefetch_hits"] = long(ahead);
647 auto timings= gather_timings(world);
648 if (world.
rank() == 0) {
649 printf(
" cpu time spent in multiply1 %8.2fs\n", timings[
"multiply1"].
template get<double>());
650 printf(
" cpu time spent in apply %8.2fs\n", timings[
"apply"].
template get<double>());
651 printf(
" cpu time spent in multiply2 %8.2fs\n", timings[
"multiply2"].
template get<double>());
652 printf(
" total wall time %8.2fs\n", timings[
"total"].
template get<double>());
655 const long resident = timings[
"batch_cache_hits"].template get<long>();
656 const long fetched = timings[
"batch_cache_misses"].template get<long>();
657 const long ahead = timings[
"batch_prefetch_hits"].template get<long>();
658 if (resident + fetched + ahead > 0)
659 printf(
" operand batches resident/ahead/fetched %6ld /%6ld /%6ld\n",
660 resident, ahead, fetched);
683 mo_bra =
copy(world, bra);
684 mo_ket =
copy(world, ket);
687 std::string
info()
const {
return "K";}
713 macro_task_info =
info;
719 if (world.
rank() == 0 && printdebug()) {
720 print(
"set macrotaskinfo to");
721 print(macro_task_info);
738 batch_granularity_ = level;
743 cost_aware_assign_ = flag;
749 accumulation_mode_ = mode;
762 j[
"symmetric"] = symmetric_;
765 j[
"mul_tol"] = mul_tol;
766 j[
"printlevel"] = printlevel;
768 j[
"macro_task_info"] = macro_task_info.
to_json();
769 auto timings = gather_timings(world);
777 vecfuncT K_macrotask_efficient(
const vecfuncT& vket,
const double mul_tol = 0.0)
const;
780 vecfuncT K_macrotask_efficient_row(
const vecfuncT& vket,
const double mul_tol = 0.0)
const;
783 vecfuncT K_small_memory(
const vecfuncT& vket,
const double mul_tol = 0.0)
const;
786 vecfuncT K_large_memory(
const vecfuncT& vket,
const double mul_tol = 0.0)
const;
790 const vecfuncT& vket, std::shared_ptr<real_convolution_3d> poisson,
791 const bool symmetric,
const double mul_tol = 0.0);
794 inline bool printprogress()
const {
return (printlevel>=4) and (not (printdebug()));}
800 bool symmetric_ =
false;
808 long batch_granularity_ = 1;
811 int accumulation_mode_ = 2;
814 bool cost_aware_assign_ =
true;
822 double mul_tol = 1.e-7;
823 bool symmetric =
false;
825 bool owner_pinned =
false;
826 long granularity_level = 1;
834 long batch_salt_ = 0;
839 bool bra_shares_ket_ =
true;
840 bool vf_shares_ket_ =
true;
844 int accumulation_mode_ = 2;
846 bool cost_aware_ =
true;
851 long universe_rank_ = 0;
860 static inline long cache_world_id_ = -1;
880 std::shared_ptr<Future<batch_bytesT>>
fut;
896 static inline long exchange_call_index_ = 0;
901 static inline long prof_task_seq_ = 0;
909 static inline bool Kf_local_initialized_ =
false;
910 static inline long Kf_local_world_id_ = -1;
912 static inline bool Kf_node_initialized_ =
false;
913 static inline long Kf_node_world_id_ = -1;
923 static inline long universe_reducer_world_id_ = -1;
925 static inline long node_reducer_world_id_ = -1;
927 static inline bool finalize_stage1_done_ =
false;
928 static inline bool finalize_universe_done_ =
false;
931 batch_cache_.
clear();
940 const std::size_t per_node = std::size_t(1) << (2 *
NDIM);
941 return std::max<std::size_t>(1, (1u << 20) / (per_node *
k *
k *
k *
sizeof(T) + 1));
947 if (not universe_reducer_ or universe_reducer_world_id_ !=
long(world.
id())) {
948 universe_reducer_ = std::make_shared<FinalizeReducer<T, NDIM>>(world);
949 universe_reducer_world_id_ = long(world.
id());
951 return *universe_reducer_;
955 if (not node_reducer_ or node_reducer_world_id_ !=
long(world.
id())) {
956 node_reducer_ = std::make_shared<FinalizeReducer<T, NDIM>>(world);
957 node_reducer_world_id_ = long(world.
id());
959 return *node_reducer_;
964 if (cache_world_id_ !=
long(world.
id())) {
965 clear_local_caches();
966 cache_world_id_ = long(world.
id());
978 ensure_cache_world(world);
979 if (
const vecfuncT* resident = batch_cache_.
find(record)) {
984 const bool owned = (cloud.
batch_owner(record) == universe_rank_);
986 for (
PrefetchSlot* slot : {&prefetch_current_, &prefetch_next_}) {
987 if (slot->valid and slot->key == record) {
988 vecfuncT data = cloud.template deserialize_batch_p2p<T, NDIM>(
989 world, *slot->fut, record,
false);
991 ++batch_prefetch_hits_;
993 return batch_cache_.
insert(record, std::move(
data), owned);
996 ++batch_cache_misses_;
998 vecfuncT data = cloud.template fetch_batch_p2p<T, NDIM>(world, record,
false);
999 return batch_cache_.
insert(record, std::move(
data), owned);
1009 const long granularity_level = 1)
1010 : symmetric(symmetric), owner_pinned(owner_pinned),
1011 granularity_level(granularity_level) {
1015 bool symmetric =
false;
1018 bool owner_pinned =
false;
1019 long granularity_level = 1;
1022 const std::string policy)
const override {
1024 if (owner_pinned and not symmetric) {
1029 Batch batch(column, row, _);
1030 result.push_back(std::make_pair(batch, compute_priority(batch)));
1039 const std::vector<Batch_1D> batches =
1042 for (
long i = 0; i < long(batches.size()); ++i) {
1043 for (
long j = 0; j <= i; ++j) {
1044 Batch batch(batches[i], batches[j], _);
1045 result.push_back(std::make_pair(batch, compute_priority(batch)));
1051 partitionT partition1 = do_1d_partition(vsize1, policy);
1052 partitionT partition2 = do_1d_partition(vsize2, policy);
1054 for (
auto i = partition1.begin(); i != partition1.end(); ++i) {
1056 for (
auto j = i; j != partition1.end(); ++j) {
1057 Batch batch(i->first.input[0], j->first.input[0], _);
1058 double priority=compute_priority(batch);
1059 result.push_back(std::make_pair(batch,priority));
1062 for (
auto j = partition2.begin(); j != partition2.end(); ++j) {
1063 Batch batch(i->first.input[0], j->first.input[0], _);
1064 double priority=compute_priority(batch);
1065 result.push_back(std::make_pair(batch,priority));
1077 long nrow = batch.
input[0].size();
1078 long ncol = batch.
input[1].size();
1079 return double(nrow * ncol);
1085 const bool symmetric,
const bool owner_pinned =
false,
1086 const long granularity_level = 1,
const long universe_rank = 0,
1087 const int accumulation_mode = 2,
const bool cost_aware =
true,
1088 const long batch_salt = 0,
const bool bra_shares_ket =
true,
1089 const bool vf_shares_ket =
true)
1090 : nresult(nresult),
lo(
lo), mul_tol(mul_tol), symmetric(symmetric),
1091 owner_pinned(owner_pinned), granularity_level(granularity_level),
1092 batch_salt_(batch_salt), bra_shares_ket_(bra_shares_ket),
1093 vf_shares_ket_(vf_shares_ket),
1094 accumulation_mode_(accumulation_mode), cost_aware_(cost_aware),
1095 universe_rank_(universe_rank) {
1097 name=
"MacroTaskExchangeSimple";
1114 batch_cache_hits_ = 0l; batch_cache_misses_ = 0l; batch_prefetch_hits_ = 0l;
1125 const long nsubworld) {
1127 if (not owner_pinned or nsubworld <= 0)
return;
1129 if (not symmetric) {
1132 std::map<long,long> column_index, row_index;
1133 for (
const auto& [task_batch, priority] : partition) {
1135 "owner-pinned exchange expects two-dimensional task batches");
1136 column_index[task_batch.input[0].begin] = 0;
1137 row_index[task_batch.input[1].begin] = 0;
1140 for (
auto& [begin, index] : column_index) index = next++;
1142 for (
auto& [begin, index] : row_index) index = next++;
1145 long(row_index.size()), nsubworld);
1146 for (
const auto& [task_batch, priority] : partition) {
1147 const long c = column_index[task_batch.input[0].begin];
1148 const long r = row_index[task_batch.input[1].begin];
1149 auto it = assignment.find({
c, r});
1150 owner_map_[{task_batch.input[0].begin, task_batch.input[1].begin}] =
1151 (it != assignment.end()) ? it->second : (
c % nsubworld);
1156 cost_this_call_.clear();
1157 batch_begin_to_index_.clear();
1161 const std::vector<Batch_1D>
split =
1163 const long M = long(
split.size());
1164 std::map<long,long> begin_to_index;
1165 for (
long k = 0;
k < M; ++
k) begin_to_index[
split[
k].begin] =
k;
1171 ++exchange_call_index_;
1172 batch_begin_to_index_ = begin_to_index;
1173 const std::size_t ntask = std::size_t(M) * std::size_t(M + 1) / 2;
1174 cost_this_call_.assign(ntask, 0.0);
1175 const bool use_cost = cost_aware_ and exchange_call_index_ >= 3
1176 and cost_reference_.size() == ntask;
1177 const std::map<std::pair<long,long>,
long> assignment =
1181 for (
const auto& [task_batch, priority] : partition) {
1183 "owner-pinned exchange expects two-dimensional task batches");
1184 const long column_begin = task_batch.input[0].begin;
1185 const long row_begin = task_batch.input[1].begin;
1186 auto ic = begin_to_index.find(column_begin);
1187 auto jr = begin_to_index.find(row_begin);
1189 "owner-pinned exchange: a task batch is not one of the split batches");
1191 const long i = std::max(ic->second, jr->second);
1192 const long j = std::min(ic->second, jr->second);
1193 auto it = assignment.find({i, j});
1194 owner_map_[{column_begin, row_begin}] =
1195 (it != assignment.end()) ? it->second : (i % nsubworld);
1205 if (not owner_pinned or nsubworld <= 0 or owner_map_.empty())
return -1;
1207 "owner-pinned exchange expects two-dimensional task batches");
1208 auto it = owner_map_.find({task_batch.
input[0].begin, task_batch.
input[1].begin});
1209 return (it != owner_map_.end()) ? it->second : -1;
1214 typedef std::tuple<const std::vector<Function<T, NDIM>>&,
1215 const std::vector<Function<T, NDIM>>&,
1223 std::size_t n = std::get<0>(argtuple).size();
1224 resultT result = zero_functions_compressed<T, NDIM>(world, n);
1246 const long nsubworld) {
1247 if (not owner_pinned)
return;
1253 "owner-pinned exchange needs one subworld per rank");
1254 const vecfuncT& vf = std::get<0>(argtuple);
1255 const vecfuncT& mo_bra = std::get<1>(argtuple);
1256 const vecfuncT& mo_ket = std::get<2>(argtuple);
1267 std::vector<std::pair<long, vecfuncT>> owned;
1270 auto stage = [&](
const vecfuncT&
v,
const int dim,
const std::vector<Batch_1D>&
split) {
1271 for (
long k = 0;
k < long(
split.size()); ++
k) {
1275 if (
k % nsubworld == world.
rank()) {
1277 for (
long i = r.
begin; i < r.
end; ++i)
1278 local[i - r.
begin] =
copy(subworld,
v[i],
false);
1279 owned.emplace_back(record, std::move(local));
1287 "exchange: bra and ket are a paired set and must have equal length");
1292 const std::vector<Batch_1D>
split =
1309 for (
auto& [record, batch] : owned)
1331 const bool has_next)
const {
1332 if (not owner_pinned)
return;
1333 ensure_cache_world(subworld);
1338 prefetch_current_ = prefetch_next_;
1340 if (not has_next or cloud_ptr ==
nullptr)
return;
1341 Cloud& cloud = *cloud_ptr;
1342 const long salt = batch_salt_;
1347 const std::vector<Batch_1D> candidates =
1348 symmetric ? std::vector<Batch_1D>{next_col, next_row}
1349 : std::vector<Batch_1D>{next_row};
1350 for (
const auto& r : candidates) {
1352 if (cloud.
batch_owner(record) == universe_rank_)
continue;
1353 if (batch_cache_.
contains(record))
continue;
1354 if (prefetch_current_.
valid and prefetch_current_.
key == record)
continue;
1355 prefetch_next_.
key = record;
1356 prefetch_next_.
fut = std::make_shared<Future<batch_bytesT>>(
1358 prefetch_next_.
valid =
true;
1372 clear_local_caches();
1373 cache_world_id_ = -1;
1376 Kf_local_initialized_ =
false;
1377 Kf_local_world_id_ = -1;
1379 Kf_node_initialized_ =
false;
1380 Kf_node_world_id_ = -1;
1381 finalize_stage1_done_ =
false;
1382 finalize_universe_done_ =
false;
1387 universe_reducer_.reset();
1388 universe_reducer_world_id_ = -1;
1389 node_reducer_.reset();
1390 node_reducer_world_id_ = -1;
1404 return owner_pinned and accumulation_mode_ == 2;
1420 std::vector<long> idx;
1421 auto add_range = [&](
const Batch_1D&
b) {
1422 const long s =
b.is_full_size() ? 0 :
b.begin;
1423 const long e =
b.is_full_size() ? long(nresult) :
b.end;
1424 for (
long i = s; i <
e and i < long(nresult); ++i) idx.push_back(i);
1426 if (batch.input.empty()) {
1427 for (
long i = 0; i < long(nresult); ++i) idx.push_back(i);
1430 add_range(batch.input[0]);
1431 if (symmetric and batch.input.size() > 1 and not (batch.input[1] == batch.input[0]))
1432 add_range(batch.input[1]);
1433 std::sort(idx.begin(), idx.end());
1434 idx.erase(std::unique(idx.begin(), idx.end()), idx.end());
1440 const long wid = long(subworld.
id());
1441 if (not Kf_local_initialized_ or Kf_local_world_id_ != wid) {
1442 Kf_local_ = zero_functions_compressed<T, NDIM>(subworld, nresult);
1443 Kf_local_initialized_ =
true;
1444 Kf_local_world_id_ = wid;
1448 const std::vector<long> touched = touched_result_indices();
1450 rs_sub.reserve(touched.size());
1451 kf_sub.reserve(touched.size());
1452 for (
long i : touched) { rs_sub.push_back(result_subworld[i]); kf_sub.push_back(Kf_local_[i]); }
1453 if (rs_sub.empty())
return;
1457 gaxpy(1.0, kf_sub, 1.0, rs_sub,
false);
1468 const long wid = long(nodeworld.
id());
1469 if (Kf_node_initialized_ and Kf_node_world_id_ == wid)
return;
1471 Kf_node_.resize(nresult);
1472 for (
long i = 0; i < nresult; ++i)
1478 Kf_node_initialized_ =
true;
1479 Kf_node_world_id_ = wid;
1484 if (not nodeworld)
return;
1485 if (finalize_stage1_done_)
return;
1486 finalize_stage1_done_ =
true;
1487 ensure_node_accumulator(*nodeworld);
1490 vecfuncT& src = Kf_local_initialized_ ? Kf_local_ : empty;
1491 coalesced_gaxpy<T, NDIM>(*nodeworld, get_node_reducer(*nodeworld),
1492 Kf_node_, src, T(1.0), finalize_chunk_entries());
1497 if (finalize_universe_done_)
return;
1498 finalize_universe_done_ =
true;
1499 if (universe_result.empty())
return;
1500 World& universe = universe_result.front().world();
1504 if (Kf_node_initialized_) src = &Kf_node_;
1506 if (Kf_local_initialized_) {
1513 coalesced_gaxpy<T, NDIM>(universe, get_universe_reducer(universe),
1514 universe_result, *src, T(1.0), finalize_chunk_entries());
1518 std::vector<Function<T, NDIM>>
1525 MADNESS_CHECK_THROW(subworld_ptr !=
nullptr,
"MacroTaskExchangeSimple: subworld_ptr is null");
1526 World& world = *subworld_ptr;
1527 resultT Kf = zero_functions_compressed<T, NDIM>(world, nresult);
1529 bool diagonal_block = batch.input[0] == batch.input[1];
1530 auto& bra_range = batch.input[1];
1531 auto& vf_range = batch.input[0];
1533 if (vf_range.is_full_size()) vf_range.end = vf_batch.size();
1534 if (bra_range.is_full_size()) bra_range.end = bra_batch.size();
1539 const double tile_wall_start =
wall_time();
1540 const bool profiling = profile_active();
1543 prof_.
task_id = prof_task_seq_++;
1558 vecfuncT bra_owned, vf_owned, ket_row_owned, ket_column_owned;
1559 const vecfuncT* bra_work = &bra_batch;
1560 const vecfuncT* vf_work = &vf_batch;
1563 Cloud& cloud = *cloud_ptr;
1564 const long salt = batch_salt_;
1571 bra_owned = fetch_batch(world, cloud,
1573 vf_owned = fetch_batch(world, cloud,
1575 ket_row_owned = fetch_batch(world, cloud,
1577 ket_column_owned = diagonal_block
1579 : fetch_batch(world, cloud,
1585 vf_owned = fetch_batch(world, cloud,
1587 bra_owned = fetch_batch(world, cloud,
1589 ket_row_owned = fetch_batch(world, cloud,
1592 bra_work = &bra_owned;
1593 vf_work = &vf_owned;
1596 const double compute_wall_start =
wall_time();
1597 const double compute_cpu_start = process_cpu_time();
1602 const vecfuncT ket_rows = owner_pinned ? ket_row_owned : bra_range.copy_batch(vket);
1604 if (symmetric and diagonal_block) {
1605 vecfuncT resultcolumn = compute_diagonal_batch_in_symmetric_matrix(world, ket_rows, *bra_work,
1608 for (
int i = vf_range.begin; i < vf_range.end; ++i){
1609 Kf[i] += resultcolumn[i - vf_range.begin];}
1611 }
else if (symmetric and not diagonal_block) {
1612 const vecfuncT ket_columns = owner_pinned ? ket_column_owned
1613 : vf_range.copy_batch(vket);
1614 auto[resultcolumn, resultrow]=compute_offdiagonal_batch_in_symmetric_matrix(world, ket_rows,
1616 *bra_work, *vf_work);
1618 for (
int i = bra_range.begin; i < bra_range.end; ++i){
1619 Kf[i] += resultcolumn[i - bra_range.begin];}
1620 for (
int i = vf_range.begin; i < vf_range.end; ++i){
1621 Kf[i] += resultrow[i - vf_range.begin];}
1623 vecfuncT resultcolumn = compute_batch_in_asymmetric_matrix(world, ket_rows,
1624 *bra_work, *vf_work);
1625 for (
int i = vf_range.begin; i < vf_range.end; ++i)
1626 Kf[i] += resultcolumn[i - vf_range.begin];
1634 prof_.
compute_cpu = process_cpu_time() - compute_cpu_start;
1641 if (owner_pinned and not cost_this_call_.empty()) {
1642 const auto ic = batch_begin_to_index_.find(vf_range.begin);
1643 const auto jr = batch_begin_to_index_.find(bra_range.begin);
1644 if (ic != batch_begin_to_index_.end() and jr != batch_begin_to_index_.end()) {
1646 if (t <
long(cost_this_call_.size()))
1647 cost_this_call_[t] +=
wall_time() - tile_wall_start;
1670 "symmetric diagonal tile: ket/bra batch size mismatch");
1672 "symmetric diagonal tile: vf/bra batch size mismatch");
1674 const long n = long(vf_batch.size());
1675 vecfuncT resultcolumn = zero_functions_compressed<T, NDIM>(subworld, n);
1679 const bool prof_on = profile_active();
1680 auto tick = [&](
double& acc,
const double t0) {
if (prof_on) acc +=
wall_time() - t0; };
1682 for (
long i = 0; i < n; ++i) {
1684 double w0 = prof_on ?
wall_time() : 0.0;
1685 const vecfuncT vf_subset(vf_batch.begin(), vf_batch.begin() + i + 1);
1692 mul1_timer += long((cpu1 - cpu0) * 1000l);
1696 psif =
apply(subworld, *poisson.get(), psif);
1702 apply_timer += long((cpu1 - cpu0) * 1000l);
1707 vecfuncT update = zero_functions_compressed<T, NDIM>(subworld, n);
1708 double w1 = prof_on ?
wall_time() : 0.0;
1712 for (
long j = 0; j <= i; ++j)
update[j] += row_contrib[j];
1713 for (
long j = 0; j < i; ++j) {
1718 update[i] += mirrored[0];
1722 mul2_timer += long((cpu1 - cpu0) * 1000l);
1725 return resultcolumn;
1739 double symmetric =
false;
1750 std::pair<vecfuncT, vecfuncT> compute_offdiagonal_batch_in_symmetric_matrix(
World& subworld,
1762 double mul_tol = 1.e-7;
1763 bool symmetric =
false;
1776 : nresult(nresult),
lo(
lo), mul_tol(mul_tol), algorithm_(algorithm) {
1778 name=
"MacroTaskExchangeRow";
1782 typedef std::tuple<const std::vector<Function<T, NDIM>>&,
1783 const std::vector<Function<T, NDIM>>&,
1791 std::size_t n = std::get<0>(argtuple).size();
1792 resultT result = zero_functions_compressed<T, NDIM>(world, n);
1800 std::vector<Function<T, NDIM>>
1804 std::vector<Function<T,NDIM>> result;
1805 if (algorithm_==fetch_compute) {
1806 result=row_fetch_compute(vket,mo_bra,mo_ket);
1807 }
else if (algorithm_==multiworld_efficient_row) {
1808 result=row(vket,mo_bra,mo_ket);
1810 MADNESS_EXCEPTION(
"unknown algorithm in Exchange::MacroTaskExchangeRow::operator()",1);
1815 std::vector<Function<T,NDIM>>
1821 World& world = vket.front().world();
1823 resultT Kf = zero_functions_compressed<T, NDIM>(world, 1);
1824 vecfuncT psif = zero_functions_compressed<T,NDIM>(world, mo_bra.
size());
1830 MADNESS_CHECK_THROW(vket.size()==1,
"out-of-bounds error in Exchange::MacroTaskExchangeRow::operator()");
1831 size_t min_tile = 10;
1832 size_t ntile = std::min(mo_bra.size(), min_tile);
1834 for (
size_t ilo=0; ilo<mo_bra.size(); ilo+=ntile){
1836 size_t iend = std::min(ilo+ntile,mo_bra.size());
1837 vecfuncT tmp_mo_bra(mo_bra.begin()+ilo,mo_bra.begin()+iend);
1838 auto tmp_psif =
mul_sparse(world, vket[i], tmp_mo_bra, mul_tol);
1841 mul1_timer += long((cpu1 - cpu0) * 1000l);
1844 tmp_psif =
apply(world, *poisson.get(), tmp_psif);
1847 apply_timer += long((cpu1 - cpu0) * 1000l);
1850 vecfuncT tmp_mo_ket(mo_ket.begin()+ilo,mo_ket.begin()+iend);
1852 auto tmp_Kf =
dot(world, tmp_mo_ket, tmp_psif,
true,
true, mul_tol);
1854 mul2_timer += long((cpu1 - cpu0) * 1000l);
1863 std::vector<Function<T,NDIM>>
1869 double total_execution_time=0.0;
1870 double total_fetch_time=0.0;
1871 double total_fetch_spawn_time=0.0;
1873 resultT Kf = zero_functions_compressed<T, NDIM>(*subworld_ptr, 1);
1879 std::shared_ptr<World> fetching_world(
new World(comm.
Clone()));
1880 std::shared_ptr<World> executing_world(
new World(comm.
Clone()));
1882 print(
"time to create two worlds:",cpu1-cpu0,
"seconds");
1883 print(
"executing_world.id()",executing_world->id(),
"fetching_world.id()",fetching_world->id(),
"in MacroTaskExchangeRow");
1894 MADNESS_CHECK_THROW(vket.size()==1,
"out-of-bounds error in Exchange::MacroTaskExchangeRow::operator()");
1895 size_t min_tile = 10;
1896 size_t ntile = std::min(mo_bra.size(), min_tile);
1906 auto fetch_data = [&](
World& world,
const Tile& tile) {
1908 "bra and ket size mismatch in Exchange::MacroTaskExchangeRow::execute()");
1910 std::size_t sz=tile.iend-tile.ilo;
1913 for (
size_t i=tile.ilo; i<tile.iend; ++i) {
1914 auto f=
copy(world,mo_bra[i],
false);
1915 subworld_bra[i-tile.ilo]=
f;
1916 subworld_ket.push_back(
copy(world, mo_ket[i],
false));
1918 return std::make_pair(subworld_bra,subworld_ket);
1924 "bra and ket size mismatch in Exchange::MacroTaskExchangeRow::execute()");
1926 auto world_id=world.
id();
1927 auto phi_id=phi.world().id();
1928 auto bra_id=mo_bra.front().world().id();
1929 auto ket_id=mo_ket.front().world().id();
1930 std::string msg=
"world mismatch in Exchange::MacroTaskExchangeRow::execute(): ";
1931 msg+=
"world.id()="+std::to_string(world_id)+
", ";
1932 msg+=
"phi.world().id()="+std::to_string(phi_id)+
", ";
1933 msg+=
"bra.world().id()="+std::to_string(bra_id)+
", ";
1934 msg+=
"ket.world().id()="+std::to_string(ket_id);
1935 if (not (world_id==phi_id && world_id==bra_id && world_id==ket_id)) {
1938 MADNESS_CHECK_THROW(world_id==phi_id && world_id==bra_id && world_id==ket_id,msg.c_str());
1941 auto tmp_psif =
mul_sparse(world, phi, mo_bra, mul_tol);
1944 mul1_timer += long((cpu1 - cpu0) * 1000l);
1947 tmp_psif =
apply(world, *poisson.get(), tmp_psif);
1950 apply_timer += long((cpu1 - cpu0) * 1000l);
1953 auto tmp_Kf =
dot(world, mo_ket, tmp_psif);
1955 mul2_timer += long((cpu1 - cpu0) * 1000l);
1957 return tmp_Kf.truncate();
1961 std::vector<Tile> tiles;
1962 for (
size_t ilo=0; ilo<mo_bra.size(); ilo+=ntile) {
1963 tiles.push_back(Tile{ilo,std::min(ilo+ntile,mo_bra.size())});
1969 for (
size_t itile=0; itile<tiles.size(); ++itile) {
1970 Tile& tile = tiles[itile];
1974 print(
"fetching tile",tile.ilo,
"into world",executing_world->id());
1975 std::tie(tmp_mo_bra1,tmp_mo_ket1)=fetch_data(*executing_world,tiles[itile]);
1976 fetching_world->gop.set_forbid_fence(
false);
1978 executing_world->gop.fence();
1980 total_fetch_time += (t1 - t0);
1981 total_fetch_spawn_time += (t2 - t0);
1985 fetching_world->gop.set_forbid_fence(
true);
1986 if (itile<tiles.size()-1) {
1988 print(
"fetching tile",tiles[itile+1].ilo,
"into world",fetching_world->id(),
" at time ",
wall_time());
1989 std::tie(tmp_mo_bra2,tmp_mo_ket2)=fetch_data(*fetching_world,tiles[itile+1]);
1991 fetching_world->gop.set_forbid_fence(
false);
1996 total_fetch_time += (t1 - t0);
1997 total_fetch_spawn_time += (t2 - t0);
1999 print(
"executing tile",tile.ilo,
"in world",executing_world->id());
2001 Kf[0]+=execute(*executing_world,poisson1,phi1,tmp_mo_bra1,tmp_mo_ket1);
2003 print(
"time to execute tile",tile.ilo,
"in world",executing_world->id(),dpu1-dpu0,
"seconds");
2004 total_execution_time += dpu1-dpu0;
2006 fetching_world->gop.fence();
2009 std::swap(poisson1,poisson2);
2010 std::swap(phi1,phi2);
2011 std::swap(tmp_mo_bra2,tmp_mo_bra1);
2012 std::swap(tmp_mo_ket2,tmp_mo_ket1);
2013 std::swap(executing_world,fetching_world);
2018 fetching_world->gop.fence();
2019 executing_world->gop.fence();
2021 print(
"overall time: ",cpu2-cpu0,
"seconds");
2022 print(
"total execution time:",total_execution_time,
"seconds");
2023 print(
"total fetch time:",total_fetch_time,
"seconds");
2024 print(
"total fetch spawn time:",total_fetch_spawn_time,
"seconds");
Operators for the molecular HF and DFT code.
static const double small
Definition binaryop.cc:117
Definition test_ar.cc:118
Definition test_ar.cc:141
Definition test_ar.cc:170
Wrapper around MPI_Comm. Has a shallow copy constructor; use Create(Get_group()) for deep copy.
Definition safempi.h:497
Intracomm Clone() const
Definition safempi.h:696
Definition macrotaskpartitioner.h:55
long size() const
Definition macrotaskpartitioner.h:71
long end
first and first past last index [begin,end)
Definition macrotaskpartitioner.h:59
long begin
Definition macrotaskpartitioner.h:59
a batch consists of a 2D-input batch and a 1D-output batch: K-batch <- (I-batch, J-batch)
Definition macrotaskpartitioner.h:124
std::vector< Batch_1D > input
Definition macrotaskpartitioner.h:127
cloud class
Definition cloud.h:338
Future< batch_bytesT > request_batch_bytes_async(const keyT record) const
start fetching record from its owner; the trigger is in flight on return
Definition cloud.h:1044
ProcessID batch_owner(const keyT record) const
the owner of a batch record; a pmap lookup, no communication
Definition cloud.h:1004
void register_batch_owner(const keyT record, const ProcessID owner)
Register the owner of a batch record; local map insert, no communication.
Definition cloud.h:782
keyT store_batch(madness::World &world, const std::vector< Function< T, NDIM > > &batch, const ProcessID owner, const keyT record, const bool fence=true)
Store a batch of functions as one owner-pinned record.
Definition cloud.h:796
Bounded cache of fetched exchange batches, keyed by cloud record key.
Definition exchangeoperator.h:443
std::list< Slot > slots_
Definition exchangeoperator.h:491
void set_transient_capacity(const std::size_t c)
how many non-owned entries may be resident; at least one is always allowed
Definition exchangeoperator.h:446
std::size_t size() const
Definition exchangeoperator.h:481
std::size_t transient_capacity_
Definition exchangeoperator.h:492
void clear()
drop every entry; the capacity setting survives
Definition exchangeoperator.h:479
std::size_t transient_capacity() const
Definition exchangeoperator.h:447
bool contains(const keyT &key) const
Definition exchangeoperator.h:449
std::size_t n_transient() const
Definition exchangeoperator.h:483
const dataT & insert(const keyT &key, dataT &&data, const bool pinned)
Insert as most-recently-used. pinned marks a batch this rank owns.
Definition exchangeoperator.h:466
const dataT * find(const keyT &key)
Definition exchangeoperator.h:455
custom partitioning for the exchange operator in exchangeoperator.h
Definition exchangeoperator.h:1767
MacroTaskPartitionerRow()
Definition exchangeoperator.h:1769
Definition exchangeoperator.h:1758
resultT allocator(World &world, const argtupleT &argtuple) const
Definition exchangeoperator.h:1790
std::vector< Function< T, NDIM > > row_fetch_compute(const std::vector< Function< T, NDIM > > &vket, const std::vector< Function< T, NDIM > > &mo_bra, const std::vector< Function< T, NDIM > > &mo_ket)
Definition exchangeoperator.h:1864
std::vector< Function< T, NDIM > > operator()(const std::vector< Function< T, NDIM > > &vket, const std::vector< Function< T, NDIM > > &mo_bra, const std::vector< Function< T, NDIM > > &mo_ket)
compute exchange row-wise for a fixed orbital phi_i of vket
Definition exchangeoperator.h:1801
long nresult
Definition exchangeoperator.h:1760
std::tuple< const std::vector< Function< T, NDIM > > &, const std::vector< Function< T, NDIM > > &, const std::vector< Function< T, NDIM > > & > argtupleT
Definition exchangeoperator.h:1784
std::vector< Function< T, NDIM > > row(const std::vector< Function< T, NDIM > > &vket, const std::vector< Function< T, NDIM > > &mo_bra, const std::vector< Function< T, NDIM > > &mo_ket)
Definition exchangeoperator.h:1816
std::vector< Function< T, NDIM > > resultT
Definition exchangeoperator.h:1786
Algorithm algorithm_
Definition exchangeoperator.h:1764
MacroTaskExchangeRow(const long nresult, const double lo, const double mul_tol, const Algorithm algorithm)
Definition exchangeoperator.h:1775
custom partitioning for the exchange operator in exchangeoperator.h
Definition exchangeoperator.h:1006
double compute_priority(const Batch &batch) const override
compute the priority of this task for non-dumb scheduling
Definition exchangeoperator.h:1075
MacroTaskPartitionerExchange(const bool symmetric, const bool owner_pinned=false, const long granularity_level=1)
Definition exchangeoperator.h:1008
partitionT do_partitioning(const std::size_t &vsize1, const std::size_t &vsize2, const std::string policy) const override
override this if you want your own partitioning
Definition exchangeoperator.h:1021
Definition exchangeoperator.h:818
void ensure_cache_world(World &world) const
drop cached batches when the subworld changes; they belong to the old one
Definition exchangeoperator.h:963
static std::shared_ptr< FinalizeReducer< T, NDIM > > node_reducer_
Definition exchangeoperator.h:924
vecfuncT compute_diagonal_batch_in_symmetric_matrix(World &subworld, const vecfuncT &ket_batch, const vecfuncT &bra_batch, const vecfuncT &vf_batch) const
compute a batch of the exchange matrix, with identical ranges, exploiting the matrix symmetry
Definition exchangeoperator.h:1664
static long exchange_call_index()
Definition exchangeoperator.h:1108
static void clear_local_caches()
Definition exchangeoperator.h:930
void finalize_stage1(World &subworld, World *nodeworld)
reduce this subworld's accumulator into the node-shared one
Definition exchangeoperator.h:1483
static void commit_cost_reference()
make this call's measured costs the reference for the next one
Definition exchangeoperator.h:1112
static long batch_cache_hits()
Definition exchangeoperator.h:1102
void cleanup() override
Drop the cached batches while the subworld holding them is still alive.
Definition exchangeoperator.h:1371
static std::vector< double > cost_reference_
What each task cost last time, to place them better this time.
Definition exchangeoperator.h:893
bool wants_node_local_reduction() const
Definition exchangeoperator.h:1403
static ExchangeBatchLRU< long, vecfuncT > batch_cache_
Batches fetched from the cloud, reused across the tasks that run in one subworld.
Definition exchangeoperator.h:859
static FinalizeReducer< T, NDIM > & get_universe_reducer(World &world)
Definition exchangeoperator.h:946
void finalize_stage2(World &subworld, World *nodeworld, vecfuncT &universe_result)
drain into the universe result, from the node accumulator if there is one
Definition exchangeoperator.h:1496
static vecfuncT Kf_local_
Definition exchangeoperator.h:908
static std::vector< double > & cost_this_call()
Definition exchangeoperator.h:1107
bool profile_active() const
per-task profiling on for this task?
Definition exchangeoperator.h:1106
long nresult
Definition exchangeoperator.h:820
static std::map< long, long > batch_begin_to_index_
batch offset -> index
Definition exchangeoperator.h:895
static std::atomic< long > batch_cache_hits_
Definition exchangeoperator.h:861
std::vector< Function< T, NDIM > > resultT
Definition exchangeoperator.h:1218
vecfuncT compute_batch_in_asymmetric_matrix(World &subworld, const vecfuncT &ket_batch, const vecfuncT &bra_batch, const vecfuncT &vf_batch) const
compute a batch of the exchange matrix, with non-identical ranges
Definition exchangeoperator.h:1735
void ensure_node_accumulator(World &nodeworld) const
Collectively (re)build the node-shared accumulator in the node world.
Definition exchangeoperator.h:1467
static FinalizeReducer< T, NDIM > & get_node_reducer(World &world)
Definition exchangeoperator.h:954
void prepare_owner_assignment(const MacroTaskPartitioner::partitionT &partition, const long nsubworld)
Assign every task to the rank that will own one of its two batches.
Definition exchangeoperator.h:1124
static PrefetchSlot prefetch_next_
requested during this task
Definition exchangeoperator.h:883
void sym_pipeline_advance(World &subworld, const vecfuncT &, const Batch_1D &next_col, const Batch_1D &next_row, const bool has_next) const
Request the batch the next task will have to fetch, before computing this one.
Definition exchangeoperator.h:1329
bool accumulates_own_output() const override
Definition exchangeoperator.h:1397
static long batch_cache_misses()
Definition exchangeoperator.h:1103
void accumulate_locally(World &subworld, const vecfuncT &result_subworld) const
sum one tile's result into this subworld's accumulator
Definition exchangeoperator.h:1439
std::vector< long > touched_result_indices() const
The result entries this tile actually wrote.
Definition exchangeoperator.h:1419
ExchTaskProfile prof_
Definition exchangeoperator.h:900
std::vector< Function< T, NDIM > > operator()(const std::vector< Function< T, NDIM > > &vf_batch, const std::vector< Function< T, NDIM > > &bra_batch, const std::vector< Function< T, NDIM > > &vket)
Definition exchangeoperator.h:1519
std::tuple< const std::vector< Function< T, NDIM > > &, const std::vector< Function< T, NDIM > > &, const std::vector< Function< T, NDIM > > & > argtupleT
Definition exchangeoperator.h:1216
bool handles_own_data_movement() const override
the owner-pinned path fetches its operand batches from the cloud itself
Definition exchangeoperator.h:1364
resultT allocator(World &world, const argtupleT &argtuple) const
Definition exchangeoperator.h:1222
static void reset_batch_cache_counters()
Definition exchangeoperator.h:1113
static long batch_prefetch_hits()
Definition exchangeoperator.h:1104
static std::atomic< long > batch_cache_misses_
Definition exchangeoperator.h:862
int bra_role() const
the record role carrying the bra, and the one carrying the vf over a shared split
Definition exchangeoperator.h:1200
static std::vector< double > cost_this_call_
rank-local, summed after the call
Definition exchangeoperator.h:894
std::map< std::pair< long, long >, long > owner_map_
Definition exchangeoperator.h:849
const vecfuncT & fetch_batch(World &world, Cloud &cloud, const long record) const
Fetch one owner-pinned batch, from the local cache if it is resident.
Definition exchangeoperator.h:977
static long cost_matrix_dimension()
number of batches this application split into, which squares to the cost matrix
Definition exchangeoperator.h:1110
MacroTaskExchangeSimple(const long nresult, const double lo, const double mul_tol, const bool symmetric, const bool owner_pinned=false, const long granularity_level=1, const long universe_rank=0, const int accumulation_mode=2, const bool cost_aware=true, const long batch_salt=0, const bool bra_shares_ket=true, const bool vf_shares_ket=true)
Definition exchangeoperator.h:1084
void store_batches(World &world, World &subworld, Cloud &cloud, const argtupleT &argtuple, const long nsubworld)
Store the orbitals as owner-pinned batches, one record per batch.
Definition exchangeoperator.h:1245
static PrefetchSlot prefetch_current_
promoted from the previous task
Definition exchangeoperator.h:882
static std::atomic< long > batch_prefetch_hits_
Definition exchangeoperator.h:863
static vecfuncT Kf_node_
Definition exchangeoperator.h:911
static std::size_t finalize_chunk_entries()
entries per chunk in coalesced_gaxpy, sized so one message stays modest at any k
Definition exchangeoperator.h:938
int vf_role() const
Definition exchangeoperator.h:1201
static std::shared_ptr< FinalizeReducer< T, NDIM > > universe_reducer_
Receiving endpoints for the two drains, one per world they transfer within.
Definition exchangeoperator.h:922
long owner_hint(const Batch &task_batch, const long nsubworld) const override
Definition exchangeoperator.h:1204
Definition exchangeoperator.h:601
static std::atomic< long > mul1_timer
timing
Definition exchangeoperator.h:607
Exchange< T, NDIM >::ExchangeAlgorithm Algorithm
Definition exchangeoperator.h:665
bool printtimings() const
Definition exchangeoperator.h:795
ExchangeImpl & symmetric(const bool flag)
Definition exchangeoperator.h:707
ExchangeImpl & set_printlevel(const long &level)
Definition exchangeoperator.h:731
nlohmann::json statistics
statistics of the Cloud (timings, memory) and of the parameters of this run
Definition exchangeoperator.h:816
static double elapsed_time
Definition exchangeoperator.h:608
void print_timer(World &world) const
Definition exchangeoperator.h:646
ExchangeImpl & set_batch_granularity(const long level)
Definition exchangeoperator.h:736
World & get_world() const
Definition exchangeoperator.h:755
ExchangeImpl & set_macro_task_info(const std::vector< std::string > &info)
Definition exchangeoperator.h:717
nlohmann::json get_statistics() const
Definition exchangeoperator.h:757
ExchangeImpl & set_macro_task_info(const MacroTaskInfo &info)
Definition exchangeoperator.h:712
static void reset_timer()
Definition exchangeoperator.h:610
vecfuncT mo_bra
is the exchange matrix symmetric? K phi_i = \sum_k \phi_k \int \phi_k \phi_i
Definition exchangeoperator.h:801
World & world
Definition exchangeoperator.h:798
std::shared_ptr< MacroTaskQ > taskq
Definition exchangeoperator.h:799
Function< T, NDIM > functionT
Definition exchangeoperator.h:602
nlohmann::json gather_statistics() const
return some statistics about the current settings
Definition exchangeoperator.h:760
bool is_symmetric() const
Definition exchangeoperator.h:700
ExchangeImpl & set_taskq(std::shared_ptr< MacroTaskQ > taskq1)
Definition exchangeoperator.h:702
std::vector< functionT > vecfuncT
Definition exchangeoperator.h:603
ExchangeImpl & set_cost_aware_assignment(const bool flag)
Definition exchangeoperator.h:742
ExchangeImpl & set_algorithm(const Algorithm &alg)
Definition exchangeoperator.h:726
bool printprogress() const
Definition exchangeoperator.h:794
static std::atomic< long > apply_timer
Definition exchangeoperator.h:605
ExchangeImpl & set_accumulation_mode(const int mode)
Definition exchangeoperator.h:747
ExchangeImpl(World &world, const double lo, const double thresh)
default ctor
Definition exchangeoperator.h:670
std::string info() const
Definition exchangeoperator.h:687
nlohmann::json gather_timings(World &world) const
Definition exchangeoperator.h:619
bool printtimings_detail() const
Definition exchangeoperator.h:796
bool printdebug() const
Definition exchangeoperator.h:793
std::shared_ptr< MacroTaskQ > get_taskq() const
Definition exchangeoperator.h:753
static auto set_poisson(World &world, const double lo, const double econv=FunctionDefaults< 3 >::get_thresh())
Definition exchangeoperator.h:689
static std::atomic< long > mul2_timer
Definition exchangeoperator.h:606
void set_bra_and_ket(const vecfuncT &bra, const vecfuncT &ket)
set the bra and ket orbital spaces, and the occupation
Definition exchangeoperator.h:682
Definition SCFOperators.h:105
static std::string to_string(const ExchangeAlgorithm alg)
Definition SCFOperators.h:144
ExchangeAlgorithm
Definition SCFOperators.h:117
@ multiworld_efficient_row
Definition SCFOperators.h:118
Function< T, NDIM > operator()(const Function< T, NDIM > &ket) const
Definition SCFOperators.h:207
std::vector< functionT > vecfuncT
Definition SCFOperators.h:111
std::string info() const
print some information about this operator
Definition SCFOperators.h:173
Receiving end of the exchange finalize, living in the world the transfer rides on.
Definition exchangeoperator.h:516
T beta_
Definition exchangeoperator.h:547
FinalizeReducer(World &world)
Definition exchangeoperator.h:521
std::vector< implT * > dests_
Definition exchangeoperator.h:546
FinalizeNodeRec< T, NDIM > recT
Definition exchangeoperator.h:519
FunctionImpl< T, NDIM > implT
Definition exchangeoperator.h:518
void accumulate_chunk(const std::vector< recT > &recs)
Definition exchangeoperator.h:532
void set_targets(std::vector< implT * > dests, T beta)
point at the destinations for the next drain; local, called by every rank
Definition exchangeoperator.h:527
FunctionDefaults holds default paramaters as static class members.
Definition funcdefaults.h:100
static const double & get_thresh()
Returns the default threshold.
Definition funcdefaults.h:177
FunctionFactory implements the named-parameter idiom for Function.
Definition function_factory.h:86
FunctionImpl holds all Function state to facilitate shallow copy semantics.
Definition funcimpl.h:970
FunctionNode holds the coefficients, etc., at each node of the 2^NDIM-tree.
Definition funcimpl.h:136
A multiresolution adaptive numerical function.
Definition mra.h:144
Key is the index for a node of the 2^NDIM-tree.
Definition key.h:70
Definition macrotaskq.h:1604
partition one (two) vectors into 1D (2D) batches.
Definition macrotaskpartitioner.h:182
std::list< std::pair< Batch, double > > partitionT
Definition macrotaskpartitioner.h:186
The Nemo class.
Definition nemo.h:362
nlohmann::json statistics
Definition SCFOperators.h:64
std::shared_ptr< MacroTaskQ > taskq
Definition SCFOperators.h:71
void fence(bool debug=false)
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition worldgop.cc:176
void sum(T *buf, size_t nelem)
Inplace global sum while still processing AM & tasks.
Definition worldgop.h:890
Implements most parts of a globally addressable object (via unique ID).
Definition world_object.h:491
void process_pending()
To be called from derived constructor to process pending messages.
Definition world_object.h:787
detail::task_result_type< memfnT >::futureT task(ProcessID dest, memfnT memfn, const TaskAttributes &attr=TaskAttributes()) const
Sends task to derived class method returnT (this->*memfn)().
Definition world_object.h:1132
A parallel world class.
Definition world.h:134
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:344
ProcessID size() const
Returns the number of processes in this World (same as MPI_Comm_size()).
Definition world.h:354
unsigned long id() const
Definition world.h:324
WorldGopInterface & gop
Global operations.
Definition world.h:216
Declares the Cloud class for storing data and transfering them between worlds.
double(* f)(const coord_3d &)
Definition derivatives.cc:54
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
static double lo
Definition dirac-hatom.cc:23
std::vector< Spinor > truncate(std::vector< Spinor > arg)
Definition dirac-hatom.cc:503
Fcwf apply(World &world, real_convolution_3d &op, const Fcwf &psi)
Definition fcwf.cc:281
Fcwf copy(Fcwf psi)
Definition fcwf.cc:338
const double beta
Definition gygi_soltion.cc:62
static const double v
Definition hatom_sf_dirac.cc:20
Declares the macrotaskq and MacroTaskBase classes.
General header file for using MADNESS.
#define MADNESS_CHECK(condition)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:182
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
#define MADNESS_CHECK_THROW(condition, msg)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:207
Function< double, 3 > functionT
Definition mcpfit.cc:50
vector< functionT > vecfuncT
Definition mcpfit.cc:51
void print(const tensorT &t)
Definition mcpfit.cc:140
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
std::vector< std::pair< Batch_1D, Batch_1D > > exchange_row_owner_grid(const std::size_t ncolumn, const std::size_t nrow, const long nsubworld)
The asymmetric task grid: every (column, row) pair over two independent splits.
Definition exchangeoperator.h:79
long exchange_sym_owner_nbatch(const std::size_t n, const long nsubworld, const long granularity_level)
Number of batches M for the owner-pinned symmetric exchange algorithm.
Definition exchangeoperator.h:31
double get_rss_usage_in_GB()
Definition ranks_and_hosts.cpp:10
void coalesced_gaxpy(World &transport_world, FinalizeReducer< T, NDIM > &reducer, std::vector< Function< T, NDIM > > &dest_vec, std::vector< Function< T, NDIM > > &src_vec, const T beta, const std::size_t chunk_entries)
Accumulate src_vec into dest_vec in bulk, one message per destination rank per chunk.
Definition exchangeoperator.h:562
std::vector< Batch_1D > exchange_sym_owner_split(const std::size_t n, const long nsubworld, const long granularity_level)
Split a vector of length n into M = exchange_sym_owner_nbatch(...) contiguous batches.
Definition exchangeoperator.h:45
std::map< std::pair< long, long >, long > exchange_sym_cost_aware_assign(const long n, const long M, const std::vector< double > &cost)
Cost-aware owner assignment for the symmetric algorithm's triangular task matrix.
Definition exchangeoperator.h:242
long exchange_batch_record_key(const long salt, const int dim, const Batch_1D &r)
Deterministic cloud record key for one stored batch: (salt, dimension, range).
Definition exchangeoperator.h:424
std::vector< std::shared_ptr< FunctionImpl< T, NDIM > > > get_impl(const std::vector< Function< T, NDIM > > &v)
Definition vmra.h:731
TreeState
Definition funcdefaults.h:59
@ reconstructed
s coeffs at the leaves only
Definition funcdefaults.h:60
@ compressed
d coeffs in internal nodes, s and d coeffs at the root, empty leaves may be present
Definition funcdefaults.h:61
long exchange_sym_tri(const long i, const long j)
Triangular index of a batch pair, collapsing (i,j) and (j,i): a*(a+1)/2 + b.
Definition exchangeoperator.h:124
void compress(World &world, const std::vector< Function< T, NDIM > > &v, bool fence=true)
Compress a vector of functions.
Definition vmra.h:149
Function< TENSOR_RESULT_TYPE(T, R), NDIM > dot(World &world, const std::vector< Function< T, NDIM > > &a, const std::vector< Function< R, NDIM > > &b, bool fence=true, bool do_make_redundant=true, double tol=0.0)
Multiplies and sums two vectors of functions r = \sum_i a[i] * b[i].
Definition vmra.h:1645
void hash_combine(hashT &seed, const T &v)
Combine hash values.
Definition worldhash.h:260
std::map< std::pair< long, long >, long > exchange_row_owner_assign(const long ncolumn, const long nrow, const long nworker)
Owner of every task in the asymmetric grid: all tasks of a column go to one worker.
Definition exchangeoperator.h:112
bool exch_task_profile_enabled()
Is per-task exchange profiling on? Read once per process.
Definition exchangeoperator.h:323
long exchange_batch_salt(const std::vector< Function< T, NDIM > > &ket)
Per-invocation salt for the exchange batch record keys, from the ket identities.
Definition exchangeoperator.h:415
void exch_write_task_profile(const ExchTaskProfile &p)
Append one record to exch_taskprof.r<rank>.jsonl.
Definition exchangeoperator.h:344
void print(const T &t, const Ts &... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:227
std::vector< Batch_1D > exchange_row_owner_split(const std::size_t n, const long nsubworld)
Batch boundaries for the asymmetric row/column split: one batch per rank.
Definition exchangeoperator.h:67
@ TT_FULL
Definition gentensor.h:120
NDIM & f
Definition mra.h:2622
const Function< T, NDIM > & change_tree_state(const Function< T, NDIM > &f, const TreeState finalstate, bool fence=true)
change tree state of a function
Definition mra.h:2948
double wall_time()
Returns the wall time in seconds relative to an arbitrary origin.
Definition timers.cc:48
static SeparatedConvolution< double, 3 > * CoulombOperatorPtr(World &world, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with 1/r in 3D.
Definition operator.h:1764
bool exch_force_general_path()
Send a symmetric application down the general (bra, ket, vf) path? Read once per process.
Definition exchangeoperator.h:334
void exch_write_cost_matrix(const long call_index, const long k, const long M, const std::vector< double > &cost)
Write the measured per-task cost matrix of one application, for offline inspection.
Definition exchangeoperator.h:384
Function< TENSOR_RESULT_TYPE(L, R), NDIM > mul_sparse(const Function< L, NDIM > &left, const Function< R, NDIM > &right, double tol, bool fence=true, bool do_make_redundant=true)
Sparse multiplication; the scalar interface redirects to the vector one in vmra.h.
Definition mra.h:1929
void load(Function< T, NDIM > &f, const std::string name)
Definition mra.h:2986
bool exchange_same_operands(const std::vector< Function< T, NDIM > > &a, const std::vector< Function< T, NDIM > > &b)
Are these the same functions, so that one stored record can serve both operand roles?
Definition exchangeoperator.h:96
std::string name(const FuncType &type, const int ex=-1)
Definition ccpairfunction.h:28
madness::hashT hash_value(const std::array< T, N > &a)
Hash std::array with madness hash.
Definition array_addons.h:78
std::map< std::pair< long, long >, long > exchange_sym_round_robin_assign(const long n, const long M)
Round-robin owner assignment for the symmetric algorithm's triangular task matrix.
Definition exchangeoperator.h:148
ExchangeBatchDim
which of the three exchange operand vectors a stored batch belongs to
Definition exchangeoperator.h:401
@ EXCHANGE_BATCH_BRA
Definition exchangeoperator.h:401
@ EXCHANGE_BATCH_VF
Definition exchangeoperator.h:401
@ EXCHANGE_BATCH_KET
Definition exchangeoperator.h:401
Function< T, NDIM > copy(const Function< T, NDIM > &f, const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > &pmap, bool fence=true)
Create a new copy of the function with different distribution and optional fence.
Definition mra.h:2187
void gaxpy(const double a, ScalarResult< T > &left, const double b, const T &right, const bool fence=true)
the result type of a macrotask must implement gaxpy
Definition macrotaskq.h:244
@ nemo
nemo's regularized orbitals F = psi/R
static const double b
Definition nonlinschro.cc:119
static const double a
Definition nonlinschro.cc:118
static const double c
Definition relops.cc:10
static const double thresh
Definition rk.cc:45
static const long k
Definition rk.cc:44
Definition test_ccpairfunction.cc:22
One task's record for the exchange profiler.
Definition exchangeoperator.h:293
double mul1_wall
Definition exchangeoperator.h:309
double compute_cpu
Definition exchangeoperator.h:304
double mul2_wall
Definition exchangeoperator.h:309
double thresh
which protocol tier this task ran in
Definition exchangeoperator.h:298
long k
Definition exchangeoperator.h:299
long task_id
Definition exchangeoperator.h:294
double truncate_wall
Definition exchangeoperator.h:309
long col_end
Definition exchangeoperator.h:301
double apply_wall
Definition exchangeoperator.h:309
unsigned long subworld_id
Definition exchangeoperator.h:296
long row_begin
Definition exchangeoperator.h:301
bool waited
a cold fetch happened, so this task paid latency
Definition exchangeoperator.h:311
double wait_for_data_wall
task entry until its operands are in hand
Definition exchangeoperator.h:303
long col_begin
Definition exchangeoperator.h:301
void reset()
Definition exchangeoperator.h:314
double wall_end
Definition exchangeoperator.h:302
long universe_rank
keys the output file: one per process
Definition exchangeoperator.h:295
int subworld_nrank
Definition exchangeoperator.h:297
double compute_wall
Definition exchangeoperator.h:304
bool diagonal
Definition exchangeoperator.h:300
long row_end
Definition exchangeoperator.h:301
double wall_start
Definition exchangeoperator.h:302
int operand_source
worst of its fetches: 0 resident, 1 ahead, 2 cold
Definition exchangeoperator.h:310
void observe_fetch_tier(const int tier)
keep the worst source, since that is the one that set the task's wait
Definition exchangeoperator.h:316
double peak_rss_gb
Definition exchangeoperator.h:312
Definition exchangeoperator.h:490
dataT data
Definition exchangeoperator.h:490
bool pinned
Definition exchangeoperator.h:490
keyT key
Definition exchangeoperator.h:490
One batch requested ahead of the task that will read it.
Definition exchangeoperator.h:873
std::shared_ptr< Future< batch_bytesT > > fut
Definition exchangeoperator.h:880
long key
Definition exchangeoperator.h:875
bool valid
Definition exchangeoperator.h:874
One coefficient node in transit during the exchange finalize.
Definition exchangeoperator.h:501
std::size_t f
index into the destination function vector
Definition exchangeoperator.h:502
Key< NDIM > key
tree-node key
Definition exchangeoperator.h:503
void serialize(Archive &ar)
Definition exchangeoperator.h:506
FunctionNode< T, NDIM > node
the source node
Definition exchangeoperator.h:504
Definition macrotaskq.h:280
static MacroTaskInfo preset(const std::string name)
Definition macrotaskq.h:313
nlohmann::json to_json() const
Definition macrotaskq.h:454
void from_vector_of_strings(const std::vector< std::string > &vec)
set policy from a vector of strings, assuming the order is storage policy, cloud distribution policy,...
Definition macrotaskq.h:380
World & world
Memoized reference to the world to which this object belongs.
Definition world_object.h:348
class to temporarily redirect output to cout
Definition print.h:300
void split(const Range< ConcurrentHashMap< int, int >::iterator > &range)
Definition test_hashthreaded.cc:63
double cpu_time()
Definition test_list.cc:43
void e()
Definition test_sig.cc:75
std::complex< double > dataT
Definition testcomplexfunctionsolver.cc:10
vector_complex_function_3d update(World &world, const vector_complex_function_3d &psi, vector_complex_function_3d &vpsi, const tensor_real &e, int iter)
Definition testcosine.cc:210
constexpr std::size_t NDIM
Definition testgconv.cc:54
int ProcessID
Used to clearly identify process number/rank.
Definition worldtypes.h:43