1 ;;;; low-level time functions
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!IMPL")
14 ;;; Internal epoch, used as base for real-time.
15 (declaim (unsigned-byte *internal-epoch*))
16 (defvar *internal-epoch* 0)
19 (setf *internal-epoch* (system-internal-real-time)))
21 (defun get-internal-real-time ()
23 "Return the real time (\"wallclock time\") since startup in the internal
24 time format. (See INTERNAL-TIME-UNITS-PER-SECOND.)"
25 (- (system-internal-real-time) *internal-epoch*))
27 (defun get-internal-run-time ()
29 "Return the run time used by the process in the internal time format. (See
30 INTERNAL-TIME-UNITS-PER-SECOND.) This is useful for finding CPU usage.
31 Includes both \"system\" and \"user\" time."
32 (system-internal-run-time))
34 ;;;; Encode and decode universal times.
36 ;;; In August 2003, work was done in this file for more plausible
37 ;;; timezone handling after the unix timezone database runs out in
38 ;;; 2038. We assume that timezone rules are trending sane rather than
39 ;;; insane, so for all years after the end of time_t we apply the
40 ;;; rules for 2035/2036 instead of the actual date asked for. Making
41 ;;; the same assumption about the early 1900s would be less
42 ;;; reasonable, however, so please note that we're still broken for
43 ;;; local time between 1900-1-1 and 1901-12-13
45 ;;; It should be noted that 64 bit machines don't actually fix this
46 ;;; problem, at least as of 2003, because the Unix zonefiles are
47 ;;; specified in terms of 32 bit fields even on, say, the Alpha. So,
48 ;;; references to the range of time_t elsewhere in this file should
49 ;;; rightly be read as shorthand for the range of an signed 32 bit
50 ;;; number of seconds since 1970-01-01
52 ;;; I'm obliged to Erik Naggum's "Long, Painful History of Time" paper
53 ;;; <http://heim.ifi.uio.no/~enag/lugm-time.html> for the choice of epoch
54 ;;; here. By starting the year in March, we avoid having to test the month
55 ;;; whenever deciding whether to account for a leap day. 2000 is especially
56 ;;; special, because it's disvisible by 400, hence the start of a 400 year
59 ;;; If a universal-time is after time_t runs out, we find its offset
60 ;;; from 1st March of whichever year it falls in, then add that to
61 ;;; 2035-3-1. This date has two relevant properties: (1) somewhere
62 ;;; near the end of time_t, and (2) preceding a leap year. Thus a
63 ;;; date which is e.g. 365.5 days from March 1st in its year will be
64 ;;; treated for timezone lookup as if it were Feb 29th 2036
66 ;;; This epoch is used only for fixing the timezones-outside-time_t
67 ;;; problem. Someday it would be nice to come back to this code and
68 ;;; see if the rest of the file and its references to Spice Lisp
69 ;;; history (Perq time base?) could be cleaned up any on this basis.
70 ;;; -- dan, 2003-08-08
72 ;;; In order to accomodate universal times between January 1st 1900
73 ;;; and sometime on December 13th 1901, I'm doing the same calculation
74 ;;; as described above in order to handle dates in that interval, by
75 ;;; normalizing them to March 1st 1903, which shares the same special
76 ;;; properties described above (except for the 400-year property, but
77 ;;; this isn't an issue for the limited range we need to handle).
79 ;;; One open issue is whether to pass UNIX a 64-bit time_t value on
80 ;;; 64-bit platforms. I don't know if time_t is always 64-bit on those
81 ;;; platforms, and looking at this file reveals a scary amount of
82 ;;; literal 31 and 32s.
83 ;;; -- bem, 2005-08-09
85 ;;; Subtract from the returned Internal-Time to get the universal
86 ;;; time. The offset between our time base and the Perq one is 2145
87 ;;; weeks and five days.
88 (defconstant seconds-in-week (* 60 60 24 7))
89 (defconstant weeks-offset 2145)
90 (defconstant seconds-offset 432000)
91 (defconstant minutes-per-day (* 24 60))
92 (defconstant quarter-days-per-year (1+ (* 365 4)))
93 (defconstant quarter-days-per-century 146097)
94 (defconstant november-17-1858 678882)
95 (defconstant weekday-november-17-1858 2)
96 (defconstant unix-to-universal-time 2208988800)
98 (defun get-universal-time ()
100 "Return a single integer for the current time of day in universal time
102 (multiple-value-bind (res secs) (sb!unix:unix-gettimeofday)
103 (declare (ignore res))
104 (+ secs unix-to-universal-time)))
106 (defun get-decoded-time ()
108 "Return nine values specifying the current time as follows:
109 second, minute, hour, date, month, year, day of week (0 = Monday), T
110 (daylight savings times) or NIL (standard time), and timezone."
111 (decode-universal-time (get-universal-time)))
113 (defconstant +mar-1-2000+ #.(encode-universal-time 0 0 0 1 3 2000 0))
114 (defconstant +mar-1-2035+ #.(encode-universal-time 0 0 0 1 3 2035 0))
116 (defconstant +mar-1-1903+ #.(encode-universal-time 0 0 0 1 3 1903 0))
118 (defun years-since-mar-2000 (utime)
119 "Returns number of complete years since March 1st 2000, and remainder in seconds"
120 (let* ((days-in-year (* 86400 365))
121 (days-in-4year (+ (* 4 days-in-year) 86400))
122 (days-in-100year (- (* 25 days-in-4year) 86400))
123 (days-in-400year (+ (* 4 days-in-100year) 86400))
124 (offset (- utime +mar-1-2000+))
126 (labels ((whole-num (x y inc max)
127 (let ((w (truncate x y)))
128 (when (and max (> w max)) (setf w max))
129 (incf year (* w inc))
131 (decf offset (whole-num offset days-in-400year 400 nil))
132 (decf offset (whole-num offset days-in-100year 100 3))
133 (decf offset (whole-num offset days-in-4year 4 25))
134 (decf offset (whole-num offset days-in-year 1 3))
135 (values year offset))))
137 (defun truncate-to-unix-range (utime)
138 (let ((unix-time (- utime unix-to-universal-time)))
140 ((< unix-time (- (ash 1 31)))
141 (multiple-value-bind (year offset) (years-since-mar-2000 utime)
142 (declare (ignore year))
143 (+ +mar-1-1903+ (- unix-to-universal-time) offset)))
144 ((>= unix-time (ash 1 31))
145 (multiple-value-bind (year offset) (years-since-mar-2000 utime)
146 (declare (ignore year))
147 (+ +mar-1-2035+ (- unix-to-universal-time) offset)))
150 (defun decode-universal-time (universal-time &optional time-zone)
152 "Converts a universal-time to decoded time format returning the following
153 nine values: second, minute, hour, date, month, year, day of week (0 =
154 Monday), T (daylight savings time) or NIL (standard time), and timezone.
155 Completely ignores daylight-savings-time when time-zone is supplied."
156 (multiple-value-bind (daylight seconds-west)
158 (values nil (* time-zone 60 60))
159 (multiple-value-bind (ignore seconds-west daylight)
160 (sb!unix::get-timezone (truncate-to-unix-range universal-time))
161 (declare (ignore ignore))
162 (declare (fixnum seconds-west))
163 (values daylight seconds-west)))
164 (declare (fixnum seconds-west))
165 (multiple-value-bind (weeks secs)
166 (truncate (+ (- universal-time seconds-west) seconds-offset)
168 (let ((weeks (+ weeks weeks-offset)))
169 (multiple-value-bind (t1 second)
171 (let ((tday (truncate t1 minutes-per-day)))
172 (multiple-value-bind (hour minute)
173 (truncate (- t1 (* tday minutes-per-day)) 60)
174 (let* ((t2 (1- (* (+ (* weeks 7) tday november-17-1858) 4)))
175 (tcent (truncate t2 quarter-days-per-century)))
176 (setq t2 (mod t2 quarter-days-per-century))
177 (setq t2 (+ (- t2 (mod t2 4)) 3))
178 (let* ((year (+ (* tcent 100)
179 (truncate t2 quarter-days-per-year)))
181 (1+ (truncate (mod t2 quarter-days-per-year) 4)))
182 (day (mod (+ tday weekday-november-17-1858) 7))
183 (t3 (+ (* days-since-mar0 5) 456)))
185 (setq t3 (- t3 1836))
186 (setq year (1+ year))))
187 (multiple-value-bind (month t3)
189 (let ((date (1+ (truncate t3 5))))
190 (values second minute hour date month year day
193 (1+ (/ seconds-west 60 60))
194 (/ seconds-west 60 60))))))))))))))
196 (defun pick-obvious-year (year)
197 (declare (type (mod 100) year))
198 (let* ((current-year (nth-value 5 (get-decoded-time)))
199 (guess (+ year (* (truncate (- current-year 50) 100) 100))))
200 (declare (type (integer 1900 9999) current-year guess))
201 (if (> (- current-year guess) 50)
205 (defun leap-years-before (year)
206 (let ((years (- year 1901)))
207 (+ (- (truncate years 4)
208 (truncate years 100))
209 (truncate (+ years 300) 400))))
211 (defvar *days-before-month*
212 #.(let ((reversed-result nil)
214 (push nil reversed-result)
215 (dolist (days-in-month '(31 28 31 30 31 30 31 31 30 31 30 31))
216 (push sum reversed-result)
217 (incf sum days-in-month))
218 (coerce (nreverse reversed-result) 'simple-vector)))
221 (defun encode-universal-time (second minute hour date month year
224 "The time values specified in decoded format are converted to
225 universal time, which is returned."
226 (declare (type (mod 60) second)
227 (type (mod 60) minute)
229 (type (integer 1 31) date)
230 (type (integer 1 12) month)
231 (type (or (integer 0 99) (integer 1899)) year)
232 ;; that type used to say (integer 1900), but that's
233 ;; incorrect when a time-zone is specified: we should be
234 ;; able to encode to produce 0 when a non-zero timezone is
235 ;; specified - bem, 2005-08-09
236 (type (or null rational) time-zone))
237 (let* ((year (if (< year 100)
238 (pick-obvious-year year)
241 (aref *days-before-month* month)
243 (leap-years-before (1+ year))
244 (leap-years-before year))
245 (* (- year 1900) 365)))
246 (hours (+ hour (* days 24)))
249 (setf encoded-time (+ second (* (+ minute (* (+ hours time-zone) 60)) 60)))
250 (let* ((secwest-guess
251 (sb!unix::unix-get-seconds-west
252 (truncate-to-unix-range (* hours 60 60))))
253 (guess (+ second (* 60 (+ minute (* hours 60)))
256 (sb!unix::unix-get-seconds-west
257 (truncate-to-unix-range guess))))
258 (setf encoded-time (+ guess (- secwest secwest-guess)))))
259 (assert (typep encoded-time '(integer 0)))
264 (defvar *gc-run-time* 0
266 "the total CPU time spent doing garbage collection (as reported by
267 GET-INTERNAL-RUN-TIME)")
268 (declaim (type index *gc-run-time*))
270 (defmacro time (form)
272 "Execute FORM and print timing information on *TRACE-OUTPUT*."
273 `(%time (lambda () ,form)))
275 ;;; Return all the data that we want TIME to report.
276 (defun time-get-sys-info ()
277 (multiple-value-bind (user sys faults) (sb!sys:get-system-info)
278 (values user sys faults (get-bytes-consed))))
280 ;;; The guts of the TIME macro. Compute overheads, run the (compiled)
281 ;;; function, report the times.
283 (declare (type function fun))
299 ;; Calculate the overhead...
301 (old-run-utime old-run-stime old-page-faults old-bytes-consed)
303 ;; Do it a second time to make sure everything is faulted in.
305 (old-run-utime old-run-stime old-page-faults old-bytes-consed)
308 (new-run-utime new-run-stime new-page-faults new-bytes-consed)
310 (setq run-utime-overhead (- new-run-utime old-run-utime))
311 (setq run-stime-overhead (- new-run-stime old-run-stime))
312 (setq page-faults-overhead (- new-page-faults old-page-faults))
313 (setq old-real-time (get-internal-real-time))
314 (setq old-real-time (get-internal-real-time))
315 (setq new-real-time (get-internal-real-time))
316 (setq real-time-overhead (- new-real-time old-real-time))
317 (setq cons-overhead (- new-bytes-consed old-bytes-consed))
318 ;; Now get the initial times.
320 (old-run-utime old-run-stime old-page-faults old-bytes-consed)
322 (setq old-real-time (get-internal-real-time))
323 (let ((start-gc-run-time *gc-run-time*)
324 #!+sb-eval (sb!eval:*eval-calls* 0))
325 (declare #!+sb-eval (special sb!eval:*eval-calls*))
326 (multiple-value-prog1
327 ;; Execute the form and return its values.
330 (new-run-utime new-run-stime new-page-faults new-bytes-consed)
332 (setq new-real-time (- (get-internal-real-time) real-time-overhead))
333 (let ((gc-run-time (max (- *gc-run-time* start-gc-run-time) 0)))
334 (format *trace-output*
335 "~&Evaluation took:~% ~
336 ~S second~:P of real time~% ~
337 ~S second~:P of user run time~% ~
338 ~S second~:P of system run time~% ~
339 ~@[[Run times include ~S second~:P GC run time.]~% ~]~
340 ~@[~S call~:P to %EVAL~% ~]~
341 ~S page fault~:P and~% ~
343 (max (/ (- new-real-time old-real-time)
344 (float sb!xc:internal-time-units-per-second))
346 (max (/ (- new-run-utime old-run-utime) 1000000.0) 0.0)
347 (max (/ (- new-run-stime old-run-stime) 1000000.0) 0.0)
348 (unless (zerop gc-run-time)
349 (/ (float gc-run-time)
350 (float sb!xc:internal-time-units-per-second)))
351 #!+sb-eval sb!eval:*eval-calls* #!-sb-eval nil
352 (max (- new-page-faults old-page-faults) 0)
353 (max (- new-bytes-consed old-bytes-consed) 0)))))))