1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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>
21 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
23 # include <sys/param.h>
24 # include <sys/sysctl.h>
27 #if defined(__DragonFly__) || defined(__FreeBSD__)
28 # include <sys/user.h>
31 #if defined(__NetBSD__)
33 # define KERN_PROC KERN_PROC2
34 # define KINFO_PROC struct kinfo_proc2
36 # define KINFO_PROC struct kinfo_proc
39 #if defined(__DragonFly__)
40 # define KP_START_SEC kp_start.tv_sec
41 # define KP_START_USEC kp_start.tv_usec
42 #elif defined(__FreeBSD__)
43 # define KP_START_SEC ki_start.tv_sec
44 # define KP_START_USEC ki_start.tv_usec
46 # define KP_START_SEC p_ustart_sec
47 # define KP_START_USEC p_ustart_usec
50 #include "mozilla/Sprintf.h"
51 #include "mozilla/TimeStamp.h"
53 #if !defined(__wasi__)
57 // Estimate of the smallest duration of time we can measure.
58 static uint64_t sResolution
;
59 static uint64_t sResolutionSigDigs
;
61 #ifdef CLOCK_MONOTONIC_COARSE
62 static bool sSupportsMonotonicCoarseClock
= false;
65 #if !defined(__wasi__)
66 static const uint16_t kNsPerUs
= 1000;
69 static const uint64_t kNsPerMs
= 1000000;
70 static const uint64_t kNsPerSec
= 1000000000;
71 static const double kNsPerMsd
= 1000000.0;
72 static const double kNsPerSecd
= 1000000000.0;
74 static uint64_t TimespecToNs(const struct timespec
& aTs
) {
75 uint64_t baseNs
= uint64_t(aTs
.tv_sec
) * kNsPerSec
;
76 return baseNs
+ uint64_t(aTs
.tv_nsec
);
79 static uint64_t ClockTimeNs(const clockid_t aClockId
= CLOCK_MONOTONIC
) {
81 #ifdef CLOCK_MONOTONIC_COARSE
83 aClockId
== CLOCK_MONOTONIC
||
84 (sSupportsMonotonicCoarseClock
&& aClockId
== CLOCK_MONOTONIC_COARSE
));
86 MOZ_RELEASE_ASSERT(aClockId
== CLOCK_MONOTONIC
);
88 // this can't fail: we know &ts is valid, and TimeStamp::Startup()
89 // checks that CLOCK_MONOTONIC / CLOCK_MONOTONIC_COARSE are
90 // supported (and aborts if the former is not).
91 clock_gettime(aClockId
, &ts
);
93 // tv_sec is defined to be relative to an arbitrary point in time,
94 // but it would be madness for that point in time to be earlier than
95 // the Epoch. So we can safely assume that even if time_t is 32
96 // bits, tv_sec won't overflow while the browser is open. Revisit
97 // this argument if we're still building with 32-bit time_t around
99 return TimespecToNs(ts
);
102 static uint64_t ClockResolutionNs() {
103 // NB: why not rely on clock_getres()? Two reasons: (i) it might
104 // lie, and (ii) it might return an "ideal" resolution that while
105 // theoretically true, could never be measured in practice. Since
106 // clock_gettime() likely involves a system call on your platform,
107 // the "actual" timing resolution shouldn't be lower than syscall
110 uint64_t start
= ClockTimeNs();
111 uint64_t end
= ClockTimeNs();
112 uint64_t minres
= (end
- start
);
114 // 10 total trials is arbitrary: what we're trying to avoid by
115 // looping is getting unlucky and being interrupted by a context
116 // switch or signal, or being bitten by paging/cache effects
117 for (int i
= 0; i
< 9; ++i
) {
118 start
= ClockTimeNs();
121 uint64_t candidate
= (start
- end
);
122 if (candidate
< minres
) {
128 // measurable resolution is either incredibly low, ~1ns, or very
129 // high. fall back on clock_getres()
131 if (0 == clock_getres(CLOCK_MONOTONIC
, &ts
)) {
132 minres
= TimespecToNs(ts
);
137 // clock_getres probably failed. fall back on NSPR's resolution
139 minres
= 1 * kNsPerMs
;
147 double BaseTimeDurationPlatformUtils::ToSeconds(int64_t aTicks
) {
148 return double(aTicks
) / kNsPerSecd
;
151 double BaseTimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks
) {
152 // don't report a value < mResolution ...
153 int64_t valueSigDigs
= sResolution
* (aTicks
/ sResolution
);
154 // and chop off insignificant digits
155 valueSigDigs
= sResolutionSigDigs
* (valueSigDigs
/ sResolutionSigDigs
);
156 return double(valueSigDigs
) / kNsPerSecd
;
159 int64_t BaseTimeDurationPlatformUtils::TicksFromMilliseconds(
160 double aMilliseconds
) {
161 double result
= aMilliseconds
* kNsPerMsd
;
162 if (result
> double(INT64_MAX
)) {
165 if (result
< INT64_MIN
) {
172 int64_t BaseTimeDurationPlatformUtils::ResolutionInTicks() {
173 return static_cast<int64_t>(sResolution
);
176 static bool gInitialized
= false;
178 void TimeStamp::Startup() {
183 struct timespec dummy
;
184 if (clock_gettime(CLOCK_MONOTONIC
, &dummy
) != 0) {
185 MOZ_CRASH("CLOCK_MONOTONIC is absent!");
188 #ifdef CLOCK_MONOTONIC_COARSE
189 if (clock_gettime(CLOCK_MONOTONIC_COARSE
, &dummy
) == 0) {
190 sSupportsMonotonicCoarseClock
= true;
194 sResolution
= ClockResolutionNs();
196 // find the number of significant digits in sResolution, for the
197 // sake of ToSecondsSigDigits()
198 for (sResolutionSigDigs
= 1; !(sResolutionSigDigs
== sResolution
||
199 10 * sResolutionSigDigs
> sResolution
);
200 sResolutionSigDigs
*= 10);
205 void TimeStamp::Shutdown() {}
207 TimeStamp
TimeStamp::Now(bool aHighResolution
) {
208 #ifdef CLOCK_MONOTONIC_COARSE
209 if (!aHighResolution
&& sSupportsMonotonicCoarseClock
) {
210 return TimeStamp(ClockTimeNs(CLOCK_MONOTONIC_COARSE
));
213 return TimeStamp(ClockTimeNs(CLOCK_MONOTONIC
));
216 #if defined(XP_LINUX) || defined(ANDROID)
218 // Calculates the amount of jiffies that have elapsed since boot and up to the
219 // starttime value of a specific process as found in its /proc/*/stat file.
220 // Returns 0 if an error occurred.
222 static uint64_t JiffiesSinceBoot(const char* aFile
) {
225 FILE* f
= fopen(aFile
, "r");
230 int n
= fread(&stat
, 1, sizeof(stat
) - 1, f
);
240 long long unsigned startTime
= 0; // instead of uint64_t to keep GCC quiet
241 char* s
= strrchr(stat
, ')');
247 int rv
= sscanf(s
+ 2,
248 "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u "
249 "%*u %*u %*u %*d %*d %*d %*d %*d %*d %llu",
252 if (rv
!= 1 || !startTime
) {
259 // Computes the interval that has elapsed between the thread creation and the
260 // process creation by comparing the starttime fields in the respective
261 // /proc/*/stat files. The resulting value will be a good approximation of the
262 // process uptime. This value will be stored at the address pointed by aTime;
263 // if an error occurred 0 will be stored instead.
265 static void* ComputeProcessUptimeThread(void* aTime
) {
266 uint64_t* uptime
= static_cast<uint64_t*>(aTime
);
267 long hz
= sysconf(_SC_CLK_TCK
);
276 SprintfLiteral(threadStat
, "/proc/self/task/%d/stat",
277 (pid_t
)syscall(__NR_gettid
));
279 uint64_t threadJiffies
= JiffiesSinceBoot(threadStat
);
280 uint64_t selfJiffies
= JiffiesSinceBoot("/proc/self/stat");
282 if (!threadJiffies
|| !selfJiffies
) {
286 *uptime
= ((threadJiffies
- selfJiffies
) * kNsPerSec
) / hz
;
290 // Computes and returns the process uptime in us on Linux & its derivatives.
291 // Returns 0 if an error was encountered.
293 uint64_t TimeStamp::ComputeProcessUptime() {
295 pthread_t uptime_pthread
;
297 if (pthread_create(&uptime_pthread
, nullptr, ComputeProcessUptimeThread
,
299 MOZ_CRASH("Failed to create process uptime thread.");
303 pthread_join(uptime_pthread
, NULL
);
305 return uptime
/ kNsPerUs
;
308 #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
311 // Computes and returns the process uptime in us on various BSD flavors.
312 // Returns 0 if an error was encountered.
314 uint64_t TimeStamp::ComputeProcessUptime() {
316 int rv
= clock_gettime(CLOCK_REALTIME
, &ts
);
328 # if defined(__NetBSD__) || defined(__OpenBSD__)
334 u_int mibLen
= sizeof(mib
) / sizeof(mib
[0]);
337 size_t bufferSize
= sizeof(proc
);
338 rv
= sysctl(mib
, mibLen
, &proc
, &bufferSize
, nullptr, 0);
344 uint64_t startTime
= ((uint64_t)proc
.KP_START_SEC
* kNsPerSec
) +
345 (proc
.KP_START_USEC
* kNsPerUs
);
346 uint64_t now
= ((uint64_t)ts
.tv_sec
* kNsPerSec
) + ts
.tv_nsec
;
348 if (startTime
> now
) {
352 return (now
- startTime
) / kNsPerUs
;
357 uint64_t TimeStamp::ComputeProcessUptime() { return 0; }
361 } // namespace mozilla