/home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/common/assembly_schedule.hh Source File#

DiFfRG: /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/common/assembly_schedule.hh Source File
DiFfRG
Discretization Framework for functional Renormalization Group flows
assembly_schedule.hh
Go to the documentation of this file.
1#pragma once
2
3// external libraries
4#include <deal.II/base/multithread_info.h>
5#include <deal.II/distributed/tria_base.h>
6#include <deal.II/dofs/dof_handler.h>
7#include <deal.II/grid/filtered_iterator.h>
8#include <deal.II/grid/tria.h>
9
10// DiFfRG
14
15// std
16#include <algorithm>
17#include <cmath>
18#include <optional>
19
20namespace DiFfRG
21{
35
36 friend bool operator==(const AssemblySchedule &, const AssemblySchedule &) = default;
37 };
38
45 namespace assembly_cost
46 {
48 inline constexpr double local_fe = 250.;
50 inline constexpr double algebraic = 1000.;
53 inline constexpr double momentum_integral = 3000.;
54 } // namespace assembly_cost
55
56 namespace assembly_schedule_defaults
57 {
61 inline constexpr double chunk_work_ns = 8.0e3;
62
70 inline constexpr double worker_work_ns = 64.0e3;
71
74 inline constexpr uint chunk_cap = 256;
75 } // namespace assembly_schedule_defaults
76
83 std::optional<uint> queue_length;
84 std::optional<uint> chunk_size;
85
87 {
89 if (config.contains("/discretization/mesh_workers"))
90 overrides.queue_length = config.get_uint("/discretization/mesh_workers");
91 if (config.contains("/discretization/batch_size"))
92 overrides.chunk_size = config.get_uint("/discretization/batch_size");
93 return overrides;
94 }
95 };
96
114 inline AssemblySchedule make_assembly_schedule(const uint n_local_cells, const uint thread_budget,
115 const double cost_ns, const AssemblyScheduleOverrides &overrides = {})
116 {
117 using namespace assembly_schedule_defaults;
118
119 const uint threads = std::max(1u, thread_budget);
120 const double cost = std::max(1.0, cost_ns);
121
122 uint chunk =
123 static_cast<uint>(std::clamp(std::llround(chunk_work_ns / cost), 1ll, static_cast<long long>(chunk_cap)));
124
125 // Allocating past the end of the mesh is pure cost: mesh_loop reserves queue_length *
126 // chunk_size CopyData objects whether or not there are cells to put in them.
127 if (n_local_cells > 0) chunk = std::min(chunk, n_local_cells);
128 chunk = std::max(1u, chunk);
129
130 const uint n_chunks = (n_local_cells + chunk - 1) / chunk;
131 const auto workers_paid_for = std::llround(double(n_local_cells) * cost / worker_work_ns);
132 // Below the thread count, never at it: the integrators spawn their own TBB work from inside a
133 // cell worker, in the same arena, and a pipeline holding every thread starves that nesting.
134 const uint w_max = threads > 1 ? threads - 1 : 1u;
135
136 uint queue = static_cast<uint>(std::clamp(workers_paid_for, 1ll, static_cast<long long>(w_max)));
137 if (n_chunks > 0) queue = std::min(queue, n_chunks);
138
139 if (overrides.queue_length) queue = *overrides.queue_length;
140 if (overrides.chunk_size) chunk = *overrides.chunk_size;
141
142 // deal.II only guards these with Assert, which is compiled out in Release, and a zero here is
143 // undefined behaviour inside tbb::parallel_pipeline rather than a diagnostic.
144 return {std::max(1u, queue), std::max(1u, chunk)};
145 }
146
154 template <int dim> auto locally_owned_cells(const dealii::DoFHandler<dim> &dof_handler)
155 {
156 return dealii::filter_iterators(dof_handler.active_cell_iterators(),
157 dealii::IteratorFilters::LocallyOwnedCell());
158 }
159
167 template <typename Discretization> uint n_locally_owned_cells(const Discretization &discretization)
168 {
169 const auto &tria = discretization.get_triangulation();
170 if constexpr (Discretization::Mesh::is_parallel)
171 return static_cast<uint>(tria.n_locally_owned_active_cells());
172 else
173 return static_cast<uint>(tria.n_active_cells());
174 }
175} // namespace DiFfRG
A hierarchical configuration tree, readable from JSON and TOML files.
Definition config_tree.hh:32
constexpr double algebraic
Algebraic couplings without momentum quadrature, e.g. LDG's level-to-level transfers.
Definition assembly_schedule.hh:50
constexpr double local_fe
Local FE work only: mass matrices, refinement indicators. ~0.2-0.3 us/cell for CG p=3.
Definition assembly_schedule.hh:48
constexpr double momentum_integral
Definition assembly_schedule.hh:53
constexpr double worker_work_ns
Definition assembly_schedule.hh:70
constexpr double chunk_work_ns
Definition assembly_schedule.hh:61
constexpr uint chunk_cap
Definition assembly_schedule.hh:74
Definition complex_math.hh:10
auto locally_owned_cells(const dealii::DoFHandler< dim > &dof_handler)
The cells this rank assembles.
Definition assembly_schedule.hh:154
AssemblySchedule make_assembly_schedule(const uint n_local_cells, const uint thread_budget, const double cost_ns, const AssemblyScheduleOverrides &overrides={})
Derive one mesh_loop schedule from the cost of a cell.
Definition assembly_schedule.hh:114
uint n_locally_owned_cells(const Discretization &discretization)
How many cells locally_owned_cells() yields.
Definition assembly_schedule.hh:167
@ config
/discretization/threads.
unsigned int uint
Definition utils.hh:24
Overrides, if really wanted by the user: /discretization/{mesh_workers,batch_size}...
Definition assembly_schedule.hh:82
std::optional< uint > queue_length
Definition assembly_schedule.hh:83
std::optional< uint > chunk_size
Definition assembly_schedule.hh:84
static AssemblyScheduleOverrides from_config(const ConfigTree &config)
Definition assembly_schedule.hh:86
The two trailing arguments of dealii::MeshWorker::mesh_loop.
Definition assembly_schedule.hh:30
uint queue_length
mesh_loop's queue_length: how many work items are live in the pipeline at once.
Definition assembly_schedule.hh:32
friend bool operator==(const AssemblySchedule &, const AssemblySchedule &)=default
uint chunk_size
mesh_loop's chunk_size: cells per work item, processed back-to-back by one worker.
Definition assembly_schedule.hh:34