]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/ceph_time.cc
update ceph source to reef 18.2.0
[ceph.git] / ceph / src / common / ceph_time.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15// For ceph_timespec
7c673cae 16#include "ceph_time.h"
f67539c2
TL
17
18#include <fmt/chrono.h>
19#include <fmt/ostream.h>
20
11fdf7f2 21#include "log/LogClock.h"
7c673cae 22#include "config.h"
11fdf7f2
TL
23#include "strtol.h"
24
25#if defined(__APPLE__)
26#include <mach/mach.h>
27#include <mach/mach_time.h>
28
11fdf7f2
TL
29
30#ifndef NSEC_PER_SEC
31#define NSEC_PER_SEC 1000000000ULL
32#endif
7c673cae 33
7c673cae
FG
34int clock_gettime(int clk_id, struct timespec *tp)
35{
11fdf7f2 36 if (clk_id == CLOCK_REALTIME) {
7c673cae
FG
37 // gettimeofday is much faster than clock_get_time
38 struct timeval now;
39 int ret = gettimeofday(&now, NULL);
40 if (ret)
41 return ret;
42 tp->tv_sec = now.tv_sec;
43 tp->tv_nsec = now.tv_usec * 1000L;
44 } else {
11fdf7f2
TL
45 uint64_t t = mach_absolute_time();
46 static mach_timebase_info_data_t timebase_info;
47 if (timebase_info.denom == 0) {
48 (void)mach_timebase_info(&timebase_info);
49 }
50 auto nanos = t * timebase_info.numer / timebase_info.denom;
51 tp->tv_sec = nanos / NSEC_PER_SEC;
52 tp->tv_nsec = nanos - (tp->tv_sec * NSEC_PER_SEC);
7c673cae
FG
53 }
54 return 0;
55}
56#endif
57
f67539c2
TL
58using namespace std::literals;
59
7c673cae 60namespace ceph {
f67539c2
TL
61using std::chrono::seconds;
62using std::chrono::nanoseconds;
63void real_clock::to_ceph_timespec(const time_point& t,
64 struct ceph_timespec& ts) {
65 ts.tv_sec = to_time_t(t);
66 ts.tv_nsec = (t.time_since_epoch() % 1s).count();
67}
68struct ceph_timespec real_clock::to_ceph_timespec(const time_point& t) {
69 struct ceph_timespec ts;
70 to_ceph_timespec(t, ts);
71 return ts;
72}
73real_clock::time_point real_clock::from_ceph_timespec(
74 const struct ceph_timespec& ts) {
75 return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
76}
7c673cae 77
f67539c2
TL
78void coarse_real_clock::to_ceph_timespec(const time_point& t,
79 struct ceph_timespec& ts) {
80 ts.tv_sec = to_time_t(t);
81 ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count();
82}
83struct ceph_timespec coarse_real_clock::to_ceph_timespec(
84 const time_point& t) {
85 struct ceph_timespec ts;
86 to_ceph_timespec(t, ts);
87 return ts;
88}
89coarse_real_clock::time_point coarse_real_clock::from_ceph_timespec(
90 const struct ceph_timespec& ts) {
91 return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
92}
11fdf7f2 93
7c673cae 94
f67539c2
TL
95using std::chrono::duration_cast;
96using std::chrono::seconds;
97using std::chrono::microseconds;
7c673cae 98
f67539c2
TL
99template<typename Clock,
100 typename std::enable_if<Clock::is_steady>::type*>
101std::ostream& operator<<(std::ostream& m,
102 const std::chrono::time_point<Clock>& t) {
103 return m << std::fixed << std::chrono::duration<double>(
104 t.time_since_epoch()).count()
105 << 's';
106}
7c673cae 107
f67539c2
TL
108template<typename Clock,
109 typename std::enable_if<!Clock::is_steady>::type*>
110std::ostream& operator<<(std::ostream& m,
111 const std::chrono::time_point<Clock>& t) {
112 m.setf(std::ios::right);
113 char oldfill = m.fill();
114 m.fill('0');
115 // localtime. this looks like an absolute time.
116 // conform to http://en.wikipedia.org/wiki/ISO_8601
117 struct tm bdt;
118 time_t tt = Clock::to_time_t(t);
119 localtime_r(&tt, &bdt);
120 char tz[32] = { 0 };
121 strftime(tz, sizeof(tz), "%z", &bdt);
122 m << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07'
123 << '-' << std::setw(2) << (bdt.tm_mon+1)
124 << '-' << std::setw(2) << bdt.tm_mday
125 << 'T'
126 << std::setw(2) << bdt.tm_hour
127 << ':' << std::setw(2) << bdt.tm_min
128 << ':' << std::setw(2) << bdt.tm_sec
129 << "." << std::setw(6) << duration_cast<microseconds>(
130 t.time_since_epoch() % seconds(1)).count()
131 << tz;
132 m.fill(oldfill);
133 m.unsetf(std::ios::right);
134 return m;
135}
7c673cae 136
f67539c2
TL
137template std::ostream&
138operator<< <mono_clock>(std::ostream& m, const mono_time& t);
139template std::ostream&
140operator<< <real_clock>(std::ostream& m, const real_time& t);
141template std::ostream&
142operator<< <coarse_mono_clock>(std::ostream& m, const coarse_mono_time& t);
143template std::ostream&
144operator<< <coarse_real_clock>(std::ostream& m, const coarse_real_time& t);
7c673cae 145
f67539c2
TL
146std::string timespan_str(timespan t)
147{
148 // FIXME: somebody pretty please make a version of this function
149 // that isn't as lame as this one!
150 uint64_t nsec = std::chrono::nanoseconds(t).count();
151 std::ostringstream ss;
20effc67
TL
152 if (nsec < 2'000'000'000) {
153 ss << ((float)nsec / 1'000'000'000) << "s";
f67539c2
TL
154 return ss.str();
155 }
20effc67 156 uint64_t sec = nsec / 1'000'000'000;
f67539c2
TL
157 if (sec < 120) {
158 ss << sec << "s";
159 return ss.str();
160 }
161 uint64_t min = sec / 60;
162 if (min < 120) {
163 ss << min << "m";
164 return ss.str();
165 }
166 uint64_t hr = min / 60;
167 if (hr < 48) {
168 ss << hr << "h";
169 return ss.str();
170 }
171 uint64_t day = hr / 24;
172 if (day < 14) {
173 ss << day << "d";
174 return ss.str();
175 }
176 uint64_t wk = day / 7;
177 if (wk < 12) {
178 ss << wk << "w";
179 return ss.str();
180 }
181 uint64_t mn = day / 30;
182 if (mn < 24) {
183 ss << mn << "M";
184 return ss.str();
185 }
186 uint64_t yr = day / 365;
187 ss << yr << "y";
188 return ss.str();
189}
11fdf7f2 190
f67539c2
TL
191std::string exact_timespan_str(timespan t)
192{
193 uint64_t nsec = std::chrono::nanoseconds(t).count();
20effc67
TL
194 uint64_t sec = nsec / 1'000'000'000;
195 nsec %= 1'000'000'000;
f67539c2
TL
196 uint64_t yr = sec / (60 * 60 * 24 * 365);
197 std::ostringstream ss;
198 if (yr) {
11fdf7f2 199 ss << yr << "y";
f67539c2
TL
200 sec -= yr * (60 * 60 * 24 * 365);
201 }
202 uint64_t mn = sec / (60 * 60 * 24 * 30);
203 if (mn >= 3) {
204 ss << mn << "mo";
205 sec -= mn * (60 * 60 * 24 * 30);
206 }
207 uint64_t wk = sec / (60 * 60 * 24 * 7);
208 if (wk >= 2) {
209 ss << wk << "w";
210 sec -= wk * (60 * 60 * 24 * 7);
211 }
212 uint64_t day = sec / (60 * 60 * 24);
213 if (day >= 2) {
214 ss << day << "d";
215 sec -= day * (60 * 60 * 24);
216 }
217 uint64_t hr = sec / (60 * 60);
218 if (hr >= 2) {
219 ss << hr << "h";
220 sec -= hr * (60 * 60);
11fdf7f2 221 }
f67539c2
TL
222 uint64_t min = sec / 60;
223 if (min >= 2) {
224 ss << min << "m";
225 sec -= min * 60;
226 }
f67539c2 227 if (sec || nsec) {
20effc67
TL
228 if (nsec) {
229 ss << (((float)nsec / 1'000'000'000) + sec) << "s";
230 } else {
231 ss << sec << "s";
232 }
f67539c2
TL
233 }
234 return ss.str();
235}
11fdf7f2 236
f67539c2
TL
237std::chrono::seconds parse_timespan(const std::string& s)
238{
239 static std::map<std::string,int> units = {
240 { "s", 1 },
241 { "sec", 1 },
242 { "second", 1 },
243 { "seconds", 1 },
244 { "m", 60 },
245 { "min", 60 },
246 { "minute", 60 },
247 { "minutes", 60 },
248 { "h", 60*60 },
249 { "hr", 60*60 },
250 { "hour", 60*60 },
251 { "hours", 60*60 },
252 { "d", 24*60*60 },
253 { "day", 24*60*60 },
254 { "days", 24*60*60 },
255 { "w", 7*24*60*60 },
256 { "wk", 7*24*60*60 },
257 { "week", 7*24*60*60 },
258 { "weeks", 7*24*60*60 },
259 { "mo", 30*24*60*60 },
260 { "month", 30*24*60*60 },
261 { "months", 30*24*60*60 },
262 { "y", 365*24*60*60 },
263 { "yr", 365*24*60*60 },
264 { "year", 365*24*60*60 },
265 { "years", 365*24*60*60 },
266 };
267
268 auto r = 0s;
269 auto pos = 0u;
270 while (pos < s.size()) {
271 // skip whitespace
272 while (std::isspace(s[pos])) {
273 ++pos;
11fdf7f2 274 }
f67539c2
TL
275 if (pos >= s.size()) {
276 break;
11fdf7f2 277 }
f67539c2
TL
278
279 // consume any digits
280 auto val_start = pos;
281 while (std::isdigit(s[pos])) {
282 ++pos;
11fdf7f2 283 }
f67539c2
TL
284 if (val_start == pos) {
285 throw std::invalid_argument("expected digit");
11fdf7f2 286 }
f67539c2
TL
287 auto n = s.substr(val_start, pos - val_start);
288 std::string err;
289 auto val = strict_strtoll(n.c_str(), 10, &err);
290 if (err.size()) {
291 throw std::invalid_argument(err);
11fdf7f2 292 }
f67539c2
TL
293
294 // skip whitespace
295 while (std::isspace(s[pos])) {
296 ++pos;
11fdf7f2 297 }
f67539c2
TL
298
299 // consume unit
300 auto unit_start = pos;
301 while (std::isalpha(s[pos])) {
302 ++pos;
11fdf7f2 303 }
f67539c2
TL
304 if (unit_start != pos) {
305 auto unit = s.substr(unit_start, pos - unit_start);
306 auto p = units.find(unit);
307 if (p == units.end()) {
308 throw std::invalid_argument("unrecogized unit '"s + unit + "'");
309 }
310 val *= p->second;
311 } else if (pos < s.size()) {
312 throw std::invalid_argument("unexpected trailing '"s + s.substr(pos) + "'");
11fdf7f2 313 }
f67539c2 314 r += std::chrono::seconds(val);
11fdf7f2 315 }
f67539c2
TL
316 return r;
317}
11fdf7f2 318
f67539c2 319}
11fdf7f2 320
f67539c2
TL
321namespace std {
322template<typename Rep, typename Period>
323ostream& operator<<(ostream& m, const chrono::duration<Rep, Period>& t) {
324 if constexpr (chrono::treat_as_floating_point_v<Rep> ||
325 Period::den > 1) {
326 using seconds_t = chrono::duration<float>;
327 ::fmt::print(m, "{:.9}", chrono::duration_cast<seconds_t>(t));
328 } else {
329 ::fmt::print(m, "{}", t);
330 }
331 return m;
332}
11fdf7f2 333
f67539c2
TL
334template ostream&
335operator<< <::ceph::timespan::rep,
336 ::ceph::timespan::period> (ostream&, const ::ceph::timespan&);
11fdf7f2 337
f67539c2
TL
338template ostream&
339operator<< <::ceph::signedspan::rep,
340 ::ceph::signedspan::period> (ostream&, const ::ceph::signedspan&);
11fdf7f2 341
f67539c2
TL
342template ostream&
343operator<< <chrono::seconds::rep,
344 chrono::seconds::period> (ostream&, const chrono::seconds&);
11fdf7f2 345
f67539c2
TL
346template ostream&
347operator<< <chrono::milliseconds::rep,
348 chrono::milliseconds::period> (ostream&, const chrono::milliseconds&);
349
350} // namespace std