YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/gutil/walltime.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2012 Google Inc. All Rights Reserved.
2
//
3
// The following only applies to changes made to this file as part of YugaByte development.
4
//
5
// Portions Copyright (c) YugaByte, Inc.
6
//
7
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8
// in compliance with the License.  You may obtain a copy of the License at
9
//
10
// http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software distributed under the License
13
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14
// or implied.  See the License for the specific language governing permissions and limitations
15
// under the License.
16
//
17
// Licensed to the Apache Software Foundation (ASF) under one
18
// or more contributor license agreements.  See the NOTICE file
19
// distributed with this work for additional information
20
// regarding copyright ownership.  The ASF licenses this file
21
// to you under the Apache License, Version 2.0 (the
22
// "License"); you may not use this file except in compliance
23
// with the License.  You may obtain a copy of the License at
24
//
25
//   http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing,
28
// software distributed under the License is distributed on an
29
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
30
// KIND, either express or implied.  See the License for the
31
// specific language governing permissions and limitations
32
// under the License.
33
//
34
// Author: tkaftal@google.com (Tomasz Kaftal)
35
//
36
// The implementation of walltime functionalities.
37
#ifndef _GNU_SOURCE   // gcc3 at least defines it on the command line
38
#define _GNU_SOURCE   // Linux wants that for strptime in time.h
39
#endif
40
41
#include "yb/gutil/walltime.h"
42
43
#if defined(__APPLE__)
44
#include <mach/clock.h>
45
#include <mach/mach.h>
46
#endif  // defined(__APPLE__)
47
48
#include <memory>
49
50
#include <glog/logging.h>
51
52
#if defined(__APPLE__)
53
namespace walltime_internal {
54
55
GoogleOnceType timebase_info_once = GOOGLE_ONCE_INIT;
56
mach_timebase_info_data_t timebase_info;
57
58
17.0k
void InitializeTimebaseInfo() {
59
17.0k
  CHECK_EQ(KERN_SUCCESS, mach_timebase_info(&timebase_info))
60
0
      << "unable to initialize mach_timebase_info";
61
17.0k
}
62
} // namespace walltime_internal
63
#endif
64
65
// This is exactly like mktime() except it is guaranteed to return -1 on
66
// failure.  Some versions of glibc allow mktime() to return negative
67
// values which the standard says are undefined.  See the standard at
68
// http://www.opengroup.org/onlinepubs/007904875/basedefs/xbd_chap04.html
69
// under the heading "Seconds Since the Epoch".
70
0
static inline time_t gmktime(struct tm *tm) {
71
0
  time_t rt = mktime(tm);
72
0
  return rt < 0 ? time_t(-1) : rt;
73
0
}
74
75
void StringAppendStrftime(std::string* dst,
76
                          const char* format,
77
62.5k
                          const struct tm* tm) {
78
62.5k
  char space[1024];
79
80
62.5k
  size_t result = strftime(space, sizeof(space), format, tm);
81
82
62.5k
  if (result > 0) {
83
    // It fit
84
62.5k
    dst->append(space, result);
85
62.5k
    return;
86
62.5k
  }
87
88
0
  size_t length = sizeof(space);
89
0
  for (int sanity = 0; sanity < 5; ++sanity) {
90
0
    length *= 2;
91
0
    std::unique_ptr<char[]> buf(new char[length]);
92
93
0
    result = strftime(buf.get(), length, format, tm);
94
0
    if (result > 0) {
95
      // It fit
96
0
      dst->append(buf.get(), result);
97
0
      return;
98
0
    }
99
0
  }
100
101
  // sanity failure
102
0
  return;
103
0
}
104
105
// Convert a "struct tm" interpreted as *GMT* into a time_t (technically
106
// a long since we can't include header files in header files bla bla bla).
107
// This is basically filling a hole in the standard library.
108
//
109
// There are several approaches to mkgmtime() implementation on the net,
110
// many of them wrong.  Simply reimplementing the logic seems to be the
111
// simplest and most efficient, though it does reimplement calendar logic.
112
// The calculation is mostly straightforward; leap years are the main issue.
113
//
114
// Like gmktime() this method returns -1 on failure. Negative results
115
// are considered undefined by the standard so these cases are
116
// considered failures and thus return -1.
117
0
time_t mkgmtime(const struct tm *tm) {
118
  // Month-to-day offset for non-leap-years.
119
0
  static const int month_day[12] =
120
0
    {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
121
122
  // Most of the calculation is easy; leap years are the main difficulty.
123
0
  int month = tm->tm_mon % 12;
124
0
  int year = tm->tm_year + tm->tm_mon / 12;
125
0
  if (month < 0) {   // Negative values % 12 are still negative.
126
0
    month += 12;
127
0
    --year;
128
0
  }
129
130
  // This is the number of Februaries since 1900.
131
0
  const int year_for_leap = (month > 1) ? year + 1 : year;
132
133
0
  time_t rt = tm->tm_sec                           // Seconds
134
0
       + 60 * (tm->tm_min                          // Minute = 60 seconds
135
0
       + 60 * (tm->tm_hour                         // Hour = 60 minutes
136
0
       + 24 * (month_day[month] + tm->tm_mday - 1  // Day = 24 hours
137
0
       + 365 * (year - 70)                         // Year = 365 days
138
0
       + (year_for_leap - 69) / 4                  // Every 4 years is leap...
139
0
       - (year_for_leap - 1) / 100                 // Except centuries...
140
0
       + (year_for_leap + 299) / 400)));           // Except 400s.
141
0
  return rt < 0 ? -1 : rt;
142
0
}
143
144
bool WallTime_Parse_Timezone(const char* time_spec,
145
                             const char* format,
146
                             const struct tm* default_time,
147
                             bool local,
148
0
                             WallTime* result) {
149
0
  struct tm split_time;
150
0
  if (default_time) {
151
0
     split_time = *default_time;
152
0
  } else {
153
0
     memset(&split_time, 0, sizeof(split_time));
154
0
  }
155
0
  const char* parsed = strptime(time_spec, format, &split_time);
156
0
  if (parsed == nullptr) return false;
157
158
  // If format ends with "%S", match fractional seconds
159
0
  double fraction = 0.0;
160
0
  char junk;
161
0
  if ((*parsed == '.') &&
162
0
     (strcmp(format + strlen(format) - 2, "%S") == 0) &&
163
0
     (sscanf(parsed, "%lf%c",  // NOLINT(runtime/printf)
164
0
             &fraction, &junk) == 1)) {
165
0
     parsed = format + strlen(format);   // Parsed it all!
166
0
  }
167
0
  if (*parsed != '\0') return false;
168
169
  // Convert into seconds since epoch.  Adjust so it is interpreted
170
  // w.r.t. the daylight-saving-state at the specified time.
171
0
  split_time.tm_isdst = -1;     // Ask gmktime() to find dst imfo
172
0
  time_t ptime;
173
0
  if (local) {
174
0
    ptime = gmktime(&split_time);
175
0
  } else {
176
0
    ptime = mkgmtime(&split_time);  // Returns time in GMT instead of local.
177
0
  }
178
179
0
  if (ptime == -1) return false;
180
181
0
  *result = ptime;
182
0
  *result += fraction;
183
0
  return true;
184
0
}
185
186
20
WallTime WallTime_Now() {
187
20
#if defined(__APPLE__)
188
20
  mach_timespec_t ts;
189
20
  walltime_internal::GetCurrentTime(&ts);
190
20
  return ts.tv_sec + ts.tv_nsec / static_cast<double>(1e9);
191
#else
192
  timespec ts;
193
  clock_gettime(CLOCK_REALTIME, &ts);
194
  return ts.tv_sec + ts.tv_nsec / static_cast<double>(1e9);
195
#endif  // defined(__APPLE__)
196
20
}
197
198
void StringAppendStrftime(std::string* dst,
199
                          const char* format,
200
                          time_t when,
201
61.3k
                          bool local) {
202
61.3k
  struct tm tm;
203
61.3k
  bool conversion_error;
204
61.3k
  if (local) {
205
43.5k
    conversion_error = (localtime_r(&when, &tm) == nullptr);
206
43.5k
  } else {
207
17.8k
    conversion_error = (gmtime_r(&when, &tm) == nullptr);
208
17.8k
  }
209
61.3k
  if (conversion_error) {
210
    // If we couldn't convert the time, don't append anything.
211
0
    return;
212
0
  }
213
61.3k
  StringAppendStrftime(dst, format, &tm);
214
61.3k
}
215
216
43.5k
std::string LocalTimeAsString() {
217
43.5k
  std::string ret;
218
43.5k
  StringAppendStrftime(&ret, "%Y-%m-%d %H:%M:%S %Z", time(nullptr), true);
219
43.5k
  return ret;
220
43.5k
}
221
222
74.1M
void GetThreadUserAndSysCpuTimeMicros(MicrosecondsInt64 *user, MicrosecondsInt64 *sys) {
223
74.1M
#if defined(__APPLE__)
224
  // See https://www.gnu.org/software/hurd/gnumach-doc/Thread-Information.html
225
  // and Chromium base/time/time_mac.cc.
226
74.1M
  task_t thread = mach_thread_self();
227
74.1M
  if (thread == MACH_PORT_NULL) {
228
0
    LOG(WARNING) << "Failed to get mach_thread_self()";
229
0
    return;
230
0
  }
231
232
74.1M
  mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
233
74.1M
  thread_basic_info_data_t thread_info_data;
234
235
74.1M
  kern_return_t result = thread_info(
236
74.1M
      thread,
237
74.1M
      THREAD_BASIC_INFO,
238
74.1M
      reinterpret_cast<thread_info_t>(&thread_info_data),
239
74.1M
      &thread_info_count);
240
241
74.1M
  if (result != KERN_SUCCESS) {
242
0
    LOG(WARNING) << "Failed to get thread_info()";
243
0
    return;
244
0
  }
245
246
74.1M
  
if (74.1M
user74.1M
) {
247
74.1M
    *user = thread_info_data.user_time.seconds * 1e6L + thread_info_data.user_time.microseconds;
248
74.1M
  }
249
74.1M
  if (sys) {
250
73.8M
    *sys = thread_info_data.system_time.seconds * 1e6L + thread_info_data.system_time.microseconds;
251
73.8M
  }
252
#else
253
  struct rusage usage;
254
  CHECK_EQ(0, getrusage(RUSAGE_THREAD, &usage));
255
  if (user) {
256
    *user = usage.ru_utime.tv_sec * 1e6L + usage.ru_utime.tv_usec;
257
  }
258
  if (sys) {
259
    *sys = usage.ru_stime.tv_sec * 1e6L + usage.ru_stime.tv_usec;
260
  }
261
#endif
262
74.1M
}