xref: /aosp_15_r20/frameworks/native/libs/battery/MultiStateCounterTest.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  * Android BPF library - public API
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <gtest/gtest.h>
19 #include "MultiStateCounter.h"
20 
21 namespace android {
22 namespace battery {
23 
24 typedef MultiStateCounter<double, double> DoubleMultiStateCounter;
25 
26 template <>
delta(const double & previousValue,const double & newValue,double * outValue) const27 bool DoubleMultiStateCounter::delta(const double& previousValue, const double& newValue,
28                                     double* outValue) const {
29     *outValue = newValue - previousValue;
30     return *outValue >= 0;
31 }
32 
33 template <>
add(double * value1,const double & value2,const uint64_t numerator,const uint64_t denominator) const34 void DoubleMultiStateCounter::add(double* value1, const double& value2, const uint64_t numerator,
35                                   const uint64_t denominator) const {
36     if (numerator != denominator) {
37         // The caller ensures that denominator != 0
38         *value1 += value2 * numerator / denominator;
39     } else {
40         *value1 += value2;
41     }
42 }
43 
44 class MultiStateCounterTest : public testing::Test {};
45 
TEST_F(MultiStateCounterTest,constructor)46 TEST_F(MultiStateCounterTest, constructor) {
47     DoubleMultiStateCounter testCounter(3, 0);
48     testCounter.updateValue(0, 0);
49     testCounter.setState(1, 0);
50     double delta = testCounter.updateValue(3.14, 3000);
51 
52     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
53     EXPECT_DOUBLE_EQ(3.14, testCounter.getCount(1));
54     EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
55     EXPECT_DOUBLE_EQ(3.14, delta);
56 }
57 
TEST_F(MultiStateCounterTest,stateChange)58 TEST_F(MultiStateCounterTest, stateChange) {
59     DoubleMultiStateCounter testCounter(3, 0);
60     testCounter.updateValue(0, 0);
61     testCounter.setState(1, 0);
62     testCounter.setState(2, 1000);
63     testCounter.updateValue(6.0, 3000);
64 
65     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
66     EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
67     EXPECT_DOUBLE_EQ(4.0, testCounter.getCount(2));
68 }
69 
TEST_F(MultiStateCounterTest,copyStatesFrom)70 TEST_F(MultiStateCounterTest, copyStatesFrom) {
71     DoubleMultiStateCounter sourceCounter(3, 0);
72 
73     sourceCounter.updateValue(0, 0);
74     sourceCounter.setState(1, 0);
75     sourceCounter.setState(2, 1000);
76 
77     DoubleMultiStateCounter testCounter(3, 0);
78     testCounter.copyStatesFrom(sourceCounter);
79     testCounter.updateValue(6.0, 3000);
80 
81     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
82     EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
83     EXPECT_DOUBLE_EQ(4.0, testCounter.getCount(2));
84 }
85 
TEST_F(MultiStateCounterTest,setEnabled)86 TEST_F(MultiStateCounterTest, setEnabled) {
87     DoubleMultiStateCounter testCounter(3, 0);
88     testCounter.updateValue(0, 0);
89     testCounter.setState(1, 0);
90     testCounter.setEnabled(false, 1000);
91     testCounter.setState(2, 2000);
92     testCounter.updateValue(6.0, 3000);
93 
94     // In state 1: accumulated 1000 before disabled, that's 6.0 * 1000/3000 = 2.0
95     // In state 2: 0, since it is still disabled
96     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
97     EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
98     EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
99 
100     // Should have no effect since the counter is disabled
101     testCounter.setState(0, 3500);
102 
103     // Should have no effect since the counter is disabled
104     testCounter.updateValue(10.0, 4000);
105 
106     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
107     EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
108     EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
109 
110     testCounter.setState(2, 4500);
111 
112     // Enable the counter to partially accumulate deltas for the current state, 2
113     testCounter.setEnabled(true, 5000);
114     testCounter.setEnabled(false, 6000);
115     testCounter.setEnabled(true, 7000);
116     testCounter.updateValue(20.0, 8000);
117 
118     // The delta is 10.0 over 5000-3000=2000.
119     // Counter has been enabled in state 2 for (6000-5000)+(8000-7000) = 2000,
120     // so its share is (20.0-10.0) * 2000/(8000-4000) = 5.0
121     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
122     EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
123     EXPECT_DOUBLE_EQ(5.0, testCounter.getCount(2));
124 
125     testCounter.reset();
126     testCounter.setState(0, 0);
127     testCounter.updateValue(0, 0);
128     testCounter.setState(1, 2000);
129     testCounter.setEnabled(false, 3000);
130     testCounter.updateValue(200, 5000);
131 
132     // 200 over 5000 = 40 per second
133     // Counter was in state 0 from 0 to 2000, so 2 sec, so the count should be 40 * 2 = 80
134     // It stayed in state 1 from 2000 to 3000, at which point the counter was disabled,
135     // so the count for state 1 should be 40 * 1 = 40.
136     // The remaining 2 seconds from 3000 to 5000 don't count because the counter was disabled.
137     EXPECT_DOUBLE_EQ(80.0, testCounter.getCount(0));
138     EXPECT_DOUBLE_EQ(40.0, testCounter.getCount(1));
139     EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
140 }
141 
TEST_F(MultiStateCounterTest,reset)142 TEST_F(MultiStateCounterTest, reset) {
143     DoubleMultiStateCounter testCounter(3, 0);
144     testCounter.updateValue(0, 0);
145     testCounter.setState(1, 0);
146     testCounter.updateValue(2.72, 3000);
147 
148     testCounter.reset();
149 
150     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
151     EXPECT_DOUBLE_EQ(0, testCounter.getCount(1));
152     EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
153 
154     // Assert that we can still continue accumulating after a reset
155     testCounter.updateValue(0, 4000);
156     testCounter.updateValue(3.14, 5000);
157 
158     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
159     EXPECT_DOUBLE_EQ(3.14, testCounter.getCount(1));
160     EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
161 }
162 
TEST_F(MultiStateCounterTest,timeAdjustment_setState)163 TEST_F(MultiStateCounterTest, timeAdjustment_setState) {
164     DoubleMultiStateCounter testCounter(3, 0);
165     testCounter.updateValue(0, 0);
166     testCounter.setState(1, 0);
167     testCounter.setState(2, 2000);
168 
169     // Time moves back
170     testCounter.setState(1, 1000);
171     testCounter.updateValue(6.0, 3000);
172 
173     EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
174 
175     // We were in state 1 from 0 to 2000, which was erased because the time moved back.
176     // Then from 1000 to 3000, so we expect the count to be 6 * (2000/3000)
177     EXPECT_DOUBLE_EQ(4.0, testCounter.getCount(1));
178 
179     // No time was effectively accumulated for state 2, because the timestamp moved back
180     // while we were in state 2.
181     EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
182 }
183 
TEST_F(MultiStateCounterTest,timeAdjustment_updateValue)184 TEST_F(MultiStateCounterTest, timeAdjustment_updateValue) {
185     DoubleMultiStateCounter testCounter(1, 0);
186     testCounter.updateValue(0, 0);
187     testCounter.setState(0, 0);
188     testCounter.updateValue(6.0, 2000);
189 
190     // Time moves back. The delta over the negative interval from 2000 to 1000 is ignored
191     testCounter.updateValue(8.0, 1000);
192     double delta = testCounter.updateValue(11.0, 3000);
193 
194     // The total accumulated count is:
195     //  6.0          // For the period 0-2000
196     //  +(11.0-8.0)  // For the period 1000-3000
197     EXPECT_DOUBLE_EQ(9.0, testCounter.getCount(0));
198 
199     //  11.0-8.0
200     EXPECT_DOUBLE_EQ(3.0, delta);
201 }
202 
TEST_F(MultiStateCounterTest,updateValue_nonmonotonic)203 TEST_F(MultiStateCounterTest, updateValue_nonmonotonic) {
204     DoubleMultiStateCounter testCounter(2, 0);
205     testCounter.updateValue(0, 0);
206     testCounter.setState(0, 0);
207     testCounter.updateValue(6.0, 2000);
208 
209     // Value goes down. The negative delta from 6.0 to 4.0 is ignored
210     testCounter.updateValue(4.0, 3000);
211 
212     // Value goes up again. The positive delta from 4.0 to 7.0 is accumulated.
213     double delta = testCounter.updateValue(7.0, 4000);
214 
215     // The total accumulated count is:
216     //  6.0          // For the period 0-2000
217     //  +(7.0-4.0)   // For the period 3000-4000
218     EXPECT_DOUBLE_EQ(9.0, testCounter.getCount(0));
219 
220     //  7.0-4.0
221     EXPECT_DOUBLE_EQ(3.0, delta);
222 }
223 
TEST_F(MultiStateCounterTest,incrementValue)224 TEST_F(MultiStateCounterTest, incrementValue) {
225     DoubleMultiStateCounter testCounter(2, 0);
226     testCounter.updateValue(0, 0);
227     testCounter.setState(0, 0);
228     testCounter.updateValue(6.0, 2000);
229 
230     testCounter.setState(1, 3000);
231 
232     testCounter.incrementValue(8.0, 6000);
233 
234     // The total accumulated count is:
235     //  6.0             // For the period 0-2000
236     //  +(8.0 * 0.25)   // For the period 3000-4000
237     EXPECT_DOUBLE_EQ(8.0, testCounter.getCount(0));
238 
239     // 0                // For the period 0-3000
240     // +(8.0 * 0.75)    // For the period 3000-4000
241     EXPECT_DOUBLE_EQ(6.0, testCounter.getCount(1));
242 }
243 
TEST_F(MultiStateCounterTest,addValue)244 TEST_F(MultiStateCounterTest, addValue) {
245     DoubleMultiStateCounter testCounter(1, 0);
246     testCounter.updateValue(0, 0);
247     testCounter.setState(0, 0);
248     testCounter.updateValue(6.0, 2000);
249 
250     testCounter.addValue(8.0);
251 
252     EXPECT_DOUBLE_EQ(14.0, testCounter.getCount(0));
253 
254     testCounter.setEnabled(false, 3000);
255     testCounter.addValue(888.0);
256 
257     EXPECT_DOUBLE_EQ(14.0, testCounter.getCount(0));
258 }
259 
TEST_F(MultiStateCounterTest,toString)260 TEST_F(MultiStateCounterTest, toString) {
261     DoubleMultiStateCounter testCounter(2, 0);
262 
263     EXPECT_STREQ("[0: 0.000000, 1: 0.000000] currentState: none", testCounter.toString().c_str());
264 
265     testCounter.updateValue(0, 0);
266     testCounter.setState(1, 0);
267     testCounter.setState(1, 2000);
268     EXPECT_STREQ("[0: 0.000000, 1: 0.000000 timeInStateSinceUpdate: 2000]"
269                  " updated: 0 currentState: 1 stateChanged: 2000",
270                  testCounter.toString().c_str());
271 
272     testCounter.updateValue(3.14, 3000);
273 
274     EXPECT_STREQ("[0: 0.000000, 1: 3.140000] updated: 3000 currentState: 1",
275                  testCounter.toString().c_str());
276 }
277 
278 } // namespace battery
279 } // namespace android
280