Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals  

cache.c

00001  /*
00002   * share/cache.c : implements a cache  to speed up procedure  calls & variable
00003   *                 referencing (source)
00004   * 
00005   * Time-stamp: <2002-12-21 14:19:58 gseba>
00006   * 
00007   * Copyright (C) Sebastian Glita, email: gseba@users.sourceforge.net
00008   * 
00009   * This file is part of plint.
00010   * 
00011   * plint is free software; you can  redistribute it and/or modify it under the
00012   * terms of the  GNU General Public License as published  by the Free Software
00013   * Foundation; either version 2, or (at your option) any later version.
00014   *
00015   * plint  is distributed  in the  hope  that it  will be  useful, but  WITHOUT
00016   * ANY  WARRANTY; without  even  the implied  warranty  of MERCHANTABILITY  or
00017   * FITNESS FOR A  PARTICULAR PURLEVE.  See the GNU  General Public License for
00018   * more details.
00019   * 
00020   * You should  have received a  copy of the  GNU General Public  License along
00021   * with  plint; see  the file  COPYING.  If  not, write  to the  Free Software
00022   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA USA.
00023   *
00024   */
00025 
00026 #include "common.h"
00027 #include "cache.h"
00028 
00037 typedef struct _cache_entry
00038 {
00039 
00040   hashindex_t tag;              
00041   size_t lev;                   
00042   void * data;                  
00044 } cache_entry_t;
00045 
00050 struct _cache
00051 {
00052 
00053   struct _cache_entry * cache;  
00054   size_t size;                  
00055   size_t lru;                   
00056   size_t fill;                  
00057   cache_missfunc_t miss;        
00058   cache_invfunc_t inv;          
00060   int dis:1;                    
00062 #ifndef NDEBUG
00063   unsigned long hits;           
00064   unsigned long misses;         
00065   unsigned long invalidates;    
00066 #endif
00067 
00068 };
00069 
00070 
00071 
00076 static void cache_reset(cache_t cache) {
00077   size_t i;
00078 
00079   /* preconditions */
00080   cache->fill = 0;
00081   for (i = 0; i < cache->size; ++i)
00082     cache->cache[i].lev = i;
00083   cache->lru = 0;
00084 
00085 #ifndef NDEBUG
00086   cache->hits = 1;
00087   cache->misses = cache->invalidates = 0;
00088 #endif
00089 }
00090 
00100 void cache_init(cache_t * pcache, size_t size, cache_missfunc_t miss, cache_invfunc_t inv)
00101 {
00102   cache_t cache;
00103   cache = (cache_t)malloc(sizeof(*cache));
00104   cache->miss = miss;
00105   cache->inv = inv;
00106   cache->cache = (cache_entry_t *)malloc((cache->size = size) * sizeof(cache_entry_t));
00107   cache_reset(cache);
00108   cache_enable(cache);
00109 
00110   *pcache = cache;
00111 }
00112 
00119 void cache_finish(cache_t cache)
00120 {
00121   free(cache->cache);
00122   free(cache);
00123 }
00124 
00125 
00129 #define CACHE_UPDATE()                                  \
00130 {                                                       \
00131   size_t _i;                                            \
00132   for (_i = cache->fill; _i;)                           \
00133     if (ce[--_i].lev > lev && --ce[_i].lev == 0)        \
00134       cache->lru = _i;                                  \
00135 }
00136 
00137 
00141 static void * cache_hit(cache_t cache, size_t mru)
00142 {
00143   cache_entry_t * ce = cache->cache;
00144   size_t lev = ce[mru].lev;
00145   if (cache->fill == cache->size)
00146     CACHE_UPDATE();
00147   ce[mru].lev = cache->fill-1;
00148 
00149   return ce[mru].data;
00150 }
00151 
00159 void * cache_lookup(cache_t cache, hashindex_t tag, void * parm)
00160 {
00161   size_t i;
00162 
00163   if (cache->dis)
00164     return cache->miss(tag, parm);
00165 
00166   /* look it up, maybe it's already in cache ? */
00167   for (i = 0; i < cache->fill; ++i)
00168     if (HASH_INDEX_EQU(tag, cache->cache[i].tag))
00169       break; /* yes, i've been hit !!! */
00170   
00171   if (i == cache->fill)
00172     {
00173       /* no it's not in the cache, look it up trivially */
00174 #ifndef NDEBUG
00175       ++cache->misses;
00176 #endif
00177 
00178       if (i == cache->size)
00179         i = cache->lru;
00180       else
00181         ++cache->fill;
00182 
00183       cache->cache[i].data = cache->miss(cache->cache[i].tag = tag, parm);
00184     }
00185 #ifndef NDEBUG
00186   else
00187     ++cache->hits;
00188 #endif
00189 
00190   /* in the end, it's a hit */
00191   return cache_hit(cache, i);
00192 }
00193 
00200 int cache_invalidate(cache_t cache, void * parm)
00201 {
00202   int ret = 0;
00203   if (!cache->dis)
00204     {
00205       cache_entry_t * ce = cache->cache;
00206       size_t i, lev;
00207 
00208       /* once and for all invalidate */
00209       hashindex_t bad_tag;
00210       HASH_INDEX_DOBAD(bad_tag);
00211       if (cache->inv(&bad_tag, 0, parm))
00212         {
00213           cache_reset(cache);
00214           ret = !0;
00215         }
00216       else
00217         for (i = 0; i < cache->fill; ++i)
00218           if (cache->inv(&ce[i].tag, &ce[i].data, parm))
00219             {
00220               size_t j;
00221 
00222               lev = ce[i].lev;
00223               CACHE_UPDATE();
00224 
00225               --cache->fill;
00226 
00227               for (j = i; j < cache->fill; ++j)
00228                 ce[j] = ce[j+1];
00229 
00230               ce[j].lev = j;
00231 
00232               --i;
00233 
00234               ret = !0;
00235             }
00236     }
00237 
00238   return ret;
00239 }
00240 
00246 inline void cache_disable(cache_t cache) {
00247   cache->dis = !0;
00248 }
00249 
00255 inline void cache_enable(cache_t cache) {
00256   cache->dis = 0;
00257 }
00258 
00259 #ifndef NDEBUG
00260 
00269 void cache_status(cache_t cache, FILE * f, char const * name, int prec)
00270 {
00271   if (prec == 0)
00272     prec = 4;
00273   fprintf(f, "%s cache is %sabled: size %d, hits = %ld, misses = %ld, hit rate = %.*lf.", name,
00274           cache->dis ? "dis" : "en",
00275           cache->size,
00276           cache->hits,
00277           cache->misses,
00278           prec,
00279           (double)1.*cache->hits/(cache->hits+cache->misses));
00280 }
00281 #endif
00282 
00283 #undef CACHE_UPDATE
00284 

Generated on Thu Jan 9 19:02:37 2003 for plint by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002