xref: /aosp_15_r20/external/pigweed/pw_chrono/system_clock_facade_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include <chrono>
16 
17 #include "pw_chrono/system_clock.h"
18 #include "pw_preprocessor/util.h"
19 #include "pw_unit_test/framework.h"
20 
21 using namespace std::chrono_literals;
22 
23 namespace pw::chrono {
24 namespace {
25 
26 extern "C" {
27 
28 // Functions defined in system_clock_facade_test_c.c which call the API from C.
29 pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_CallNow();
30 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_CallTimeElapsed(
31     pw_chrono_SystemClock_TimePoint last_time,
32     pw_chrono_SystemClock_TimePoint current_time);
33 
34 pw_chrono_SystemClock_Nanoseconds pw_chrono_SystemClock_CallDurationToNsFloor(
35     pw_chrono_SystemClock_Duration ticks);
36 
37 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_100ms(void);
38 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_10s(void);
39 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_1min(void);
40 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_2h(void);
41 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_100msCeil(void);
42 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_10sCeil(void);
43 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_1minCeil(void);
44 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_2hCeil(void);
45 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_100msFloor(void);
46 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_10sFloor(void);
47 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_1minFloor(void);
48 pw_chrono_SystemClock_Duration pw_chrono_SystemClock_Macros_2hFloor(void);
49 
50 }  // extern "C"
51 
52 // While testing that the clock ticks (i.e. moves forward) we want to ensure a
53 // failure can be reported instead of deadlocking the test until it passes.
54 // Given that there isn't really a good heuristic for this we instead make some
55 // wild assumptions to bound the maximum busy loop iterations.
56 // - Assume our clock is < 6Ghz
57 // - Assume we can check the clock in a single cycle
58 // - Wait for up to 1/10th of a second @ 6Ghz, this may be a long period on a
59 //   slower (i.e. real) machine.
60 constexpr uint64_t kMaxIterations = 6'000'000'000 / 10;
61 
TEST(SystemClock,Now)62 TEST(SystemClock, Now) {
63   const SystemClock::time_point start_time = SystemClock::now();
64   // Verify the clock moves forward.
65   bool clock_moved_forward = false;
66   for (uint64_t i = 0; i < kMaxIterations; ++i) {
67     if (SystemClock::now() > start_time) {
68       clock_moved_forward = true;
69       break;
70     }
71   }
72   EXPECT_TRUE(clock_moved_forward);
73 }
74 
TEST(VirtualSystemClock,Now)75 TEST(VirtualSystemClock, Now) {
76   auto& clock = VirtualSystemClock::RealClock();
77   const SystemClock::time_point start_time = clock.now();
78   // Verify the clock moves forward.
79   bool clock_moved_forward = false;
80   for (uint64_t i = 0; i < kMaxIterations; ++i) {
81     if (clock.now() > start_time) {
82       clock_moved_forward = true;
83       break;
84     }
85   }
86   EXPECT_TRUE(clock_moved_forward);
87 }
88 
TEST(SystemClock,NowInC)89 TEST(SystemClock, NowInC) {
90   const pw_chrono_SystemClock_TimePoint start_time =
91       pw_chrono_SystemClock_CallNow();
92   // Verify the clock moves forward.
93   bool clock_moved_forward = false;
94   for (uint64_t i = 0; i < kMaxIterations; ++i) {
95     if (pw_chrono_SystemClock_CallNow().duration_since_epoch.ticks >
96         start_time.duration_since_epoch.ticks) {
97       clock_moved_forward = true;
98       break;
99     }
100   }
101   EXPECT_TRUE(clock_moved_forward);
102 }
103 
TEST(SystemClock,TimeElapsedInC)104 TEST(SystemClock, TimeElapsedInC) {
105   const pw_chrono_SystemClock_TimePoint first = pw_chrono_SystemClock_CallNow();
106   const pw_chrono_SystemClock_TimePoint last = pw_chrono_SystemClock_CallNow();
107   static_assert(SystemClock::is_monotonic);
108   EXPECT_GE(0, pw_chrono_SystemClock_CallTimeElapsed(last, first).ticks);
109 }
110 
TEST(SystemClock,DurationCastInC)111 TEST(SystemClock, DurationCastInC) {
112   // We can't control the SystemClock's period configuration, so just in case
113   // 42 hours cannot be accurately expressed in integer ticks, round the
114   // duration w/ floor.
115   static constexpr auto kRoundedArbitraryDuration =
116       std::chrono::floor<SystemClock::duration>(42h);
117   static constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryDurationInC =
118       PW_SYSTEM_CLOCK_H_FLOOR(42);
119   EXPECT_EQ(
120       std::chrono::floor<std::chrono::nanoseconds>(kRoundedArbitraryDuration)
121           .count(),
122       pw_chrono_SystemClock_CallDurationToNsFloor(
123           kRoundedArbitraryDurationInC));
124 }
125 
126 // Though the macros are intended for C use, test them in this file in C++.
TEST(SystemClock,DurationMacros)127 TEST(SystemClock, DurationMacros) {
128   EXPECT_EQ(pw_chrono_SystemClock_Macros_100ms().ticks,
129             PW_SYSTEM_CLOCK_MS(100).ticks);
130   EXPECT_EQ(pw_chrono_SystemClock_Macros_10s().ticks,
131             PW_SYSTEM_CLOCK_S(10).ticks);
132   EXPECT_EQ(pw_chrono_SystemClock_Macros_1min().ticks,
133             PW_SYSTEM_CLOCK_MIN(1).ticks);
134   EXPECT_EQ(pw_chrono_SystemClock_Macros_2h().ticks,
135             PW_SYSTEM_CLOCK_H(2).ticks);
136   EXPECT_EQ(pw_chrono_SystemClock_Macros_100msCeil().ticks,
137             PW_SYSTEM_CLOCK_MS_CEIL(100).ticks);
138   EXPECT_EQ(pw_chrono_SystemClock_Macros_10sCeil().ticks,
139             PW_SYSTEM_CLOCK_S_CEIL(10).ticks);
140   EXPECT_EQ(pw_chrono_SystemClock_Macros_1minCeil().ticks,
141             PW_SYSTEM_CLOCK_MIN_CEIL(1).ticks);
142   EXPECT_EQ(pw_chrono_SystemClock_Macros_2hCeil().ticks,
143             PW_SYSTEM_CLOCK_H_CEIL(2).ticks);
144   EXPECT_EQ(pw_chrono_SystemClock_Macros_100msFloor().ticks,
145             PW_SYSTEM_CLOCK_MS_FLOOR(100).ticks);
146   EXPECT_EQ(pw_chrono_SystemClock_Macros_10sFloor().ticks,
147             PW_SYSTEM_CLOCK_S_FLOOR(10).ticks);
148   EXPECT_EQ(pw_chrono_SystemClock_Macros_1minFloor().ticks,
149             PW_SYSTEM_CLOCK_MIN_FLOOR(1).ticks);
150   EXPECT_EQ(pw_chrono_SystemClock_Macros_2hFloor().ticks,
151             PW_SYSTEM_CLOCK_H_FLOOR(2).ticks);
152 }
153 
154 }  // namespace
155 }  // namespace pw::chrono
156