blob: 3beac9a22998c6111afc4b540140746c95bf318c [file] [log] [blame]
Peter Kasting858bf62ca2025-01-03 19:01:361// Copyright 2024 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_METRICS_SAMPLE_MAP_ITERATOR_H_
6#define BASE_METRICS_SAMPLE_MAP_ITERATOR_H_
7
8#include <stdint.h>
9
Peter Kasting852967472025-01-06 16:42:2010#include <atomic>
Peter Kasting73cd82b2025-01-03 19:09:4011#include <type_traits>
12#include <utility>
13
Peter Kasting858bf62ca2025-01-03 19:01:3614#include "base/check.h"
Peter Kasting852967472025-01-06 16:42:2015#include "base/memory/raw_ptr.h"
Peter Kasting858bf62ca2025-01-03 19:01:3616#include "base/metrics/histogram_base.h"
17#include "base/metrics/histogram_samples.h"
Peter Kasting852967472025-01-06 16:42:2018#include "base/types/to_address.h"
Peter Kasting858bf62ca2025-01-03 19:01:3619
20namespace base {
21
Peter Kasting73cd82b2025-01-03 19:09:4022// An iterator for going through a SampleMap. `MapT` is the underlying map type
23// that stores the counts. `support_extraction` should be true iff the caller
Peter Kasting852967472025-01-06 16:42:2024// wants this iterator to support extracting the values. If the counts are
25// pointers, accesses to them will be atomic; see `kUseAtomicOps` below.
Peter Kasting73cd82b2025-01-03 19:09:4026template <typename MapT, bool support_extraction>
Peter Kasting858bf62ca2025-01-03 19:01:3627class SampleMapIterator : public SampleCountIterator {
Peter Kasting73cd82b2025-01-03 19:09:4028 private:
29 using T = std::conditional_t<support_extraction, MapT, const MapT>;
30
Peter Kasting858bf62ca2025-01-03 19:01:3631 public:
32 explicit SampleMapIterator(T& sample_counts)
33 : iter_(sample_counts.begin()), end_(sample_counts.end()) {
34 SkipEmptyBuckets();
35 }
36
Peter Kasting73cd82b2025-01-03 19:09:4037 ~SampleMapIterator() override {
38 if constexpr (support_extraction) {
39 // Ensure that the user has consumed all the samples in order to ensure no
40 // samples are lost.
41 DCHECK(Done());
42 }
43 }
Peter Kasting858bf62ca2025-01-03 19:01:3644
45 // SampleCountIterator:
46 bool Done() const override { return iter_ == end_; }
Peter Kasting73cd82b2025-01-03 19:09:4047
Peter Kasting858bf62ca2025-01-03 19:01:3648 void Next() override {
49 DCHECK(!Done());
50 ++iter_;
51 SkipEmptyBuckets();
52 }
Peter Kasting73cd82b2025-01-03 19:09:4053
Ramon Cano Aparicio4a39d122025-01-20 13:00:1754 void Get(HistogramBase::Sample32* min,
Peter Kasting858bf62ca2025-01-03 19:01:3655 int64_t* max,
Ramon Cano Apariciob2cba0f2025-01-22 21:26:1056 HistogramBase::Count32* count) override {
Peter Kasting73cd82b2025-01-03 19:09:4057 DCHECK(!Done());
58 *min = iter_->first;
59 *max = int64_t{iter_->first} + 1;
Peter Kasting73cd82b2025-01-03 19:09:4060 if constexpr (support_extraction) {
61 *count = Exchange();
62 } else {
63 *count = Load();
64 }
65 }
Peter Kasting858bf62ca2025-01-03 19:01:3666
67 private:
Peter Kasting73cd82b2025-01-03 19:09:4068 using I = std::conditional_t<support_extraction,
69 typename T::iterator,
70 typename T::const_iterator>;
71
Peter Kasting852967472025-01-06 16:42:2072 // If the counts are pointers, assume they may live in shared memory, which
73 // means accesses to them must be atomic, since other processes may attempt to
74 // concurrently modify their values. (Note that a lock wouldn't help here,
75 // since said other processes would not be aware of our lock.) If they are
76 // values, we don't bother with atomic ops; callers who want thread-safety can
77 // use locking.
78 static constexpr bool kUseAtomicOps =
79 IsPointerOrRawPtr<typename T::mapped_type>;
80
Peter Kasting858bf62ca2025-01-03 19:01:3681 void SkipEmptyBuckets() {
Peter Kasting73cd82b2025-01-03 19:09:4082 while (!Done() && Load() == 0) {
Peter Kasting858bf62ca2025-01-03 19:01:3683 ++iter_;
84 }
85 }
86
Ramon Cano Apariciob2cba0f2025-01-22 21:26:1087 HistogramBase::Count32 Load() const {
Peter Kasting852967472025-01-06 16:42:2088 if constexpr (kUseAtomicOps) {
89 return iter_->second->load(std::memory_order_relaxed);
90 } else {
91 return iter_->second;
92 }
93 }
Peter Kasting73cd82b2025-01-03 19:09:4094
Ramon Cano Apariciob2cba0f2025-01-22 21:26:1095 HistogramBase::Count32 Exchange() const
Peter Kasting73cd82b2025-01-03 19:09:4096 requires support_extraction
97 {
Peter Kasting852967472025-01-06 16:42:2098 if constexpr (kUseAtomicOps) {
99 return iter_->second->exchange(0, std::memory_order_relaxed);
100 } else {
101 return std::exchange(iter_->second, 0);
102 }
Peter Kasting73cd82b2025-01-03 19:09:40103 }
104
Peter Kasting858bf62ca2025-01-03 19:01:36105 I iter_;
106 const I end_;
107};
108
109} // namespace base
110
111#endif // BASE_METRICS_SAMPLE_MAP_ITERATOR_H_