]>
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" |
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 |
31 | int 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 | ||
55 | namespace 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 | } |