apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "William A. Rowe, Jr." <wr...@rowe-clan.net>
Subject [PATCH 3] example binary BUSEC for discussion
Date Thu, 11 Jul 2002 18:49:41 GMT
At 11:31 AM 7/11/2002, Brian Pane wrote:
>I don't see a way to eliminate the "/ 1000" to convert usec to
>msec.  But we may be able to do all the math in 32-bit mode, by
>limiting the maximum timeout to the number of milliseconds that
>will fit in 32 bits, which works out to a max timeout of about
>50 days.

Actually, here is my current math, with optimized forms for specific
situations we encounter often (aprox. limits are given in the macro name).

They break down to;

apr_int32_t apr_time_sec_get(time)  deprecates apr_time_sec(time)
apr_int32_t apr_time_msec_get(time) deprecates apr_time_msec(time)
apr_int32_t apr_time_usec_get(time) deprecates apr_time_usec(time)
apr_int32_t apr_time_nsec_get(time) deprecates apr_time_nsec(time)

apr_int64_t apr_time_as_sec(time)
apr_int64_t apr_time_as_msec(time) or apr_time_as_272yrs_msec(time)
apr_int64_t apr_time_as_usec(time) or apr_time_as_3mos_usec(time)
apr_int64_t apr_time_as_nsec(time) or apr_time_as_2hrs_nsec(time)

apr_time_t apr_time_mmake(sec, msec)
apr_time_t apr_time_umake(sec, usec)
apr_time_t apr_time_nmake(sec, nsec)

apr_time_t apr_time_from_sec(sec)
apr_time_t apr_time_from_msec(msec) or apr_time_from_3mos_msec(msec)
apr_time_t apr_time_from_usec(usec) or apr_time_from_3mos_usec(usec)
apr_time_t apr_time_from_nsec(nsec) or apr_time_from_3mos_nsec(nsec)

The code follows, patch attached is hard to follow.  [Like my code isn't :o]

/* Number of binary microseconds per second is (2^20)
  * to keep the math fast and simple [binary arithmetic.]
  */
#define APR_BUSEC_BITS 20
#define APR_BUSEC_PER_SEC APR_TIME_C(2 ^ APR_BUSEC_BITS)

/* apr_time_sec_get returns 32 bits and is subject to the Y2038 bug
  * @see apr_time_as_sec for 64 bit resolution
  */
#define apr_time_sec_get(time) ((apr_int32_t)((time) >> APR_BUSEC_BITS))

/* These functions 'get' the xsec fractional component of the time.
  *
  * msec extraction won't overflow 32 bits so convert early,
  * while usec/nsec computations must be in all 64 bit math.
  */
#define apr_time_msec_get(time) \
     (((apr_int32_t)((time) & (APR_BUSEC_PER_SEC - 1)) * 1000) \
                                                    >> APR_BUSEC_BITS)

#define apr_time_usec_get(time) \
     ((apr_int32_t)((((time) & (APR_BUSEC_PER_SEC - 1)) \
                             * APR_TIME_C(1000000)) >> APR_BUSEC_BITS))

#define apr_time_nsec_get(time) \
     ((apr_int32_t)((((time) & (APR_BUSEC_PER_SEC - 1)) \
                             * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS))


/* apr_time_as_sec returns 64 bits and escapes the Y2038 bug
  * @see apr_time_sec_get for 32 bit resolution
  */
#define apr_time_as_sec(time) ((apr_int64_t)((time) >> APR_BUSEC_BITS))

/* These functions return the given time value, complete,
  * in the given resolution (not simply the fractional component)
  *
  * They carry no resolution penalty, and due to the binary math,
  * they suffer little performance penalty either.
  */
#define apr_time_as_msec(time) \
     (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
      + ((((apr_int32_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
          * 1000) >> APR_BUSEC_BITS))

#define apr_time_as_usec(time) \
     (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
      + ((((apr_int64_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
          * APR_TIME_C(1000000)) >> APR_BUSEC_BITS))

#define apr_time_as_nsec(time) \
     (((apr_int64_t)(time) >> APR_BUSEC_BITS) \
      + ((((apr_int64_t)(time) & (APR_BUSEC_PER_SEC - 1)) \
          * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS))

/* this computation is alright, but not great, we are limited to 272
  * years.  No Y2038 bug, but consider it an 'optimized form' for which
  * we have some loss of resolution.  Doing this in 32 bit signed math
  * would yield only 2 seconds, which is not worth implementing compared
  * to the existing apr_time_msec_get().
  */
#define apr_time_as_272yrs_msec(time) \
     (((apr_int64_t)(time) * APR_TIME_C(1000)) >> APR_BUSEC_BITS)

/* Another optimized form, we are limited to some 101 days.
  * Consider it a bleeding optimization with a great loss of resolution.
  */
#define apr_time_as_3mos_usec(time) \
     (((apr_int64_t)(time) * APR_TIME_C(1000000)) >> APR_BUSEC_BITS)

/* The final optimized form, we are limited to some 2.44 hours.
  * Use with extreme care.
  */
#define apr_time_as_2hrs_nsec(time) \
     (((apr_int64_t)(time) * APR_TIME_C(1000000000)) >> APR_BUSEC_BITS)


/* These have no loss of resolution if the 2nd xsec arg is < 1second
  */
#define apr_time_mmake(sec, msec) ((apr_time_t)(sec) << APR_BUSEC_BITS \
           + ((apr_time_t)(msec) << APR_BUSEC_BITS) / APR_TIME_C(1000))

#define apr_time_umake(sec, usec) ((apr_time_t)(sec) << APR_BUSEC_BITS \
           + ((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000))

#define apr_time_nmake(sec, nsec) ((apr_time_t)(sec) << APR_BUSEC_BITS \
           + ((apr_time_t)(nsec) << APR_BUSEC_BITS) / APR_TIME_C(1000000000))


#define apr_time_from_sec(sec)  ((apr_time_t)(sec) << APR_BUSEC_BITS)

/* These carry no resolution penalty, just a nasty performance penalty.
  */
#define apr_time_from_msec(msec) \
     ((((apr_time_t)(msec) / APR_TIME_C(1000)) << APR_BUSEC_BITS) \
      + ((((apr_time_t)(msec) % APR_TIME_C(1000)) << APR_BUSEC_BITS) \
         / APR_TIME_C(1000)))

#define apr_time_from_usec(usec) \
     ((((apr_time_t)(usec) / APR_TIME_C(1000000)) << APR_BUSEC_BITS) \
      + ((((apr_time_t)(usec) % APR_TIME_C(1000000)) << APR_BUSEC_BITS) \
         / APR_TIME_C(1000000)))

#define apr_time_from_nsec(nsec) \
     ((((apr_time_t)(nsec) / APR_TIME_C(1000000000)) << APR_BUSEC_BITS) \
      + ((((apr_time_t)(nsec) % APR_TIME_C(1000000000)) << APR_BUSEC_BITS) \
         / APR_TIME_C(1000000000)))

/* 97 day macros; you would expect these to be correct, until you
  * consider that the initial SHL reduces precision to 43 bits (signed)
  * of which 20 bits is the busecs.  23 remaining bits ~= 97 days.
  * The apr_time_xmake macros above doesn't suffer the problem, since
  * we presume that the xsec component is < 1 second... and the 'proper'
  * apr_time_from_xsec macros will split into integral and fractional
  * seconds while converting, so there is no unexpected loss of range.
  */
#define apr_time_from_3mos_msec(msec) \
     (((apr_time_t)(msec) << APR_BUSEC_BITS) / APR_TIME_C(1000))

#define apr_time_from_3mos_usec(usec) \
     (((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000))

#define apr_time_from_3mos_nsec(nsec) \
     (((apr_time_t)(usec) << APR_BUSEC_BITS) / APR_TIME_C(1000000000))

/* XXX These are ambiguous and dangerous.  The symbol names must be
  * deprecated to assure folks don't misuse them (_xsec_get vs _as_xsec)
  */
#define apr_time_sec apr_time_sec_get
#define apr_time_msec apr_time_msec_get
#define apr_time_usec apr_time_usec_get
#define apr_time_nsec apr_time_nsec_get

/* XXX Also dangerous, since folks might assume the literal meaning.
  * we have no need to define this constant anymore for library users
  */
#define APR_USEC_PER_SEC APR_BUSEC_PER_SEC

Mime
View raw message