summaryrefslogtreecommitdiffstats
path: root/base/metrics/sparse_histogram.h
blob: b8767377ab167187cbfca354030afaa66153e0b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_METRICS_SPARSE_HISTOGRAM_H_
#define BASE_METRICS_SPARSE_HISTOGRAM_H_

#include <stddef.h>
#include <stdint.h>

#include <map>
#include <string>

#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/sample_map.h"
#include "base/synchronization/lock.h"

namespace base {

// Sparse histograms are well suited for recording counts of exact sample values
// that are sparsely distributed over a large range.
//
// The implementation uses a lock and a map, whereas other histogram types use a
// vector and no lock. It is thus more costly to add values to, and each value
// stored has more overhead, compared to the other histogram types. However it
// may be more efficient in memory if the total number of sample values is small
// compared to the range of their values.
//
// UMA_HISTOGRAM_ENUMERATION would be better suited for a smaller range of
// enumerations that are (nearly) contiguous. Also for code that is expected to
// run often or in a tight loop.
//
// UMA_HISTOGRAM_SPARSE_SLOWLY is good for sparsely distributed and or
// infrequently recorded values.
//
// For instance, Sqlite.Version.* are SPARSE because for any given database,
// there's going to be exactly one version logged, meaning no gain to having a
// pre-allocated vector of slots once the fleet gets to version 4 or 5 or 10.
// Likewise Sqlite.Error.* are SPARSE, because most databases generate few or no
// errors and there are large gaps in the set of possible errors.
#define UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample) \
    do { \
      base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( \
          name, base::HistogramBase::kUmaTargetedHistogramFlag); \
      histogram->Add(sample); \
    } while (0)

class HistogramSamples;
class PersistentMemoryAllocator;

class BASE_EXPORT SparseHistogram : public HistogramBase {
 public:
  // If there's one with same name, return the existing one. If not, create a
  // new one.
  static HistogramBase* FactoryGet(const std::string& name, int32_t flags);

  // Create a histogram using data in persistent storage.
  static scoped_ptr<HistogramBase> PersistentCreate(
      PersistentMemoryAllocator* allocator,
      const std::string& name,
      HistogramSamples::Metadata* meta,
      HistogramSamples::Metadata* logged_meta);

  ~SparseHistogram() override;

  // HistogramBase implementation:
  uint64_t name_hash() const override;
  HistogramType GetHistogramType() const override;
  bool HasConstructionArguments(Sample expected_minimum,
                                Sample expected_maximum,
                                uint32_t expected_bucket_count) const override;
  void Add(Sample value) override;
  void AddCount(Sample value, int count) override;
  void AddSamples(const HistogramSamples& samples) override;
  bool AddSamplesFromPickle(base::PickleIterator* iter) override;
  scoped_ptr<HistogramSamples> SnapshotSamples() const override;
  scoped_ptr<HistogramSamples> SnapshotDelta() override;
  void WriteHTMLGraph(std::string* output) const override;
  void WriteAscii(std::string* output) const override;

 protected:
  // HistogramBase implementation:
  bool SerializeInfoImpl(base::Pickle* pickle) const override;

 private:
  // Clients should always use FactoryGet to create SparseHistogram.
  explicit SparseHistogram(const std::string& name);

  SparseHistogram(PersistentMemoryAllocator* allocator,
                  const std::string& name,
                  HistogramSamples::Metadata* meta,
                  HistogramSamples::Metadata* logged_meta);

  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
      base::PickleIterator* iter);
  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);

  void GetParameters(DictionaryValue* params) const override;
  void GetCountAndBucketData(Count* count,
                             int64_t* sum,
                             ListValue* buckets) const override;

  // Helpers for emitting Ascii graphic.  Each method appends data to output.
  void WriteAsciiImpl(bool graph_it,
                      const std::string& newline,
                      std::string* output) const;

  // Write a common header message describing this histogram.
  void WriteAsciiHeader(const Count total_count,
                        std::string* output) const;

  // For constuctor calling.
  friend class SparseHistogramTest;

  // Protects access to |samples_|.
  mutable base::Lock lock_;

  scoped_ptr<HistogramSamples> samples_;
  scoped_ptr<HistogramSamples> logged_samples_;

  DISALLOW_COPY_AND_ASSIGN(SparseHistogram);
};

}  // namespace base

#endif  // BASE_METRICS_SPARSE_HISTOGRAM_H_