[Openmcl-devel] #_clock_get_time on Darwin returning bogus values

Gary Byers gb at clozure.com
Thu Dec 4 10:59:52 UTC 2008



On Thu, 4 Dec 2008, Hans Hübner wrote:

> Gary,
>
> thanks for your explanation.  I think what it boils down to was that I
> was trying to use a timespec where a  mach_timespec is required,
> right?

And you were using RLET to allocate a "pointer to mach_timespec", when
you wanted to use it to allocate a mach_timespec and bind TS to a pointer
to that.

>
> -Hans
>
> On Thu, Dec 4, 2008 at 11:15, Gary Byers <gb at clozure.com> wrote:
>> (RLET ((ptr type)*) &body body)
>>
>> stack-allocates "an instance of type", binds "ptr" to a pointer to that
>> stack-allocated instance, and executes "body" with that (dynamic-extent)
>> binding in effect.
>>
>> ? (defun foo ()
>>  (rlet ((ptr-to-int :int))
>>    (print ptr-to-int)
>>    ;; Don't return the stack-allocated pointer, which becomes invalid
>>    ;; as soon as we exit the scope of the binding.
>>    nil))
>> FOO
>> ? (foo)
>> #<A Foreign Pointer [stack-allocated] (:* (:SIGNED 32)) #x7FFFFFBFEF10> NIL
>>
>> ":int" is shorthand for "signed 32-bit integer" on most platforms.  (I
>> should have said that RLET also sets some bits in the pointer that describe
>> the type of object the pointer's pointing to, which might be handy for
>> debugging.)
>>
>> "Allocating an instance of the foreign type :int" could also be described
>> as "reserving 4 bytes on the stack."  We've said nothing about what value
>> those 4 bytes will have if interpreted as an :int, and they're in fact
>> pretty much random, e.g., "whatever was last in that particular stack
>> address".
>>
>> ? (defun bar ()
>>  (rlet ((ptr-to-int :int))
>>    (format t "~&the value of the :int that PTR-TO-INT is pointing to is #x~x
>> ."
>>            (pref ptr-to-int :int))
>>    nil))
>> BAR
>> ? (bar)
>> the value of the :int that PTR-TO-INT is pointing to is #x0 .
>>
>> Well, in my case it happened to be 0.  YMMV.
>>
>> Here's another example:
>>
>> (def-foreign-type :intptr (:* :int)) ; necessary since PREF wants a symbol
>>
>> (rlet ((ptr-to-ptr-to-int :intptr))
>>  (format t "~&ptr-to-ptr-to-int = ~s, what it points to = ~s"
>>    ptr-to-ptr-to-int (pref ptr-to-ptr-to-int :intptr))
>>  nil)
>>
>> ? (rlet ((ptr-to-ptr-to-int :intptr))
>>  (format t "~&ptr-to-ptr-to-int = ~s, what it points to = ~s"
>>    ptr-to-ptr-to-int (pref ptr-to-ptr-to-int :intptr))
>>  nil)
>> ptr-to-ptr-to-int = #<A Foreign Pointer [stack-allocated] (:* (:* (:SIGNED
>> 32))) #x7FFFFFBFEF10>, what it points to = #<A Foreign Pointer #x3100000033>
>> NIL
>>
>> In that case, we allocated 8 bytes (on a 64-bit machine, would have been 4
>> bytes in a 32-bit lisp) of uninitialized storage, and bound
>> PTR-TO-PTR-TO-INT
>> to the address of those 8/4 bytes.  If we interpret those bytes as an
>> address, that "address" isn't too meaningful.
>>
>> If we had some foreign code like:
>>
>> int magic_number = 17;
>>
>> void
>> get_address_of_magic_number(int **ref)
>> {
>>  *ref = &magic_number;
>> }
>>
>> an RLET form like the one in the example above might be useful:
>>
>> (rlet ((magic-address-ptr :intptr))
>>  (exernal-call "get_address_of_magic_number" :address magic-address-ptr
>> :void)
>>  (let* ((magic-address (pref magic-address-ptr :intptr)))
>>     (format t "magic address = ~s, contents = ~s"
>>             magic-address (pref magic-address :int))))
>>
>> After we've called the foreign code (passing it a "pointer to a pointer to
>> an int" and that code has stored a "pointer to int" where we've asked it
>> to, the contents of "magic-address-ptr" would be meaningful (as a "pointer
>> ot int", and the contents of that "pointer to int" would be 17.  There -are-
>> widely-used C functions that follow these kinds of
>> conventions, but they're fortunately rare.
>>
>>
>> Back to your case:
>>
>> - a :mach_timespec is a foreign record tyype that has two 32-bit fields
>> named :tv_sec and :tv_nsec; for reasons best known to Apple, tv_sec
>> is unsigned and :tv_nsec is signed (though since the :tv_nsec field
>> is supposed to represent the number of nanoseconds in a time value
>> or interval, the value of an initialized :tv_nsec field will always
>> by >= 0 and < 1000000000).
>>
>> Note that this is a bit different from a POSIX :timespec structure,
>> where (on 64-bit OSX) the :tv_sec field is 64 bits wide (and signed.)
>>
>> - a :mach_timespec_t is a "pointer to a :mach_timespec".
>>
>> - a :clock_serv_t is an unsigned 32-bit integer
>>
>> The Mach function clock_get_time() takes two arguments; the first
>> is a clock_serv_t used to identify the clock service, and the second
>> is a :mach_timepec_t (aka, a pointer to a :mach_timespec.)
>>
>> So, one way to do this (assuming that we want to ignore the possibility
>> that the clock service port might change, e.g., if we save an image
>> and run this code in a different session or different environment):
>>
>> (rlet ((prealtime-clock-port :clock_serv_t))
>>  (#_host_get_clock_service (#_mach_host_self) #$REALTIME_CLOCK
>> prealtime-clock-port)
>>  (let* ((realtime-clock-port (pref prealtime-clock-port :clock_serv_t)))
>>   (defun read-clock-seconds ()
>>     ;; Allocate an uninitialized :mach_timespec, bind ts to a pointer to it
>>     (rlet ((ts :mach_timespec))
>>       ;; ts is a "pointer to a :mach_timepsec", or "a :mach_timespec_t".
>>       (let* ((err (#_clock_get_time realtime-clock-port ts)))
>>         (unless (eql err  #$KERN_SUCCESS)
>>            (error "Mach error reading time, code = ~s" err))
>>         ;; No error, access the tv_sec field of the :mach_timespec
>>         ;; that ts points to and return that value.
>>         (pref ts :mach_timespec.tv_sec))))))
>>
>> ;;; Unless SLEEP sleeps significantly longer than 1 second, these values
>> ;;; should increase by 1 on each iteration.
>> ? (dotimes (i 10) (print (read-clock-seconds) (sleep 1)))
>> 2939807 2939808 2939809 2939810 2939811 2939812 2939813 2939814 2939815
>> 2939816
>>
>>
>>
>>
>>
>> (let* ((
>> (defun read-clock-seconds
>>
>> On Thu, 4 Dec 2008, Hans Hübner wrote:
>>
>>> Hi,
>>>
>>> I'm trying to fix the problem in the deterministic profiler on Darwin.
>>> The problem seems to be that the clock reading function does not
>>> work.  I am using Mach timers in the profiler, and I think I'm reading
>>> them correctly, but the values returned do not make sense:
>>>
>>> PROF> (let ((clock-port (make-record :clock_serv_t)))
>>>       (#_host_get_clock_service (#_mach_host_self) #$REALTIME_CLOCK
>>> clock-port)
>>>       (defun read-clock-seconds ()
>>>         (ccl:rlet ((ts :mach_timespec_t))
>>>           (#_clock_get_time (%get-ptr clock-port) ts)
>>>           (pref ts :timespec.tv_sec))))
>>> READ-CLOCK-SECONDS
>>> PROF> (read-clock-seconds)
>>> 990852764823254945
>>> PROF> (read-clock-seconds)
>>> 957862257734252450
>>> PROF> (read-clock-seconds)
>>> 4146603814037813155
>>> PROF> (lisp-implementation-version)
>>> "Version 1.3-dev-r11396M-trunk  (DarwinX8664)"
>>>
>>> I would expect the value to be increasing (and it used to work with
>>> previous releases).  Maybe something with the header generation went
>>> wrong?
>>>
>>> Thanks,
>>> Hans
>>> _______________________________________________
>>> Openmcl-devel mailing list
>>> Openmcl-devel at clozure.com
>>> http://clozure.com/mailman/listinfo/openmcl-devel
>>>
>>
>
>


More information about the Openmcl-devel mailing list