1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <gtest/gtest_prod.h>
19 #include <stdint.h>
20 
21 namespace android {
22 namespace os {
23 namespace statsd {
24 
25 /**
26  * A simple stopwatch to time the duration of condition being true.
27  *
28  * The owner of the stopwatch (MetricProducer) is responsible to notify the stopwatch when condition
29  * changes (start/pause), and when to start a new bucket (a new lap basically). All timestamps
30  * should be elapsedRealTime in nano seconds.
31  *
32  * Keep the timer simple and inline everything. This class is *NOT* thread safe. Caller is
33  * responsible for thread safety.
34  */
35 class ConditionTimer {
36 public:
ConditionTimer(bool initCondition,int64_t bucketStartNs)37     explicit ConditionTimer(bool initCondition, int64_t bucketStartNs) : mCondition(initCondition) {
38         if (initCondition) {
39             mLastConditionTrueTimestampNs = bucketStartNs;
40         }
41     };
42 
43     // Tracks how long the condition has been stayed true in the *current* bucket.
44     // When a new bucket is created, this value will be reset to 0.
45     int64_t mTimerNs = 0;
46 
47     // Last elapsed real timestamp when condition turned to true
48     // When a new bucket is created and the condition is true, then the timestamp is set
49     // to be the bucket start timestamp.
50     int64_t mLastConditionTrueTimestampNs = 0;
51 
52     bool mCondition = false;
53 
newBucketStart(int64_t nextBucketStartNs)54     int64_t newBucketStart(int64_t nextBucketStartNs) {
55         if (mCondition) {
56             mTimerNs += (nextBucketStartNs - mLastConditionTrueTimestampNs);
57             mLastConditionTrueTimestampNs = nextBucketStartNs;
58         }
59 
60         int64_t temp = mTimerNs;
61         mTimerNs = 0;
62         return temp;
63     }
64 
onConditionChanged(bool newCondition,int64_t timestampNs)65     void onConditionChanged(bool newCondition, int64_t timestampNs) {
66         if (newCondition == mCondition) {
67             return;
68         }
69         mCondition = newCondition;
70         if (newCondition) {
71             mLastConditionTrueTimestampNs = timestampNs;
72         } else {
73             mTimerNs += (timestampNs - mLastConditionTrueTimestampNs);
74         }
75     }
76 
77     FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_False);
78     FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_True);
79 };
80 
81 }  // namespace statsd
82 }  // namespace os
83 }  // namespace android