summaryrefslogtreecommitdiffstats
path: root/chromium/base/metrics/statistics_recorder.h
blob: 002758e840e1aa404409e6a14785615e790c9ce5 (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
// 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.

// StatisticsRecorder holds all Histograms and BucketRanges that are used by
// Histograms in the system. It provides a general place for
// Histograms/BucketRanges to register, and supports a global API for accessing
// (i.e., dumping, or graphing) the data.

#ifndef BASE_METRICS_STATISTICS_RECORDER_H_
#define BASE_METRICS_STATISTICS_RECORDER_H_

#include <stdint.h>

#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/base_export.h"
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/metrics/histogram_base.h"
#include "base/strings/string_piece.h"

class SubprocessMetricsProviderTest;

namespace base {

class BucketRanges;
class Lock;

class BASE_EXPORT StatisticsRecorder {
 public:
  // A class used as a key for the histogram map below. It always references
  // a string owned outside of this class, likely in the value of the map.
  class StringKey : public StringPiece {
   public:
    // Constructs the StringKey using various sources. The source must live
    // at least as long as the created object.
    StringKey(const std::string& str) : StringPiece(str) {}
    StringKey(StringPiece str) : StringPiece(str) {}

    // Though StringPiece is better passed by value than by reference, in
    // this case it's being passed many times and likely already been stored
    // in memory (not just registers) so the benefit of pass-by-value is
    // negated.
    bool operator<(const StringKey& rhs) const {
      // Since order is unimportant in the map and string comparisons can be
      // slow, use the length as the primary sort value.
      if (length() < rhs.length())
        return true;
      if (length() > rhs.length())
        return false;

      // Fall back to an actual string comparison. The lengths are the same
      // so a simple memory-compare is sufficient. This is slightly more
      // efficient than calling operator<() for StringPiece which would
      // again have to check lengths before calling wordmemcmp().
      return wordmemcmp(data(), rhs.data(), length()) < 0;
    }
  };

  typedef std::map<StringKey, HistogramBase*> HistogramMap;
  typedef std::vector<HistogramBase*> Histograms;

  // A class for iterating over the histograms held within this global resource.
  class BASE_EXPORT HistogramIterator {
   public:
    HistogramIterator(const HistogramMap::iterator& iter,
                      bool include_persistent);
    HistogramIterator(const HistogramIterator& rhs);  // Must be copyable.
    ~HistogramIterator();

    HistogramIterator& operator++();
    HistogramIterator operator++(int) {
      HistogramIterator tmp(*this);
      operator++();
      return tmp;
    }

    bool operator==(const HistogramIterator& rhs) const {
      return iter_ == rhs.iter_;
    }
    bool operator!=(const HistogramIterator& rhs) const {
      return iter_ != rhs.iter_;
    }
    HistogramBase* operator*() { return iter_->second; }

   private:
    HistogramMap::iterator iter_;
    const bool include_persistent_;
  };

  ~StatisticsRecorder();

  // Initializes the StatisticsRecorder system. Safe to call multiple times.
  static void Initialize();

  // Find out if histograms can now be registered into our list.
  static bool IsActive();

  // Register, or add a new histogram to the collection of statistics. If an
  // identically named histogram is already registered, then the argument
  // |histogram| will deleted.  The returned value is always the registered
  // histogram (either the argument, or the pre-existing registered histogram).
  static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram);

  // Register, or add a new BucketRanges. If an identically BucketRanges is
  // already registered, then the argument |ranges| will deleted. The returned
  // value is always the registered BucketRanges (either the argument, or the
  // pre-existing one).
  static const BucketRanges* RegisterOrDeleteDuplicateRanges(
      const BucketRanges* ranges);

  // Methods for appending histogram data to a string.  Only histograms which
  // have |query| as a substring are written to |output| (an empty string will
  // process all registered histograms).
  static void WriteHTMLGraph(const std::string& query, std::string* output);
  static void WriteGraph(const std::string& query, std::string* output);

  // Returns the histograms with |query| as a substring as JSON text (an empty
  // |query| will process all registered histograms).
  static std::string ToJSON(const std::string& query);

  // Method for extracting histograms which were marked for use by UMA.
  static void GetHistograms(Histograms* output);

  // Method for extracting BucketRanges used by all histograms registered.
  static void GetBucketRanges(std::vector<const BucketRanges*>* output);

  // Find a histogram by name. It matches the exact name. This method is thread
  // safe.  It returns NULL if a matching histogram is not found.
  static HistogramBase* FindHistogram(base::StringPiece name);

  // Support for iterating over known histograms.
  static HistogramIterator begin(bool include_persistent);
  static HistogramIterator end();

  // GetSnapshot copies some of the pointers to registered histograms into the
  // caller supplied vector (Histograms). Only histograms which have |query| as
  // a substring are copied (an empty string will process all registered
  // histograms).
  static void GetSnapshot(const std::string& query, Histograms* snapshot);

  typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;

  // SetCallback sets the callback to notify when a new sample is recorded on
  // the histogram referred to by |histogram_name|. The call to this method can
  // be be done before or after the histogram is created. This method is thread
  // safe. The return value is whether or not the callback was successfully set.
  static bool SetCallback(const std::string& histogram_name,
                          const OnSampleCallback& callback);

  // ClearCallback clears any callback set on the histogram referred to by
  // |histogram_name|. This method is thread safe.
  static void ClearCallback(const std::string& histogram_name);

  // FindCallback retrieves the callback for the histogram referred to by
  // |histogram_name|, or a null callback if no callback exists for this
  // histogram. This method is thread safe.
  static OnSampleCallback FindCallback(const std::string& histogram_name);

  // Returns the number of known histograms.
  static size_t GetHistogramCount();

  // Removes a histogram from the internal set of known ones. This can be
  // necessary during testing persistent histograms where the underlying
  // memory is being released.
  static void ForgetHistogramForTesting(base::StringPiece name);

  // Creates a local StatisticsRecorder object for testing purposes. All new
  // histograms will be registered in it until it is destructed or pushed
  // aside for the lifetime of yet another SR object. The destruction of the
  // returned object will re-activate the previous one. Always release SR
  // objects in the opposite order to which they're created.
  static std::unique_ptr<StatisticsRecorder> CreateTemporaryForTesting()
      WARN_UNUSED_RESULT;

  // Resets any global instance of the statistics-recorder that was created
  // by a call to Initialize().
  static void UninitializeForTesting();

 private:
  // We keep a map of callbacks to histograms, so that as histograms are
  // created, we can set the callback properly.
  typedef std::map<std::string, OnSampleCallback> CallbackMap;

  // We keep all |bucket_ranges_| in a map, from checksum to a list of
  // |bucket_ranges_|.  Checksum is calculated from the |ranges_| in
  // |bucket_ranges_|.
  typedef std::map<uint32_t, std::list<const BucketRanges*>*> RangesMap;

  friend struct DefaultLazyInstanceTraits<StatisticsRecorder>;

  // Imports histograms from global persistent memory. The global lock must
  // not be held during this call.
  static void ImportGlobalPersistentHistograms();

  // The constructor just initializes static members. Usually client code should
  // use Initialize to do this. But in test code, you can friend this class and
  // call the constructor to get a clean StatisticsRecorder.
  StatisticsRecorder();

  // These are copies of everything that existed when the (test) Statistics-
  // Recorder was created. The global ones have to be moved aside to create a
  // clean environment.
  std::unique_ptr<HistogramMap> existing_histograms_;
  std::unique_ptr<CallbackMap> existing_callbacks_;
  std::unique_ptr<RangesMap> existing_ranges_;

  static void Reset();
  static void DumpHistogramsToVlog(void* instance);

  static HistogramMap* histograms_;
  static CallbackMap* callbacks_;
  static RangesMap* ranges_;

  // Lock protects access to above maps.
  static base::Lock* lock_;

  DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
};

}  // namespace base

#endif  // BASE_METRICS_STATISTICS_RECORDER_H_