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