Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:50

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2022-2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file corecel/sys/KernelRegistry.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <atomic>
0011 #include <cstdint>
0012 #include <iosfwd>  // IWYU pragma: keep
0013 #include <memory>
0014 #include <mutex>
0015 #include <string>
0016 #include <string_view>
0017 #include <vector>
0018 
0019 #include "corecel/Assert.hh"
0020 #include "corecel/OpaqueId.hh"
0021 
0022 #include "KernelAttributes.hh"
0023 
0024 namespace celeritas
0025 {
0026 //---------------------------------------------------------------------------//
0027 struct KernelProfiling
0028 {
0029     using value_type = std::uint_least64_t;
0030 
0031     //!< Number of times launched
0032     std::atomic<value_type> num_launches{0};
0033     //!< Number of threads integrated over all launches
0034     std::atomic<value_type> accum_threads{0};
0035 
0036     // Increment atomic counters given the number of threads
0037     inline void log_launch(value_type num_threads);
0038 };
0039 
0040 //---------------------------------------------------------------------------//
0041 struct KernelMetadata
0042 {
0043     std::string name;
0044     KernelAttributes attributes;
0045     KernelProfiling profiling;
0046 };
0047 
0048 //! Ordered identifiers for registered kernels
0049 using KernelId = OpaqueId<KernelMetadata>;
0050 
0051 //---------------------------------------------------------------------------//
0052 /*!
0053  * Keep track of kernels and launches.
0054  *
0055  * Every "insert" creates a unique \c KernelMetadata entry in a thread-safe
0056  * fashion (in case multiple threads are launching kernels for the first time).
0057  * Thus every kernel added to the registry needs a \c static local data (i.e.,
0058  * \c KernelParamCalculator) to track whether the kernel has been added and to
0059  * keep a reference to the returned profiling data counter. Kernels are always
0060  * added sequentially and can never be removed from the registry once added.
0061  * Kernels that share the same name will create independent entries!
0062  *
0063  * This class has a thread-safe methods because it's meant to be shared
0064  * across multiple threads when running. Generally \c insert is the only method
0065  * expected to have contention across threads.
0066  */
0067 class KernelRegistry
0068 {
0069   public:
0070     // Whether profiling metrics (launch count, max threads) are collected
0071     static bool profiling();
0072 
0073     // Construct without any data
0074     KernelRegistry() = default;
0075 
0076     //// CONSTRUCTION ////
0077 
0078     // Register a kernel and return optional reference to profiling info
0079     KernelProfiling* insert(std::string_view name, KernelAttributes&& attrs);
0080 
0081     //// ACCESSORS ////
0082 
0083     //! \todo rename to size
0084     // Number of kernel diagnostics available
0085     KernelId::size_type num_kernels() const;
0086 
0087     //! \todo rename to get
0088     // Access kernel data for a single kernel
0089     KernelMetadata const& kernel(KernelId id) const;
0090 
0091   private:
0092     using UPKM = std::unique_ptr<KernelMetadata>;
0093 
0094     mutable std::mutex kernels_mutex_;
0095     std::vector<UPKM> kernels_;
0096 };
0097 
0098 //---------------------------------------------------------------------------//
0099 // FREE FUNCTIONS
0100 //---------------------------------------------------------------------------//
0101 // Globally shared registry of kernels for end-of-program diagnostics
0102 KernelRegistry& kernel_registry();
0103 
0104 // Write kernel statistics to a stream
0105 std::ostream& operator<<(std::ostream& os, KernelMetadata const& md);
0106 
0107 //---------------------------------------------------------------------------//
0108 // INLINE DEFINITIONS
0109 //---------------------------------------------------------------------------//
0110 /*!
0111  * Accumulate counters for a kernel launch.
0112  */
0113 void KernelProfiling::log_launch(value_type num_threads)
0114 {
0115     CELER_EXPECT(num_threads > 0);
0116 
0117     // Increment launches by 1 and thread count by num_threads.
0118     // We don't care in what order these values are written.
0119     this->num_launches.fetch_add(1, std::memory_order_relaxed);
0120     this->accum_threads.fetch_add(num_threads, std::memory_order_relaxed);
0121 }
0122 
0123 //---------------------------------------------------------------------------//
0124 }  // namespace celeritas