//===-- runtime/time-intrinsic.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // Implements time-related intrinsic subroutines. #include "time-intrinsic.h" #include // CPU_TIME (Fortran 2018 16.9.57) // We can use std::clock() from the header as a fallback implementation // that should be available everywhere. This may not provide the best resolution // and is particularly troublesome on (some?) POSIX systems where CLOCKS_PER_SEC // is defined as 10^6 regardless of the actual precision of std::clock(). // Therefore, we will usually prefer platform-specific alternatives when they // are available. // // We can use SFINAE to choose a platform-specific alternative. To do so, we // introduce a helper function template, whose overload set will contain only // implementations relying on interfaces which are actually available. Each // overload will have a dummy parameter whose type indicates whether or not it // should be preferred. Any other parameters required for SFINAE should have // default values provided. namespace { // Types for the dummy parameter indicating the priority of a given overload. // We will invoke our helper with an integer literal argument, so the overload // with the highest priority should have the type int. using fallback_implementation = double; using preferred_implementation = int; // This is the fallback implementation, which should work everywhere. template double GetCpuTime(fallback_implementation) { std::clock_t timestamp{std::clock()}; if (timestamp != static_cast(-1)) { return static_cast(timestamp) / CLOCKS_PER_SEC; } // Return some negative value to represent failure. return -1.0; } // POSIX implementation using clock_gettime. This is only enabled if // clock_gettime is available. template double GetCpuTime(preferred_implementation, // We need some dummy parameters to pass to decltype(clock_gettime). T ClockId = 0, U *Timespec = nullptr, decltype(clock_gettime(ClockId, Timespec)) *Enabled = nullptr) { #if defined CLOCK_THREAD_CPUTIME_ID #define CLOCKID CLOCK_THREAD_CPUTIME_ID #elif defined CLOCK_PROCESS_CPUTIME_ID #define CLOCKID CLOCK_PROCESS_CPUTIME_ID #elif defined CLOCK_MONOTONIC #define CLOCKID CLOCK_MONOTONIC #else #define CLOCKID CLOCK_REALTIME #endif struct timespec tspec; if (clock_gettime(CLOCKID, &tspec) == 0) { return tspec.tv_nsec * 1.0e-9 + tspec.tv_sec; } // Return some negative value to represent failure. return -1.0; } } // anonymous namespace namespace Fortran::runtime { extern "C" { double RTNAME(CpuTime)() { return GetCpuTime(0); } } // extern "C" } // namespace Fortran::runtime