#ifndef BASE_METRICS_SAMPLE_VECTOR_H_
#define BASE_METRICS_SAMPLE_VECTOR_H_
#include <stddef.h>
#include <stdint.h>
#include <atomic>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/bucket_ranges.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
#include "base/metrics/persistent_memory_allocator.h"
namespace base {
class BucketRanges;
class BASE_EXPORT SampleVectorBase : public HistogramSamples {
public:
SampleVectorBase(const SampleVectorBase&) = delete;
SampleVectorBase& operator=(const SampleVectorBase&) = delete;
~SampleVectorBase() override;
void Accumulate(HistogramBase::Sample32 value,
HistogramBase::Count32 count) override;
HistogramBase::Count32 GetCount(HistogramBase::Sample32 value) const override;
HistogramBase::Count32 TotalCount() const override;
std::unique_ptr<SampleCountIterator> Iterator() const override;
std::unique_ptr<SampleCountIterator> ExtractingIterator() override;
HistogramBase::Count32 GetCountAtIndex(size_t bucket_index) const;
const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
AtomicSingleSample* SingleSampleForTesting() { return &single_sample(); }
protected:
SampleVectorBase(uint64_t id,
Metadata* meta,
const BucketRanges* bucket_ranges);
SampleVectorBase(uint64_t id,
std::unique_ptr<Metadata> meta,
const BucketRanges* bucket_ranges);
bool AddSubtractImpl(
SampleCountIterator* iter,
HistogramSamples::Operator op) override;
virtual size_t GetBucketIndex(HistogramBase::Sample32 value) const;
size_t GetDestinationBucketIndexAndCount(SampleCountIterator& iter,
HistogramBase::Count32* count);
void MoveSingleSampleToCounts();
void MountCountsStorageAndMoveSingleSample();
virtual bool MountExistingCountsStorage() const = 0;
virtual span<HistogramBase::Count32> CreateCountsStorageWhileLocked() = 0;
std::optional<span<HistogramBase::AtomicCount>> counts() {
HistogramBase::AtomicCount* data =
counts_data_.load(std::memory_order_acquire);
if (data == nullptr) {
return std::nullopt;
}
return UNSAFE_TODO(span(data, counts_size_));
}
std::optional<span<const HistogramBase::AtomicCount>> counts() const {
const HistogramBase::AtomicCount* data =
counts_data_.load(std::memory_order_acquire);
if (data == nullptr) {
return std::nullopt;
}
return UNSAFE_TODO(span(data, counts_size_));
}
void set_counts(span<HistogramBase::AtomicCount> counts) const {
CHECK_EQ(counts.size(), counts_size_);
counts_data_.store(counts.data(), std::memory_order_release);
}
size_t counts_size() const { return counts_size_; }
private:
friend class SampleVectorTest;
FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
FRIEND_TEST_ALL_PREFIXES(SharedHistogramTest, CorruptSampleCounts);
const HistogramBase::AtomicCount& counts_at(size_t index) const {
return (counts().value())[index];
}
HistogramBase::AtomicCount& counts_at(size_t index) {
return (counts().value())[index];
}
const raw_ptr<const BucketRanges> bucket_ranges_;
const size_t counts_size_;
mutable std::atomic<HistogramBase::AtomicCount*> counts_data_;
};
class BASE_EXPORT SampleVector : public SampleVectorBase {
public:
explicit SampleVector(const BucketRanges* bucket_ranges);
SampleVector(uint64_t id, const BucketRanges* bucket_ranges);
SampleVector(const SampleVector&) = delete;
SampleVector& operator=(const SampleVector&) = delete;
~SampleVector() override;
bool IsDefinitelyEmpty() const override;
private:
FRIEND_TEST_ALL_PREFIXES(SampleVectorTest, GetPeakBucketSize);
std::string GetAsciiBody() const override;
std::string GetAsciiHeader(std::string_view histogram_name,
int32_t flags) const override;
bool MountExistingCountsStorage() const override;
span<HistogramBase::Count32> CreateCountsStorageWhileLocked() override;
void WriteAsciiBucketContext(int64_t past,
HistogramBase::Count32 current,
int64_t remaining,
uint32_t current_bucket_index,
std::string* output) const;
double GetPeakBucketSize() const;
size_t bucket_count() const { return bucket_ranges()->bucket_count(); }
mutable std::vector<HistogramBase::AtomicCount> local_counts_;
};
class BASE_EXPORT PersistentSampleVector : public SampleVectorBase {
public:
PersistentSampleVector(std::string_view name,
uint64_t id,
const BucketRanges* bucket_ranges,
Metadata* meta,
const DelayedPersistentAllocation& counts);
PersistentSampleVector(const PersistentSampleVector&) = delete;
PersistentSampleVector& operator=(const PersistentSampleVector&) = delete;
~PersistentSampleVector() override;
bool IsDefinitelyEmpty() const override;
static void ResetMountExistingCountsStorageResultForTesting();
private:
enum class MountExistingCountsStorageResult {
kSucceeded = 0,
kNothingToRead = 1,
kCorrupt = 2,
kMaxValue = kCorrupt,
};
static std::atomic_uintptr_t atomic_histogram_pointer;
static void RecordMountExistingCountsStorageResult(
MountExistingCountsStorageResult result);
MountExistingCountsStorageResult MountExistingCountsStorageImpl() const;
bool MountExistingCountsStorage() const override;
span<HistogramBase::Count32> CreateCountsStorageWhileLocked() override;
DelayedPersistentAllocation persistent_counts_;
};
inline constexpr std::string_view kMountExistingCountsStorageResult =
"UMA.PersistentHistograms.MountExistingCountsStorageResult";
}
#endif