scieee AI-readable full text Open interactive document viewer

Working with SYCL for a portable and performant library adding reactions to particle codes used in plasma physics.

Gadgil, Sanket; Mijin, Stefan; Saunders, Will

Abstract

In plasma physics simulations and in particular those of the tokamak exhaust, atomic and molecular reactions can play an important role. These need to be incorporated into various particle codes with many complex reactions and a large number of particles that must be processed, all of these aspects in combination require both flexibility and performance. NESO-Particles is a performance portable framework for building particle codes on meshes (both structured and unstructured) developed at UKAEA, and we have chosen it as a basis for our particle reactions library. NESO-Particles is built on SYCL to provide said performance portability and we inherit this capability in our library. This allows the codes using the library to run on both CPUs and NVidia GPUs on either local machines (such as laptops) or large clusters (such as CSD3 in Cambridge). However, the use of SYCL required certain considerations to be taken into account and posed some design challenges that were overcome. For example we had to consider that all data that is used inside SYCL loops has to be compatible with the SYCL compute device (this is particularly apparent when using GPUs), while ensuring a relatively smooth and flexible installation procedure. This poster showcases various SYCL-based design constraints encountered in this project as well as how Spack was used to manage package dependencies. Additionally, there is also some exploration of the process of open-sourcing the library that has unique configuration and installation considerations owing to its portability via SYCL.

Full text

The UK Atomic Energy Authority’s mission is to lead the delivery of sustainable fusion energy and maximise scientific and economic benefit Find out more www.gov.uk/ukaea This work has been funded by the EPSRC Energy Programme [grant number EP/W006839/1] VANTAGEReactions GitHub Repo NESO-Particles GitHub Repo Working with SYCL for a portable and performant library adding reactions to particle codes used in plasma physics. Sanket Gadgil 1Stefan Mijin 1Will Saunders 1 1UK Atomic Energy Authority, Culham Campus, Abingdon, Oxfordshire, UK, OX14 3DB Introduction In magnetically confined fusion plasmas, such as those found in tokamaks, the atomic and molecular reactions found in the exhaust are important in understanding a variety of phenomena. For example, interactions between the plasma and the inner wall of the reactor. As current codes for handling this type of investigation are fairly old and lack features such as robust performance scaling and the ability to run on a GPU, we decided to write a modern performance portable C++ code (VANTAGE-Reactions) that improves on the current state-of-the-art (EIRENE[2], DEGAS2[3]). We decided to build on NESO-Particles, which is a performance portable framework for building particle codes on meshes (both structured and unstructured) developed at UKAEA(UK Atomic Energy Authority). NESO-Particles is built on SYCL[4] to provide said performance portability but whilst SYCL offers some key advantages, it also presents some challenges that must be overcome. What is SYCL? In the past, when writing code for different devices like CPUs, GPUs or FPGAs, it was necessary to write a separate optimized source code for each variant of the software you wanted to run. This required writing for a separate API and potentially running into divergent development paths. SYCL aims to resolve this for C++ by allowing developers to use a single API to write one version of the source code and compile it for different devices, which results in distinct binaries. In theory, it can go even further and allow for more expansive heterogeneous computing with multiple non-CPU devices used in the same source code (ie. different sections of the code being run on different devices). Note that, some device-specific optimization can be necessary– SYCL should give executable code but it doesn’t know about specific hardware variations. However, for our purposes, we focussed on designing around distinct parallel sections in the code that can be dispatched to a single external device based on the compilation (specifically we tested on NVidia A100 GPUs). Here’s a basic for loop as written for use with the SYCL API: auto defaultQueue = sycl::queue{}; // Wrappers for std::array<int, data_size> objects auto buf0 = sycl::buffer{array_0.data(), sycl::range{data_size}}; auto buf1 = sycl::buffer{array_1.data(), sycl::range{data_size}}; auto buf2 = sycl::buffer{array_2.data(), sycl::range{data_size}}; // Submission to the SYCL queue. defaultQueue.submit( [&](sycl::handler& cgh) { // Accessors that allow SYCL to decide how to access the data // on the device. auto acc0 = sycl::accessor{buf0, cgh, sycl::read_only}; auto acc1 = sycl::accessor{buf1, cgh, sycl::read_only}; auto acc2 = sycl::accessor{buf2, cgh, sycl::write_only}; // The main parallel_for loop. cgh.parallel_for<>( data_size, // number of iterations to loop over [=] (auto idx) { acc2[idx] = acc0[idx] + acc1[idx]; } ); } ); Challenges for VANTAGE-Reactions For the purposes of our code, we wanted to utilise dynamic polymorphism in C++ to allow us to reuse a great deal of functionality when creating objects to store data and functions related to the reactions we want to apply to particles. This presents a challenge when working with SYCL as it does not have the functionality to handle virtual functions or virtual inheritance. Additionally, there are also restrictions on what variable types are deemed to be device-copyable. The actual SYCL functionality (ie. loops, buffers, etc.) is wrapped by NESO-Particles to provide a cleaner interface for us but the limitations of SYCL still remain and we still have to be careful. Any trivially copyable types either built-in to C++ or user-defined are acceptable, so a method to allow for polymorphism via static means (using templates) could be useful. Potential solution for polymorphism via CRTP CRTP stands for Curiously Recurring Template Pattern, and is a viable alternative to dynamic polymorphism (with some limits). The idea is to construct derived class by inheriting from a template class and then to have the derived class as a template parameter for the base class. Below are two examples of inheritance in C++. On the left is the CRTP variant and on the right is a virtual member function overload based variant. Both are functionally identical but only the CRTP version is trivially copyable and is therefore device-copyable according to SYCL. template <typename Derived> class Animal_CRTP { public: void sound() { auto& underlying = static_cast<Derived&>(*this);,→ return underlying.template sound(); } }; class Cat_CRTP : public Animal_CRTP<Cat_CRTP> {,→ public: void sound() { std::cout << "Cats meow!" << std::endl; } }; class Animal_Virt { public: virtual void sound() {} }; class Cat_Virt : public Animal_Virt { public: void sound() override { std::cout << "Cats meow!" << std::endl; } }; Specifically, an object of type Cat_CRTP can be wrapped in a SYCL buffer and accessed within a SYCL loop that would be run on an external device, whereas Cat_Virt cannot. The key point is that any function that needs an Animal_CRTP derived object, could simply use a template parameter for the function like T_Animal and just specify the type of the argument in the function signature as: Animal_CRTP<T_Animal> and when called the function would accept a Cat_CRTP object. Host-Device separation for VANTAGE-Reactions An alternative solution for the specific needs of VANTAGE-Reactions was to separate out host-compatible and device-compatible objects and enforce a strict methodology for defining the device-compatible objects. Chiefly, the aim was to ensure that all device-compatible objects are device-copyable so that they are able to be accessed inside a SYCL loop and are the primary point of interaction with a SYCL loop. An example of the layout of the framework is given below (with placeholder names): HostBaseClass DeviceBaseClass HostDerivedClass_0 - device_obj: DeviceDerivedClass_0 + get_device_obj(): DeviceDerivedClass_0 HostDerivedClass_1 - device_obj: DeviceDerivedClass_1 + get_device_obj(): DeviceDerivedClass_1 HostDerivedClass_2 - device_obj: DeviceDerivedClass_2 + get_device_obj(): DeviceDerivedClass_2 DeviceDerivedClass_0 DeviceDerivedClass_1 DeviceDerivedClass_2 The general rule is that any HostDerivedClass type is mostly free to use non-SYCL compliant features (chiefly, virtual functions) but any DeviceDerivedClass type must be fully device-copyable and use only SYCL compliant features. Whenever there’s a need to run a SYCL loop with data from a DeviceDerivedClass, a copy of the object is retrieved from the HostDerivedClass object, stored in a temporary variable and then passed by value to the SYCL loop. The DeviceDerivedClass types are not implemented via CRTP due to some unique templating limitations in our code, they instead use non-virtual function overloads, since they are not ever passed to polymorphic functions. Acknowledgments & References Work on VANTAGE-Reactions was done at UKAEA (UK Atomic Energy Authority) with funding from UKRI (UK Research and Innovation). [1] SYCL-CRTP details: https://codeplay.com/portal/blogs/2019/07/12/ enabling-polymorphism-in-sycl-using-the-cpp-idiom-crtp [2] EIRENE homepage: https://www.eirene.de/ [3] DEGAS2 homepage: https://w3.pppl.gov/degas2/ [4] SYCL 2020 specification: https://registry.khronos.org/SYCL/specs/ sycl-2020/html/sycl-2020.html