YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/monotime-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  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,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include <condition_variable>
34
#include <mutex>
35
36
#include <glog/logging.h>
37
#include <gtest/gtest.h>
38
39
#include "yb/util/test_util.h"
40
41
using namespace std::literals;
42
43
namespace yb {
44
45
1
TEST(TestMonoTime, TestMonotonicity) {
46
1
  alarm(360);
47
1
  MonoTime prev(MonoTime::Now());
48
1
  MonoTime next;
49
50
1
  do {
51
1
    next = MonoTime::Now();
52
1
  } while (!prev.ComesBefore(next));
53
1
  ASSERT_FALSE(next.ComesBefore(prev));
54
1
  alarm(0);
55
1
}
56
57
1
TEST(TestMonoTime, TestComparison) {
58
1
  auto now = CoarseMonoClock::Now();
59
1
  auto future = now + 1ns;
60
61
1
  ASSERT_GT(ToNanoseconds(future - now), 0);
62
1
  ASSERT_LT(ToNanoseconds(now - future), 0);
63
1
  ASSERT_EQ(ToNanoseconds(now - now), 0);
64
65
1
  ASSERT_LT(now, future);
66
1
  ASSERT_FALSE(now < now);
67
1
  ASSERT_FALSE(future < now);
68
1
  ASSERT_LE(now, now);
69
1
  ASSERT_LE(now, future);
70
1
  ASSERT_FALSE(future <= now);
71
1
  ASSERT_GT(future, now);
72
1
  ASSERT_FALSE(now > now);
73
1
  ASSERT_FALSE(now > future);
74
1
  ASSERT_GE(now, now);
75
1
  ASSERT_GE(future, now);
76
1
  ASSERT_FALSE(now >= future);
77
78
1
  MonoDelta nano(MonoDelta::FromNanoseconds(1L));
79
1
  MonoDelta mil(MonoDelta::FromMilliseconds(1L));
80
1
  MonoDelta sec(MonoDelta::FromSeconds(1.0));
81
82
1
  ASSERT_TRUE(nano.LessThan(mil));
83
1
  ASSERT_TRUE(mil.LessThan(sec));
84
1
  ASSERT_TRUE(mil.MoreThan(nano));
85
1
  ASSERT_TRUE(sec.MoreThan(mil));
86
1
}
87
88
1
TEST(TestMonoTime, TestTimeVal) {
89
1
  struct timeval tv;
90
1
  tv.tv_sec = 0;
91
1
  tv.tv_usec = 0;
92
93
  // Normal conversion case.
94
1
  MonoDelta one_sec_one_micro(MonoDelta::FromNanoseconds(1000001000L));
95
1
  one_sec_one_micro.ToTimeVal(&tv);
96
1
  ASSERT_EQ(1, tv.tv_sec);
97
1
  ASSERT_EQ(1, tv.tv_usec);
98
99
  // Case where we are still positive but sub-micro.
100
  // Round up to nearest microsecond. This is to avoid infinite timeouts
101
  // in APIs that take a struct timeval.
102
1
  MonoDelta zero_sec_one_nano(MonoDelta::FromNanoseconds(1L));
103
1
  zero_sec_one_nano.ToTimeVal(&tv);
104
1
  ASSERT_EQ(0, tv.tv_sec);
105
1
  ASSERT_EQ(1, tv.tv_usec); // Special case: 1ns rounds up to
106
107
  // Negative conversion case. Ensure the timeval is normalized.
108
  // That means sec is negative and usec is positive.
109
1
  MonoDelta neg_micro(MonoDelta::FromMicroseconds(-1L));
110
1
  ASSERT_EQ(-1000, neg_micro.ToNanoseconds());
111
1
  neg_micro.ToTimeVal(&tv);
112
1
  ASSERT_EQ(-1, tv.tv_sec);
113
1
  ASSERT_EQ(999999, tv.tv_usec);
114
115
  // Case where we are still negative but sub-micro.
116
  // Round up to nearest microsecond. This is to avoid infinite timeouts
117
  // in APIs that take a struct timeval and for consistency.
118
1
  MonoDelta zero_sec_neg_one_nano(MonoDelta::FromNanoseconds(-1L));
119
1
  zero_sec_neg_one_nano.ToTimeVal(&tv);
120
1
  ASSERT_EQ(-1, tv.tv_sec);
121
1
  ASSERT_EQ(999999, tv.tv_usec);
122
1
}
123
124
1
TEST(TestMonoTime, TestTimeSpec) {
125
1
  timespec ts;
126
127
1
  MonoDelta::FromNanoseconds(2L).ToTimeSpec(&ts);
128
1
  ASSERT_EQ(0, ts.tv_sec);
129
1
  ASSERT_EQ(2, ts.tv_nsec);
130
131
  // Negative conversion case. Ensure the timespec is normalized.
132
  // That means sec is negative and nsec is positive.
133
1
  MonoDelta neg_nano(MonoDelta::FromNanoseconds(-1L));
134
1
  ASSERT_EQ(-1, neg_nano.ToNanoseconds());
135
1
  neg_nano.ToTimeSpec(&ts);
136
1
  ASSERT_EQ(-1, ts.tv_sec);
137
1
  ASSERT_EQ(999999999, ts.tv_nsec);
138
139
1
}
140
141
1
TEST(TestMonoTime, TestDeltas) {
142
1
  alarm(360);
143
1
  const MonoDelta max_delta(MonoDelta::FromSeconds(0.1));
144
1
  MonoTime prev(MonoTime::Now());
145
1
  MonoTime next;
146
1
  MonoDelta cur_delta;
147
1.52M
  do {
148
1.52M
    next = MonoTime::Now();
149
1.52M
    cur_delta = next.GetDeltaSince(prev);
150
1.52M
  } while (cur_delta.LessThan(max_delta));
151
1
  alarm(0);
152
1
}
153
154
1
TEST(TestMonoTime, TestDeltaConversions) {
155
  // TODO: Reliably test MonoDelta::FromSeconds() considering floating-point rounding errors
156
157
1
  MonoDelta mil(MonoDelta::FromMilliseconds(500));
158
1
  ASSERT_EQ(500 * MonoTime::kNanosecondsPerMillisecond, mil.ToNanoseconds());
159
160
1
  MonoDelta micro(MonoDelta::FromMicroseconds(500));
161
1
  ASSERT_EQ(500 * MonoTime::kNanosecondsPerMicrosecond, micro.ToNanoseconds());
162
163
1
  MonoDelta nano(MonoDelta::FromNanoseconds(500));
164
1
  ASSERT_EQ(500, nano.ToNanoseconds());
165
1
}
166
167
template <class Now>
168
2
static void DoTestMonoTimePerf(const std::string& name, Now now) {
169
2
  uint64_t num_calls = 0;
170
2
  auto start = now();
171
2
  auto stop = start + 500ms;
172
19.9M
  do {
173
19.9M
    num_calls++;
174
19.9M
  } while (now() < stop);
175
2
  LOG(INFO) << "DoTestMonoTimePerf(" << name << "): " << num_calls << " in "
176
2
        << ToSeconds(now() - start) << " seconds.";
177
2
}
monotime-test.cc:_ZN2ybL18DoTestMonoTimePerfIZNS_44TestMonoTimePerf_TestMonoTimePerfCoarse_Test8TestBodyEvE3$_0EEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_
Line
Count
Source
168
1
static void DoTestMonoTimePerf(const std::string& name, Now now) {
169
1
  uint64_t num_calls = 0;
170
1
  auto start = now();
171
1
  auto stop = start + 500ms;
172
11.0M
  do {
173
11.0M
    num_calls++;
174
11.0M
  } while (now() < stop);
175
1
  LOG(INFO) << "DoTestMonoTimePerf(" << name << "): " << num_calls << " in "
176
1
        << ToSeconds(now() - start) << " seconds.";
177
1
}
monotime-test.cc:_ZN2ybL18DoTestMonoTimePerfIZNS_42TestMonoTimePerf_TestMonoTimePerfFine_Test8TestBodyEvE3$_1EEvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEET_
Line
Count
Source
168
1
static void DoTestMonoTimePerf(const std::string& name, Now now) {
169
1
  uint64_t num_calls = 0;
170
1
  auto start = now();
171
1
  auto stop = start + 500ms;
172
8.93M
  do {
173
8.93M
    num_calls++;
174
8.93M
  } while (now() < stop);
175
1
  LOG(INFO) << "DoTestMonoTimePerf(" << name << "): " << num_calls << " in "
176
1
        << ToSeconds(now() - start) << " seconds.";
177
1
}
178
179
1
TEST(TestMonoTime, TestSleepFor) {
180
1
  MonoTime start = MonoTime::Now();
181
1
  MonoDelta sleep = MonoDelta::FromMilliseconds(100);
182
1
  SleepFor(sleep);
183
1
  MonoTime end = MonoTime::Now();
184
1
  MonoDelta actualSleep = end.GetDeltaSince(start);
185
1
  ASSERT_GE(actualSleep.ToNanoseconds(), sleep.ToNanoseconds());
186
1
}
187
188
1
TEST(TestMonoTime, TestSleepForOverflow) {
189
1
  if (!AllowSlowTests()) {
190
1
    LOG(INFO) << "Skipping test because it sleeps for ~4s";
191
1
    return;
192
1
  }
193
194
  // This quantity (~4s sleep) overflows a 32-bit integer such that
195
  // the value becomes 0.
196
0
  MonoTime start = MonoTime::Now();
197
0
  MonoDelta sleep = MonoDelta::FromNanoseconds(1L << 32);
198
0
  SleepFor(sleep);
199
0
  MonoTime end = MonoTime::Now();
200
0
  MonoDelta actualSleep = end.GetDeltaSince(start);
201
0
  ASSERT_GE(actualSleep.ToNanoseconds(), sleep.ToNanoseconds());
202
0
}
203
204
1
TEST(TestMonoTimePerf, TestMonoTimePerfCoarse) {
205
1
  alarm(360);
206
11.0M
  DoTestMonoTimePerf("CoarseMonoClock", [] { return CoarseMonoClock::Now(); });
207
1
  alarm(0);
208
1
}
209
210
1
TEST(TestMonoTimePerf, TestMonoTimePerfFine) {
211
1
  alarm(360);
212
8.93M
  DoTestMonoTimePerf("MonoTime", [] { return MonoTime::Now(); });
213
1
  alarm(0);
214
1
}
215
216
1
TEST(TestMonoTime, ToCoarse) {
217
1.00k
  for (int i = 0; i != 1000; ++i) {
218
1.00k
    auto before = CoarseMonoClock::Now();
219
1.00k
    auto converted = ToCoarse(MonoTime::Now());
220
1.00k
    auto after = CoarseMonoClock::Now();
221
222
    // Coarse mono clock has limited precision, so we add its resolution to bounds.
223
1.00k
    const auto kPrecision = ClockResolution<CoarseMonoClock>() * 2;
224
1.00k
    ASSERT_GE(converted, before);
225
1.00k
    ASSERT_LE(converted, after + kPrecision);
226
1.00k
  }
227
1
}
228
229
1
TEST(TestMonoTime, TestOverFlow) {
230
1
  EXPECT_EXIT(MonoDelta::FromMilliseconds(std::numeric_limits<int64_t>::max()),
231
1
                                          ::testing::KilledBySignal(SIGABRT), "Check failed.*");
232
  // We have to cast kint64max to double to avoid a warning on implicit cast that changes the value.
233
1
  EXPECT_EXIT(MonoDelta::FromSeconds(static_cast<double>(std::numeric_limits<int64_t>::max())),
234
1
              ::testing::KilledBySignal(SIGABRT), "Check failed.*");
235
1
  EXPECT_EXIT(MonoDelta::FromMicroseconds(std::numeric_limits<int64_t>::max()),
236
1
              ::testing::KilledBySignal(SIGABRT), "Check failed.*");
237
1
}
238
239
1
TEST(TestMonoTime, TestCondition) {
240
1
  std::mutex mutex;
241
1
  std::condition_variable cond;
242
1
  std::unique_lock<std::mutex> lock(mutex);
243
1
  auto kWaitTime = 500ms;
244
#ifndef __APPLE__
245
  auto kAllowedError = 50ms;
246
#else
247
1
  auto kAllowedError = 200ms;
248
1
#endif
249
1
  for (;;) {
250
1
    auto start = CoarseMonoClock::Now();
251
1
    if (cond.wait_until(lock, CoarseMonoClock::Now() + kWaitTime) != std::cv_status::timeout) {
252
0
      continue;
253
0
    }
254
1
    auto end = CoarseMonoClock::Now();
255
1
    LOG(INFO) << "Passed: " << ToSeconds(end - start) << " seconds.";
256
1
    ASSERT_GE(end - start, kWaitTime - kAllowedError);
257
1
    ASSERT_LE(end - start, kWaitTime + kAllowedError);
258
1
    break;
259
1
  }
260
1
}
261
262
1
TEST(TestMonoTime, TestSubtractDelta) {
263
1
  MonoTime start = MonoTime::Now();
264
1
  MonoDelta delta = MonoDelta::FromMilliseconds(100);
265
1
  ASSERT_GT(start, start - delta);
266
1
  MonoTime start_copy = start;
267
1
  start_copy.SubtractDelta(delta);
268
1
  ASSERT_EQ(start_copy, start - delta);
269
1
  ASSERT_EQ(start_copy + delta, start);
270
1
}
271
272
} // namespace yb