1 //===-- flang/unittests/Runtime/Time.cpp ----------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "gtest/gtest.h" 10 #include "flang/Runtime/time-intrinsic.h" 11 #include <algorithm> 12 #include <cctype> 13 #include <cerrno> 14 #include <string> 15 16 using namespace Fortran::runtime; 17 18 TEST(TimeIntrinsics, CpuTime) { 19 // We can't really test that we get the "right" result for CPU_TIME, but we 20 // can have a smoke test to see that we get something reasonable on the 21 // platforms where we expect to support it. 22 double start{RTNAME(CpuTime)()}; 23 ASSERT_GE(start, 0.0); 24 25 // Loop until we get a different value from CpuTime. If we don't get one 26 // before we time out, then we should probably look into an implementation 27 // for CpuTime with a better timer resolution. 28 for (double end = start; end == start; end = RTNAME(CpuTime)()) { 29 ASSERT_GE(end, 0.0); 30 ASSERT_GE(end, start); 31 } 32 } 33 34 using count_t = std::int64_t; 35 36 TEST(TimeIntrinsics, SystemClock) { 37 // We can't really test that we get the "right" result for SYSTEM_CLOCK, but 38 // we can have a smoke test to see that we get something reasonable on the 39 // platforms where we expect to support it. 40 41 // The value of the count rate and max will vary by platform, but they should 42 // always be strictly positive if we have a working implementation of 43 // SYSTEM_CLOCK. 44 EXPECT_GT(RTNAME(SystemClockCountRate)(), 0); 45 46 count_t max1{RTNAME(SystemClockCountMax)(1)}; 47 EXPECT_GT(max1, 0); 48 EXPECT_LE(max1, static_cast<count_t>(0x7f)); 49 count_t start1{RTNAME(SystemClockCount)(1)}; 50 EXPECT_GE(start1, 0); 51 EXPECT_LE(start1, max1); 52 53 count_t max2{RTNAME(SystemClockCountMax)(2)}; 54 EXPECT_GT(max2, 0); 55 EXPECT_LE(max2, static_cast<count_t>(0x7fff)); 56 count_t start2{RTNAME(SystemClockCount)(2)}; 57 EXPECT_GE(start2, 0); 58 EXPECT_LE(start2, max2); 59 60 count_t max4{RTNAME(SystemClockCountMax)(4)}; 61 EXPECT_GT(max4, 0); 62 EXPECT_LE(max4, static_cast<count_t>(0x7fffffff)); 63 count_t start4{RTNAME(SystemClockCount)(4)}; 64 EXPECT_GE(start4, 0); 65 EXPECT_LE(start4, max4); 66 67 count_t max8{RTNAME(SystemClockCountMax)(8)}; 68 EXPECT_GT(max8, 0); 69 count_t start8{RTNAME(SystemClockCount)(8)}; 70 EXPECT_GE(start8, 0); 71 EXPECT_LT(start8, max8); 72 73 count_t max16{RTNAME(SystemClockCountMax)(16)}; 74 EXPECT_GT(max16, 0); 75 count_t start16{RTNAME(SystemClockCount)(16)}; 76 EXPECT_GE(start16, 0); 77 EXPECT_LT(start16, max16); 78 79 // Loop until we get a different value from SystemClockCount. If we don't get 80 // one before we time out, then we should probably look into an implementation 81 // for SystemClokcCount with a better timer resolution on this platform. 82 for (count_t end{start8}; end == start8; end = RTNAME(SystemClockCount)(8)) { 83 EXPECT_GE(end, 0); 84 EXPECT_LE(end, max8); 85 EXPECT_GE(end, start8); 86 } 87 } 88 89 TEST(TimeIntrinsics, DateAndTime) { 90 errno = 0; 91 constexpr std::size_t bufferSize{16}; 92 std::string date(bufferSize, 'Z'), time(bufferSize, 'Z'), 93 zone(bufferSize, 'Z'); 94 RTNAME(DateAndTime) 95 (date.data(), date.size(), time.data(), time.size(), zone.data(), zone.size(), 96 /*source=*/nullptr, /*line=*/0, /*values=*/nullptr); 97 auto isBlank = [](const std::string &s) -> bool { 98 return std::all_of( 99 s.begin(), s.end(), [](char c) { return std::isblank(c); }); 100 }; 101 // Validate date is blank or YYYYMMDD. 102 if (isBlank(date)) { 103 EXPECT_TRUE(true); 104 } else { 105 count_t number{-1}; 106 // Use stol to allow GCC 7.5 to build tests 107 number = std::stol(date); 108 ASSERT_TRUE(errno != ERANGE); 109 EXPECT_GE(number, 0); 110 auto year = number / 10000; 111 auto month = (number - year * 10000) / 100; 112 auto day = number % 100; 113 // Do not assume anything about the year, the test could be 114 // run on system with fake/outdated dates. 115 EXPECT_LE(month, 12); 116 EXPECT_GT(month, 0); 117 EXPECT_LE(day, 31); 118 EXPECT_GT(day, 0); 119 } 120 121 // Validate time is hhmmss.sss or blank. 122 std::string acceptedPattern("hhmmss.sss"); 123 if (isBlank(time)) { 124 EXPECT_TRUE(true); 125 } else { 126 count_t number{-1}; 127 // Use stol to allow GCC 7.5 to build tests 128 auto dotPosition = acceptedPattern.find('.'); 129 number = std::stol(time.substr(0, dotPosition)); 130 ASSERT_TRUE(errno != ERANGE); 131 ASSERT_GE(number, 0); 132 auto hours = number / 10000; 133 auto minutes = (number - hours * 10000) / 100; 134 auto seconds = number % 100; 135 EXPECT_LE(hours, 23); 136 EXPECT_LE(minutes, 59); 137 // Accept 60 for leap seconds. 138 EXPECT_LE(seconds, 60); 139 EXPECT_EQ(time.substr(dotPosition, 1), "."); 140 141 count_t milliseconds{-1}; 142 milliseconds = std::stol(time.substr(dotPosition + 1, 3)); 143 ASSERT_TRUE(errno != ERANGE); 144 EXPECT_GE(milliseconds, 0); 145 EXPECT_LE(milliseconds, 999); 146 } 147 148 // Validate zone is +hhmm or -hhmm or blank. 149 if (isBlank(zone)) { 150 EXPECT_TRUE(true); 151 } else { 152 ASSERT_TRUE(zone.size() > 1); 153 EXPECT_TRUE(zone[0] == '+' || zone[0] == '-'); 154 count_t number{-1}; 155 // Use stol to allow GCC 7.5 to build tests 156 number = std::stol(zone.substr(1, 4)); 157 ASSERT_TRUE(errno != ERANGE); 158 ASSERT_GE(number, 0); 159 auto hours = number / 100; 160 auto minutes = number % 100; 161 EXPECT_LE(hours, 23); 162 EXPECT_LE(minutes, 59); 163 } 164 } 165