00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
00167 for (i = 0; i < cache->fill; ++i)
00168 if (HASH_INDEX_EQU(tag, cache->cache[i].tag))
00169 break;
00170
00171 if (i == cache->fill)
00172 {
00173
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
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
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