Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:55:06

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 /*!
0006  * \file corecel/math/Atomics.hh
0007  * \brief Atomics for use in kernel code (CUDA/HIP/OpenMP).
0008  *
0009  * \note On CPU, these functions assume the atomic add is being done in
0010  * with \em track-level parallelism rather than \em event-level because these
0011  * utilities are meant for "kernel" code. Multiple independent events
0012  * must \em not use these functions to simultaneously modify shared data.
0013  *
0014  * ---------------------------------------------------------------------------*/
0015 #pragma once
0016 
0017 #include "corecel/Assert.hh"
0018 #include "corecel/Macros.hh"
0019 #include "corecel/Types.hh"
0020 
0021 #include "Algorithms.hh"
0022 
0023 #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 600)
0024 #    error "Celeritas requires CUDA arch 6.0 (P100) or greater"
0025 #endif
0026 
0027 #if defined(_OPENMP) && CELERITAS_OPENMP == CELERITAS_OPENMP_TRACK
0028 //! Capture the subsequent expression as an OpenMP atomic
0029 #    define CELER_CAPTURE_IF_OPENMP_TRACK _Pragma("omp atomic capture")
0030 #else
0031 //! Simply scope the next block
0032 #    define CELER_CAPTURE_IF_OPENMP_TRACK
0033 #endif
0034 
0035 namespace celeritas
0036 {
0037 //---------------------------------------------------------------------------//
0038 /*!
0039  * Add to a value, returning the original value.
0040  */
0041 template<class T>
0042 CELER_FORCEINLINE_FUNCTION T atomic_add(T* address, T value)
0043 {
0044 #if CELER_DEVICE_COMPILE
0045     return atomicAdd(address, value);
0046 #else
0047     CELER_EXPECT(address);
0048     T initial;
0049     CELER_CAPTURE_IF_OPENMP_TRACK
0050     {
0051         initial = *address;
0052         *address += value;
0053     }
0054     return initial;
0055 #endif
0056 }
0057 
0058 //---------------------------------------------------------------------------//
0059 /*!
0060  * Set the value to the minimum of the actual and given, returning old.
0061  */
0062 template<class T>
0063 CELER_FORCEINLINE_FUNCTION T atomic_min(T* address, T value)
0064 {
0065 #if CELER_DEVICE_COMPILE
0066     return atomicMin(address, value);
0067 #else
0068     CELER_EXPECT(address);
0069     T initial;
0070     CELER_CAPTURE_IF_OPENMP_TRACK
0071     {
0072         initial = *address;
0073         *address = celeritas::min(initial, value);
0074     }
0075     return initial;
0076 #endif
0077 }
0078 
0079 //---------------------------------------------------------------------------//
0080 /*!
0081  * Set the value to the maximum of the actual and given, returning old.
0082  */
0083 template<class T>
0084 CELER_FORCEINLINE_FUNCTION T atomic_max(T* address, T value)
0085 {
0086 #if CELER_DEVICE_COMPILE
0087     return atomicMax(address, value);
0088 #else
0089     CELER_EXPECT(address);
0090     T initial;
0091     CELER_CAPTURE_IF_OPENMP_TRACK
0092     {
0093         initial = *address;
0094         *address = celeritas::max(initial, value);
0095     }
0096     return initial;
0097 #endif
0098 }
0099 
0100 //---------------------------------------------------------------------------//
0101 }  // namespace celeritas