Is this the right place to be caching, or should this become a straightforward
optimization to apr's time.c functions?  I'd think the advantages are many for
keeping 15 current seconds in apr, and would pay off across the board.  Within
apr, we can always recalculate just the ms as well, for fun.

Bill

----- Original Message ----- 
From: "Brian Pane" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Sunday, September 09, 2001 9:46 PM
Subject: [PATCH] performance patch for mod_log_config


> The call to apr_explode_localtime() in mod_log_config is one of the more
> expensive operations in the httpd.  This patch attempts to reduce the
> overhead by caching the result.
> 
> --Brian
> 
> 
> Index: modules/loggers/mod_log_config.c
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/modules/loggers/mod_log_config.c,v
> retrieving revision 1.68
> diff -r1.68 mod_log_config.c
> 447a448,498
>  >
>  > /* Cache of expanded timestamps:
>  >  *  Because apr_explode_localtime is an expensive function call,
>  >  *  we cache the exploded time and re-use it for the rest of the
>  >  *  current second.
>  >  */
>  >
>  > struct exploded_time_cache_element {
>  >     apr_int64_t t;
>  >     apr_exploded_time_t xt;
>  > };
>  >
>  > #define TIME_CACHE_SIZE 16
>  > static struct exploded_time_cache_element 
> exploded_time_cache[TIME_CACHE_SIZE];
>  >
>  > static void cached_explode_localtime(apr_exploded_time_t *xt, 
> apr_time_t t)
>  > {
>  >     apr_int64_t seconds = t / APR_USEC_PER_SEC;
>  >     struct exploded_time_cache_element *cache =
>  >         &(exploded_time_cache[seconds % TIME_CACHE_SIZE]);
>  >
>  >     /* The cache is implemented as a ring buffer.  Each second,
>  >      * it uses a different element in the buffer.  The timestamp
>  >      * in the element indicates whether the element contains the
>  >      * exploded time for the current second (vs the time
>  >      * 'now - TIME_CACHE_SIZE' seconds ago).  If the cached
>  >      * value is for the current time, we use it.  Otherwise,
>  >      * we compute the apr_exploded_time_t and store it in this
>  >      * cache element. Note that the timestamp in the cache
>  >      * element is updated only after the exploded time.  Thus
>  >      * if two threads hit this cache element simultaneously
>  >      * at the start of a new second, they'll both explode the
>  >      * time and store it.  I.e., the writers will collide, but
>  >      * they'll be writing the same value.
>  >      */
>  >     if (cache->t >= seconds) {
>  >         /* Note: If this memcpy ever takes more than TIME_CACHE_SIZE
>  >          * seconds, the value will be unpredictable (because this
>  >          * bucket in the ring buffer will have been recycled).
>  >          * This memcpy should never take multiple seconds, but to
>  >          * be safe we use a relatively large value for TIME_CACHE_SIZE.
>  >          */
>  >         memcpy(xt, &(cache->xt), sizeof(apr_exploded_time_t));
>  >     }
>  >     else {
>  >         apr_explode_localtime(xt, t);
>  >         memcpy(&(cache->xt), xt, sizeof(apr_exploded_time_t));
>  >         cache->t = seconds;
>  >     }
>  > }
>  >
> 466c517
> <     apr_explode_localtime(&xt, apr_time_now());
> ---
>  >     cached_explode_localtime(&xt, apr_time_now());
> 468c519
> <     apr_explode_localtime(&xt, r->request_time);
> ---
>  >     cached_explode_localtime(&xt, r->request_time);
> 
> 
> 
> 
> 
> 
> 
> 

Reply via email to