56 [[nodiscard]] std::shared_ptr<const SortingThresholdInfoInterface>
getSoAThreshold()
const {
return _soaThresholds; }
63 [[nodiscard]] std::shared_ptr<const SortingThresholdInfoInterface>
getAoSThreshold()
const {
return _aosThresholds; }
69 [[nodiscard]]
bool hasRunSoA()
const {
return _hasRunSoA; }
75 [[nodiscard]]
bool hasRunAoS()
const {
return _hasRunAoS; }
88 template <
class Functor_T,
class Particle_T>
91 for (
const auto &n3 : Newton3Option::getAllOptions()) {
92 for (
const auto &cellDirection : SortingDirectionOption::getAllOptions()) {
94 n3, cellDirection,
true,
95 runSearch<Functor_T, Particle_T, true, true>(functor, defaultParticle, cellDirection, n3));
96 if (n3 == Newton3Option::disabled) {
98 n3, cellDirection,
false,
99 runSearch<Functor_T, Particle_T, true, false>(functor, defaultParticle, cellDirection, n3));
103 _soaThresholds = std::make_shared<const SortingThresholdInfo2B>(thresholds);
117 template <
class Functor_T,
class Particle_T>
120 for (
const auto &n3 : Newton3Option::getAllOptions()) {
121 for (
const auto &cellDirection : SortingDirectionOption::getAllOptions()) {
123 n3, cellDirection,
true,
124 runSearch<Functor_T, Particle_T, false, true>(functor, defaultParticle, cellDirection, n3));
125 if (n3 == Newton3Option::disabled) {
127 n3, cellDirection,
false,
128 runSearch<Functor_T, Particle_T, false, false>(functor, defaultParticle, cellDirection, n3));
132 _aosThresholds = std::make_shared<const SortingThresholdInfo2B>(thresholds);
140 bool _hasRunSoA{
false};
145 bool _hasRunAoS{
false};
153 std::shared_ptr<const SortingThresholdInfoInterface> _soaThresholds;
161 std::shared_ptr<const SortingThresholdInfoInterface> _aosThresholds;
166 const size_t _iterations = 25;
171 const size_t _repetitions = 100;
177 const size_t _maxSoAParticles = 250;
187 const size_t _maxAoSParticles = 50;
194 const double _sortedWinMarginFraction = 0.05;
201 const double _requiredSortedWinRatio = 0.7;
206 const double _scatterFactor = 0.2;
229 template <
class Functor_T,
class Particle_T,
bool useSoA,
bool b
idirectional>
230 size_t executeRun(Functor_T &functor,
const Particle_T &defaultParticle, SortingDirectionOption cellDirection,
231 size_t numParticles, Newton3Option newton3) {
232 using BenchCell = FullParticleCell<Particle_T>;
233 using BenchCF = internal::CellFunctor<BenchCell, Functor_T, bidirectional>;
235 const double cutoff = functor.getCutoff();
236 const double invSqrt3 = 1. /
sqrt(3.);
237 const double invSqrt2 = 1. /
sqrt(2.);
239 auto numParticlesEqDistr =
static_cast<size_t>(std::ceil(numParticles * (1. - _scatterFactor)));
240 size_t numParticlesScatter = numParticles - numParticlesEqDistr + numParticlesEqDistr % 2;
241 size_t numParticlesPerCell = numParticlesEqDistr / 2;
244 std::random_device rd;
245 std::mt19937 gen(rd());
246 std::uniform_int_distribution<size_t> distrib(0, numParticlesScatter);
249 BenchCell cell1, cell2;
251 std::array cell1Low = {0., 0., 0.};
252 std::array cell1High = {cutoff, cutoff, cutoff};
254 std::array cell2Low = {0., 0., 0.};
255 std::array cell2High = {cutoff, cutoff, cutoff};
257 std::array sortingDirection = {0., 0., 0.};
259 switch (cellDirection) {
260 case SortingDirectionOption::corner:
261 cell2Low = {cutoff, cutoff, cutoff};
262 cell2High = {2. * cutoff, 2. * cutoff, 2. * cutoff};
263 sortingDirection = {invSqrt3, invSqrt3, invSqrt3};
265 case SortingDirectionOption::edge:
266 cell2Low = {cutoff, cutoff, 0.};
267 cell2High = {2. * cutoff, 2. * cutoff, cutoff};
268 sortingDirection = {invSqrt2, invSqrt2, 0.};
270 case SortingDirectionOption::face:
271 cell2Low = {cutoff, 0., 0.};
272 cell2High = {2 * cutoff, cutoff, cutoff};
273 sortingDirection = {1, 0., 0.};
279 utils::Timer sortedTimer, unsortedTimer;
280 BenchCF cellFunctor{functor, cutoff, useSoA ? DataLayoutOption::soa : DataLayoutOption::aos,
281 newton3 == Newton3Option::enabled};
282 size_t sortedWins = 0;
284 const SortingThresholdInfoSingle zeroThreshold(0);
285 cellFunctor.setSoASortingThresholds(zeroThreshold);
286 cellFunctor.setAoSSortingThresholds(zeroThreshold);
290 auto measureUnsorted = [&]() {
291 unsortedTimer.start();
292 for (
size_t j = 0; j < _iterations; j++) {
293 if constexpr (useSoA) {
294 functor.SoALoader(cell1, cell1._particleSoABuffer, 0,
false);
295 functor.SoALoader(cell2, cell2._particleSoABuffer, 0,
false);
298 cellFunctor.processCellPair(cell1, cell2, {0., 0., 0.});
300 return unsortedTimer.stop();
302 auto measureSorted = [&]() {
304 for (
size_t j = 0; j < _iterations; j++) {
305 if constexpr (useSoA) {
306 functor.SoALoader(cell1, cell1._particleSoABuffer, 0,
false);
307 functor.SoALoader(cell2, cell2._particleSoABuffer, 0,
false);
309 cellFunctor.processCellPair(cell1, cell2, sortingDirection);
311 return sortedTimer.stop();
314 for (
size_t i = 0; i < _repetitions; i++) {
319 size_t toAddCell1 = distrib(gen);
323 numParticlesPerCell + toAddCell1,
324 static_cast<unsigned int>(2 * i));
326 numParticlesPerCell + numParticlesScatter - toAddCell1,
327 static_cast<unsigned int>(2 * i + 1));
329 long unsortedDelta = 0;
330 long sortedDelta = 0;
334 unsortedDelta = measureUnsorted();
335 sortedDelta = measureSorted();
337 sortedDelta = measureSorted();
338 unsortedDelta = measureUnsorted();
341 AutoPasLog(TRACE,
"SortingThresholdBenchmark rep {}/{} cell direction={} n={}: unsorted={}ns sorted={}ns", i + 1,
342 _repetitions, cellDirection, numParticles, unsortedDelta, sortedDelta);
345 if (
static_cast<double>(sortedDelta) <
static_cast<double>(unsortedDelta) * (1. - _sortedWinMarginFraction)) {
350 const long meanSorted = sortedTimer.getTotalTime() /
static_cast<long>(_repetitions);
351 const long meanUnsorted = unsortedTimer.getTotalTime() /
static_cast<long>(_repetitions);
353 "SortingThresholdBenchmark cell direction={} n={}: mean unsorted={}ns mean sorted={}ns sortedWins={}/{}",
354 cellDirection, numParticles, meanUnsorted, meanSorted, sortedWins, _repetitions);
373 template <
class Functor_T,
class Particle_T,
bool useSoA,
bool b
idirectional>
374 size_t runSearch(Functor_T &functor,
const Particle_T &defaultParticle, SortingDirectionOption cellDirection,
375 Newton3Option newton3) {
377 const size_t upperBound = useSoA ? _maxSoAParticles : _maxAoSParticles;
378 size_t highCount = upperBound;
380 while (lowCount < highCount) {
381 size_t mid = lowCount + (highCount - lowCount) / 2;
383 const auto outcome = executeRun<Functor_T, Particle_T, useSoA, bidirectional>(functor, defaultParticle,
384 cellDirection, mid, newton3);
385 const double winRatio =
static_cast<double>(outcome) /
static_cast<double>(_repetitions);
389 if (winRatio >= _requiredSortedWinRatio) {
391 AutoPasLog(TRACE,
"SortingThresholdBenchmark search {} cell direction={} n={}: sorted won {}/{} reps → high={}",
392 newton3, cellDirection, mid, outcome, _repetitions, highCount);
396 "SortingThresholdBenchmark search {} cell direction={} n={}: sorted won only {}/{} reps → low={}",
397 newton3, cellDirection, mid, outcome, _repetitions, lowCount);
400 AutoPasLog(DEBUG,
"SortingThresholdBenchmark {} cell direction={} threshold={}", newton3, cellDirection, lowCount);
402 if (lowCount == upperBound) {
403 return std::numeric_limits<unsigned long>::max();
constexpr std::enable_if_t< std::is_floating_point_v< T >, T > sqrt(T x, T epsilon)
Calculates the square root of floating point values x based on Newton-Raphson methon.
Definition: ConstexprMath.h:22
#define AutoPasLog(lvl, fmt,...)
Macro for logging providing common meta information without filename.
Definition: Logger.h:24
Determines the per-Newton3-state, per-direction-type particle-count threshold at which using a sorted...
Definition: SortingThresholdBenchmark.h:38
void runAoSBenchmark(Functor_T &functor, const Particle_T &defaultParticle)
Runs the micro-benchmark for the AoS sorting threshold, sweeping both Newton3 (and bidirectional for ...
Definition: SortingThresholdBenchmark.h:118
std::shared_ptr< const SortingThresholdInfoInterface > getAoSThreshold() const
Return all per-Newton3-state, per-direction-type AoS pair-sorting thresholds if hasRunAoS() is true,...
Definition: SortingThresholdBenchmark.h:63
bool hasRunAoS() const
Returns whether runAoSBenchmark() has already been called.
Definition: SortingThresholdBenchmark.h:75
std::shared_ptr< const SortingThresholdInfoInterface > getSoAThreshold() const
Return all per-Newton3-state, per-direction-type SoA sorting thresholds if hasRunSoA() is true,...
Definition: SortingThresholdBenchmark.h:56
SortingThresholdBenchmark(size_t aosSortingThresholdDefault, size_t soaSortingThresholdDefault)
Constructs a benchmark whose thresholds default to the given uniform values until/unless a benchmark ...
Definition: SortingThresholdBenchmark.h:47
void runSoABenchmark(Functor_T &functor, const Particle_T &defaultParticle)
Runs the micro-benchmark for the SoA sorting threshold, sweeping both Newton3 (and bidirectional for ...
Definition: SortingThresholdBenchmark.h:89
bool hasRunSoA() const
Returns whether runSoABenchmark() has already been called.
Definition: SortingThresholdBenchmark.h:69
static void exception(const Exception e)
Handle an exception derived by std::exception.
Definition: ExceptionHandler.h:64
This is the main namespace of AutoPas.
Definition: AutoPasDecl.h:34
Per-Newton3-state, per-SortingDirectionOption pair-sorting thresholds for a 2-body CellFunctor.
Definition: SortingThresholdInfo2B.h:21
void setThresholdByOption(Newton3Option n3, SortingDirectionOption cellDirection, bool bidirectional, size_t value)
Setter to set struct values by configuration, represented by options.
Definition: SortingThresholdInfo2B.h:151
Single threshold value struct.
Definition: SortingThresholdInfoSingle.h:18