statistics.hpp
1 
5 #pragma once
6 #include <atomic>
7 #include <cstddef>
8 #include <filesystem>
9 #include <initializer_list>
10 #include <limits>
11 #include <map>
12 #include <memory>
13 #include <mutex>
14 #include <optional>
15 #include <ostream>
16 #include <span>
17 #include <string>
18 #include <string_view>
19 #include <utility>
20 #include <vector>
21 
22 #include <rapidsmpf/config.hpp>
23 #include <rapidsmpf/memory/memory_type.hpp>
24 #include <rapidsmpf/memory/pinned_memory_resource.hpp>
25 #include <rapidsmpf/rmm_resource_adaptor.hpp>
26 #include <rapidsmpf/utils/misc.hpp>
27 
28 namespace rapidsmpf {
29 
30 class StreamOrderedTiming;
31 
71 class Statistics {
72  public:
99  enum class Formatter : std::uint8_t {
100  Default = 0,
101  Bytes,
102  Duration,
103  HitRate,
104  MemoryThroughput,
105  _Count,
106  };
107 
114  Statistics(bool enabled = true);
115 
127  std::shared_ptr<PinnedMemoryResource> pinned_mr = PinnedMemoryResource::Disabled
128  );
129 
140  static std::shared_ptr<Statistics> from_options(
142  config::Options options,
143  std::shared_ptr<PinnedMemoryResource> pinned_mr = PinnedMemoryResource::Disabled
144  );
145 
146  ~Statistics() noexcept;
147 
148  // `Statistics` is owned exclusively through `std::shared_ptr` (see `disabled()` and
149  // `from_options()`).
150  Statistics(Statistics const&) = delete;
151  Statistics& operator=(Statistics const&) = delete;
152  Statistics(Statistics&&) = delete;
153  Statistics& operator=(Statistics&&) = delete;
154 
163  static std::shared_ptr<Statistics> disabled();
164 
170  bool enabled() const noexcept {
171  return enabled_.load(std::memory_order_acquire);
172  }
173 
177  void enable() noexcept {
178  enabled_.store(true, std::memory_order_release);
179  }
180 
184  void disable() noexcept {
185  enabled_.store(false, std::memory_order_release);
186  }
187 
206  std::string report(std::string const& header = "Statistics:") const;
207 
220  void write_json(std::ostream& os) const;
221 
228  void write_json(std::filesystem::path const& filepath) const;
229 
237  [[nodiscard]] std::shared_ptr<Statistics> copy() const;
238 
246  [[nodiscard]] std::vector<std::uint8_t> serialize() const;
247 
257  [[nodiscard]] static std::shared_ptr<Statistics> deserialize(
258  std::span<std::uint8_t const> data
259  );
260 
282  [[nodiscard]] static std::shared_ptr<Statistics> merge(
283  std::span<std::shared_ptr<Statistics> const> stats
284  );
285 
292  class Stat {
293  public:
297  Stat() = default;
298 
306  Stat(std::size_t count, double value, double max);
307 
315  auto operator<=>(Stat const&) const noexcept = default;
316 
322  void add(double value);
323 
329  [[nodiscard]] std::size_t count() const noexcept;
330 
336  [[nodiscard]] double value() const noexcept;
337 
344  [[nodiscard]] double max() const noexcept;
345 
354  [[nodiscard]] static constexpr std::size_t serialized_size() noexcept {
355  return sizeof(std::uint64_t) + sizeof(double) + sizeof(double);
356  }
357 
365  std::uint8_t* serialize(std::uint8_t* out) const;
366 
376  [[nodiscard]] static std::pair<Stat, std::span<std::uint8_t const>> deserialize(
377  std::span<std::uint8_t const> data
378  );
379 
388  [[nodiscard]] Stat merge(Stat const& other) const;
389 
390  private:
391  std::size_t count_{0};
392  double value_{0};
393  double max_{-std::numeric_limits<double>::infinity()};
394  };
395 
402  Stat get_stat(std::string const& name) const;
403 
414  void add_stat(std::string const& name, double value);
415 
433  std::string const& report_entry_name,
434  std::initializer_list<std::string_view> stat_names,
435  Formatter formatter
436  );
437 
438  // clang-format off
444  // clang-format on
446  std::string const& report_entry_name,
447  std::vector<std::string> stat_names,
448  Formatter formatter
449  );
450 
461  void add_bytes_stat(std::string const& name, std::size_t nbytes);
462 
473  void add_duration_stat(std::string const& name, Duration seconds);
474 
496  MemoryType src, MemoryType dst, std::size_t nbytes, StreamOrderedTiming&& timing
497  );
498 
517  MemoryType mem_type, std::size_t nbytes, StreamOrderedTiming&& timing
518  );
519 
525  std::vector<std::string> list_stat_names() const;
526 
532  void clear();
533 
540 
544  struct MemoryRecord {
546  std::int64_t global_peak{0};
547  std::uint64_t num_calls{0};
548  };
549 
556  public:
560  MemoryRecorder() = default;
561 
569  MemoryRecorder(Statistics* stats, RmmResourceAdaptor mr, std::string name);
570 
577 
579  MemoryRecorder(MemoryRecorder const&) = delete;
580  MemoryRecorder& operator=(MemoryRecorder const&) = delete;
581  MemoryRecorder(MemoryRecorder&&) = delete;
582  MemoryRecorder& operator=(MemoryRecorder&&) = delete;
583 
584  private:
585  Statistics* stats_{nullptr};
586  std::optional<RmmResourceAdaptor> mr_;
587  std::string name_;
588  };
589 
599 
605  std::unordered_map<std::string, MemoryRecord> const& get_memory_records() const;
606 
607  private:
611  struct ReportEntry {
612  std::vector<std::string> stat_names;
613  Formatter formatter;
614  };
615 
616  mutable std::mutex mutex_;
617  std::atomic<bool> enabled_;
618  std::map<std::string, Stat> stats_;
619  std::map<std::string, ReportEntry> report_entries_;
620  std::unordered_map<std::string, MemoryRecord> memory_records_;
621  std::optional<RmmResourceAdaptor> mr_;
622  std::shared_ptr<PinnedMemoryResource>
623  pinned_mr_;
624 };
625 
649 #define RAPIDSMPF_MEMORY_PROFILE(...) \
650  RAPIDSMPF_OVERLOAD_BY_ARG_COUNT( \
651  __VA_ARGS__, RAPIDSMPF_MEMORY_PROFILE_2, RAPIDSMPF_MEMORY_PROFILE_1 \
652  ) \
653  (__VA_ARGS__)
654 
655 // Version with default function name (__func__)
656 #define RAPIDSMPF_MEMORY_PROFILE_1(stats) RAPIDSMPF_MEMORY_PROFILE_2(stats, __func__)
657 
658 // Version with custom function name
659 #define RAPIDSMPF_MEMORY_PROFILE_2(stats, funcname) \
660  auto&& RAPIDSMPF_CONCAT(_rapidsmpf_stats_, __LINE__) = (stats); \
661  auto const RAPIDSMPF_CONCAT(_rapidsmpf_memory_recorder_, __LINE__) = \
662  ((rapidsmpf::detail::to_pointer(RAPIDSMPF_CONCAT(_rapidsmpf_stats_, __LINE__)) \
663  && rapidsmpf::detail::to_pointer( \
664  RAPIDSMPF_CONCAT(_rapidsmpf_stats_, __LINE__) \
665  ) -> is_memory_profiling_enabled()) \
666  ? rapidsmpf::detail::to_pointer( \
667  RAPIDSMPF_CONCAT(_rapidsmpf_stats_, __LINE__) \
668  ) \
669  ->create_memory_recorder( \
670  std::string(__FILE__) + ":" + RAPIDSMPF_STRINGIFY(__LINE__) + "(" \
671  + std::string(funcname) + ")" \
672  ) \
673  : rapidsmpf::Statistics::MemoryRecorder{})
674 
675 } // namespace rapidsmpf
static constexpr auto Disabled
Sentinel value used to disable pinned host memory.
A RMM memory resource adaptor tailored to RapidsMPF.
RAII-style object for scoped memory usage tracking.
Definition: statistics.hpp:555
MemoryRecorder(MemoryRecorder const &)=delete
Deleted copy and move constructors/assignments.
MemoryRecorder()=default
Constructs a no-op MemoryRecorder (disabled state).
MemoryRecorder(Statistics *stats, RmmResourceAdaptor mr, std::string name)
Constructs an active MemoryRecorder.
Represents a single tracked statistic.
Definition: statistics.hpp:292
void add(double value)
Adds a value to this statistic.
std::size_t count() const noexcept
Returns the number of updates applied to this statistic.
double max() const noexcept
Returns the maximum value seen across all add() calls.
std::uint8_t * serialize(std::uint8_t *out) const
Serializes this Stat to a byte buffer.
Stat merge(Stat const &other) const
Merges another Stat into this one, returning the combined result.
Stat(std::size_t count, double value, double max)
Constructs a Stat with explicit field values.
double value() const noexcept
Returns the total accumulated value.
auto operator<=>(Stat const &) const noexcept=default
Three-way comparison operator.
static std::pair< Stat, std::span< std::uint8_t const > > deserialize(std::span< std::uint8_t const > data)
Deserializes a Stat from a byte buffer.
Stat()=default
Default-constructs a Stat.
static constexpr std::size_t serialized_size() noexcept
Returns the serialized size of this Stat in bytes.
Definition: statistics.hpp:354
Tracks statistics across rapidsmpf operations.
Definition: statistics.hpp:71
std::string report(std::string const &header="Statistics:") const
Generates a formatted report of all collected statistics.
Formatter
Identifies a predefined formatter used by report().
Definition: statistics.hpp:99
@ _Count
Sentinel; must remain last.
bool is_memory_profiling_enabled() const
Checks whether memory profiling is enabled.
Stat get_stat(std::string const &name) const
Retrieves a statistic by name.
static std::shared_ptr< Statistics > from_options(RmmResourceAdaptor mr, config::Options options, std::shared_ptr< PinnedMemoryResource > pinned_mr=PinnedMemoryResource::Disabled)
Construct from configuration options.
void clear()
Clears all statistics.
MemoryRecorder create_memory_recorder(std::string name)
Creates a scoped memory recorder for the given name.
static std::shared_ptr< Statistics > disabled()
Returns a shared pointer to a disabled (no-op) Statistics instance.
void write_json(std::ostream &os) const
Writes a JSON representation of all collected statistics to a stream.
std::shared_ptr< Statistics > copy() const
Creates a deep copy of this Statistics object.
void add_bytes_stat(std::string const &name, std::size_t nbytes)
Adds a byte count to the named statistic.
void enable() noexcept
Enable statistics tracking for this instance.
Definition: statistics.hpp:177
void record_alloc(MemoryType mem_type, std::size_t nbytes, StreamOrderedTiming &&timing)
Record size and wall-clock duration for a buffer allocation.
void add_duration_stat(std::string const &name, Duration seconds)
Adds a duration to the named statistic.
void add_report_entry(std::string const &report_entry_name, std::vector< std::string > stat_names, Formatter formatter)
Associate a formatter with one or more named statistics for report rendering.
std::vector< std::string > list_stat_names() const
Get the names of all statistics.
Statistics(bool enabled=true)
Constructs a Statistics object without memory profiling.
void add_stat(std::string const &name, double value)
Adds a numeric value to the named statistic.
static std::shared_ptr< Statistics > merge(std::span< std::shared_ptr< Statistics > const > stats)
Merge a set of Statistics into a new instance.
std::vector< std::uint8_t > serialize() const
Serializes the stats and report entries to a binary byte vector.
void record_copy(MemoryType src, MemoryType dst, std::size_t nbytes, StreamOrderedTiming &&timing)
Record byte count and wall-clock duration for a memory copy operation.
bool enabled() const noexcept
Checks if statistics tracking is enabled.
Definition: statistics.hpp:170
void write_json(std::filesystem::path const &filepath) const
Writes a JSON report of all collected statistics to a file.
static std::shared_ptr< Statistics > deserialize(std::span< std::uint8_t const > data)
Deserializes a Statistics object from a binary byte vector.
void disable() noexcept
Disable statistics tracking for this instance.
Definition: statistics.hpp:184
Statistics(RmmResourceAdaptor mr, std::shared_ptr< PinnedMemoryResource > pinned_mr=PinnedMemoryResource::Disabled)
Constructs a Statistics object with memory profiling enabled.
void add_report_entry(std::string const &report_entry_name, std::initializer_list< std::string_view > stat_names, Formatter formatter)
Associate a formatter with one or more named statistics for report rendering.
std::unordered_map< std::string, MemoryRecord > const & get_memory_records() const
Retrieves all memory profiling records stored by this instance.
Stream-ordered wall-clock timer that records its result into Statistics.
Manages configuration options for RapidsMPF operations.
Definition: config.hpp:140
RAPIDS Multi-Processor interfaces.
Definition: backend.hpp:14
std::chrono::duration< double > Duration
Alias for a duration type representing time in seconds as a double.
Definition: misc.hpp:33
MemoryType
Enum representing the type of memory sorted in decreasing order of preference.
Definition: memory_type.hpp:16
Memory statistics for a specific scope.
Holds memory profiling information for a named scope.
Definition: statistics.hpp:544
std::int64_t global_peak
Peak global memory usage during the scope.
Definition: statistics.hpp:546
ScopedMemoryRecord scoped
Scoped memory stats.
Definition: statistics.hpp:545
std::uint64_t num_calls
Number of times the scope was invoked.
Definition: statistics.hpp:547