Bug 1507844 - Push the devtools.inspector.flexboxHighlighter.enabled pref in browser_...
[gecko.git] / mozglue / misc / TimeStamp_posix.cpp
blob975ecde64c0be5cebc24c853cd967af8bd65f3e0
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/. */
7 //
8 // Implement TimeStamp::Now() with POSIX clocks.
9 //
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>
17 #include <time.h>
18 #include <unistd.h>
19 #include <string.h>
21 #if defined(__DragonFly__) || defined(__FreeBSD__) \
22 || defined(__NetBSD__) || defined(__OpenBSD__)
23 #include <sys/param.h>
24 #include <sys/sysctl.h>
25 #endif
27 #if defined(__DragonFly__) || defined(__FreeBSD__)
28 #include <sys/user.h>
29 #endif
31 #if defined(__NetBSD__)
32 #undef KERN_PROC
33 #define KERN_PROC KERN_PROC2
34 #define KINFO_PROC struct kinfo_proc2
35 #else
36 #define KINFO_PROC struct kinfo_proc
37 #endif
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
45 #else
46 #define KP_START_SEC p_ustart_sec
47 #define KP_START_USEC p_ustart_usec
48 #endif
50 #include "mozilla/Sprintf.h"
51 #include "mozilla/TimeStamp.h"
52 #include <pthread.h>
54 // Estimate of the smallest duration of time we can measure.
55 static uint64_t sResolution;
56 static uint64_t sResolutionSigDigs;
58 static const uint16_t kNsPerUs = 1000;
59 static const uint64_t kNsPerMs = 1000000;
60 static const uint64_t kNsPerSec = 1000000000;
61 static const double kNsPerMsd = 1000000.0;
62 static const double kNsPerSecd = 1000000000.0;
64 static uint64_t
65 TimespecToNs(const struct timespec& aTs)
67 uint64_t baseNs = uint64_t(aTs.tv_sec) * kNsPerSec;
68 return baseNs + uint64_t(aTs.tv_nsec);
71 static uint64_t
72 ClockTimeNs()
74 struct timespec ts;
75 // this can't fail: we know &ts is valid, and TimeStamp::Startup()
76 // checks that CLOCK_MONOTONIC is supported (and aborts if not)
77 clock_gettime(CLOCK_MONOTONIC, &ts);
79 // tv_sec is defined to be relative to an arbitrary point in time,
80 // but it would be madness for that point in time to be earlier than
81 // the Epoch. So we can safely assume that even if time_t is 32
82 // bits, tv_sec won't overflow while the browser is open. Revisit
83 // this argument if we're still building with 32-bit time_t around
84 // the year 2037.
85 return TimespecToNs(ts);
88 static uint64_t
89 ClockResolutionNs()
91 // NB: why not rely on clock_getres()? Two reasons: (i) it might
92 // lie, and (ii) it might return an "ideal" resolution that while
93 // theoretically true, could never be measured in practice. Since
94 // clock_gettime() likely involves a system call on your platform,
95 // the "actual" timing resolution shouldn't be lower than syscall
96 // overhead.
98 uint64_t start = ClockTimeNs();
99 uint64_t end = ClockTimeNs();
100 uint64_t minres = (end - start);
102 // 10 total trials is arbitrary: what we're trying to avoid by
103 // looping is getting unlucky and being interrupted by a context
104 // switch or signal, or being bitten by paging/cache effects
105 for (int i = 0; i < 9; ++i) {
106 start = ClockTimeNs();
107 end = ClockTimeNs();
109 uint64_t candidate = (start - end);
110 if (candidate < minres) {
111 minres = candidate;
115 if (0 == minres) {
116 // measurable resolution is either incredibly low, ~1ns, or very
117 // high. fall back on clock_getres()
118 struct timespec ts;
119 if (0 == clock_getres(CLOCK_MONOTONIC, &ts)) {
120 minres = TimespecToNs(ts);
124 if (0 == minres) {
125 // clock_getres probably failed. fall back on NSPR's resolution
126 // assumption
127 minres = 1 * kNsPerMs;
130 return minres;
133 namespace mozilla {
135 double
136 BaseTimeDurationPlatformUtils::ToSeconds(int64_t aTicks)
138 return double(aTicks) / kNsPerSecd;
141 double
142 BaseTimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
144 // don't report a value < mResolution ...
145 int64_t valueSigDigs = sResolution * (aTicks / sResolution);
146 // and chop off insignificant digits
147 valueSigDigs = sResolutionSigDigs * (valueSigDigs / sResolutionSigDigs);
148 return double(valueSigDigs) / kNsPerSecd;
151 int64_t
152 BaseTimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
154 double result = aMilliseconds * kNsPerMsd;
155 if (result > INT64_MAX) {
156 return INT64_MAX;
158 if (result < INT64_MIN) {
159 return INT64_MIN;
162 return result;
165 int64_t
166 BaseTimeDurationPlatformUtils::ResolutionInTicks()
168 return static_cast<int64_t>(sResolution);
171 static bool gInitialized = false;
173 void
174 TimeStamp::Startup()
176 if (gInitialized) {
177 return;
180 struct timespec dummy;
181 if (clock_gettime(CLOCK_MONOTONIC, &dummy) != 0) {
182 MOZ_CRASH("CLOCK_MONOTONIC is absent!");
185 sResolution = ClockResolutionNs();
187 // find the number of significant digits in sResolution, for the
188 // sake of ToSecondsSigDigits()
189 for (sResolutionSigDigs = 1;
190 !(sResolutionSigDigs == sResolution ||
191 10 * sResolutionSigDigs > sResolution);
192 sResolutionSigDigs *= 10);
194 gInitialized = true;
197 void
198 TimeStamp::Shutdown()
202 TimeStamp
203 TimeStamp::Now(bool aHighResolution)
205 return TimeStamp::NowFuzzy(TimeStampValue(false, ClockTimeNs()));
208 TimeStamp
209 TimeStamp::NowUnfuzzed(bool aHighResolution)
211 return TimeStamp(TimeStampValue(false, ClockTimeNs()));
214 #if defined(XP_LINUX) || defined(ANDROID)
216 // Calculates the amount of jiffies that have elapsed since boot and up to the
217 // starttime value of a specific process as found in its /proc/*/stat file.
218 // Returns 0 if an error occurred.
220 static uint64_t
221 JiffiesSinceBoot(const char* aFile)
223 char stat[512];
225 FILE* f = fopen(aFile, "r");
226 if (!f) {
227 return 0;
230 int n = fread(&stat, 1, sizeof(stat) - 1, f);
232 fclose(f);
234 if (n <= 0) {
235 return 0;
238 stat[n] = 0;
240 long long unsigned startTime = 0; // instead of uint64_t to keep GCC quiet
241 char* s = strrchr(stat, ')');
243 if (!s) {
244 return 0;
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",
250 &startTime);
252 if (rv != 1 || !startTime) {
253 return 0;
256 return 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*
266 ComputeProcessUptimeThread(void* aTime)
268 uint64_t* uptime = static_cast<uint64_t*>(aTime);
269 long hz = sysconf(_SC_CLK_TCK);
271 *uptime = 0;
273 if (!hz) {
274 return nullptr;
277 char threadStat[40];
278 SprintfLiteral(threadStat, "/proc/self/task/%d/stat", (pid_t)syscall(__NR_gettid));
280 uint64_t threadJiffies = JiffiesSinceBoot(threadStat);
281 uint64_t selfJiffies = JiffiesSinceBoot("/proc/self/stat");
283 if (!threadJiffies || !selfJiffies) {
284 return nullptr;
287 *uptime = ((threadJiffies - selfJiffies) * kNsPerSec) / hz;
288 return nullptr;
291 // Computes and returns the process uptime in us on Linux & its derivatives.
292 // Returns 0 if an error was encountered.
294 uint64_t
295 TimeStamp::ComputeProcessUptime()
297 uint64_t uptime = 0;
298 pthread_t uptime_pthread;
300 if (pthread_create(&uptime_pthread, nullptr, ComputeProcessUptimeThread, &uptime)) {
301 MOZ_CRASH("Failed to create process uptime thread.");
302 return 0;
305 pthread_join(uptime_pthread, NULL);
307 return uptime / kNsPerUs;
310 #elif defined(__DragonFly__) || defined(__FreeBSD__) \
311 || defined(__NetBSD__) || defined(__OpenBSD__)
313 // Computes and returns the process uptime in us on various BSD flavors.
314 // Returns 0 if an error was encountered.
316 uint64_t
317 TimeStamp::ComputeProcessUptime()
319 struct timespec ts;
320 int rv = clock_gettime(CLOCK_REALTIME, &ts);
322 if (rv == -1) {
323 return 0;
326 int mib[] = {
327 CTL_KERN,
328 KERN_PROC,
329 KERN_PROC_PID,
330 getpid(),
331 #if defined(__NetBSD__) || defined(__OpenBSD__)
332 sizeof(KINFO_PROC),
334 #endif
336 u_int mibLen = sizeof(mib) / sizeof(mib[0]);
338 KINFO_PROC proc;
339 size_t bufferSize = sizeof(proc);
340 rv = sysctl(mib, mibLen, &proc, &bufferSize, nullptr, 0);
342 if (rv == -1) {
343 return 0;
346 uint64_t startTime = ((uint64_t)proc.KP_START_SEC * kNsPerSec) +
347 (proc.KP_START_USEC * kNsPerUs);
348 uint64_t now = ((uint64_t)ts.tv_sec * kNsPerSec) + ts.tv_nsec;
350 if (startTime > now) {
351 return 0;
354 return (now - startTime) / kNsPerUs;
357 #else
359 uint64_t
360 TimeStamp::ComputeProcessUptime()
362 return 0;
365 #endif
367 } // namespace mozilla