benchmark/src/timers.cc
Go to the documentation of this file.
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 #undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
21 #include <versionhelpers.h>
22 #include <windows.h>
23 #else
24 #include <fcntl.h>
25 #ifndef BENCHMARK_OS_FUCHSIA
26 #include <sys/resource.h>
27 #endif
28 #include <sys/time.h>
29 #include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
30 #include <unistd.h>
31 #if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_DRAGONFLY || \
32  defined BENCHMARK_OS_MACOSX
33 #include <sys/sysctl.h>
34 #endif
35 #if defined(BENCHMARK_OS_MACOSX)
36 #include <mach/mach_init.h>
37 #include <mach/mach_port.h>
38 #include <mach/thread_act.h>
39 #endif
40 #endif
41 
42 #ifdef BENCHMARK_OS_EMSCRIPTEN
43 #include <emscripten.h>
44 #endif
45 
46 #include <cerrno>
47 #include <cstdint>
48 #include <cstdio>
49 #include <cstdlib>
50 #include <cstring>
51 #include <ctime>
52 #include <iostream>
53 #include <limits>
54 #include <mutex>
55 
56 #include "check.h"
57 #include "log.h"
58 #include "sleep.h"
59 #include "string_util.h"
60 
61 namespace benchmark {
62 
63 // Suppress unused warnings on helper functions.
64 #if defined(__GNUC__)
65 #pragma GCC diagnostic ignored "-Wunused-function"
66 #endif
67 
68 namespace {
69 #if defined(BENCHMARK_OS_WINDOWS)
70 double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) {
71  ULARGE_INTEGER kernel;
72  ULARGE_INTEGER user;
73  kernel.HighPart = kernel_time.dwHighDateTime;
74  kernel.LowPart = kernel_time.dwLowDateTime;
75  user.HighPart = user_time.dwHighDateTime;
76  user.LowPart = user_time.dwLowDateTime;
77  return (static_cast<double>(kernel.QuadPart) +
78  static_cast<double>(user.QuadPart)) *
79  1e-7;
80 }
81 #elif !defined(BENCHMARK_OS_FUCHSIA)
82 double MakeTime(struct rusage const& ru) {
83  return (static_cast<double>(ru.ru_utime.tv_sec) +
84  static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 +
85  static_cast<double>(ru.ru_stime.tv_sec) +
86  static_cast<double>(ru.ru_stime.tv_usec) * 1e-6);
87 }
88 #endif
89 #if defined(BENCHMARK_OS_MACOSX)
90 double MakeTime(thread_basic_info_data_t const& info) {
91  return (static_cast<double>(info.user_time.seconds) +
92  static_cast<double>(info.user_time.microseconds) * 1e-6 +
93  static_cast<double>(info.system_time.seconds) +
94  static_cast<double>(info.system_time.microseconds) * 1e-6);
95 }
96 #endif
97 #if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID)
98 double MakeTime(struct timespec const& ts) {
99  return ts.tv_sec + (static_cast<double>(ts.tv_nsec) * 1e-9);
100 }
101 #endif
102 
103 BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) {
104  std::cerr << "ERROR: " << msg << std::endl;
105  std::exit(EXIT_FAILURE);
106 }
107 
108 } // end namespace
109 
110 double ProcessCPUUsage() {
111 #if defined(BENCHMARK_OS_WINDOWS)
112  HANDLE proc = GetCurrentProcess();
113  FILETIME creation_time;
114  FILETIME exit_time;
115  FILETIME kernel_time;
116  FILETIME user_time;
117  if (GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time,
118  &user_time))
119  return MakeTime(kernel_time, user_time);
120  DiagnoseAndExit("GetProccessTimes() failed");
121 #elif defined(BENCHMARK_OS_EMSCRIPTEN)
122  // clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten.
123  // Use Emscripten-specific API. Reported CPU time would be exactly the
124  // same as total time, but this is ok because there aren't long-latency
125  // syncronous system calls in Emscripten.
126  return emscripten_get_now() * 1e-3;
127 #elif defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX)
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  struct timespec spec;
131  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0)
132  return MakeTime(spec);
133  DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed");
134 #else
135  struct rusage ru;
136  if (getrusage(RUSAGE_SELF, &ru) == 0) return MakeTime(ru);
137  DiagnoseAndExit("getrusage(RUSAGE_SELF, ...) failed");
138 #endif
139 }
140 
141 double ThreadCPUUsage() {
142 #if defined(BENCHMARK_OS_WINDOWS)
143  HANDLE this_thread = GetCurrentThread();
144  FILETIME creation_time;
145  FILETIME exit_time;
146  FILETIME kernel_time;
147  FILETIME user_time;
148  GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time,
149  &user_time);
150  return MakeTime(kernel_time, user_time);
151 #elif defined(BENCHMARK_OS_MACOSX)
152  // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See
153  // https://github.com/google/benchmark/pull/292
154  mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
155  thread_basic_info_data_t info;
156  mach_port_t thread = pthread_mach_thread_np(pthread_self());
157  if (thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count) ==
158  KERN_SUCCESS) {
159  return MakeTime(info);
160  }
161  DiagnoseAndExit("ThreadCPUUsage() failed when evaluating thread_info");
162 #elif defined(BENCHMARK_OS_EMSCRIPTEN)
163  // Emscripten doesn't support traditional threads
164  return ProcessCPUUsage();
165 #elif defined(BENCHMARK_OS_RTEMS)
166  // RTEMS doesn't support CLOCK_THREAD_CPUTIME_ID. See
167  // https://github.com/RTEMS/rtems/blob/master/cpukit/posix/src/clockgettime.c
168  return ProcessCPUUsage();
169 #elif defined(BENCHMARK_OS_SOLARIS)
170  struct rusage ru;
171  if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru);
172  DiagnoseAndExit("getrusage(RUSAGE_LWP, ...) failed");
173 #elif defined(CLOCK_THREAD_CPUTIME_ID)
174  struct timespec ts;
175  if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts);
176  DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed");
177 #else
178 #error Per-thread timing is not available on your system.
179 #endif
180 }
181 
183  // Write the local time in RFC3339 format yyyy-mm-ddTHH:MM:SS+/-HH:MM.
184  typedef std::chrono::system_clock Clock;
185  std::time_t now = Clock::to_time_t(Clock::now());
186  const std::size_t kTzOffsetLen = 6;
187  const std::size_t kTimestampLen = 19;
188 
189  std::size_t tz_len;
190  std::size_t timestamp_len;
191  long int offset_minutes;
192  char tz_offset_sign = '+';
193  // tz_offset is set in one of three ways:
194  // * strftime with %z - This either returns empty or the ISO 8601 time. The maximum length an
195  // ISO 8601 string can be is 7 (e.g. -03:30, plus trailing zero).
196  // * snprintf with %c%02li:%02li - The maximum length is 41 (one for %c, up to 19 for %02li,
197  // one for :, up to 19 %02li, plus trailing zero).
198  // * A fixed string of "-00:00". The maximum length is 7 (-00:00, plus trailing zero).
199  //
200  // Thus, the maximum size this needs to be is 41.
201  char tz_offset[41];
202  // Long enough buffer to avoid format-overflow warnings
203  char storage[128];
204 
205 #if defined(BENCHMARK_OS_WINDOWS)
206  std::tm *timeinfo_p = ::localtime(&now);
207 #else
208  std::tm timeinfo;
209  std::tm *timeinfo_p = &timeinfo;
210  ::localtime_r(&now, &timeinfo);
211 #endif
212 
213  tz_len = std::strftime(tz_offset, sizeof(tz_offset), "%z", timeinfo_p);
214 
215  if (tz_len < kTzOffsetLen && tz_len > 1) {
216  // Timezone offset was written. strftime writes offset as +HHMM or -HHMM,
217  // RFC3339 specifies an offset as +HH:MM or -HH:MM. To convert, we parse
218  // the offset as an integer, then reprint it to a string.
219 
220  offset_minutes = ::strtol(tz_offset, NULL, 10);
221  if (offset_minutes < 0) {
222  offset_minutes *= -1;
223  tz_offset_sign = '-';
224  }
225 
226  tz_len = ::snprintf(tz_offset, sizeof(tz_offset), "%c%02li:%02li",
227  tz_offset_sign, offset_minutes / 100, offset_minutes % 100);
228  BM_CHECK(tz_len == kTzOffsetLen);
229  ((void)tz_len); // Prevent unused variable warning in optimized build.
230  } else {
231  // Unknown offset. RFC3339 specifies that unknown local offsets should be
232  // written as UTC time with -00:00 timezone.
233 #if defined(BENCHMARK_OS_WINDOWS)
234  // Potential race condition if another thread calls localtime or gmtime.
235  timeinfo_p = ::gmtime(&now);
236 #else
237  ::gmtime_r(&now, &timeinfo);
238 #endif
239 
240  strncpy(tz_offset, "-00:00", kTzOffsetLen + 1);
241  }
242 
243  timestamp_len = std::strftime(storage, sizeof(storage), "%Y-%m-%dT%H:%M:%S",
244  timeinfo_p);
245  BM_CHECK(timestamp_len == kTimestampLen);
246  // Prevent unused variable warning in optimized build.
247  ((void)kTimestampLen);
248 
249  std::strncat(storage, tz_offset, sizeof(storage) - timestamp_len - 1);
250  return std::string(storage);
251 }
252 
253 } // end namespace benchmark
log.h
benchmark::ProcessCPUUsage
double ProcessCPUUsage()
Definition: benchmark/src/timers.cc:110
now
static double now(void)
Definition: test/core/fling/client.cc:130
check.h
benchmark
Definition: bm_alarm.cc:55
BM_CHECK
#define BM_CHECK(b)
Definition: benchmark/src/check.h:58
timers.h
BENCHMARK_NORETURN
#define BENCHMARK_NORETURN
Definition: benchmark/src/internal_macros.h:40
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
run_interop_tests.spec
def spec
Definition: run_interop_tests.py:1394
absl::FormatConversionChar::e
@ e
benchmark::ThreadCPUUsage
double ThreadCPUUsage()
Definition: benchmark/src/timers.cc:141
sleep.h
msg
std::string msg
Definition: client_interceptors_end2end_test.cc:372
tm
static uv_timer_t tm
Definition: test-tcp-open.c:41
internal_macros.h
string_util.h
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
absl::status_internal::storage
static ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook< StatusPayloadPrinter > storage
Definition: abseil-cpp/absl/status/status_payload_printer.cc:26
benchmark::LocalDateTimeString
std::string LocalDateTimeString()
Definition: benchmark/src/timers.cc:182
thread
static uv_thread_t thread
Definition: test-async-null-cb.c:29


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:38