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