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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla code.
17 : *
18 : * The Initial Developer of the Original Code is the Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Chris Jones <jones.chris.g@gmail.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : //
40 : // Implement TimeStamp::Now() with POSIX clocks.
41 : //
42 : // The "tick" unit for POSIX clocks is simply a nanosecond, as this is
43 : // the smallest unit of time representable by struct timespec. That
44 : // doesn't mean that a nanosecond is the resolution of TimeDurations
45 : // obtained with this API; see TimeDuration::Resolution;
46 : //
47 :
48 : #include <time.h>
49 :
50 : #include "mozilla/TimeStamp.h"
51 :
52 : // Estimate of the smallest duration of time we can measure.
53 : static PRUint64 sResolution;
54 : static PRUint64 sResolutionSigDigs;
55 :
56 : static const PRUint16 kNsPerUs = 1000;
57 : static const PRUint64 kNsPerMs = 1000000;
58 : static const PRUint64 kNsPerSec = 1000000000;
59 : static const double kNsPerMsd = 1000000.0;
60 : static const double kNsPerSecd = 1000000000.0;
61 :
62 : static PRUint64
63 1902456 : TimespecToNs(const struct timespec& ts)
64 : {
65 1902456 : PRUint64 baseNs = PRUint64(ts.tv_sec) * kNsPerSec;
66 1902456 : return baseNs + PRUint64(ts.tv_nsec);
67 : }
68 :
69 : static PRUint64
70 1901698 : ClockTimeNs()
71 : {
72 : struct timespec ts;
73 : // this can't fail: we know &ts is valid, and TimeStamp::Init()
74 : // checks that CLOCK_MONOTONIC is supported (and aborts if not)
75 1901698 : clock_gettime(CLOCK_MONOTONIC, &ts);
76 :
77 : // tv_sec is defined to be relative to an arbitrary point in time,
78 : // but it would be madness for that point in time to be earlier than
79 : // the Epoch. So we can safely assume that even if time_t is 32
80 : // bits, tv_sec won't overflow while the browser is open. Revisit
81 : // this argument if we're still building with 32-bit time_t around
82 : // the year 2037.
83 1901711 : return TimespecToNs(ts);
84 : }
85 :
86 : static PRUint64
87 1464 : ClockResolutionNs()
88 : {
89 : // NB: why not rely on clock_getres()? Two reasons: (i) it might
90 : // lie, and (ii) it might return an "ideal" resolution that while
91 : // theoretically true, could never be measured in practice. Since
92 : // clock_gettime() likely involves a system call on your platform,
93 : // the "actual" timing resolution shouldn't be lower than syscall
94 : // overhead.
95 :
96 1464 : PRUint64 start = ClockTimeNs();
97 1464 : PRUint64 end = ClockTimeNs();
98 1464 : PRUint64 minres = (end - start);
99 :
100 : // 10 total trials is arbitrary: what we're trying to avoid by
101 : // looping is getting unlucky and being interrupted by a context
102 : // switch or signal, or being bitten by paging/cache effects
103 14640 : for (int i = 0; i < 9; ++i) {
104 13176 : start = ClockTimeNs();
105 13176 : end = ClockTimeNs();
106 :
107 13176 : PRUint64 candidate = (start - end);
108 13176 : if (candidate < minres)
109 39 : minres = candidate;
110 : }
111 :
112 1464 : if (0 == minres) {
113 : // measurable resolution is either incredibly low, ~1ns, or very
114 : // high. fall back on clock_getres()
115 : struct timespec ts;
116 745 : if (0 == clock_getres(CLOCK_MONOTONIC, &ts)) {
117 745 : minres = TimespecToNs(ts);
118 : }
119 : }
120 :
121 1464 : if (0 == minres) {
122 : // clock_getres probably failed. fall back on NSPR's resolution
123 : // assumption
124 0 : minres = 1 * kNsPerMs;
125 : }
126 :
127 1464 : return minres;
128 : }
129 :
130 :
131 : namespace mozilla {
132 :
133 : double
134 905803 : TimeDuration::ToSeconds() const
135 : {
136 905803 : return double(mValue) / kNsPerSecd;
137 : }
138 :
139 : double
140 0 : TimeDuration::ToSecondsSigDigits() const
141 : {
142 : // don't report a value < mResolution ...
143 0 : PRInt64 valueSigDigs = sResolution * (mValue / sResolution);
144 : // and chop off insignificant digits
145 0 : valueSigDigs = sResolutionSigDigs * (valueSigDigs / sResolutionSigDigs);
146 0 : return double(valueSigDigs) / kNsPerSecd;
147 : }
148 :
149 : TimeDuration
150 72098 : TimeDuration::FromMilliseconds(double aMilliseconds)
151 : {
152 72098 : return TimeDuration::FromTicks(aMilliseconds * kNsPerMsd);
153 : }
154 :
155 : TimeDuration
156 0 : TimeDuration::Resolution()
157 : {
158 0 : return TimeDuration::FromTicks(PRInt64(sResolution));
159 : }
160 :
161 : struct TimeStampInitialization
162 : {
163 1464 : TimeStampInitialization() {
164 1464 : TimeStamp::Startup();
165 1464 : }
166 1487 : ~TimeStampInitialization() {
167 1487 : TimeStamp::Shutdown();
168 1487 : }
169 : };
170 :
171 1464 : static TimeStampInitialization initOnce;
172 : static bool gInitialized = false;
173 :
174 : nsresult
175 1464 : TimeStamp::Startup()
176 : {
177 1464 : if (gInitialized)
178 0 : return NS_OK;
179 :
180 : struct timespec dummy;
181 1464 : if (0 != clock_gettime(CLOCK_MONOTONIC, &dummy))
182 0 : NS_RUNTIMEABORT("CLOCK_MONOTONIC is absent!");
183 :
184 1464 : sResolution = ClockResolutionNs();
185 :
186 : // find the number of significant digits in sResolution, for the
187 : // sake of ToSecondsSigDigits()
188 14094 : for (sResolutionSigDigs = 1;
189 : !(sResolutionSigDigs == sResolution
190 14094 : || 10*sResolutionSigDigs > sResolution);
191 : sResolutionSigDigs *= 10);
192 :
193 1464 : gInitialized = true;
194 1464 : return NS_OK;
195 : }
196 :
197 : void
198 1487 : TimeStamp::Shutdown()
199 : {
200 1487 : }
201 :
202 : TimeStamp
203 1872421 : TimeStamp::Now()
204 : {
205 1872421 : return TimeStamp(ClockTimeNs());
206 : }
207 :
208 4392 : }
|