Skip to content

Commit aa6593c

Browse files
authored
Improve ORANGE construction performance by presizing label vectors (#2246)
* Preallocate label sizes * Move labels and avoid grid copies
1 parent 1633d84 commit aa6593c

6 files changed

Lines changed: 191 additions & 70 deletions

File tree

src/orange/OrangeParams.cc

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,60 @@
4040

4141
namespace celeritas
4242
{
43+
namespace
44+
{
45+
//---------------------------------------------------------------------------//
46+
//! Utility for counters, labels
47+
template<class T>
48+
struct Components
49+
{
50+
T universe{};
51+
T volume{};
52+
T surface{};
53+
};
54+
55+
using ComponentLabels = Components<std::vector<Label>>;
56+
57+
//---------------------------------------------------------------------------//
58+
//! Determine number of label components and reserve space for them
59+
ComponentLabels make_reserved_label_vecs(OrangeInput const& input)
60+
{
61+
Components<std::size_t> sizes;
62+
sizes.universe = input.universes.size();
63+
64+
for (auto const& u : input.universes)
65+
{
66+
std::visit(Overload{
67+
[&sizes](UnitInput const& i) {
68+
using InserterT = detail::UnitInserter;
69+
sizes.surface += InserterT::num_surfaces(i);
70+
sizes.volume += InserterT::num_volumes(i);
71+
},
72+
[&sizes](RectArrayInput const& i) {
73+
using InserterT = detail::RectArrayInserter;
74+
sizes.surface += InserterT::num_surfaces(i);
75+
sizes.volume += InserterT::num_volumes(i);
76+
},
77+
},
78+
u);
79+
}
80+
81+
CELER_LOG(debug) << "Allocating labels for " << sizes.universe
82+
<< " universes with " << sizes.volume
83+
<< " impl volumes and " << sizes.surface
84+
<< " impl surfaces";
85+
86+
Components<std::vector<Label>> result;
87+
result.universe.reserve(sizes.universe);
88+
result.volume.reserve(sizes.volume);
89+
result.surface.reserve(sizes.surface);
90+
91+
return result;
92+
}
93+
94+
//---------------------------------------------------------------------------//
95+
} // namespace
96+
4397
//---------------------------------------------------------------------------//
4498
/*!
4599
* Build by loading a GDML file.
@@ -202,14 +256,12 @@ OrangeParams::OrangeParams(OrangeInput&& input, SPConstVolumes&& volumes)
202256

203257
// Insert all universes
204258
{
205-
std::vector<Label> universe_labels;
206-
std::vector<Label> impl_surface_labels;
207-
std::vector<Label> impl_volume_labels;
259+
ComponentLabels labels = make_reserved_label_vecs(input);
208260

209261
detail::UniverseInserter insert_universe_base{volumes_,
210-
&universe_labels,
211-
&impl_surface_labels,
212-
&impl_volume_labels,
262+
&labels.universe,
263+
&labels.surface,
264+
&labels.volume,
213265
&host_data};
214266
Overload insert_universe{
215267
detail::UnitInserter{
@@ -221,12 +273,13 @@ OrangeParams::OrangeParams(OrangeInput&& input, SPConstVolumes&& volumes)
221273
std::visit(insert_universe, std::move(u));
222274
}
223275

276+
univ_labels_ = UniverseMap{"universe", std::move(labels.universe)};
224277
impl_surf_labels_
225-
= SurfaceMap{"impl surface", std::move(impl_surface_labels)};
226-
univ_labels_ = UniverseMap{"universe", std::move(universe_labels)};
278+
= SurfaceMap{"impl surface", std::move(labels.surface)};
227279
impl_vol_labels_
228-
= ImplVolumeMap{"impl volume", std::move(impl_volume_labels)};
280+
= ImplVolumeMap{"impl volume", std::move(labels.volume)};
229281
}
282+
230283
// Clear captured input since we've consumed and modified it
231284
std::move(input) = {};
232285

src/orange/detail/RectArrayInserter.cc

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ namespace
2626
//! Return correctly sized volume labels
2727
std::vector<Label> make_volume_labels(RectArrayInput const& inp)
2828
{
29+
CELER_EXPECT(std::all_of(inp.grid.begin(),
30+
inp.grid.end(),
31+
[](auto const& g) { return g.size() >= 2; }));
2932
std::vector<Label> result;
3033
for (auto i : range(inp.grid[to_int(Axis::x)].size() - 1))
3134
{
@@ -50,6 +53,34 @@ std::vector<Label> make_volume_labels(RectArrayInput const& inp)
5053
//---------------------------------------------------------------------------//
5154
} // namespace
5255

56+
//---------------------------------------------------------------------------//
57+
/*!
58+
* Number of surfaces created by the input.
59+
*/
60+
std::size_t RectArrayInserter::num_surfaces(Input const& i)
61+
{
62+
std::size_t result{0};
63+
for (auto ax : range(Axis::size_))
64+
{
65+
result += i.grid[to_int(ax)].size();
66+
}
67+
return result;
68+
}
69+
70+
//---------------------------------------------------------------------------//
71+
/*!
72+
* Number of volumes created by the input.
73+
*/
74+
std::size_t RectArrayInserter::num_volumes(Input const& i)
75+
{
76+
std::size_t result{1};
77+
for (auto ax : range(Axis::size_))
78+
{
79+
result *= i.grid[to_int(ax)].size() - 1;
80+
}
81+
return result;
82+
}
83+
5384
//---------------------------------------------------------------------------//
5485
/*!
5586
* Construct from full parameter data.
@@ -70,7 +101,7 @@ RectArrayInserter::RectArrayInserter(UniverseInserter* insert_universe,
70101
/*!
71102
* Create a rect array unit and return its ID.
72103
*/
73-
UnivId RectArrayInserter::operator()(RectArrayInput const& inp)
104+
UnivId RectArrayInserter::operator()(RectArrayInput&& inp)
74105
{
75106
CELER_VALIDATE(
76107
inp, << "rect array '" << inp.label << "' is not properly constructed");
@@ -83,7 +114,7 @@ UnivId RectArrayInserter::operator()(RectArrayInput const& inp)
83114

84115
for (auto ax : range(Axis::size_))
85116
{
86-
std::vector<double> grid = inp.grid[to_int(ax)];
117+
auto& grid = inp.grid[to_int(ax)];
87118
CELER_VALIDATE(grid.size() >= 2,
88119
<< "grid for " << to_char(ax) << " axis in '"
89120
<< inp.label << "' is too small (size " << grid.size()
@@ -94,6 +125,7 @@ UnivId RectArrayInserter::operator()(RectArrayInput const& inp)
94125

95126
// Suppress the outer grid boundaries to avoid coincident surfaces with
96127
// other universes
128+
// FIXME: replace with bump using orange_data.scalars.tol
97129
grid.front() = -std::numeric_limits<real_type>::infinity();
98130
grid.back() = std::numeric_limits<real_type>::infinity();
99131

@@ -104,13 +136,11 @@ UnivId RectArrayInserter::operator()(RectArrayInput const& inp)
104136
record.grid[to_int(ax)] = reals_.insert_back(grid.begin(), grid.end());
105137

106138
// Create surface labels
107-
for (auto i : range(inp.grid[to_int(ax)].size()))
139+
for (auto i : range(grid.size()))
108140
{
109-
Label sl;
110-
sl.name = std::string("{" + std::string(1, to_char(ax)) + ","
111-
+ std::to_string(i) + "}");
112-
sl.ext = inp.label.name;
113-
surface_labels.push_back(std::move(sl));
141+
auto name = std::string("{" + std::string(1, to_char(ax)) + ","
142+
+ std::to_string(i) + "}");
143+
surface_labels.emplace_back(std::move(name), inp.label.name);
114144
}
115145
}
116146

@@ -139,11 +169,16 @@ UnivId RectArrayInserter::operator()(RectArrayInput const& inp)
139169
CELER_ASSERT(record);
140170
rect_arrays_.push_back(record);
141171

172+
// Save labels and clear input
173+
auto vol_labels = make_volume_labels(inp);
174+
Label unit_label{std::move(inp.label)};
175+
std::move(inp) = {};
176+
142177
// Construct universe
143178
return (*insert_universe_)(UnivType::rect_array,
144-
inp.label,
179+
std::move(unit_label),
145180
std::move(surface_labels),
146-
make_volume_labels(inp));
181+
std::move(vol_labels));
147182
}
148183

149184
//---------------------------------------------------------------------------//

src/orange/detail/RectArrayInserter.hh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,31 @@ class UniverseInserter;
2323
//---------------------------------------------------------------------------//
2424
/*!
2525
* Convert a RectArrayInput a RectArrayRecord.
26+
*
27+
* The inserted array has one surface per grid point per axis (i.e., one per
28+
* grid plane). This matches the surfaces that would be constructed for a
29+
* "pseudoarray" with CSG elements.
2630
*/
2731
class RectArrayInserter
2832
{
2933
public:
3034
//!@{
3135
//! \name Type aliases
3236
using Data = HostVal<OrangeParamsData>;
37+
using Input = RectArrayInput;
3338
//!@}
3439

3540
public:
41+
// Number of elements created by the input
42+
static std::size_t num_surfaces(Input const& i);
43+
// Number of volumes created by the input
44+
static std::size_t num_volumes(Input const& i);
45+
3646
// Construct with universe inserter and parameter data
3747
RectArrayInserter(UniverseInserter* insert_universe, Data* orange_data);
3848

3949
// Create a simple unit and return its ID
40-
UnivId operator()(RectArrayInput const& inp);
50+
UnivId operator()(Input&& inp);
4151

4252
private:
4353
Data* orange_data_{nullptr};

src/orange/detail/UnitInserter.cc

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -134,50 +134,61 @@ std::vector<Label> make_surface_labels(UnitInput& inp)
134134
|| inp.surface_labels.size() == inp.surfaces.size());
135135

136136
std::vector<Label> result;
137-
result.resize(inp.surfaces.size());
137+
result.reserve(inp.surfaces.size());
138138

139-
for (auto i : range(inp.surface_labels.size()))
139+
if (!inp.surface_labels.empty())
140140
{
141-
Label surface_label = std::move(inp.surface_labels[i]);
142-
if (surface_label.ext.empty())
141+
for (auto& surface_label : inp.surface_labels)
143142
{
144-
surface_label.ext = inp.label.name;
143+
if (surface_label.ext.empty())
144+
{
145+
surface_label.ext = inp.label.name;
146+
}
147+
result.emplace_back(std::move(surface_label));
145148
}
146-
result[i] = std::move(surface_label);
147149
}
148-
inp.surface_labels.clear();
150+
else
151+
{
152+
result.assign(inp.surfaces.size(), {});
153+
}
154+
149155
return result;
150156
}
151157

152158
//---------------------------------------------------------------------------//
153159
//! Construct volume labels from the input volumes
154-
auto make_volume_labels(UnitInput const& inp)
160+
auto make_volume_labels(UnitInput& inp)
155161
{
156162
UniverseInserter::VecVarLabel result;
157-
for (auto const& v : inp.volumes)
163+
result.reserve(inp.volumes.size());
164+
165+
for (auto& v : inp.volumes)
158166
{
159167
// Convert a <Label, VolInstId> -> <Label, VolInstId, VolId>
160168
// using a default extension
161169
result.emplace_back(
162-
std::visit(return_as<UniverseInserter::VariantLabel>(Overload{
163-
[](auto&& obj) { return obj; },
164-
[&inp](Label const& label) {
165-
Label result = label;
166-
// Add the unit's name as an extension if blank
167-
if (result.ext.empty())
168-
{
169-
result.ext = inp.label.name;
170-
}
171-
return result;
172-
},
173-
}),
174-
v.label));
170+
std::visit(return_as<UniverseInserter::VariantLabel>(
171+
Overload{[&ext = inp.label.name](Label&& label) {
172+
Label result{std::move(label)};
173+
// Add the unit's name as an extension
174+
// if blank
175+
if (result.ext.empty())
176+
{
177+
result.ext = ext;
178+
}
179+
return result;
180+
},
181+
[](VolumeInstanceId vid) {
182+
CELER_ASSERT(vid);
183+
return vid;
184+
}}),
185+
std::move(v.label)));
175186
}
176187

177-
if (auto const& bg = inp.background)
188+
if (auto& bg = inp.background)
178189
{
179190
CELER_ASSERT(bg.volume < result.size());
180-
result[bg.volume.get()] = bg.label;
191+
result[bg.volume.get()] = std::move(bg.label);
181192
}
182193

183194
return result;
@@ -569,8 +580,14 @@ UnivId UnitInserter::operator()(UnitInput&& inp)
569580
simple_units_.push_back(unit);
570581
auto surf_labels = make_surface_labels(inp);
571582
auto vol_labels = make_volume_labels(inp);
583+
584+
// Save universe label before returning
585+
auto univ_label = std::move(inp.label);
586+
// Clear captured input since we've consumed and modified it
587+
std::move(inp) = {};
588+
572589
return (*insert_universe_)(UnivType::simple,
573-
std::move(inp.label),
590+
std::move(univ_label),
574591
std::move(surf_labels),
575592
std::move(vol_labels));
576593
}

src/orange/detail/UnitInserter.hh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,22 @@ class UnitInserter
3535
//!@{
3636
//! \name Type aliases
3737
using Data = HostVal<OrangeParamsData>;
38+
using Input = UnitInput;
3839
//!@}
3940

4041
public:
42+
//! Number of surfaces created by the input
43+
static auto num_surfaces(Input const& i) { return i.surfaces.size(); }
44+
//! Number of volumes created by the input
45+
static auto num_volumes(Input const& i) { return i.volumes.size(); }
46+
4147
// Construct from full parameter data
4248
UnitInserter(UniverseInserter* insert_universe,
4349
Data* orange_data,
4450
ConstructionOptions const* opts);
4551

4652
// Create a simple unit and store in in OrangeParamsData
47-
UnivId operator()(UnitInput&& inp);
53+
UnivId operator()(Input&& inp);
4854

4955
private:
5056
Data* orange_data_{nullptr};

0 commit comments

Comments
 (0)