Orrery
A GPU-accelerated N-body gravitational simulator
Loading...
Searching...
No Matches
orrery::solvers::SyclTreeSolver Class Referencefinal

Barnes-Hut with the traversal on a SYCL device. More...

#include <orrery/solvers/sycl_tree_solver.hpp>

Inheritance diagram for orrery::solvers::SyclTreeSolver:
orrery::solvers::ForceSolver orrery::integrators::AccelerationField

Public Member Functions

 SyclTreeSolver (const SyclTreeSolver &)=delete
SyclTreeSolver & operator= (const SyclTreeSolver &)=delete
 SyclTreeSolver (SyclTreeSolver &&) noexcept
SyclTreeSolver & operator= (SyclTreeSolver &&) noexcept
void evaluate (core::Vec3Span< const core::Real > positions, std::span< const core::Real > masses, core::Vec3Span< core::Real > accelerations) override
 Write the acceleration at each position into accelerations.
std::string_view name () const noexcept override
 The solver's name, for benchmark tables and test messages.
core::Softening softening () const noexcept override
 The softening this solver applies.
InteractionCount interaction_count () const noexcept override
 The work done since construction or since the last reset.
void reset_interaction_count () noexcept override
 Set every counter back to zero.
const TreeParametersparameters () const noexcept
 The tree parameters in force, after the corrections TreeParameters documents.
const Octreetree () const noexcept
 The tree the last evaluation built, empty before the first.
TreeTraversal traversal () const noexcept
 Which traversal the next evaluation will run.
void select_traversal (TreeTraversal traversal) noexcept
void select_sub_group_width (unsigned width) noexcept
 Ask for a particular sub-group width, and settle for the device's own choice if it cannot provide that one.
unsigned sub_group_width () const noexcept
 The width asked for, which is zero when the compiler is choosing.
std::span< const unsigned > supported_sub_group_widths () const noexcept
 The widths this device will compile a kernel for, ascending.
core::Index work_group_size () const noexcept
 The work-group size the traversal launches with.
std::uint64_t node_visits () const noexcept
 How many nodes the traversal visited, summed over work-items, since the count was last reset.
const backend::DeviceDescriptiondevice () const noexcept
 What the runtime says about the device this solver runs on.
const SyclTreeTimingstimings () const noexcept
 Where the last evaluation spent its time.
bool uses_shared_memory () const noexcept
 Whether the arrays the traversal reads are shared unified memory, asked of the runtime rather than assumed.
Public Member Functions inherited from orrery::solvers::ForceSolver
 ~ForceSolver () override=default
 Public and virtual, the second by inheritance from AccelerationField.

Static Public Member Functions

static std::unique_ptr< SyclTreeSolver > try_create (TreeParameters parameters={}, core::Softening softening={}, backend::Executor *executor=nullptr)
 A solver on this machine's GPU, or nothing.

Additional Inherited Members

Protected Member Functions inherited from orrery::solvers::ForceSolver
 ForceSolver (const ForceSolver &)=default
 ForceSolver (ForceSolver &&)=default
ForceSolver & operator= (const ForceSolver &)=default
ForceSolver & operator= (ForceSolver &&)=default
Protected Member Functions inherited from orrery::integrators::AccelerationField
 AccelerationField (const AccelerationField &)=default
 AccelerationField (AccelerationField &&)=default
AccelerationField & operator= (const AccelerationField &)=default
AccelerationField & operator= (AccelerationField &&)=default

Detailed Description

Barnes-Hut with the traversal on a SYCL device.

Declared only where the backend is compiled, on the same terms as SyclDirectSolver. A caller that must work either way asks backend::kSyclBackendCompiled first.

Member Function Documentation

◆ try_create()

std::unique_ptr< SyclTreeSolver > orrery::solvers::SyclTreeSolver::try_create ( TreeParameters parameters = {},
core::Softening softening = {},
backend::Executor * executor = nullptr )
staticnodiscard

A solver on this machine's GPU, or nothing.

Returns null on the same three conditions SyclDirectSolver::try_create documents: no GPU, a device that cannot run this build's precision, or a runtime that fails to make a queue. None is an error and all three mean the caller should use the CPU tree solver, which computes the same thing.

executor schedules the host half, which is the sort and the tree build, and is referred to rather than owned. Null runs the host half on the calling thread. The result does not depend on which, since the ordering is total and the tree is a function of the sorted particles alone.

◆ evaluate()

void orrery::solvers::SyclTreeSolver::evaluate ( core::Vec3Span< const core::Real > positions,
std::span< const core::Real > masses,
core::Vec3Span< core::Real > accelerations )
overridevirtual

Write the acceleration at each position into accelerations.

The three views must describe the same particles in the same order and have the same length. Safe to call with no particles.

Blocks until the device has finished, for the reason SyclDirectSolver::evaluate gives: there is nothing for the host to overlap the wait with, since the integrator cannot advance until the accelerations exist.

Implements orrery::integrators::AccelerationField.

◆ name()

std::string_view orrery::solvers::SyclTreeSolver::name ( ) const
inlinenodiscardoverridevirtualnoexcept

The solver's name, for benchmark tables and test messages.

Implements orrery::solvers::ForceSolver.

◆ softening()

core::Softening orrery::solvers::SyclTreeSolver::softening ( ) const
nodiscardoverridevirtualnoexcept

The softening this solver applies.

Exposed so that a caller measuring energies asks the solver what it softened with rather than carrying a second copy of the value alongside it. Two copies of a number that must agree are how they come to disagree, and a potential energy computed with a different softening from the force kernel turns the project's headline conservation result into a measurement of the mismatch (ADR-0008).

Implements orrery::solvers::ForceSolver.

◆ interaction_count()

InteractionCount orrery::solvers::SyclTreeSolver::interaction_count ( ) const
nodiscardoverridevirtualnoexcept

The work done since construction or since the last reset.

Cheap: solvers accumulate this as they go and this call only reads it.

Implements orrery::solvers::ForceSolver.

◆ reset_interaction_count()

void orrery::solvers::SyclTreeSolver::reset_interaction_count ( )
overridevirtualnoexcept

Set every counter back to zero.

A benchmark counts the work of the measured region rather than of the warm-up that preceded it, and the two are otherwise indistinguishable once they have been added together.

Implements orrery::solvers::ForceSolver.

◆ tree()

const Octree & orrery::solvers::SyclTreeSolver::tree ( ) const
nodiscardnoexcept

The tree the last evaluation built, empty before the first.

The host tree rather than the device copy, since the two describe the same cells and only this one can be inspected without a kernel. Exposed so that a benchmark can report the tree's shape beside its timing and a test can assert that the GPU and CPU solvers built the same tree.

◆ select_sub_group_width()

void orrery::solvers::SyclTreeSolver::select_sub_group_width ( unsigned width)
noexcept

Ask for a particular sub-group width, and settle for the device's own choice if it cannot provide that one.

Zero means the compiler chooses, which is the default and what a run should use. The knob exists because the width is the granularity of the coherence: it decides how many targets agree to walk together, and so sets both the redundancy the scheme costs and the divergence it removes. Sweeping it is the most direct measurement of the mitigation available, and docs/performance/sycl_tree.md reports the sweep.

Only widths the device reports are accepted, so a request the hardware cannot meet becomes the default rather than a submission that throws. supported_sub_group_widths says which those are.

◆ work_group_size()

core::Index orrery::solvers::SyclTreeSolver::work_group_size ( ) const
nodiscardnoexcept

The work-group size the traversal launches with.

A multiple of every sub-group width the device offers, since a work-group that is not one cannot be divided into whole sub-groups.

◆ node_visits()

std::uint64_t orrery::solvers::SyclTreeSolver::node_visits ( ) const
nodiscardnoexcept

How many nodes the traversal visited, summed over work-items, since the count was last reset.

The measurement the phase turns on, and it means different things for the two traversals, which is the point of it. For the independent walk it is the sum of the lengths of the individual walks, which is the algorithm's own figure. For the coherent walk it is the sub-group's union walk counted once per lane, so the ratio between the two is exactly the redundancy coherence costs.

Reset by reset_interaction_count, alongside the interaction counters it belongs beside.

◆ uses_shared_memory()

bool orrery::solvers::SyclTreeSolver::uses_shared_memory ( ) const
nodiscardnoexcept

Whether the arrays the traversal reads are shared unified memory, asked of the runtime rather than assumed.

The same evidence SyclDirectSolver::uses_shared_memory provides, asked of the node array as well as of the particles, because the node array is the allocation this phase adds.


The documentation for this class was generated from the following file: