|
|
|||
File indexing completed on 2026-10-26 09:34:33
0001 //------------------------------ -*- C++ -*- -------------------------------// 0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details 0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT) 0004 //---------------------------------------------------------------------------// 0005 //! \file corecel/data/Ldg.hh 0006 //---------------------------------------------------------------------------// 0007 #pragma once 0008 0009 #include <type_traits> 0010 0011 #include "corecel/Macros.hh" 0012 #if CELER_DEVICE_COMPILE 0013 // Make sure __ldg is available for HIP 0014 # include "corecel/DeviceRuntimeApi.hh" 0015 #endif 0016 0017 namespace celeritas 0018 { 0019 //---------------------------------------------------------------------------// 0020 /*! 0021 * \page ldg Cached device loading 0022 * 0023 * On GPUs, reading from global memory through the L1/texture cache can improve 0024 * throughput when many threads access the same address. 0025 * The \c __ldg intrinsic (CUDA/HIP) performs such a cached load, using 0026 * L1/texture memory rather than the ordinary data cache. 0027 * The hardware contract is that the pointed-to memory must be \em read-only 0028 * for the lifetime of the kernel; this is generally true for \em Params data 0029 * (physics tables, geometry) but not for \em State data. 0030 * On the host the \c ldg family of functions falls back to a plain 0031 * dereference, so no special-casing is needed in caller code. 0032 * Because \c ldg is only for \em read-only addresses in \em global memory, all 0033 * arguments \em must match only \c const_pointer types. 0034 * 0035 * \par Scalar values 0036 * 0037 * Pass a const pointer to any supported type to the one-argument \c ldg: 0038 * \code 0039 * real_type energy = ldg(&record.energy); 0040 * MaterialId mat = ldg(&record.material); // OpaqueId supported 0041 * \endcode 0042 * 0043 * Built-in implementations cover: 0044 * 0045 * - arithmetic types (identity, the default), 0046 * - enum types (reinterpret-cast to the underlying integer), 0047 * - \c OpaqueId (pointer to the underlying index \c T), 0048 * - \c Quantity (pointer to the underlying value \c T), 0049 * - \c Array (successive loads to each element). 0050 * 0051 * \par Spans and collections 0052 * 0053 * \c LdgSpan<T const> (from \c corecel/cont/LdgSpan.hh) is an alias for 0054 * \c Span whose iterator triggers \c __ldg on every element access. 0055 * Use it as you would any ordinary span: 0056 * \code 0057 * LdgSpan<real_type const> energies = params.get_energies(); 0058 * for (real_type e : energies) // each read uses __ldg 0059 * process(e); 0060 * \endcode 0061 * 0062 * \c Collection<T, Ownership::const_reference, MemSpace::device> returns 0063 * \c LdgSpan automatically when the element type supports \c ldg, so View 0064 * classes built on device \c const_reference collections benefit without any 0065 * extra work. 0066 * 0067 * \par Extending ldg to a new type 0068 * 0069 * The \c ldg function is found by argument-dependent lookup (ADL). 0070 * Implement a \c friend function \c ldg that takes a const pointer and returns 0071 * a value: 0072 * \code 0073 * template<class T> 0074 * class MyClass 0075 * { 0076 * public: 0077 * CELER_CONSTEXPR_FUNCTION friend MyClass ldg(MyClass const* m) 0078 * { 0079 * return MyClass{ldg(&m->value_)}; 0080 * } 0081 * 0082 * private: 0083 * T value_; 0084 * }; 0085 * \endcode 0086 * See \c OpaqueId, \c Quantity and \c Array for examples. 0087 * 0088 * \internal 0089 * 0090 * \par Implementation details 0091 * 0092 * \c detail::LdgWrapper<T const> is a thin proxy (similar to 0093 * \c std::reference_wrapper) that stores a \c const pointer and implicitly 0094 * converts to the value type by calling \c ldg. The result is always a 0095 * \em value, not a reference, and the load goes through \c __ldg on device. 0096 * 0097 * \c detail::LdgIterator<T const> is a random-access iterator whose 0098 * \c operator* returns an \c LdgWrapper. 0099 * Wrapping it in \c Span yields \c LdgSpan: range-for loops and standard 0100 * algorithms transparently trigger \c __ldg on every element access without 0101 * requiring any change at the call site. 0102 */ 0103 0104 //---------------------------------------------------------------------------// 0105 /*! 0106 * Wrap the low-level CUDA/HIP "load read-only global memory" function. 0107 * 0108 * On CUDA the load is cached in L1/texture memory, improving performance when 0109 * data is repeatedly read by many threads in a kernel. 0110 * 0111 * \warning The target must be \c global memory (or else the kernel may crash) 0112 * and \c read-only (or else the result may be wrong) for the lifetime of the 0113 * kernel. 0114 * This is generally true for Params data but not State data. 0115 */ 0116 template<class T> 0117 CELER_CONSTEXPR_FUNCTION std::enable_if_t<std::is_arithmetic_v<T>, T> ldg( 0118 T const* ptr) noexcept 0119 { 0120 #if CELER_DEVICE_COMPILE 0121 return __ldg(ptr); 0122 #else 0123 return *ptr; 0124 #endif 0125 } 0126 0127 //---------------------------------------------------------------------------// 0128 //! \cond (CELERITAS_DOC_DEV) 0129 /*! 0130 * Get a pointer to the underlying integer for an enum type. 0131 */ 0132 template<class T> 0133 CELER_CONSTEXPR_FUNCTION std::enable_if_t<std::is_enum_v<T>, T> ldg( 0134 T const* ptr) noexcept 0135 { 0136 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 0137 auto const* data = reinterpret_cast<std::underlying_type_t<T> const*>(ptr); 0138 return static_cast<T>(ldg(data)); 0139 } 0140 0141 //---------------------------------------------------------------------------// 0142 /*! 0143 * Load a struct member via \c ldg using a pointer-to-member. 0144 * 0145 * Convenience overload for when the member is known at the call site. 0146 * \code 0147 * BvhNodeId parent = ldg(node, &BvhLeafNode::parent); 0148 * \endcode 0149 */ 0150 template<class Class, class T> 0151 CELER_CONSTEXPR_FUNCTION T ldg(Class const& obj, T Class::* mp) noexcept 0152 { 0153 using ::celeritas::ldg; 0154 return ldg(&(obj.*mp)); 0155 } 0156 0157 //! \endcond 0158 //---------------------------------------------------------------------------// 0159 /*! 0160 * Storable projector that loads a struct member via \c ldg . 0161 * 0162 * Stores a pointer-to-member and, when called with an object, returns the 0163 * member value loaded via \c __ldg . Use this when the load must be captured 0164 * as a callable; for immediate use prefer the two-argument \c ldg overload. 0165 * 0166 * \code 0167 * auto load_parent = LdgMember{&BvhLeafNode::parent}; 0168 * BvhNodeId parent = load_parent(node); 0169 * \endcode 0170 */ 0171 template<class Class, class T> 0172 struct LdgMember 0173 { 0174 //// TYPES //// 0175 0176 using MemberPtr = T Class::*; 0177 0178 //// DATA //// 0179 0180 MemberPtr mp; 0181 0182 //// FUNCTIONS //// 0183 0184 CELER_CONSTEXPR_FUNCTION T operator()(Class const& obj) const 0185 { 0186 using ::celeritas::ldg; 0187 return ldg(&(obj.*mp)); 0188 } 0189 }; 0190 0191 //! Deduction guide: \c LdgMember{&Foo::bar} deduces \c LdgMember<Foo,Bar> 0192 template<class Class, class T> 0193 LdgMember(T Class::*) -> LdgMember<Class, T>; 0194 0195 //---------------------------------------------------------------------------// 0196 } // namespace celeritas
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|