| 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 |