1/* Wrappers for platform timing functions. 2 Copyright (C) 2003-2022 Free Software Foundation, Inc. 3 4This file is part of the GNU Fortran runtime library (libgfortran). 5 6Libgfortran is free software; you can redistribute it and/or 7modify it under the terms of the GNU General Public 8License as published by the Free Software Foundation; either 9version 3 of the License, or (at your option) any later version. 10 11Libgfortran is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16Under Section 7 of GPL version 3, you are granted additional 17permissions described in the GCC Runtime Library Exception, version 183.1, as published by the Free Software Foundation. 19 20You should have received a copy of the GNU General Public License and 21a copy of the GCC Runtime Library Exception along with this program; 22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23<http://www.gnu.org/licenses/>. */ 24 25#ifndef LIBGFORTRAN_TIME_H 26#define LIBGFORTRAN_TIME_H 27 28#ifdef HAVE_UNISTD_H 29#include <unistd.h> 30#endif 31 32#include <errno.h> 33 34/* The time related intrinsics (DTIME, ETIME, CPU_TIME) to "compare 35 different algorithms on the same computer or discover which parts 36 are the most expensive", need a way to get the CPU time with the 37 finest resolution possible. We can only be accurate up to 38 microseconds. 39 40 As usual with UNIX systems, unfortunately no single way is 41 available for all systems. */ 42 43#ifdef HAVE_SYS_TIME_H 44#include <sys/time.h> 45#endif 46 47#include <time.h> 48 49#ifdef HAVE_SYS_TYPES_H 50 #include <sys/types.h> 51#endif 52 53/* The most accurate way to get the CPU time is getrusage (). */ 54#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) 55# include <sys/resource.h> 56#endif /* HAVE_GETRUSAGE && HAVE_SYS_RESOURCE_H */ 57 58/* The most accurate way to get the CPU time is getrusage (). 59 If we have times(), that's good enough, too. */ 60#if !defined (HAVE_GETRUSAGE) || !defined (HAVE_SYS_RESOURCE_H) 61/* For times(), we _must_ know the number of clock ticks per second. */ 62# if defined (HAVE_TIMES) && (defined (HZ) || defined (_SC_CLK_TCK) || defined (CLK_TCK)) 63# ifdef HAVE_SYS_PARAM_H 64# include <sys/param.h> 65# endif 66# if defined (HAVE_SYS_TIMES_H) 67# include <sys/times.h> 68# endif 69# ifndef HZ 70# if defined _SC_CLK_TCK 71# define HZ sysconf(_SC_CLK_TCK) 72# else 73# define HZ CLK_TCK 74# endif 75# endif 76# endif /* HAVE_TIMES etc. */ 77#endif /* !HAVE_GETRUSAGE || !HAVE_SYS_RESOURCE_H */ 78 79 80/* If the re-entrant version of localtime is not available, provide a 81 fallback implementation. On some targets where the _r version is 82 not available, localtime uses thread-local storage so it's 83 threadsafe. */ 84 85#ifndef HAVE_LOCALTIME_R 86/* If _POSIX is defined localtime_r gets defined by mingw-w64 headers. */ 87#ifdef localtime_r 88#undef localtime_r 89#endif 90 91static inline struct tm * 92localtime_r (const time_t * timep, struct tm * result) 93{ 94 *result = *localtime (timep); 95 return result; 96} 97#endif 98 99 100/* Helper function for the actual implementation of the DTIME, ETIME and 101 CPU_TIME intrinsics. Returns 0 for success or -1 if no 102 CPU time could be computed. */ 103 104#if defined(__MINGW32__) 105 106#define WIN32_LEAN_AND_MEAN 107#include <windows.h> 108 109static inline int 110gf_cputime (long *user_sec, long *user_usec, long *system_sec, long *system_usec) 111{ 112 union { 113 FILETIME ft; 114 unsigned long long ulltime; 115 } kernel_time, user_time; 116 117 FILETIME unused1, unused2; 118 119 /* No support for Win9x. The high order bit of the DWORD 120 returned by GetVersion is 0 for NT and higher. */ 121 if (GetVersion () >= 0x80000000) 122 { 123 *user_sec = *system_sec = 0; 124 *user_usec = *system_usec = 0; 125 return -1; 126 } 127 128 /* The FILETIME structs filled in by GetProcessTimes represent 129 time in 100 nanosecond units. */ 130 GetProcessTimes (GetCurrentProcess (), &unused1, &unused2, 131 &kernel_time.ft, &user_time.ft); 132 133 *user_sec = user_time.ulltime / 10000000; 134 *user_usec = (user_time.ulltime % 10000000) / 10; 135 136 *system_sec = kernel_time.ulltime / 10000000; 137 *system_usec = (kernel_time.ulltime % 10000000) / 10; 138 return 0; 139} 140 141#else 142 143static inline int 144gf_cputime (long *user_sec, long *user_usec, long *system_sec, long *system_usec) 145{ 146#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) 147 struct rusage usage; 148 int err; 149 err = getrusage (RUSAGE_SELF, &usage); 150 151 *user_sec = usage.ru_utime.tv_sec; 152 *user_usec = usage.ru_utime.tv_usec; 153 *system_sec = usage.ru_stime.tv_sec; 154 *system_usec = usage.ru_stime.tv_usec; 155 return err; 156 157#elif defined HAVE_TIMES 158 struct tms buf; 159 clock_t err; 160 err = times (&buf); 161 long hz = HZ; 162 *user_sec = buf.tms_utime / hz; 163 *user_usec = (buf.tms_utime % hz) * (1000000. / hz); 164 *system_sec = buf.tms_stime / hz; 165 *system_usec = (buf.tms_stime % hz) * (1000000. / hz); 166 if ((err == (clock_t) -1) && errno != 0) 167 return -1; 168 return 0; 169 170#elif defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_PROCESS_CPUTIME_ID) \ 171 || defined(CLOCK_THREAD_CPUTIME_ID)) 172 /* Newer versions of VxWorks have CLOCK_THREAD_CPUTIME_ID giving 173 per-thread CPU time. CLOCK_PROCESS_CPUTIME_ID would be better 174 but is not available. */ 175#ifndef CLOCK_PROCESS_CPUTIME_ID 176#define CLOCK_PROCESS_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID 177#endif 178 struct timespec ts; 179 int err = clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &ts); 180 *user_sec = ts.tv_sec; 181 *user_usec = ts.tv_nsec / 1000; 182 *system_sec = *system_usec = 0; 183 return err; 184 185#else 186 clock_t c = clock (); 187 *user_sec = c / CLOCKS_PER_SEC; 188 *user_usec = (c % CLOCKS_PER_SEC) * (1000000. / CLOCKS_PER_SEC); 189 *system_sec = *system_usec = 0; 190 if (c == (clock_t) -1) 191 return -1; 192 return 0; 193 194#endif 195} 196 197#endif 198 199 200/* Realtime clock with microsecond resolution, falling back to other 201 functions if the target does not support gettimeofday(). 202 203 Arguments: 204 secs - OUTPUT, seconds 205 usecs - OUTPUT, microseconds 206 207 The OUTPUT arguments shall represent the number of seconds and 208 microseconds since the Epoch. 209 210 Return value: 0 for success, -1 for error. In case of error, errno 211 is set. 212*/ 213static inline int 214gf_gettime (time_t * secs, long * usecs) 215{ 216#ifdef HAVE_CLOCK_GETTIME 217 struct timespec ts; 218 int err = clock_gettime (CLOCK_REALTIME, &ts); 219 *secs = ts.tv_sec; 220 *usecs = ts.tv_nsec / 1000; 221 return err; 222#elif defined(HAVE_GETTIMEOFDAY) 223 struct timeval tv; 224 int err; 225 err = gettimeofday (&tv, NULL); 226 *secs = tv.tv_sec; 227 *usecs = tv.tv_usec; 228 return err; 229#else 230 time_t t = time (NULL); 231 *secs = t; 232 *usecs = 0; 233 if (t == ((time_t)-1)) 234 return -1; 235 return 0; 236#endif 237} 238 239 240#endif /* LIBGFORTRAN_TIME_H */ 241