1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
16 #include "ceph_time.h"
17 #include "log/LogClock.h"
21 #if defined(__APPLE__)
22 #include <mach/mach.h>
23 #include <mach/mach_time.h>
25 #include <ostringstream>
28 #define NSEC_PER_SEC 1000000000ULL
31 int clock_gettime(int clk_id
, struct timespec
*tp
)
33 if (clk_id
== CLOCK_REALTIME
) {
34 // gettimeofday is much faster than clock_get_time
36 int ret
= gettimeofday(&now
, NULL
);
39 tp
->tv_sec
= now
.tv_sec
;
40 tp
->tv_nsec
= now
.tv_usec
* 1000L;
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
);
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
);
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();
62 struct ceph_timespec
real_clock::to_ceph_timespec(const time_point
& t
) {
63 struct ceph_timespec ts
;
64 to_ceph_timespec(t
, ts
);
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
));
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();
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
);
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
));
90 using std::chrono::duration_cast
;
91 using std::chrono::seconds
;
92 using std::chrono::microseconds
;
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
) {
98 return m
<< std::fixed
<< std::chrono::duration
<double>(
99 t
.time_since_epoch()).count()
103 std::ostream
& operator<<(std::ostream
& m
, const timespan
& t
) {
104 static_assert(std::is_unsigned_v
<timespan::rep
>);
105 m
<< std::chrono::duration_cast
<std::chrono::seconds
>(t
).count();
106 if (auto ns
= (t
% 1s
).count(); ns
> 0) {
107 char oldfill
= m
.fill();
109 m
<< '.' << std::setw(9) << ns
;
115 template<typename Clock
,
116 typename
std::enable_if
<!Clock::is_steady
>::type
*>
117 std::ostream
& operator<<(std::ostream
& m
,
118 const std::chrono::time_point
<Clock
>& t
) {
119 m
.setf(std::ios::right
);
120 char oldfill
= m
.fill();
122 // localtime. this looks like an absolute time.
123 // conform to http://en.wikipedia.org/wiki/ISO_8601
125 time_t tt
= Clock::to_time_t(t
);
126 localtime_r(&tt
, &bdt
);
128 strftime(tz
, sizeof(tz
), "%z", &bdt
);
129 m
<< std::setw(4) << (bdt
.tm_year
+1900) // 2007 -> '07'
130 << '-' << std::setw(2) << (bdt
.tm_mon
+1)
131 << '-' << std::setw(2) << bdt
.tm_mday
133 << std::setw(2) << bdt
.tm_hour
134 << ':' << std::setw(2) << bdt
.tm_min
135 << ':' << std::setw(2) << bdt
.tm_sec
136 << "." << std::setw(6) << duration_cast
<microseconds
>(
137 t
.time_since_epoch() % seconds(1)).count()
140 m
.unsetf(std::ios::right
);
144 template std::ostream
&
145 operator<< <mono_clock
>(std::ostream
& m
, const mono_time
& t
);
146 template std::ostream
&
147 operator<< <real_clock
>(std::ostream
& m
, const real_time
& t
);
148 template std::ostream
&
149 operator<< <coarse_mono_clock
>(std::ostream
& m
, const coarse_mono_time
& t
);
150 template std::ostream
&
151 operator<< <coarse_real_clock
>(std::ostream
& m
, const coarse_real_time
& t
);
153 std::string
timespan_str(timespan t
)
155 // FIXME: somebody pretty please make a version of this function
156 // that isn't as lame as this one!
157 uint64_t nsec
= std::chrono::nanoseconds(t
).count();
159 if (nsec
< 2000000000) {
160 ss
<< ((float)nsec
/ 1000000000) << "s";
163 uint64_t sec
= nsec
/ 1000000000;
168 uint64_t min
= sec
/ 60;
173 uint64_t hr
= min
/ 60;
178 uint64_t day
= hr
/ 24;
183 uint64_t wk
= day
/ 7;
188 uint64_t mn
= day
/ 30;
193 uint64_t yr
= day
/ 365;
198 std::string
exact_timespan_str(timespan t
)
200 uint64_t nsec
= std::chrono::nanoseconds(t
).count();
201 uint64_t sec
= nsec
/ 1000000000;
203 uint64_t yr
= sec
/ (60 * 60 * 24 * 365);
207 sec
-= yr
* (60 * 60 * 24 * 365);
209 uint64_t mn
= sec
/ (60 * 60 * 24 * 30);
212 sec
-= mn
* (60 * 60 * 24 * 30);
214 uint64_t wk
= sec
/ (60 * 60 * 24 * 7);
217 sec
-= wk
* (60 * 60 * 24 * 7);
219 uint64_t day
= sec
/ (60 * 60 * 24);
222 sec
-= day
* (60 * 60 * 24);
224 uint64_t hr
= sec
/ (60 * 60);
227 sec
-= hr
* (60 * 60);
229 uint64_t min
= sec
/ 60;
238 ss
<< ((float)nsec
/ 1000000000);
246 std::chrono::seconds
parse_timespan(const std::string
& s
)
248 static std::map
<string
,int> units
= {
263 { "days", 24*60*60 },
265 { "wk", 7*24*60*60 },
266 { "week", 7*24*60*60 },
267 { "weeks", 7*24*60*60 },
268 { "mo", 30*24*60*60 },
269 { "month", 30*24*60*60 },
270 { "months", 30*24*60*60 },
271 { "y", 365*24*60*60 },
272 { "yr", 365*24*60*60 },
273 { "year", 365*24*60*60 },
274 { "years", 365*24*60*60 },
279 while (pos
< s
.size()) {
281 while (std::isspace(s
[pos
])) {
284 if (pos
>= s
.size()) {
288 // consume any digits
289 auto val_start
= pos
;
290 while (std::isdigit(s
[pos
])) {
293 if (val_start
== pos
) {
294 throw invalid_argument("expected digit");
296 string n
= s
.substr(val_start
, pos
- val_start
);
298 auto val
= strict_strtoll(n
.c_str(), 10, &err
);
300 throw invalid_argument(err
);
304 while (std::isspace(s
[pos
])) {
309 auto unit_start
= pos
;
310 while (std::isalpha(s
[pos
])) {
313 if (unit_start
!= pos
) {
314 string unit
= s
.substr(unit_start
, pos
- unit_start
);
315 auto p
= units
.find(unit
);
316 if (p
== units
.end()) {
317 throw invalid_argument("unrecogized unit '"s
+ unit
+ "'");
320 } else if (pos
< s
.size()) {
321 throw invalid_argument("unexpected trailing '"s
+ s
.substr(pos
) + "'");
323 r
+= chrono::seconds(val
);