]>
Commit | Line | Data |
---|---|---|
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 |
34 | int 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 |
58 | using namespace std::literals; |
59 | ||
7c673cae | 60 | namespace ceph { |
f67539c2 TL |
61 | using std::chrono::seconds; |
62 | using std::chrono::nanoseconds; | |
63 | void 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 | } | |
68 | struct 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 | } | |
73 | real_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 |
78 | void 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 | } | |
83 | struct 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 | } | |
89 | coarse_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 |
95 | using std::chrono::duration_cast; |
96 | using std::chrono::seconds; | |
97 | using std::chrono::microseconds; | |
7c673cae | 98 | |
f67539c2 TL |
99 | template<typename Clock, |
100 | typename std::enable_if<Clock::is_steady>::type*> | |
101 | std::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 |
108 | template<typename Clock, |
109 | typename std::enable_if<!Clock::is_steady>::type*> | |
110 | std::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 |
137 | template std::ostream& |
138 | operator<< <mono_clock>(std::ostream& m, const mono_time& t); | |
139 | template std::ostream& | |
140 | operator<< <real_clock>(std::ostream& m, const real_time& t); | |
141 | template std::ostream& | |
142 | operator<< <coarse_mono_clock>(std::ostream& m, const coarse_mono_time& t); | |
143 | template std::ostream& | |
144 | operator<< <coarse_real_clock>(std::ostream& m, const coarse_real_time& t); | |
7c673cae | 145 | |
f67539c2 TL |
146 | std::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 |
191 | std::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 |
237 | std::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 |
321 | namespace std { |
322 | template<typename Rep, typename Period> | |
323 | ostream& 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 |
334 | template ostream& |
335 | operator<< <::ceph::timespan::rep, | |
336 | ::ceph::timespan::period> (ostream&, const ::ceph::timespan&); | |
11fdf7f2 | 337 | |
f67539c2 TL |
338 | template ostream& |
339 | operator<< <::ceph::signedspan::rep, | |
340 | ::ceph::signedspan::period> (ostream&, const ::ceph::signedspan&); | |
11fdf7f2 | 341 | |
f67539c2 TL |
342 | template ostream& |
343 | operator<< <chrono::seconds::rep, | |
344 | chrono::seconds::period> (ostream&, const chrono::seconds&); | |
11fdf7f2 | 345 | |
f67539c2 TL |
346 | template ostream& |
347 | operator<< <chrono::milliseconds::rep, | |
348 | chrono::milliseconds::period> (ostream&, const chrono::milliseconds&); | |
349 | ||
350 | } // namespace std |