1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 // Implement TimeStamp::Now() with POSIX clocks.
10 // The "tick" unit for POSIX clocks is simply a nanosecond, as this is
11 // the smallest unit of time representable by struct timespec. That
12 // doesn't mean that a nanosecond is the resolution of TimeDurations
13 // obtained with this API; see TimeDuration::Resolution;
16 #include <sys/syscall.h>
20 #if defined(__DragonFly__) || defined(__FreeBSD__) \
21 || defined(__NetBSD__) || defined(__OpenBSD__)
22 #include <sys/param.h>
23 #include <sys/sysctl.h>
26 #if defined(__DragonFly__) || defined(__FreeBSD__)
30 #if defined(__NetBSD__)
32 #define KERN_PROC KERN_PROC2
33 #define KINFO_PROC struct kinfo_proc2
35 #define KINFO_PROC struct kinfo_proc
38 #if defined(__DragonFly__)
39 #define KP_START_SEC kp_start.tv_sec
40 #define KP_START_USEC kp_start.tv_usec
41 #elif defined(__FreeBSD__)
42 #define KP_START_SEC ki_start.tv_sec
43 #define KP_START_USEC ki_start.tv_usec
45 #define KP_START_SEC p_ustart_sec
46 #define KP_START_USEC p_ustart_usec
49 #include "mozilla/TimeStamp.h"
55 // Estimate of the smallest duration of time we can measure.
56 static uint64_t sResolution
;
57 static uint64_t sResolutionSigDigs
;
59 static const uint16_t kNsPerUs
= 1000;
60 static const uint64_t kNsPerMs
= 1000000;
61 static const uint64_t kNsPerSec
= 1000000000;
62 static const double kNsPerMsd
= 1000000.0;
63 static const double kNsPerSecd
= 1000000000.0;
66 TimespecToNs(const struct timespec
& aTs
)
68 uint64_t baseNs
= uint64_t(aTs
.tv_sec
) * kNsPerSec
;
69 return baseNs
+ uint64_t(aTs
.tv_nsec
);
76 // this can't fail: we know &ts is valid, and TimeStamp::Startup()
77 // checks that CLOCK_MONOTONIC is supported (and aborts if not)
78 clock_gettime(CLOCK_MONOTONIC
, &ts
);
80 // tv_sec is defined to be relative to an arbitrary point in time,
81 // but it would be madness for that point in time to be earlier than
82 // the Epoch. So we can safely assume that even if time_t is 32
83 // bits, tv_sec won't overflow while the browser is open. Revisit
84 // this argument if we're still building with 32-bit time_t around
86 return TimespecToNs(ts
);
92 // NB: why not rely on clock_getres()? Two reasons: (i) it might
93 // lie, and (ii) it might return an "ideal" resolution that while
94 // theoretically true, could never be measured in practice. Since
95 // clock_gettime() likely involves a system call on your platform,
96 // the "actual" timing resolution shouldn't be lower than syscall
99 uint64_t start
= ClockTimeNs();
100 uint64_t end
= ClockTimeNs();
101 uint64_t minres
= (end
- start
);
103 // 10 total trials is arbitrary: what we're trying to avoid by
104 // looping is getting unlucky and being interrupted by a context
105 // switch or signal, or being bitten by paging/cache effects
106 for (int i
= 0; i
< 9; ++i
) {
107 start
= ClockTimeNs();
110 uint64_t candidate
= (start
- end
);
111 if (candidate
< minres
) {
117 // measurable resolution is either incredibly low, ~1ns, or very
118 // high. fall back on clock_getres()
120 if (0 == clock_getres(CLOCK_MONOTONIC
, &ts
)) {
121 minres
= TimespecToNs(ts
);
126 // clock_getres probably failed. fall back on NSPR's resolution
128 minres
= 1 * kNsPerMs
;
137 TimeDuration::ToSeconds() const
139 return double(mValue
) / kNsPerSecd
;
143 TimeDuration::ToSecondsSigDigits() const
145 // don't report a value < mResolution ...
146 int64_t valueSigDigs
= sResolution
* (mValue
/ sResolution
);
147 // and chop off insignificant digits
148 valueSigDigs
= sResolutionSigDigs
* (valueSigDigs
/ sResolutionSigDigs
);
149 return double(valueSigDigs
) / kNsPerSecd
;
153 TimeDuration::FromMilliseconds(double aMilliseconds
)
155 return TimeDuration::FromTicks(aMilliseconds
* kNsPerMsd
);
159 TimeDuration::Resolution()
161 return TimeDuration::FromTicks(int64_t(sResolution
));
164 static bool gInitialized
= false;
173 struct timespec dummy
;
174 if (clock_gettime(CLOCK_MONOTONIC
, &dummy
) != 0) {
175 NS_RUNTIMEABORT("CLOCK_MONOTONIC is absent!");
178 sResolution
= ClockResolutionNs();
180 // find the number of significant digits in sResolution, for the
181 // sake of ToSecondsSigDigits()
182 for (sResolutionSigDigs
= 1;
183 !(sResolutionSigDigs
== sResolution
||
184 10 * sResolutionSigDigs
> sResolution
);
185 sResolutionSigDigs
*= 10);
193 TimeStamp::Shutdown()
198 TimeStamp::Now(bool aHighResolution
)
200 return TimeStamp(ClockTimeNs());
203 #if defined(LINUX) || defined(ANDROID)
205 // Calculates the amount of jiffies that have elapsed since boot and up to the
206 // starttime value of a specific process as found in its /proc/*/stat file.
207 // Returns 0 if an error occurred.
210 JiffiesSinceBoot(const char* aFile
)
214 FILE* f
= fopen(aFile
, "r");
219 int n
= fread(&stat
, 1, sizeof(stat
) - 1, f
);
229 long long unsigned startTime
= 0; // instead of uint64_t to keep GCC quiet
230 char* s
= strrchr(stat
, ')');
236 int rv
= sscanf(s
+ 2,
237 "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u "
238 "%*u %*u %*u %*d %*d %*d %*d %*d %*d %llu",
241 if (rv
!= 1 || !startTime
) {
248 // Computes the interval that has elapsed between the thread creation and the
249 // process creation by comparing the starttime fields in the respective
250 // /proc/*/stat files. The resulting value will be a good approximation of the
251 // process uptime. This value will be stored at the address pointed by aTime;
252 // if an error occurred 0 will be stored instead.
255 ComputeProcessUptimeThread(void* aTime
)
257 uint64_t* uptime
= static_cast<uint64_t*>(aTime
);
258 long hz
= sysconf(_SC_CLK_TCK
);
267 sprintf(threadStat
, "/proc/self/task/%d/stat", (pid_t
)syscall(__NR_gettid
));
269 uint64_t threadJiffies
= JiffiesSinceBoot(threadStat
);
270 uint64_t selfJiffies
= JiffiesSinceBoot("/proc/self/stat");
272 if (!threadJiffies
|| !selfJiffies
) {
276 *uptime
= ((threadJiffies
- selfJiffies
) * kNsPerSec
) / hz
;
279 // Computes and returns the process uptime in us on Linux & its derivatives.
280 // Returns 0 if an error was encountered.
283 TimeStamp::ComputeProcessUptime()
286 PRThread
* thread
= PR_CreateThread(PR_USER_THREAD
,
287 ComputeProcessUptimeThread
,
294 PR_JoinThread(thread
);
296 return uptime
/ kNsPerUs
;
299 #elif defined(__DragonFly__) || defined(__FreeBSD__) \
300 || defined(__NetBSD__) || defined(__OpenBSD__)
302 // Computes and returns the process uptime in us on various BSD flavors.
303 // Returns 0 if an error was encountered.
306 TimeStamp::ComputeProcessUptime()
309 int rv
= clock_gettime(CLOCK_REALTIME
, &ts
);
320 #if defined(__NetBSD__) || defined(__OpenBSD__)
325 u_int mibLen
= sizeof(mib
) / sizeof(mib
[0]);
328 size_t bufferSize
= sizeof(proc
);
329 rv
= sysctl(mib
, mibLen
, &proc
, &bufferSize
, nullptr, 0);
335 uint64_t startTime
= ((uint64_t)proc
.KP_START_SEC
* kNsPerSec
) +
336 (proc
.KP_START_USEC
* kNsPerUs
);
337 uint64_t now
= ((uint64_t)ts
.tv_sec
* kNsPerSec
) + ts
.tv_nsec
;
339 if (startTime
> now
) {
343 return (now
- startTime
) / kNsPerUs
;
349 TimeStamp::ComputeProcessUptime()
356 } // namespace mozilla