github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/clock_gettime.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://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, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <pthread.h> 16 #include <sys/time.h> 17 18 #include <cerrno> 19 #include <cstdint> 20 #include <ctime> 21 #include <list> 22 #include <memory> 23 #include <string> 24 25 #include "gmock/gmock.h" 26 #include "gtest/gtest.h" 27 #include "absl/time/clock.h" 28 #include "absl/time/time.h" 29 #include "test/util/test_util.h" 30 #include "test/util/thread_util.h" 31 32 namespace gvisor { 33 namespace testing { 34 35 namespace { 36 37 int64_t clock_gettime_nsecs(clockid_t id) { 38 struct timespec ts; 39 TEST_PCHECK(clock_gettime(id, &ts) == 0); 40 return (ts.tv_sec * 1000000000 + ts.tv_nsec); 41 } 42 43 // Spin on the CPU for at least ns nanoseconds, based on 44 // CLOCK_THREAD_CPUTIME_ID. 45 void spin_ns(int64_t ns) { 46 int64_t start = clock_gettime_nsecs(CLOCK_THREAD_CPUTIME_ID); 47 int64_t end = start + ns; 48 49 do { 50 constexpr int kLoopCount = 1000000; // large and arbitrary 51 // volatile to prevent the compiler from skipping this loop. 52 for (volatile int i = 0; i < kLoopCount; i++) { 53 } 54 } while (clock_gettime_nsecs(CLOCK_THREAD_CPUTIME_ID) < end); 55 } 56 57 // Test that CLOCK_PROCESS_CPUTIME_ID is a superset of CLOCK_THREAD_CPUTIME_ID. 58 TEST(ClockGettime, CputimeId) { 59 constexpr int kNumThreads = 13; // arbitrary 60 61 absl::Duration spin_time = absl::Seconds(1); 62 63 // Start off the worker threads and compute the aggregate time spent by 64 // the workers. Note that we test CLOCK_PROCESS_CPUTIME_ID by having the 65 // workers execute in parallel and verifying that CLOCK_PROCESS_CPUTIME_ID 66 // accumulates the runtime of all threads. 67 int64_t start = clock_gettime_nsecs(CLOCK_PROCESS_CPUTIME_ID); 68 69 // Create a kNumThreads threads. 70 std::list<ScopedThread> threads; 71 for (int i = 0; i < kNumThreads; i++) { 72 threads.emplace_back( 73 [spin_time] { spin_ns(absl::ToInt64Nanoseconds(spin_time)); }); 74 } 75 for (auto& t : threads) { 76 t.Join(); 77 } 78 79 int64_t end = clock_gettime_nsecs(CLOCK_PROCESS_CPUTIME_ID); 80 81 // The aggregate time spent in the worker threads must be at least 82 // 'kNumThreads' times the time each thread spun. 83 ASSERT_GE(end - start, kNumThreads * absl::ToInt64Nanoseconds(spin_time)); 84 } 85 86 TEST(ClockGettime, JavaThreadTime) { 87 clockid_t clockid; 88 ASSERT_EQ(0, pthread_getcpuclockid(pthread_self(), &clockid)); 89 struct timespec tp; 90 ASSERT_THAT(clock_getres(clockid, &tp), SyscallSucceeds()); 91 EXPECT_TRUE(tp.tv_sec > 0 || tp.tv_nsec > 0); 92 // A thread cputime is updated each 10msec and there is no approximation 93 // if a task is running. 94 do { 95 ASSERT_THAT(clock_gettime(clockid, &tp), SyscallSucceeds()); 96 } while (tp.tv_sec == 0 && tp.tv_nsec == 0); 97 EXPECT_TRUE(tp.tv_sec > 0 || tp.tv_nsec > 0); 98 } 99 100 // There is not much to test here, since CLOCK_REALTIME may be discontiguous. 101 TEST(ClockGettime, RealtimeWorks) { 102 struct timespec tp; 103 EXPECT_THAT(clock_gettime(CLOCK_REALTIME, &tp), SyscallSucceeds()); 104 } 105 106 class MonotonicClockTest : public ::testing::TestWithParam<clockid_t> {}; 107 108 TEST_P(MonotonicClockTest, IsMonotonic) { 109 auto end = absl::Now() + absl::Seconds(5); 110 111 struct timespec tp; 112 EXPECT_THAT(clock_gettime(GetParam(), &tp), SyscallSucceeds()); 113 114 auto prev = absl::TimeFromTimespec(tp); 115 while (absl::Now() < end) { 116 EXPECT_THAT(clock_gettime(GetParam(), &tp), SyscallSucceeds()); 117 auto now = absl::TimeFromTimespec(tp); 118 EXPECT_GE(now, prev); 119 prev = now; 120 } 121 } 122 123 std::string PrintClockId(::testing::TestParamInfo<clockid_t> info) { 124 switch (info.param) { 125 case CLOCK_MONOTONIC: 126 return "CLOCK_MONOTONIC"; 127 case CLOCK_MONOTONIC_COARSE: 128 return "CLOCK_MONOTONIC_COARSE"; 129 case CLOCK_MONOTONIC_RAW: 130 return "CLOCK_MONOTONIC_RAW"; 131 case CLOCK_BOOTTIME: 132 // CLOCK_BOOTTIME is a monotonic clock. 133 return "CLOCK_BOOTTIME"; 134 default: 135 return absl::StrCat(info.param); 136 } 137 } 138 139 INSTANTIATE_TEST_SUITE_P(ClockGettime, MonotonicClockTest, 140 ::testing::Values(CLOCK_MONOTONIC, 141 CLOCK_MONOTONIC_COARSE, 142 CLOCK_MONOTONIC_RAW, CLOCK_BOOTTIME), 143 PrintClockId); 144 145 TEST(ClockGettime, UnimplementedReturnsEINVAL) { 146 SKIP_IF(!IsRunningOnGvisor()); 147 148 struct timespec tp; 149 EXPECT_THAT(clock_gettime(CLOCK_REALTIME_ALARM, &tp), 150 SyscallFailsWithErrno(EINVAL)); 151 EXPECT_THAT(clock_gettime(CLOCK_BOOTTIME_ALARM, &tp), 152 SyscallFailsWithErrno(EINVAL)); 153 } 154 155 TEST(ClockGettime, InvalidClockIDReturnsEINVAL) { 156 struct timespec tp; 157 EXPECT_THAT(clock_gettime(-1, &tp), SyscallFailsWithErrno(EINVAL)); 158 } 159 160 } // namespace 161 162 } // namespace testing 163 } // namespace gvisor