statistics.hpp
1 
5 #pragma once
6 #include <atomic>
7 #include <cstddef>
8 #include <filesystem>
9 #include <functional>
10 #include <limits>
11 #include <map>
12 #include <mutex>
13 #include <ostream>
14 #include <string>
15 #include <utility>
16 #include <vector>
17 
18 #include <rapidsmpf/config.hpp>
19 #include <rapidsmpf/memory/memory_type.hpp>
20 #include <rapidsmpf/rmm_resource_adaptor.hpp>
21 #include <rapidsmpf/utils/misc.hpp>
22 
23 namespace rapidsmpf {
24 
25 class StreamOrderedTiming;
26 
62 class Statistics {
63  public:
70  Statistics(bool enabled = true);
71 
83 
93  static std::shared_ptr<Statistics> from_options(
95  );
96 
97  ~Statistics() noexcept;
98  Statistics(Statistics const&) = delete;
99  Statistics& operator=(Statistics const&) = delete;
100 
109  static std::shared_ptr<Statistics> disabled();
110 
116  Statistics(Statistics&& o) noexcept
117  : enabled_(o.enabled()),
118  stats_{std::move(o.stats_)},
119  formatters_{std::move(o.formatters_)} {}
120 
127  Statistics& operator=(Statistics&& o) noexcept {
128  enabled_ = o.enabled();
129  stats_ = std::move(o.stats_);
130  formatters_ = std::move(o.formatters_);
131  return *this;
132  }
133 
139  bool enabled() const noexcept {
140  return enabled_.load(std::memory_order_acquire);
141  }
142 
146  void enable() noexcept {
147  enabled_.store(true, std::memory_order_release);
148  }
149 
153  void disable() noexcept {
154  enabled_.store(false, std::memory_order_release);
155  }
156 
173  std::string report(std::string const& header = "Statistics:") const;
174 
188  void write_json(std::ostream& os) const;
189 
196  void write_json(std::filesystem::path const& filepath) const;
197 
201  class Stat {
202  public:
206  Stat() = default;
207 
215  auto operator<=>(Stat const&) const noexcept = default;
216 
222  void add(double value) {
223  ++count_;
224  value_ += value;
225  max_ = std::max(max_, value);
226  }
227 
233  [[nodiscard]] std::size_t count() const noexcept {
234  return count_;
235  }
236 
242  [[nodiscard]] double value() const noexcept {
243  return value_;
244  }
245 
252  [[nodiscard]] double max() const noexcept {
253  return max_;
254  }
255 
256  private:
257  std::size_t count_{0};
258  double value_{0};
259  double max_{-std::numeric_limits<double>::infinity()};
260  };
261 
267  using Formatter = std::function<void(std::ostream&, std::vector<Stat> const&)>;
268 
275  Stat get_stat(std::string const& name) const;
276 
285  void add_stat(std::string const& name, double value);
286 
301  bool exist_report_entry_name(std::string const& name) const;
302 
313  void register_formatter(std::string const& name, Formatter formatter);
314 
328  std::string const& report_entry_name,
329  std::vector<std::string> const& stat_names,
330  Formatter formatter
331  );
332 
343  void add_bytes_stat(std::string const& name, std::size_t nbytes);
344 
355  void add_duration_stat(std::string const& name, Duration seconds);
356 
378  MemoryType src, MemoryType dst, std::size_t nbytes, StreamOrderedTiming&& timing
379  );
380 
399  MemoryType mem_type, std::size_t nbytes, StreamOrderedTiming&& timing
400  );
401 
407  std::vector<std::string> list_stat_names() const;
408 
414  void clear();
415 
422 
426  struct MemoryRecord {
428  std::int64_t global_peak{0};
429  std::uint64_t num_calls{0};
430  };
431 
438  public:
442  MemoryRecorder() = default;
443 
451  MemoryRecorder(Statistics* stats, RmmResourceAdaptor* mr, std::string name);
452 
459 
461  MemoryRecorder(MemoryRecorder const&) = delete;
462  MemoryRecorder& operator=(MemoryRecorder const&) = delete;
463  MemoryRecorder(MemoryRecorder&&) = delete;
464  MemoryRecorder& operator=(MemoryRecorder&&) = delete;
465 
466  private:
467  Statistics* stats_{nullptr};
468  RmmResourceAdaptor* mr_{nullptr};
469  std::string name_;
470  ScopedMemoryRecord main_record_;
471  };
472 
482 
488  std::unordered_map<std::string, MemoryRecord> const& get_memory_records() const;
489 
490  private:
494  struct FormatterEntry {
495  std::vector<std::string> stat_names;
496  Formatter fn;
497  };
498 
499  mutable std::mutex mutex_;
500  std::atomic<bool> enabled_;
501  std::map<std::string, Stat> stats_;
502  std::map<std::string, FormatterEntry> formatters_;
503  std::unordered_map<std::string, MemoryRecord> memory_records_;
504  RmmResourceAdaptor* mr_;
505 };
506 
530 #define RAPIDSMPF_MEMORY_PROFILE(...) \
531  RAPIDSMPF_OVERLOAD_BY_ARG_COUNT( \
532  __VA_ARGS__, RAPIDSMPF_MEMORY_PROFILE_2, RAPIDSMPF_MEMORY_PROFILE_1 \
533  ) \
534  (__VA_ARGS__)
535 
536 // Version with default function name (__func__)
537 #define RAPIDSMPF_MEMORY_PROFILE_1(stats) RAPIDSMPF_MEMORY_PROFILE_2(stats, __func__)
538 
539 // Version with custom function name
540 #define RAPIDSMPF_MEMORY_PROFILE_2(stats, funcname) \
541  auto&& RAPIDSMPF_CONCAT(_rapidsmpf_stats_, __LINE__) = (stats); \
542  auto const RAPIDSMPF_CONCAT(_rapidsmpf_memory_recorder_, __LINE__) = \
543  ((rapidsmpf::detail::to_pointer(RAPIDSMPF_CONCAT(_rapidsmpf_stats_, __LINE__)) \
544  && rapidsmpf::detail::to_pointer( \
545  RAPIDSMPF_CONCAT(_rapidsmpf_stats_, __LINE__) \
546  ) -> is_memory_profiling_enabled()) \
547  ? rapidsmpf::detail::to_pointer( \
548  RAPIDSMPF_CONCAT(_rapidsmpf_stats_, __LINE__) \
549  ) \
550  ->create_memory_recorder( \
551  std::string(__FILE__) + ":" + RAPIDSMPF_STRINGIFY(__LINE__) + "(" \
552  + std::string(funcname) + ")" \
553  ) \
554  : rapidsmpf::Statistics::MemoryRecorder{})
555 
556 } // namespace rapidsmpf
A RMM memory resource adaptor tailored to RapidsMPF.
RAII-style object for scoped memory usage tracking.
Definition: statistics.hpp:437
MemoryRecorder(Statistics *stats, RmmResourceAdaptor *mr, std::string name)
Constructs an active MemoryRecorder.
MemoryRecorder(MemoryRecorder const &)=delete
Deleted copy and move constructors/assignments.
MemoryRecorder()=default
Constructs a no-op MemoryRecorder (disabled state).
Represents a single tracked statistic.
Definition: statistics.hpp:201
void add(double value)
Adds a value to this statistic.
Definition: statistics.hpp:222
std::size_t count() const noexcept
Returns the number of updates applied to this statistic.
Definition: statistics.hpp:233
double max() const noexcept
Returns the maximum value seen across all add() calls.
Definition: statistics.hpp:252
double value() const noexcept
Returns the total accumulated value.
Definition: statistics.hpp:242
auto operator<=>(Stat const &) const noexcept=default
Three-way comparison operator.
Stat()=default
Default-constructs a Stat.
Tracks statistics across rapidsmpf operations.
Definition: statistics.hpp:62
std::string report(std::string const &header="Statistics:") const
Generates a formatted report of all collected statistics.
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.
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.
bool exist_report_entry_name(std::string const &name) const
Check whether a report entry name already has a formatter registered.
void register_formatter(std::string const &report_entry_name, std::vector< std::string > const &stat_names, Formatter formatter)
Register a formatter that takes multiple named statistics.
void write_json(std::ostream &os) const
Writes a JSON representation of all collected statistics to a stream.
static std::shared_ptr< Statistics > from_options(RmmResourceAdaptor *mr, config::Options options)
Construct from configuration options.
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:146
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.
Statistics(RmmResourceAdaptor *mr)
Constructs a Statistics object with memory profiling enabled.
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.
std::function< void(std::ostream &, std::vector< Stat > const &)> Formatter
Type alias for a statistics formatting function.
Definition: statistics.hpp:267
void register_formatter(std::string const &name, Formatter formatter)
Register a formatter for a single named statistic.
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:139
void write_json(std::filesystem::path const &filepath) const
Writes a JSON report of all collected statistics to a file.
void disable() noexcept
Disable statistics tracking for this instance.
Definition: statistics.hpp:153
Statistics & operator=(Statistics &&o) noexcept
Move assignment operator.
Definition: statistics.hpp:127
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:13
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:426
std::int64_t global_peak
Peak global memory usage during the scope.
Definition: statistics.hpp:428
ScopedMemoryRecord scoped
Scoped memory stats.
Definition: statistics.hpp:427
std::uint64_t num_calls
Number of times the scope was invoked.
Definition: statistics.hpp:429