xref: /aosp_15_r20/external/cronet/base/metrics/persistent_sample_map.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2016 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/metrics/persistent_sample_map.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include "base/atomicops.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/containers/contains.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/debug/crash_logging.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/metrics/persistent_histogram_allocator.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker namespace base {
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker typedef HistogramBase::Count Count;
19*6777b538SAndroid Build Coastguard Worker typedef HistogramBase::Sample Sample;
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker namespace {
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker // An iterator for going through a PersistentSampleMap. The logic here is
24*6777b538SAndroid Build Coastguard Worker // identical to that of the iterator for SampleMap but with different data
25*6777b538SAndroid Build Coastguard Worker // structures. Changes here likely need to be duplicated there.
26*6777b538SAndroid Build Coastguard Worker template <typename T, typename I>
27*6777b538SAndroid Build Coastguard Worker class IteratorTemplate : public SampleCountIterator {
28*6777b538SAndroid Build Coastguard Worker  public:
IteratorTemplate(T & sample_counts)29*6777b538SAndroid Build Coastguard Worker   explicit IteratorTemplate(T& sample_counts)
30*6777b538SAndroid Build Coastguard Worker       : iter_(sample_counts.begin()), end_(sample_counts.end()) {
31*6777b538SAndroid Build Coastguard Worker     SkipEmptyBuckets();
32*6777b538SAndroid Build Coastguard Worker   }
33*6777b538SAndroid Build Coastguard Worker 
34*6777b538SAndroid Build Coastguard Worker   ~IteratorTemplate() override;
35*6777b538SAndroid Build Coastguard Worker 
36*6777b538SAndroid Build Coastguard Worker   // SampleCountIterator:
Done() const37*6777b538SAndroid Build Coastguard Worker   bool Done() const override { return iter_ == end_; }
Next()38*6777b538SAndroid Build Coastguard Worker   void Next() override {
39*6777b538SAndroid Build Coastguard Worker     DCHECK(!Done());
40*6777b538SAndroid Build Coastguard Worker     ++iter_;
41*6777b538SAndroid Build Coastguard Worker     SkipEmptyBuckets();
42*6777b538SAndroid Build Coastguard Worker   }
43*6777b538SAndroid Build Coastguard Worker   void Get(HistogramBase::Sample* min,
44*6777b538SAndroid Build Coastguard Worker            int64_t* max,
45*6777b538SAndroid Build Coastguard Worker            HistogramBase::Count* count) override;
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker  private:
SkipEmptyBuckets()48*6777b538SAndroid Build Coastguard Worker   void SkipEmptyBuckets() {
49*6777b538SAndroid Build Coastguard Worker     while (!Done() && subtle::NoBarrier_Load(iter_->second) == 0) {
50*6777b538SAndroid Build Coastguard Worker       ++iter_;
51*6777b538SAndroid Build Coastguard Worker     }
52*6777b538SAndroid Build Coastguard Worker   }
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker   I iter_;
55*6777b538SAndroid Build Coastguard Worker   const I end_;
56*6777b538SAndroid Build Coastguard Worker };
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker typedef std::map<HistogramBase::Sample, HistogramBase::Count*> SampleToCountMap;
59*6777b538SAndroid Build Coastguard Worker typedef IteratorTemplate<const SampleToCountMap,
60*6777b538SAndroid Build Coastguard Worker                          SampleToCountMap::const_iterator>
61*6777b538SAndroid Build Coastguard Worker     PersistentSampleMapIterator;
62*6777b538SAndroid Build Coastguard Worker 
63*6777b538SAndroid Build Coastguard Worker template <>
64*6777b538SAndroid Build Coastguard Worker PersistentSampleMapIterator::~IteratorTemplate() = default;
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker // Get() for an iterator of a PersistentSampleMap.
67*6777b538SAndroid Build Coastguard Worker template <>
Get(Sample * min,int64_t * max,Count * count)68*6777b538SAndroid Build Coastguard Worker void PersistentSampleMapIterator::Get(Sample* min, int64_t* max, Count* count) {
69*6777b538SAndroid Build Coastguard Worker   DCHECK(!Done());
70*6777b538SAndroid Build Coastguard Worker   *min = iter_->first;
71*6777b538SAndroid Build Coastguard Worker   *max = strict_cast<int64_t>(iter_->first) + 1;
72*6777b538SAndroid Build Coastguard Worker   // We have to do the following atomically, because even if the caller is using
73*6777b538SAndroid Build Coastguard Worker   // a lock, a separate process (that is not aware of this lock) may
74*6777b538SAndroid Build Coastguard Worker   // concurrently modify the value (note that iter_->second is a pointer to a
75*6777b538SAndroid Build Coastguard Worker   // sample count, which may live in shared memory).
76*6777b538SAndroid Build Coastguard Worker   *count = subtle::NoBarrier_Load(iter_->second);
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker typedef IteratorTemplate<SampleToCountMap, SampleToCountMap::iterator>
80*6777b538SAndroid Build Coastguard Worker     ExtractingPersistentSampleMapIterator;
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker template <>
~IteratorTemplate()83*6777b538SAndroid Build Coastguard Worker ExtractingPersistentSampleMapIterator::~IteratorTemplate() {
84*6777b538SAndroid Build Coastguard Worker   // Ensure that the user has consumed all the samples in order to ensure no
85*6777b538SAndroid Build Coastguard Worker   // samples are lost.
86*6777b538SAndroid Build Coastguard Worker   DCHECK(Done());
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker // Get() for an extracting iterator of a PersistentSampleMap.
90*6777b538SAndroid Build Coastguard Worker template <>
Get(Sample * min,int64_t * max,Count * count)91*6777b538SAndroid Build Coastguard Worker void ExtractingPersistentSampleMapIterator::Get(Sample* min,
92*6777b538SAndroid Build Coastguard Worker                                                 int64_t* max,
93*6777b538SAndroid Build Coastguard Worker                                                 Count* count) {
94*6777b538SAndroid Build Coastguard Worker   DCHECK(!Done());
95*6777b538SAndroid Build Coastguard Worker   *min = iter_->first;
96*6777b538SAndroid Build Coastguard Worker   *max = strict_cast<int64_t>(iter_->first) + 1;
97*6777b538SAndroid Build Coastguard Worker   // We have to do the following atomically, because even if the caller is using
98*6777b538SAndroid Build Coastguard Worker   // a lock, a separate process (that is not aware of this lock) may
99*6777b538SAndroid Build Coastguard Worker   // concurrently modify the value (note that iter_->second is a pointer to a
100*6777b538SAndroid Build Coastguard Worker   // sample count, which may live in shared memory).
101*6777b538SAndroid Build Coastguard Worker   *count = subtle::NoBarrier_AtomicExchange(iter_->second, 0);
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker // This structure holds an entry for a PersistentSampleMap within a persistent
105*6777b538SAndroid Build Coastguard Worker // memory allocator. The "id" must be unique across all maps held by an
106*6777b538SAndroid Build Coastguard Worker // allocator or they will get attached to the wrong sample map.
107*6777b538SAndroid Build Coastguard Worker struct SampleRecord {
108*6777b538SAndroid Build Coastguard Worker   // SHA1(SampleRecord): Increment this if structure changes!
109*6777b538SAndroid Build Coastguard Worker   static constexpr uint32_t kPersistentTypeId = 0x8FE6A69F + 1;
110*6777b538SAndroid Build Coastguard Worker 
111*6777b538SAndroid Build Coastguard Worker   // Expected size for 32/64-bit check.
112*6777b538SAndroid Build Coastguard Worker   static constexpr size_t kExpectedInstanceSize = 16;
113*6777b538SAndroid Build Coastguard Worker 
114*6777b538SAndroid Build Coastguard Worker   uint64_t id;   // Unique identifier of owner.
115*6777b538SAndroid Build Coastguard Worker   Sample value;  // The value for which this record holds a count.
116*6777b538SAndroid Build Coastguard Worker   Count count;   // The count associated with the above value.
117*6777b538SAndroid Build Coastguard Worker };
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker }  // namespace
120*6777b538SAndroid Build Coastguard Worker 
PersistentSampleMap(uint64_t id,PersistentHistogramAllocator * allocator,Metadata * meta)121*6777b538SAndroid Build Coastguard Worker PersistentSampleMap::PersistentSampleMap(
122*6777b538SAndroid Build Coastguard Worker     uint64_t id,
123*6777b538SAndroid Build Coastguard Worker     PersistentHistogramAllocator* allocator,
124*6777b538SAndroid Build Coastguard Worker     Metadata* meta)
125*6777b538SAndroid Build Coastguard Worker     : HistogramSamples(id, meta), allocator_(allocator) {}
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker PersistentSampleMap::~PersistentSampleMap() = default;
128*6777b538SAndroid Build Coastguard Worker 
Accumulate(Sample value,Count count)129*6777b538SAndroid Build Coastguard Worker void PersistentSampleMap::Accumulate(Sample value, Count count) {
130*6777b538SAndroid Build Coastguard Worker   // We have to do the following atomically, because even if the caller is using
131*6777b538SAndroid Build Coastguard Worker   // a lock, a separate process (that is not aware of this lock) may
132*6777b538SAndroid Build Coastguard Worker   // concurrently modify the value.
133*6777b538SAndroid Build Coastguard Worker   subtle::NoBarrier_AtomicIncrement(GetOrCreateSampleCountStorage(value),
134*6777b538SAndroid Build Coastguard Worker                                     count);
135*6777b538SAndroid Build Coastguard Worker   IncreaseSumAndCount(strict_cast<int64_t>(count) * value, count);
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker 
GetCount(Sample value) const138*6777b538SAndroid Build Coastguard Worker Count PersistentSampleMap::GetCount(Sample value) const {
139*6777b538SAndroid Build Coastguard Worker   // Have to override "const" to make sure all samples have been loaded before
140*6777b538SAndroid Build Coastguard Worker   // being able to know what value to return.
141*6777b538SAndroid Build Coastguard Worker   Count* count_pointer =
142*6777b538SAndroid Build Coastguard Worker       const_cast<PersistentSampleMap*>(this)->GetSampleCountStorage(value);
143*6777b538SAndroid Build Coastguard Worker   return count_pointer ? subtle::NoBarrier_Load(count_pointer) : 0;
144*6777b538SAndroid Build Coastguard Worker }
145*6777b538SAndroid Build Coastguard Worker 
TotalCount() const146*6777b538SAndroid Build Coastguard Worker Count PersistentSampleMap::TotalCount() const {
147*6777b538SAndroid Build Coastguard Worker   // Have to override "const" in order to make sure all samples have been
148*6777b538SAndroid Build Coastguard Worker   // loaded before trying to iterate over the map.
149*6777b538SAndroid Build Coastguard Worker   const_cast<PersistentSampleMap*>(this)->ImportSamples(
150*6777b538SAndroid Build Coastguard Worker       /*until_value=*/std::nullopt);
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   Count count = 0;
153*6777b538SAndroid Build Coastguard Worker   for (const auto& entry : sample_counts_) {
154*6777b538SAndroid Build Coastguard Worker     count += subtle::NoBarrier_Load(entry.second);
155*6777b538SAndroid Build Coastguard Worker   }
156*6777b538SAndroid Build Coastguard Worker   return count;
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker 
Iterator() const159*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> PersistentSampleMap::Iterator() const {
160*6777b538SAndroid Build Coastguard Worker   // Have to override "const" in order to make sure all samples have been
161*6777b538SAndroid Build Coastguard Worker   // loaded before trying to iterate over the map.
162*6777b538SAndroid Build Coastguard Worker   const_cast<PersistentSampleMap*>(this)->ImportSamples(
163*6777b538SAndroid Build Coastguard Worker       /*until_value=*/std::nullopt);
164*6777b538SAndroid Build Coastguard Worker   return std::make_unique<PersistentSampleMapIterator>(sample_counts_);
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker 
ExtractingIterator()167*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> PersistentSampleMap::ExtractingIterator() {
168*6777b538SAndroid Build Coastguard Worker   // Make sure all samples have been loaded before trying to iterate over the
169*6777b538SAndroid Build Coastguard Worker   // map.
170*6777b538SAndroid Build Coastguard Worker   ImportSamples(/*until_value=*/std::nullopt);
171*6777b538SAndroid Build Coastguard Worker   return std::make_unique<ExtractingPersistentSampleMapIterator>(
172*6777b538SAndroid Build Coastguard Worker       sample_counts_);
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker 
IsDefinitelyEmpty() const175*6777b538SAndroid Build Coastguard Worker bool PersistentSampleMap::IsDefinitelyEmpty() const {
176*6777b538SAndroid Build Coastguard Worker   // Not implemented.
177*6777b538SAndroid Build Coastguard Worker   NOTREACHED();
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker   // Always return false. If we are wrong, this will just make the caller
180*6777b538SAndroid Build Coastguard Worker   // perform some extra work thinking that |this| is non-empty.
181*6777b538SAndroid Build Coastguard Worker   return false;
182*6777b538SAndroid Build Coastguard Worker }
183*6777b538SAndroid Build Coastguard Worker 
184*6777b538SAndroid Build Coastguard Worker // static
185*6777b538SAndroid Build Coastguard Worker PersistentMemoryAllocator::Reference
GetNextPersistentRecord(PersistentMemoryAllocator::Iterator & iterator,uint64_t * sample_map_id,Sample * value)186*6777b538SAndroid Build Coastguard Worker PersistentSampleMap::GetNextPersistentRecord(
187*6777b538SAndroid Build Coastguard Worker     PersistentMemoryAllocator::Iterator& iterator,
188*6777b538SAndroid Build Coastguard Worker     uint64_t* sample_map_id,
189*6777b538SAndroid Build Coastguard Worker     Sample* value) {
190*6777b538SAndroid Build Coastguard Worker   const SampleRecord* record = iterator.GetNextOfObject<SampleRecord>();
191*6777b538SAndroid Build Coastguard Worker   if (!record) {
192*6777b538SAndroid Build Coastguard Worker     return 0;
193*6777b538SAndroid Build Coastguard Worker   }
194*6777b538SAndroid Build Coastguard Worker 
195*6777b538SAndroid Build Coastguard Worker   *sample_map_id = record->id;
196*6777b538SAndroid Build Coastguard Worker   *value = record->value;
197*6777b538SAndroid Build Coastguard Worker   return iterator.GetAsReference(record);
198*6777b538SAndroid Build Coastguard Worker }
199*6777b538SAndroid Build Coastguard Worker 
200*6777b538SAndroid Build Coastguard Worker // static
201*6777b538SAndroid Build Coastguard Worker PersistentMemoryAllocator::Reference
CreatePersistentRecord(PersistentMemoryAllocator * allocator,uint64_t sample_map_id,Sample value)202*6777b538SAndroid Build Coastguard Worker PersistentSampleMap::CreatePersistentRecord(
203*6777b538SAndroid Build Coastguard Worker     PersistentMemoryAllocator* allocator,
204*6777b538SAndroid Build Coastguard Worker     uint64_t sample_map_id,
205*6777b538SAndroid Build Coastguard Worker     Sample value) {
206*6777b538SAndroid Build Coastguard Worker   SampleRecord* record = allocator->New<SampleRecord>();
207*6777b538SAndroid Build Coastguard Worker   if (!record) {
208*6777b538SAndroid Build Coastguard Worker     if (!allocator->IsFull()) {
209*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
210*6777b538SAndroid Build Coastguard Worker       // TODO(crbug/1432981): Remove these. They are used to investigate
211*6777b538SAndroid Build Coastguard Worker       // unexpected failures.
212*6777b538SAndroid Build Coastguard Worker       SCOPED_CRASH_KEY_BOOL("PersistentSampleMap", "corrupted",
213*6777b538SAndroid Build Coastguard Worker                             allocator->IsCorrupt());
214*6777b538SAndroid Build Coastguard Worker #endif  // !BUILDFLAG(IS_NACL)
215*6777b538SAndroid Build Coastguard Worker       DUMP_WILL_BE_NOTREACHED_NORETURN()
216*6777b538SAndroid Build Coastguard Worker           << "corrupt=" << allocator->IsCorrupt();
217*6777b538SAndroid Build Coastguard Worker     }
218*6777b538SAndroid Build Coastguard Worker     return 0;
219*6777b538SAndroid Build Coastguard Worker   }
220*6777b538SAndroid Build Coastguard Worker 
221*6777b538SAndroid Build Coastguard Worker   record->id = sample_map_id;
222*6777b538SAndroid Build Coastguard Worker   record->value = value;
223*6777b538SAndroid Build Coastguard Worker   record->count = 0;
224*6777b538SAndroid Build Coastguard Worker 
225*6777b538SAndroid Build Coastguard Worker   PersistentMemoryAllocator::Reference ref = allocator->GetAsReference(record);
226*6777b538SAndroid Build Coastguard Worker   allocator->MakeIterable(ref);
227*6777b538SAndroid Build Coastguard Worker   return ref;
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker 
AddSubtractImpl(SampleCountIterator * iter,Operator op)230*6777b538SAndroid Build Coastguard Worker bool PersistentSampleMap::AddSubtractImpl(SampleCountIterator* iter,
231*6777b538SAndroid Build Coastguard Worker                                           Operator op) {
232*6777b538SAndroid Build Coastguard Worker   Sample min;
233*6777b538SAndroid Build Coastguard Worker   int64_t max;
234*6777b538SAndroid Build Coastguard Worker   Count count;
235*6777b538SAndroid Build Coastguard Worker   for (; !iter->Done(); iter->Next()) {
236*6777b538SAndroid Build Coastguard Worker     iter->Get(&min, &max, &count);
237*6777b538SAndroid Build Coastguard Worker     if (count == 0)
238*6777b538SAndroid Build Coastguard Worker       continue;
239*6777b538SAndroid Build Coastguard Worker     if (strict_cast<int64_t>(min) + 1 != max)
240*6777b538SAndroid Build Coastguard Worker       return false;  // SparseHistogram only supports bucket with size 1.
241*6777b538SAndroid Build Coastguard Worker 
242*6777b538SAndroid Build Coastguard Worker     // We have to do the following atomically, because even if the caller is
243*6777b538SAndroid Build Coastguard Worker     // using a lock, a separate process (that is not aware of this lock) may
244*6777b538SAndroid Build Coastguard Worker     // concurrently modify the value.
245*6777b538SAndroid Build Coastguard Worker     subtle::Barrier_AtomicIncrement(
246*6777b538SAndroid Build Coastguard Worker         GetOrCreateSampleCountStorage(min),
247*6777b538SAndroid Build Coastguard Worker         (op == HistogramSamples::ADD) ? count : -count);
248*6777b538SAndroid Build Coastguard Worker   }
249*6777b538SAndroid Build Coastguard Worker   return true;
250*6777b538SAndroid Build Coastguard Worker }
251*6777b538SAndroid Build Coastguard Worker 
GetSampleCountStorage(Sample value)252*6777b538SAndroid Build Coastguard Worker Count* PersistentSampleMap::GetSampleCountStorage(Sample value) {
253*6777b538SAndroid Build Coastguard Worker   // If |value| is already in the map, just return that.
254*6777b538SAndroid Build Coastguard Worker   auto it = sample_counts_.find(value);
255*6777b538SAndroid Build Coastguard Worker   if (it != sample_counts_.end())
256*6777b538SAndroid Build Coastguard Worker     return it->second;
257*6777b538SAndroid Build Coastguard Worker 
258*6777b538SAndroid Build Coastguard Worker   // Import any new samples from persistent memory looking for the value.
259*6777b538SAndroid Build Coastguard Worker   return ImportSamples(/*until_value=*/value);
260*6777b538SAndroid Build Coastguard Worker }
261*6777b538SAndroid Build Coastguard Worker 
GetOrCreateSampleCountStorage(Sample value)262*6777b538SAndroid Build Coastguard Worker Count* PersistentSampleMap::GetOrCreateSampleCountStorage(Sample value) {
263*6777b538SAndroid Build Coastguard Worker   // Get any existing count storage.
264*6777b538SAndroid Build Coastguard Worker   Count* count_pointer = GetSampleCountStorage(value);
265*6777b538SAndroid Build Coastguard Worker   if (count_pointer)
266*6777b538SAndroid Build Coastguard Worker     return count_pointer;
267*6777b538SAndroid Build Coastguard Worker 
268*6777b538SAndroid Build Coastguard Worker   // Create a new record in persistent memory for the value. |records_| will
269*6777b538SAndroid Build Coastguard Worker   // have been initialized by the GetSampleCountStorage() call above.
270*6777b538SAndroid Build Coastguard Worker   CHECK(records_);
271*6777b538SAndroid Build Coastguard Worker   PersistentMemoryAllocator::Reference ref = records_->CreateNew(value);
272*6777b538SAndroid Build Coastguard Worker   if (!ref) {
273*6777b538SAndroid Build Coastguard Worker     // If a new record could not be created then the underlying allocator is
274*6777b538SAndroid Build Coastguard Worker     // full or corrupt. Instead, allocate the counter from the heap. This
275*6777b538SAndroid Build Coastguard Worker     // sample will not be persistent, will not be shared, and will leak...
276*6777b538SAndroid Build Coastguard Worker     // but it's better than crashing.
277*6777b538SAndroid Build Coastguard Worker     count_pointer = new Count(0);
278*6777b538SAndroid Build Coastguard Worker     sample_counts_[value] = count_pointer;
279*6777b538SAndroid Build Coastguard Worker     return count_pointer;
280*6777b538SAndroid Build Coastguard Worker   }
281*6777b538SAndroid Build Coastguard Worker 
282*6777b538SAndroid Build Coastguard Worker   // A race condition between two independent processes (i.e. two independent
283*6777b538SAndroid Build Coastguard Worker   // histogram objects sharing the same sample data) could cause two of the
284*6777b538SAndroid Build Coastguard Worker   // above records to be created. The allocator, however, forces a strict
285*6777b538SAndroid Build Coastguard Worker   // ordering on iterable objects so use the import method to actually add the
286*6777b538SAndroid Build Coastguard Worker   // just-created record. This ensures that all PersistentSampleMap objects
287*6777b538SAndroid Build Coastguard Worker   // will always use the same record, whichever was first made iterable.
288*6777b538SAndroid Build Coastguard Worker   // Thread-safety within a process where multiple threads use the same
289*6777b538SAndroid Build Coastguard Worker   // histogram object is delegated to the controlling histogram object which,
290*6777b538SAndroid Build Coastguard Worker   // for sparse histograms, is a lock object.
291*6777b538SAndroid Build Coastguard Worker   count_pointer = ImportSamples(/*until_value=*/value);
292*6777b538SAndroid Build Coastguard Worker   DCHECK(count_pointer);
293*6777b538SAndroid Build Coastguard Worker   return count_pointer;
294*6777b538SAndroid Build Coastguard Worker }
295*6777b538SAndroid Build Coastguard Worker 
GetRecords()296*6777b538SAndroid Build Coastguard Worker PersistentSampleMapRecords* PersistentSampleMap::GetRecords() {
297*6777b538SAndroid Build Coastguard Worker   // The |records_| pointer is lazily fetched from the |allocator_| only on
298*6777b538SAndroid Build Coastguard Worker   // first use. Sometimes duplicate histograms are created by race conditions
299*6777b538SAndroid Build Coastguard Worker   // and if both were to grab the records object, there would be a conflict.
300*6777b538SAndroid Build Coastguard Worker   // Use of a histogram, and thus a call to this method, won't occur until
301*6777b538SAndroid Build Coastguard Worker   // after the histogram has been de-dup'd.
302*6777b538SAndroid Build Coastguard Worker   if (!records_) {
303*6777b538SAndroid Build Coastguard Worker     records_ = allocator_->CreateSampleMapRecords(id());
304*6777b538SAndroid Build Coastguard Worker   }
305*6777b538SAndroid Build Coastguard Worker   return records_.get();
306*6777b538SAndroid Build Coastguard Worker }
307*6777b538SAndroid Build Coastguard Worker 
ImportSamples(std::optional<Sample> until_value)308*6777b538SAndroid Build Coastguard Worker Count* PersistentSampleMap::ImportSamples(std::optional<Sample> until_value) {
309*6777b538SAndroid Build Coastguard Worker   std::vector<PersistentMemoryAllocator::Reference> refs;
310*6777b538SAndroid Build Coastguard Worker   PersistentSampleMapRecords* records = GetRecords();
311*6777b538SAndroid Build Coastguard Worker   while (!(refs = records->GetNextRecords(until_value)).empty()) {
312*6777b538SAndroid Build Coastguard Worker     // GetNextRecords() returns a list of new unseen records belonging to this
313*6777b538SAndroid Build Coastguard Worker     // map. Iterate through them all and store them internally. Note that if
314*6777b538SAndroid Build Coastguard Worker     // |until_value| was found, it will be the last element in |refs|.
315*6777b538SAndroid Build Coastguard Worker     for (auto ref : refs) {
316*6777b538SAndroid Build Coastguard Worker       SampleRecord* record = records->GetAsObject<SampleRecord>(ref);
317*6777b538SAndroid Build Coastguard Worker       if (!record) {
318*6777b538SAndroid Build Coastguard Worker         continue;
319*6777b538SAndroid Build Coastguard Worker       }
320*6777b538SAndroid Build Coastguard Worker 
321*6777b538SAndroid Build Coastguard Worker       DCHECK_EQ(id(), record->id);
322*6777b538SAndroid Build Coastguard Worker 
323*6777b538SAndroid Build Coastguard Worker       // Check if the record's value is already known.
324*6777b538SAndroid Build Coastguard Worker       if (!Contains(sample_counts_, record->value)) {
325*6777b538SAndroid Build Coastguard Worker         // No: Add it to map of known values.
326*6777b538SAndroid Build Coastguard Worker         sample_counts_[record->value] = &record->count;
327*6777b538SAndroid Build Coastguard Worker       } else {
328*6777b538SAndroid Build Coastguard Worker         // Yes: Ignore it; it's a duplicate caused by a race condition -- see
329*6777b538SAndroid Build Coastguard Worker         // code & comment in GetOrCreateSampleCountStorage() for details.
330*6777b538SAndroid Build Coastguard Worker         // Check that nothing ever operated on the duplicate record.
331*6777b538SAndroid Build Coastguard Worker         DCHECK_EQ(0, record->count);
332*6777b538SAndroid Build Coastguard Worker       }
333*6777b538SAndroid Build Coastguard Worker 
334*6777b538SAndroid Build Coastguard Worker       // Check if it's the value being searched for and, if so, stop here.
335*6777b538SAndroid Build Coastguard Worker       // Because race conditions can cause multiple records for a single value,
336*6777b538SAndroid Build Coastguard Worker       // be sure to return the first one found.
337*6777b538SAndroid Build Coastguard Worker       if (until_value.has_value() && record->value == until_value.value()) {
338*6777b538SAndroid Build Coastguard Worker         // Ensure that this was the last value in |refs|.
339*6777b538SAndroid Build Coastguard Worker         CHECK_EQ(refs.back(), ref);
340*6777b538SAndroid Build Coastguard Worker 
341*6777b538SAndroid Build Coastguard Worker         return &record->count;
342*6777b538SAndroid Build Coastguard Worker       }
343*6777b538SAndroid Build Coastguard Worker     }
344*6777b538SAndroid Build Coastguard Worker   }
345*6777b538SAndroid Build Coastguard Worker 
346*6777b538SAndroid Build Coastguard Worker   return nullptr;
347*6777b538SAndroid Build Coastguard Worker }
348*6777b538SAndroid Build Coastguard Worker 
349*6777b538SAndroid Build Coastguard Worker }  // namespace base
350