brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.4 KiB · 667e7b2 Raw
277 lines · plain
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 at6//7//     http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// 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 and13// limitations under the License.14 15#include "timers.h"16 17#include "internal_macros.h"18 19#ifdef BENCHMARK_OS_WINDOWS20#include <shlwapi.h>21#undef StrCat  // Don't let StrCat in string_util.h be renamed to lstrcatA22#include <versionhelpers.h>23#include <windows.h>24#else25#include <fcntl.h>26#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT)27#include <sys/resource.h>28#endif29#include <sys/time.h>30#include <sys/types.h>  // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD31#include <unistd.h>32#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_DRAGONFLY || \33    defined BENCHMARK_OS_MACOSX34#include <sys/sysctl.h>35#endif36#if defined(BENCHMARK_OS_MACOSX)37#include <mach/mach_init.h>38#include <mach/mach_port.h>39#include <mach/thread_act.h>40#endif41#if defined(BENCHMARK_OS_QURT)42#include <qurt.h>43#endif44#endif45 46#ifdef BENCHMARK_OS_EMSCRIPTEN47#include <emscripten.h>48#endif49 50#include <cerrno>51#include <cstdint>52#include <cstdio>53#include <cstdlib>54#include <cstring>55#include <ctime>56#include <iostream>57#include <limits>58#include <mutex>59 60#include "check.h"61#include "log.h"62#include "string_util.h"63 64namespace benchmark {65 66// Suppress unused warnings on helper functions.67#if defined(__GNUC__)68#pragma GCC diagnostic ignored "-Wunused-function"69#endif70#if defined(__NVCOMPILER)71#pragma diag_suppress declared_but_not_referenced72#endif73 74namespace {75#if defined(BENCHMARK_OS_WINDOWS)76double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) {77  ULARGE_INTEGER kernel;78  ULARGE_INTEGER user;79  kernel.HighPart = kernel_time.dwHighDateTime;80  kernel.LowPart = kernel_time.dwLowDateTime;81  user.HighPart = user_time.dwHighDateTime;82  user.LowPart = user_time.dwLowDateTime;83  return (static_cast<double>(kernel.QuadPart) +84          static_cast<double>(user.QuadPart)) *85         1e-7;86}87#elif !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT)88double MakeTime(struct rusage const& ru) {89  return (static_cast<double>(ru.ru_utime.tv_sec) +90          static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 +91          static_cast<double>(ru.ru_stime.tv_sec) +92          static_cast<double>(ru.ru_stime.tv_usec) * 1e-6);93}94#endif95#if defined(BENCHMARK_OS_MACOSX)96double MakeTime(thread_basic_info_data_t const& info) {97  return (static_cast<double>(info.user_time.seconds) +98          static_cast<double>(info.user_time.microseconds) * 1e-6 +99          static_cast<double>(info.system_time.seconds) +100          static_cast<double>(info.system_time.microseconds) * 1e-6);101}102#endif103#if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID)104double MakeTime(struct timespec const& ts) {105  return static_cast<double>(ts.tv_sec) +106         (static_cast<double>(ts.tv_nsec) * 1e-9);107}108#endif109 110BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) {111  std::cerr << "ERROR: " << msg << std::endl;112  std::exit(EXIT_FAILURE);113}114 115}  // end namespace116 117double ProcessCPUUsage() {118#if defined(BENCHMARK_OS_WINDOWS)119  HANDLE proc = GetCurrentProcess();120  FILETIME creation_time;121  FILETIME exit_time;122  FILETIME kernel_time;123  FILETIME user_time;124  if (GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time,125                      &user_time))126    return MakeTime(kernel_time, user_time);127  DiagnoseAndExit("GetProccessTimes() failed");128#elif defined(BENCHMARK_OS_QURT)129  return static_cast<double>(130             qurt_timer_timetick_to_us(qurt_timer_get_ticks())) *131         1.0e-6;132#elif defined(BENCHMARK_OS_EMSCRIPTEN)133  // clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten.134  // Use Emscripten-specific API. Reported CPU time would be exactly the135  // same as total time, but this is ok because there aren't long-latency136  // synchronous system calls in Emscripten.137  return emscripten_get_now() * 1e-3;138#elif defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX)139  // FIXME We want to use clock_gettime, but its not available in MacOS 10.11.140  // See https://github.com/google/benchmark/pull/292141  struct timespec spec;142  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0)143    return MakeTime(spec);144  DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed");145#else146  struct rusage ru;147  if (getrusage(RUSAGE_SELF, &ru) == 0) return MakeTime(ru);148  DiagnoseAndExit("getrusage(RUSAGE_SELF, ...) failed");149#endif150}151 152double ThreadCPUUsage() {153#if defined(BENCHMARK_OS_WINDOWS)154  HANDLE this_thread = GetCurrentThread();155  FILETIME creation_time;156  FILETIME exit_time;157  FILETIME kernel_time;158  FILETIME user_time;159  GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time,160                 &user_time);161  return MakeTime(kernel_time, user_time);162#elif defined(BENCHMARK_OS_QURT)163  return static_cast<double>(164             qurt_timer_timetick_to_us(qurt_timer_get_ticks())) *165         1.0e-6;166#elif defined(BENCHMARK_OS_MACOSX)167  // FIXME We want to use clock_gettime, but its not available in MacOS 10.11.168  // See https://github.com/google/benchmark/pull/292169  mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;170  thread_basic_info_data_t info;171  mach_port_t thread = pthread_mach_thread_np(pthread_self());172  if (thread_info(thread, THREAD_BASIC_INFO,173                  reinterpret_cast<thread_info_t>(&info),174                  &count) == KERN_SUCCESS) {175    return MakeTime(info);176  }177  DiagnoseAndExit("ThreadCPUUsage() failed when evaluating thread_info");178#elif defined(BENCHMARK_OS_EMSCRIPTEN)179  // Emscripten doesn't support traditional threads180  return ProcessCPUUsage();181#elif defined(BENCHMARK_OS_RTEMS)182  // RTEMS doesn't support CLOCK_THREAD_CPUTIME_ID. See183  // https://github.com/RTEMS/rtems/blob/master/cpukit/posix/src/clockgettime.c184  return ProcessCPUUsage();185#elif defined(BENCHMARK_OS_ZOS)186  // z/OS doesn't support CLOCK_THREAD_CPUTIME_ID.187  return ProcessCPUUsage();188#elif defined(BENCHMARK_OS_SOLARIS)189  struct rusage ru;190  if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru);191  DiagnoseAndExit("getrusage(RUSAGE_LWP, ...) failed");192#elif defined(CLOCK_THREAD_CPUTIME_ID)193  struct timespec ts;194  if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts);195  DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed");196#else197#error Per-thread timing is not available on your system.198#endif199}200 201std::string LocalDateTimeString() {202  // Write the local time in RFC3339 format yyyy-mm-ddTHH:MM:SS+/-HH:MM.203  typedef std::chrono::system_clock Clock;204  std::time_t now = Clock::to_time_t(Clock::now());205  const std::size_t kTzOffsetLen = 6;206  const std::size_t kTimestampLen = 19;207 208  std::size_t tz_len;209  std::size_t timestamp_len;210  long int offset_minutes;211  char tz_offset_sign = '+';212  // tz_offset is set in one of three ways:213  // * strftime with %z - This either returns empty or the ISO 8601 time.  The214  // maximum length an215  //   ISO 8601 string can be is 7 (e.g. -03:30, plus trailing zero).216  // * snprintf with %c%02li:%02li - The maximum length is 41 (one for %c, up to217  // 19 for %02li,218  //   one for :, up to 19 %02li, plus trailing zero).219  // * A fixed string of "-00:00".  The maximum length is 7 (-00:00, plus220  // trailing zero).221  //222  // Thus, the maximum size this needs to be is 41.223  char tz_offset[41];224  // Long enough buffer to avoid format-overflow warnings225  char storage[128];226 227#if defined(BENCHMARK_OS_WINDOWS)228  std::tm* timeinfo_p = ::localtime(&now);229#else230  std::tm timeinfo;231  std::tm* timeinfo_p = &timeinfo;232  ::localtime_r(&now, &timeinfo);233#endif234 235  tz_len = std::strftime(tz_offset, sizeof(tz_offset), "%z", timeinfo_p);236 237  if (tz_len < kTzOffsetLen && tz_len > 1) {238    // Timezone offset was written. strftime writes offset as +HHMM or -HHMM,239    // RFC3339 specifies an offset as +HH:MM or -HH:MM. To convert, we parse240    // the offset as an integer, then reprint it to a string.241 242    offset_minutes = ::strtol(tz_offset, NULL, 10);243    if (offset_minutes < 0) {244      offset_minutes *= -1;245      tz_offset_sign = '-';246    }247 248    tz_len =249        ::snprintf(tz_offset, sizeof(tz_offset), "%c%02li:%02li",250                   tz_offset_sign, offset_minutes / 100, offset_minutes % 100);251    BM_CHECK(tz_len == kTzOffsetLen);252    ((void)tz_len);  // Prevent unused variable warning in optimized build.253  } else {254    // Unknown offset. RFC3339 specifies that unknown local offsets should be255    // written as UTC time with -00:00 timezone.256#if defined(BENCHMARK_OS_WINDOWS)257    // Potential race condition if another thread calls localtime or gmtime.258    timeinfo_p = ::gmtime(&now);259#else260    ::gmtime_r(&now, &timeinfo);261#endif262 263    strncpy(tz_offset, "-00:00", kTzOffsetLen + 1);264  }265 266  timestamp_len =267      std::strftime(storage, sizeof(storage), "%Y-%m-%dT%H:%M:%S", timeinfo_p);268  BM_CHECK(timestamp_len == kTimestampLen);269  // Prevent unused variable warning in optimized build.270  ((void)kTimestampLen);271 272  std::strncat(storage, tz_offset, sizeof(storage) - timestamp_len - 1);273  return std::string(storage);274}275 276}  // end namespace benchmark277