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

From: Jon Zeppieri (zeppieri at gmail.com)
Date: Fri Jul 15 20:40:13 EDT 2011

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.