[racket] FFI question: 0 microseconds returned from gettimeofday call

From: keydana at gmx.de (keydana at gmx.de)
Date: Sun Jul 17 11:43:04 EDT 2011

Hi Jon,

thanks a lot for your "find-out-yourself" code - not only will I remember this method for application to future problems, but also did it really solve my problem!

In fact the result was _int64 for the seconds and _int32 for the microseconds, which left me wondering why my code didn't work, as I had experimented with  _int32 for μsecs already... until I realized the error must be with the first field then!

It turns out I'd read the documentation sloppily, and had always thought that _int was turned into either 64 or  32 bit depending on the architecture - now I see it's _long that is...  And having defined the secs as an _int, with my 64 bit Racket executable, I've "left over" a portion of the secs for the μsecs (which also explains the "too long" like 9359042975779072 that I obtained when having μsecs as _long).

(Just out of curiosity, I also ran my original code on a manually compiled 32-bit version of DrRacket I have, and there it indeed worked fine :-;)

So, thanks again!


Am 16.07.2011 um 02:40 schrieb Jon Zeppieri:

> On Fri, Jul 15, 2011 at 4:28 PM, keydana at gmx.de <keydana at gmx.de> wrote:
> [snip]
>>> There is, however, a PLaneT package (planet dherman/c:4:0) providing the
>>> facilities to parse header files and extract structure layout
>>> information like that required here using the system's C compiler.
>> Thanks for the pointer (pun intended :-;), I will have a look... But in fact I hope that other than experimenting with calls like these, that is, when working with a "real", user-friendly library, I will not have too great a need to use it :-)
> If you want the code to be portable, you're going to have to do
> something a bit nasty, since the types in question simply don't have a
> standard size.
> If you're only interested in running the code on your machine (or on
> some particular set of systems), you can just support those.
> Have you tried looking at the output of
> (current-inexact-milliseconds)? If your system supports millisecond
> resolution (and if racket knows how to get it), milliseconds should be
> given in the fractional portion of the result.
>>> The zero microseconds value could mean that you were actually "lucky"
>>> with the call, that your system simply doesn't support time values with
>>> microsecond precision or that your system's implementation of
>>> gettimeofday doesn't support that.
>> Well, I think I should at least get the milliseconds, because Racket has them in (current-milliseconds), so in that case I'd expect to see something like 123000 in the microsecond field...
> (current-milliseconds) does not necessarily (and simply does not,
> period, on my machine) return milliseconds since the epoch. The docs
> say: "Returns the current “time” in fixnum milliseconds (possibly
> negative). This time is based on a platform-specific starting date or
> on the machine’s start-up time."
> You might be able to determine the right size at runtime...
> The following works by starting out with 64-bit ints and narrowing,
> first the seconds field, then the microseconds. I *think* it's fairly
> safe; it should always err on the side of passing in too large a chunk
> of memory, so it shouldn't start stomping on random addresses. But,
> you know, make sure you save whatever you have before trying it.
> #lang racket
> (require ffi/unsafe)
> (define sizes (list _int64 _int32 _int16 _int8))
> (define num-iterations 5)
> (define (make-gettimeofday stype utype)
>  (get-ffi-obj 'gettimeofday #f
>               (_fun [timeval : (_ptr o (_list-struct stype utype))]
>                     (_intptr = 0)
>                     -> _int
>                     -> timeval)))
> (define (find-seconds-type)
>  (for/first ([s (in-list sizes)]
>              #:when (let* ([fn      (make-gettimeofday s _int64)]
>                            [timeval (fn)])
>                       (= (current-seconds) (first timeval))))
>    s))
> (define (find-micro-type stype)
>  (for/first ([s (in-list sizes)]
>              #:when (for/and ([i (in-range num-iterations)])
>                       (let* ([fn      (make-gettimeofday stype s)]
>                              [timeval (fn)]
>                              [millis  (current-inexact-milliseconds)]
>                              [micros  (remainder (* millis 1000) 1000000)])
>                         (and (>= (second timeval) 0)
>                              (>= micros (second timeval))
>                              (< (- micros (second timeval)) 100)))))
>    s))
> (define gettimeofday
>  (let* ([stype (find-seconds-type)]
>         [utype (and stype (find-micro-type stype))])
>    (cond [utype
>           (printf "(~a, ~a)\n" stype utype)
>           (make-gettimeofday stype utype)]
>          [else
>           (error "Unable to determine type for gettimeofday")])))

Posted on the users mailing list.