include/stats/histogram.h (84 lines of code) (raw):

// // Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All rights reserved. // #ifndef NCCL_OFI_STATS_HISTOGRAM #define NCCL_OFI_STATS_HISTOGRAM #include <cassert> #include <chrono> #include <cstddef> #include <string> #include <sstream> #include <vector> #include "nccl_ofi_log.h" #include "histogram_binner.h" // // Base histogram class. Histograms are a lightweight mechanism for tracking // events occurances in code and are used for instrumenting the plugin code. // // T is the type of the data that will be inserted into the histogram. Any POD // will work, and little effort has been put into making the interface safe for // non-Pods. // template <typename T, typename Binner> class histogram { public: histogram(const std::string& description_arg, Binner binner_arg) : description(description_arg), binner(binner_arg), bins(binner.get_num_bins()), num_samples(0), first_insert(true) { } void insert(const T& input_val) { if (OFI_UNLIKELY(first_insert)) { max_val = min_val = input_val; first_insert = false; } if (input_val > max_val) { max_val = input_val; } else if (input_val < min_val) { min_val = input_val; } bins[binner.get_bin(input_val)]++; num_samples++; } void print_stats(void) { auto range_labels = binner.get_bin_ranges(); NCCL_OFI_INFO(NCCL_NET, "histogram %s", description.c_str()); NCCL_OFI_INFO(NCCL_NET, " min: %ld, max: %ld, num_samples: %lu", (long int)min_val, (long int)max_val, num_samples); for (size_t i = 0 ; i < bins.size() ; ++i) { std::stringstream ss; ss << " " << range_labels[i] << " - "; if (i + 1 != bins.size()) { ss << range_labels[i + 1] - 1; } else { ss << " "; } ss << " " << bins[i]; NCCL_OFI_INFO(NCCL_NET, "%s", ss.str().c_str()); } } protected: std::string description; Binner binner; std::vector<std::size_t> bins; T max_val; T min_val; std::size_t num_samples; bool first_insert; }; // // Histogram class for tracking intervals. A timer_histogram class can only // track one interval at a time, and will auto-insert the result when // stop_timer() is called. Times are recorded in microseconds. // // T is the type of the data that will be inserted into the histogram. Any POD // will work, and little effort has been put into making the interface safe for // non-Pods. template <typename Binner, typename clock = std::chrono::steady_clock, typename T = std::size_t> class timer_histogram : public histogram<T, Binner> { public: using rep = T; using histogram<T, Binner>::insert; timer_histogram(const std::string &description_arg, Binner binner_arg) : histogram<T, Binner>(description_arg, binner_arg) { } void start_timer(void) { start_time = clock::now(); asm volatile ("" : : : "memory"); } rep stop_timer(void) { asm volatile ("" : : : "memory"); auto now = clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(now - start_time); insert(duration.count()); return duration.count(); } protected: typename clock::time_point start_time; }; #endif