1 // Copyright 2015 Google Inc. All rights reserved. 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 "timers.h" 16 #include "internal_macros.h" 17 18 #ifdef BENCHMARK_OS_WINDOWS 19 #include <Shlwapi.h> 20 #include <VersionHelpers.h> 21 #include <Windows.h> 22 #else 23 #include <fcntl.h> 24 #include <sys/resource.h> 25 #include <sys/time.h> 26 #include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD 27 #include <unistd.h> 28 #if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX 29 #include <sys/sysctl.h> 30 #endif 31 #if defined(BENCHMARK_OS_MACOSX) 32 #include <mach/mach_init.h> 33 #include <mach/mach_port.h> 34 #include <mach/thread_act.h> 35 #endif 36 #endif 37 38 #include <cerrno> 39 #include <cstdint> 40 #include <cstdio> 41 #include <cstdlib> 42 #include <cstring> 43 #include <ctime> 44 #include <iostream> 45 #include <limits> 46 #include <mutex> 47 48 #include "check.h" 49 #include "log.h" 50 #include "sleep.h" 51 #include "string_util.h" 52 53 namespace benchmark { 54 55 // Suppress unused warnings on helper functions. 56 #if defined(__GNUC__) 57 #pragma GCC diagnostic ignored "-Wunused-function" 58 #endif 59 60 namespace { 61 #if defined(BENCHMARK_OS_WINDOWS) 62 double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) { 63 ULARGE_INTEGER kernel; 64 ULARGE_INTEGER user; 65 kernel.HighPart = kernel_time.dwHighDateTime; 66 kernel.LowPart = kernel_time.dwLowDateTime; 67 user.HighPart = user_time.dwHighDateTime; 68 user.LowPart = user_time.dwLowDateTime; 69 return (static_cast<double>(kernel.QuadPart) + 70 static_cast<double>(user.QuadPart)) * 71 1e-7; 72 } 73 #else 74 double MakeTime(struct rusage const& ru) { 75 return (static_cast<double>(ru.ru_utime.tv_sec) + 76 static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 + 77 static_cast<double>(ru.ru_stime.tv_sec) + 78 static_cast<double>(ru.ru_stime.tv_usec) * 1e-6); 79 } 80 #endif 81 #if defined(BENCHMARK_OS_MACOSX) 82 double MakeTime(thread_basic_info_data_t const& info) { 83 return (static_cast<double>(info.user_time.seconds) + 84 static_cast<double>(info.user_time.microseconds) * 1e-6 + 85 static_cast<double>(info.system_time.seconds) + 86 static_cast<double>(info.system_time.microseconds) * 1e-6); 87 } 88 #endif 89 #if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID) 90 double MakeTime(struct timespec const& ts) { 91 return ts.tv_sec + (static_cast<double>(ts.tv_nsec) * 1e-9); 92 } 93 #endif 94 95 BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) { 96 std::cerr << "ERROR: " << msg << std::endl; 97 std::exit(EXIT_FAILURE); 98 } 99 100 } // end namespace 101 102 double ProcessCPUUsage() { 103 // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See 104 // https://github.com/google/benchmark/pull/292 105 #if defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX) 106 struct timespec spec; 107 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0) 108 return MakeTime(spec); 109 DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed"); 110 #elif defined(BENCHMARK_OS_WINDOWS) 111 HANDLE proc = GetCurrentProcess(); 112 FILETIME creation_time; 113 FILETIME exit_time; 114 FILETIME kernel_time; 115 FILETIME user_time; 116 if (GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time, 117 &user_time)) 118 return MakeTime(kernel_time, user_time); 119 DiagnoseAndExit("GetProccessTimes() failed"); 120 #else 121 struct rusage ru; 122 if (getrusage(RUSAGE_SELF, &ru) == 0) return MakeTime(ru); 123 DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed"); 124 #endif 125 } 126 127 double ThreadCPUUsage() { 128 // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See 129 // https://github.com/google/benchmark/pull/292 130 #if defined(CLOCK_THREAD_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX) 131 struct timespec ts; 132 if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts); 133 DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed"); 134 #elif defined(BENCHMARK_OS_WINDOWS) 135 HANDLE this_thread = GetCurrentThread(); 136 FILETIME creation_time; 137 FILETIME exit_time; 138 FILETIME kernel_time; 139 FILETIME user_time; 140 GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time, 141 &user_time); 142 return MakeTime(kernel_time, user_time); 143 #elif defined(BENCHMARK_OS_MACOSX) 144 mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; 145 thread_basic_info_data_t info; 146 mach_port_t thread = pthread_mach_thread_np(pthread_self()); 147 if (thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count) == 148 KERN_SUCCESS) { 149 return MakeTime(info); 150 } 151 DiagnoseAndExit("ThreadCPUUsage() failed when evaluating thread_info"); 152 #else 153 #error Per-thread timing is not available on your system. 154 #endif 155 } 156 157 namespace { 158 159 std::string DateTimeString(bool local) { 160 typedef std::chrono::system_clock Clock; 161 std::time_t now = Clock::to_time_t(Clock::now()); 162 const std::size_t kStorageSize = 128; 163 char storage[kStorageSize]; 164 std::size_t written; 165 166 if (local) { 167 #if defined(BENCHMARK_OS_WINDOWS) 168 written = 169 std::strftime(storage, sizeof(storage), "%x %X", ::localtime(&now)); 170 #else 171 std::tm timeinfo; 172 std::memset(&timeinfo, 0, sizeof(std::tm)); 173 ::localtime_r(&now, &timeinfo); 174 written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo); 175 #endif 176 } else { 177 #if defined(BENCHMARK_OS_WINDOWS) 178 written = std::strftime(storage, sizeof(storage), "%x %X", ::gmtime(&now)); 179 #else 180 std::tm timeinfo; 181 std::memset(&timeinfo, 0, sizeof(std::tm)); 182 ::gmtime_r(&now, &timeinfo); 183 written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo); 184 #endif 185 } 186 CHECK(written < kStorageSize); 187 ((void)written); // prevent unused variable in optimized mode. 188 return std::string(storage); 189 } 190 191 } // end namespace 192 193 std::string LocalDateTimeString() { return DateTimeString(true); } 194 195 } // end namespace benchmark 196