OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef METRICS_COUNTER_H_ | 5 #ifndef METRICS_COUNTER_H_ |
6 #define METRICS_COUNTER_H_ | 6 #define METRICS_COUNTER_H_ |
7 | 7 |
| 8 #include <string> |
8 #include <time.h> | 9 #include <time.h> |
9 | 10 |
10 #include <base/basictypes.h> | 11 #include <base/basictypes.h> |
11 #include <base/scoped_ptr.h> | 12 #include <base/scoped_ptr.h> |
12 #include <gtest/gtest_prod.h> // for FRIEND_TEST | 13 #include <gtest/gtest_prod.h> // for FRIEND_TEST |
13 | 14 |
| 15 class MetricsLibraryInterface; |
| 16 |
14 namespace chromeos_metrics { | 17 namespace chromeos_metrics { |
15 | 18 |
16 // Constants useful for frequency statistics. | 19 // Constants useful for frequency statistics. |
17 const int kSecondsPerDay = 60 * 60 * 24; | 20 const int kSecondsPerDay = 60 * 60 * 24; |
18 const int kSecondsPerWeek = kSecondsPerDay * 7; | 21 const int kSecondsPerWeek = kSecondsPerDay * 7; |
19 | 22 |
20 // TaggedCounter maintains a persistent storage (i.e., a file) | 23 // TaggedCounter maintains a persistent storage (i.e., a file) |
21 // aggregation counter for a given tag (e.g., day, hour) that survives | 24 // aggregation counter for a given tag (e.g., day, hour) that survives |
22 // system shutdowns, reboots and crashes, as well as daemon process | 25 // system shutdowns, reboots and crashes, as well as daemon process |
23 // restarts. The counter object is initialized by pointing to the | 26 // restarts. The counter object is initialized by pointing to the |
(...skipping 13 matching lines...) Expand all Loading... |
37 // Once this callback is invoked by the counter, the reported | 40 // Once this callback is invoked by the counter, the reported |
38 // aggregated data is discarded. | 41 // aggregated data is discarded. |
39 // | 42 // |
40 // |handle| is the |reporter_handle| pointer passed through Init. | 43 // |handle| is the |reporter_handle| pointer passed through Init. |
41 // |tag| is the tag associated with the aggregated count. | 44 // |tag| is the tag associated with the aggregated count. |
42 // |count| is aggregated count. | 45 // |count| is aggregated count. |
43 typedef void (*Reporter)(void* handle, int32 tag, int32 count); | 46 typedef void (*Reporter)(void* handle, int32 tag, int32 count); |
44 | 47 |
45 virtual ~TaggedCounterInterface() {} | 48 virtual ~TaggedCounterInterface() {} |
46 | 49 |
47 // Initializes the counter by providing the persistent storage | |
48 // location |filename| and a |reporter| callback for reporting | |
49 // aggregated counts. |reporter_handle| is sent to the |reporter| | |
50 // along with the aggregated counts. | |
51 // | |
52 // NOTE: The assumption is that this object is the sole owner of the | |
53 // persistent storage file so no locking is currently implemented. | |
54 virtual void Init(const char* filename, | |
55 Reporter reporter, void* reporter_handle) = 0; | |
56 | |
57 // Adds |count| of events for the given |tag|. If there's an | 50 // Adds |count| of events for the given |tag|. If there's an |
58 // existing aggregated count for a different tag, it's reported | 51 // existing aggregated count for a different tag, it's reported |
59 // through the reporter callback and discarded. | 52 // through the reporter callback and discarded. |
60 virtual void Update(int32 tag, int32 count) = 0; | 53 virtual void Update(int32 tag, int32 count) = 0; |
61 | 54 |
62 // Reports the current aggregated count (if any) through the | 55 // Reports the current aggregated count (if any) through the |
63 // reporter callback and discards it. | 56 // reporter callback and discards it. |
64 virtual void Flush() = 0; | 57 virtual void Flush() = 0; |
65 }; | 58 }; |
66 | 59 |
67 class TaggedCounter : public TaggedCounterInterface { | 60 class TaggedCounter : public TaggedCounterInterface { |
68 public: | 61 public: |
69 TaggedCounter(); | 62 TaggedCounter(); |
70 ~TaggedCounter(); | 63 virtual ~TaggedCounter(); |
| 64 |
| 65 // Initializes the counter by providing the persistent storage |
| 66 // location |filename| and a |reporter| callback for reporting |
| 67 // aggregated counts. |reporter_handle| is sent to the |reporter| |
| 68 // along with the aggregated counts. |
| 69 // |
| 70 // NOTE: The assumption is that this object is the sole owner of the |
| 71 // persistent storage file so no locking is currently implemented. |
| 72 virtual void Init(const char* filename, |
| 73 Reporter reporter, void* reporter_handle); |
71 | 74 |
72 // Implementation of interface methods. | 75 // Implementation of interface methods. |
73 void Init(const char* filename, Reporter reporter, void* reporter_handle); | 76 virtual void Update(int32 tag, int32 count); |
74 void Update(int32 tag, int32 count); | 77 virtual void Flush(); |
75 void Flush(); | |
76 | 78 |
77 private: | 79 private: |
78 friend class RecordTest; | 80 friend class RecordTest; |
79 friend class TaggedCounterTest; | 81 friend class TaggedCounterTest; |
80 FRIEND_TEST(TaggedCounterTest, BadFileLocation); | 82 FRIEND_TEST(TaggedCounterTest, BadFileLocation); |
81 FRIEND_TEST(TaggedCounterTest, Flush); | 83 FRIEND_TEST(TaggedCounterTest, Flush); |
82 FRIEND_TEST(TaggedCounterTest, InitFromFile); | 84 FRIEND_TEST(TaggedCounterTest, InitFromFile); |
83 FRIEND_TEST(TaggedCounterTest, Update); | 85 FRIEND_TEST(TaggedCounterTest, Update); |
84 | 86 |
85 // The current tag/count record is cached by the counter object to | 87 // The current tag/count record is cached by the counter object to |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 // record with the same tag as |tag|. If |flush| is true, the method | 141 // record with the same tag as |tag|. If |flush| is true, the method |
140 // asserts that the cached record is null and returns. | 142 // asserts that the cached record is null and returns. |
141 void UpdateRecord(int32 tag, int32 count, bool flush); | 143 void UpdateRecord(int32 tag, int32 count, bool flush); |
142 | 144 |
143 // If the cached record state is dirty, updates the persistent | 145 // If the cached record state is dirty, updates the persistent |
144 // storage specified through file descriptor |fd| and switches the | 146 // storage specified through file descriptor |fd| and switches the |
145 // record state to non-dirty. | 147 // record state to non-dirty. |
146 void WriteRecord(int fd); | 148 void WriteRecord(int fd); |
147 | 149 |
148 // Persistent storage file path. | 150 // Persistent storage file path. |
149 const char* filename_; | 151 std::string filename_; |
150 | 152 |
151 // Aggregated data reporter callback and handle to pass-through. | 153 // Aggregated data reporter callback and handle to pass-through. |
152 Reporter reporter_; | 154 Reporter reporter_; |
153 void* reporter_handle_; | 155 void* reporter_handle_; |
154 | 156 |
155 // Current cached aggregation record. | 157 // Current cached aggregation record. |
156 Record record_; | 158 Record record_; |
157 | 159 |
158 // Current cached aggregation record state. | 160 // Current cached aggregation record state. |
159 RecordState record_state_; | 161 RecordState record_state_; |
160 }; | 162 }; |
161 | 163 |
| 164 // TaggedCounterReporter provides a TaggedCounterInterface which both |
| 165 // counts tagged events and reports them up through the metrics |
| 166 // library to UMA. |
| 167 class TaggedCounterReporter : public TaggedCounterInterface { |
| 168 public: |
| 169 TaggedCounterReporter(); |
| 170 virtual ~TaggedCounterReporter(); |
| 171 |
| 172 // Set the metrics library used by all TaggedCounterReporter |
| 173 // instances. We assume there is only one metrics library |
| 174 // shared amongst all reporters. |
| 175 static void SetMetricsLibraryInterface(MetricsLibraryInterface* metrics_lib) { |
| 176 metrics_lib_ = metrics_lib; |
| 177 } |
| 178 |
| 179 // Initializes the counter by providing the persistent storage |
| 180 // location |filename|, a |histogram_name| (a linear histogram) to |
| 181 // report to with |min|, |max|, and |buckets| attributes for the |
| 182 // histogram. |
| 183 virtual void Init(const char* filename, |
| 184 const char* histogram_name, |
| 185 int min, |
| 186 int max, |
| 187 int buckets); |
| 188 |
| 189 // Implementation of interface method. |
| 190 virtual void Update(int32 tag, int32 count) { |
| 191 tagged_counter_->Update(tag, count); |
| 192 } |
| 193 // Implementation of interface method. |
| 194 virtual void Flush() { |
| 195 tagged_counter_->Flush(); |
| 196 } |
| 197 |
| 198 // Accessor functions. |
| 199 const std::string& histogram_name() const { |
| 200 return histogram_name_; |
| 201 } |
| 202 |
| 203 int min() const { |
| 204 return min_; |
| 205 } |
| 206 |
| 207 int max() const { |
| 208 return max_; |
| 209 } |
| 210 |
| 211 int buckets() const { |
| 212 return buckets_; |
| 213 } |
| 214 |
| 215 protected: |
| 216 friend class TaggedCounterReporterTest; |
| 217 FRIEND_TEST(TaggedCounterReporterTest, Report); |
| 218 |
| 219 static void Report(void* handle, int32 tag, int32 count); |
| 220 |
| 221 static MetricsLibraryInterface* metrics_lib_; |
| 222 scoped_ptr<TaggedCounter> tagged_counter_; |
| 223 std::string histogram_name_; |
| 224 int min_; |
| 225 int max_; |
| 226 int buckets_; |
| 227 }; |
| 228 |
162 // FrequencyCounter uses TaggedCounter to maintain a persistent | 229 // FrequencyCounter uses TaggedCounter to maintain a persistent |
163 // storage of the number of events that occur in a given cycle | 230 // storage of the number of events that occur in a given cycle |
164 // duration (in other words, a frequency count). For example, to | 231 // duration (in other words, a frequency count). For example, to |
165 // count the number of blips per day, initialize |cycle_duration| to | 232 // count the number of blips per day, initialize |cycle_duration| to |
166 // chromeos_metrics::kSecondsPerDay, and call Update with the number | 233 // chromeos_metrics::kSecondsPerDay, and call Update with the number |
167 // of blips that happen concurrently (usually 1). Reporting of the | 234 // of blips that happen concurrently (usually 1). Reporting of the |
168 // value is done through TaggedCounter's reporter function. | 235 // value is done through TaggedCounter's reporter function. |
169 class FrequencyCounter { | 236 class FrequencyCounter { |
170 public: | 237 public: |
171 // Create a new frequency counter. | 238 // Create a new frequency counter. |
172 FrequencyCounter(); | 239 FrequencyCounter(); |
173 virtual ~FrequencyCounter(); | 240 virtual ~FrequencyCounter(); |
174 | 241 |
175 // Initialize a frequency counter, which is necessary before first use. | 242 // Initialize a frequency counter, which is necessary before first |
176 // |filename|, |reporter|, and |reporter_handle| are used as in | 243 // use. |tagged_counter| is used to store the counts, its memory |
177 // TaggedCounter::Init. |cycle_duration| is the number of seconds | 244 // will be managed by this FrequencyCounter. |cycle_duration| is |
178 // in a cycle. | 245 // the number of seconds in a cycle. |
179 virtual void Init(const char* filename, | 246 virtual void Init(TaggedCounterInterface* tagged_counter, |
180 TaggedCounterInterface::Reporter reporter, | |
181 void* reporter_handle, | |
182 time_t cycle_duration); | 247 time_t cycle_duration); |
183 // Record that an event occurred. |count| is the number of concurrent | 248 // Record that an event occurred. |count| is the number of concurrent |
184 // events that have occurred. The time is implicitly assumed to be the | 249 // events that have occurred. The time is implicitly assumed to be the |
185 // time of the call. | 250 // time of the call. |
186 virtual void Update(int32 count) { | 251 virtual void Update(int32 count) { |
187 UpdateInternal(count, time(NULL)); | 252 UpdateInternal(count, time(NULL)); |
188 } | 253 } |
189 | 254 |
| 255 // Update the frequency counter based on the current time. If a |
| 256 // cycle has finished, this will have the effect of flushing the |
| 257 // cycle's count, without first requiring another update to the |
| 258 // frequency counter. The more often this is called, the lower the |
| 259 // latency to have a new sample submitted. |
| 260 virtual void FlushFinishedCycles() { |
| 261 Update(0); |
| 262 } |
| 263 |
| 264 // Accessor function. |
| 265 const TaggedCounterInterface& tagged_counter() const { |
| 266 return *tagged_counter_; |
| 267 } |
| 268 |
| 269 time_t cycle_duration() const { |
| 270 return cycle_duration_; |
| 271 } |
| 272 |
190 private: | 273 private: |
191 friend class FrequencyCounterTest; | 274 friend class FrequencyCounterTest; |
192 FRIEND_TEST(FrequencyCounterTest, UpdateInternal); | 275 FRIEND_TEST(FrequencyCounterTest, UpdateInternal); |
| 276 FRIEND_TEST(FrequencyCounterTest, GetCycleNumberForWeek); |
| 277 FRIEND_TEST(FrequencyCounterTest, GetCycleNumberForDay); |
193 | 278 |
194 void UpdateInternal(int32 count, time_t now); | 279 void UpdateInternal(int32 count, time_t now); |
195 int32 GetCycleNumber(time_t now); | 280 int32 GetCycleNumber(time_t now); |
196 | 281 |
197 time_t cycle_duration_; | 282 time_t cycle_duration_; |
198 scoped_ptr<TaggedCounterInterface> tagged_counter_; | 283 scoped_ptr<TaggedCounterInterface> tagged_counter_; |
199 }; | 284 }; |
200 | 285 |
201 } // namespace chromeos_metrics | 286 } // namespace chromeos_metrics |
202 | 287 |
203 #endif // METRICS_COUNTER_H_ | 288 #endif // METRICS_COUNTER_H_ |
OLD | NEW |