| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #ifndef BENCHMARK_PERF_COUNTERS_H |
| #define BENCHMARK_PERF_COUNTERS_H |
|
|
| #include <array> |
| #include <cstdint> |
| #include <cstring> |
| #include <memory> |
| #include <vector> |
|
|
| #include "benchmark/benchmark.h" |
| #include "check.h" |
| #include "log.h" |
| #include "mutex.h" |
|
|
| #ifndef BENCHMARK_OS_WINDOWS |
| #include <unistd.h> |
| #endif |
|
|
| #if defined(_MSC_VER) |
| #pragma warning(push) |
| |
| #pragma warning(disable : 4251) |
| #endif |
|
|
| namespace benchmark { |
| namespace internal { |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class BENCHMARK_EXPORT PerfCounterValues { |
| public: |
| explicit PerfCounterValues(size_t nr_counters) : nr_counters_(nr_counters) { |
| BM_CHECK_LE(nr_counters_, kMaxCounters); |
| } |
|
|
| |
| uint64_t operator[](size_t pos) const { return values_[pos]; } |
|
|
| |
| |
| static constexpr size_t kMaxCounters = 32; |
|
|
| private: |
| friend class PerfCounters; |
| |
| |
| std::pair<char*, size_t> get_data_buffer() { |
| return {reinterpret_cast<char*>(values_.data()), |
| sizeof(uint64_t) * (kPadding + nr_counters_)}; |
| } |
|
|
| |
| |
| |
| size_t Read(const std::vector<int>& leaders); |
|
|
| |
| |
| static constexpr size_t kPadding = 2; |
| std::array<uint64_t, kPadding + kMaxCounters> values_; |
| const size_t nr_counters_; |
| }; |
|
|
| |
| |
| |
| class BENCHMARK_EXPORT PerfCounters final { |
| public: |
| |
| static const bool kSupported; |
|
|
| |
| static PerfCounters NoCounters() { return PerfCounters(); } |
|
|
| ~PerfCounters() { CloseCounters(); } |
| PerfCounters() = default; |
| PerfCounters(PerfCounters&&) = default; |
| PerfCounters(const PerfCounters&) = delete; |
| PerfCounters& operator=(PerfCounters&&) noexcept; |
| PerfCounters& operator=(const PerfCounters&) = delete; |
|
|
| |
| |
| static bool Initialize(); |
|
|
| |
| |
| static bool IsCounterSupported(const std::string& name); |
|
|
| |
| |
| |
| |
| |
| static PerfCounters Create(const std::vector<std::string>& counter_names); |
|
|
| |
| |
| |
| BENCHMARK_ALWAYS_INLINE bool Snapshot(PerfCounterValues* values) const { |
| #ifndef BENCHMARK_OS_WINDOWS |
| assert(values != nullptr); |
| return values->Read(leader_ids_) == counter_ids_.size(); |
| #else |
| (void)values; |
| return false; |
| #endif |
| } |
|
|
| const std::vector<std::string>& names() const { return counter_names_; } |
| size_t num_counters() const { return counter_names_.size(); } |
|
|
| private: |
| PerfCounters(const std::vector<std::string>& counter_names, |
| std::vector<int>&& counter_ids, std::vector<int>&& leader_ids) |
| : counter_ids_(std::move(counter_ids)), |
| leader_ids_(std::move(leader_ids)), |
| counter_names_(counter_names) {} |
|
|
| void CloseCounters() const; |
|
|
| std::vector<int> counter_ids_; |
| std::vector<int> leader_ids_; |
| std::vector<std::string> counter_names_; |
| }; |
|
|
| |
| class BENCHMARK_EXPORT PerfCountersMeasurement final { |
| public: |
| PerfCountersMeasurement(const std::vector<std::string>& counter_names); |
|
|
| size_t num_counters() const { return counters_.num_counters(); } |
|
|
| std::vector<std::string> names() const { return counters_.names(); } |
|
|
| BENCHMARK_ALWAYS_INLINE bool Start() { |
| if (num_counters() == 0) return true; |
| |
| |
| ClobberMemory(); |
| valid_read_ &= counters_.Snapshot(&start_values_); |
| ClobberMemory(); |
|
|
| return valid_read_; |
| } |
|
|
| BENCHMARK_ALWAYS_INLINE bool Stop( |
| std::vector<std::pair<std::string, double>>& measurements) { |
| if (num_counters() == 0) return true; |
| |
| |
| ClobberMemory(); |
| valid_read_ &= counters_.Snapshot(&end_values_); |
| ClobberMemory(); |
|
|
| for (size_t i = 0; i < counters_.names().size(); ++i) { |
| double measurement = static_cast<double>(end_values_[i]) - |
| static_cast<double>(start_values_[i]); |
| measurements.push_back({counters_.names()[i], measurement}); |
| } |
|
|
| return valid_read_; |
| } |
|
|
| private: |
| PerfCounters counters_; |
| bool valid_read_ = true; |
| PerfCounterValues start_values_; |
| PerfCounterValues end_values_; |
| }; |
|
|
| BENCHMARK_UNUSED static bool perf_init_anchor = PerfCounters::Initialize(); |
|
|
| } |
| } |
|
|
| #if defined(_MSC_VER) |
| #pragma warning(pop) |
| #endif |
|
|
| #endif |
|
|