1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2008 VMware, Inc. 4848b8605Smrg * All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the 8848b8605Smrg * "Software"), to deal in the Software without restriction, including 9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to 11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 12848b8605Smrg * the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice (including the 15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions 16848b8605Smrg * of the Software. 17848b8605Smrg * 18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25848b8605Smrg * 26848b8605Smrg **************************************************************************/ 27848b8605Smrg 28848b8605Smrg/** 29848b8605Smrg * @file 30848b8605Smrg * Improved cache implementation. 31848b8605Smrg * 32848b8605Smrg * Fixed size array with linear probing on collision and LRU eviction 33848b8605Smrg * on full. 34848b8605Smrg * 35848b8605Smrg * @author Jose Fonseca <jfonseca@vmware.com> 36848b8605Smrg */ 37848b8605Smrg 38848b8605Smrg 39848b8605Smrg#include "pipe/p_compiler.h" 40848b8605Smrg#include "util/u_debug.h" 41848b8605Smrg 42848b8605Smrg#include "util/u_math.h" 43848b8605Smrg#include "util/u_memory.h" 44848b8605Smrg#include "util/u_cache.h" 45b8e80941Smrg#include "util/simple_list.h" 46848b8605Smrg 47848b8605Smrg 48848b8605Smrgstruct util_cache_entry 49848b8605Smrg{ 50848b8605Smrg enum { EMPTY = 0, FILLED, DELETED } state; 51848b8605Smrg uint32_t hash; 52848b8605Smrg 53848b8605Smrg struct util_cache_entry *next; 54848b8605Smrg struct util_cache_entry *prev; 55848b8605Smrg 56848b8605Smrg void *key; 57848b8605Smrg void *value; 58848b8605Smrg 59848b8605Smrg#ifdef DEBUG 60848b8605Smrg unsigned count; 61848b8605Smrg#endif 62848b8605Smrg}; 63848b8605Smrg 64848b8605Smrg 65848b8605Smrgstruct util_cache 66848b8605Smrg{ 67848b8605Smrg /** Hash function */ 68848b8605Smrg uint32_t (*hash)(const void *key); 69848b8605Smrg 70848b8605Smrg /** Compare two keys */ 71848b8605Smrg int (*compare)(const void *key1, const void *key2); 72848b8605Smrg 73848b8605Smrg /** Destroy a (key, value) pair */ 74848b8605Smrg void (*destroy)(void *key, void *value); 75848b8605Smrg 76b8e80941Smrg /** Max entries in the cache */ 77848b8605Smrg uint32_t size; 78848b8605Smrg 79b8e80941Smrg /** Array [size] of entries */ 80848b8605Smrg struct util_cache_entry *entries; 81848b8605Smrg 82b8e80941Smrg /** Number of entries in the cache */ 83848b8605Smrg unsigned count; 84b8e80941Smrg 85b8e80941Smrg /** Head of list, sorted from Least-recently used to Most-recently used */ 86848b8605Smrg struct util_cache_entry lru; 87848b8605Smrg}; 88848b8605Smrg 89b8e80941Smrg 90848b8605Smrgstatic void 91848b8605Smrgensure_sanity(const struct util_cache *cache); 92848b8605Smrg 93848b8605Smrg#define CACHE_DEFAULT_ALPHA 2 94848b8605Smrg 95b8e80941Smrg/** 96b8e80941Smrg * Create a new cache with 'size' entries. Also provide functions for 97b8e80941Smrg * hashing keys, comparing keys and destroying (key,value) pairs. 98b8e80941Smrg */ 99848b8605Smrgstruct util_cache * 100848b8605Smrgutil_cache_create(uint32_t (*hash)(const void *key), 101848b8605Smrg int (*compare)(const void *key1, const void *key2), 102848b8605Smrg void (*destroy)(void *key, void *value), 103848b8605Smrg uint32_t size) 104848b8605Smrg{ 105848b8605Smrg struct util_cache *cache; 106848b8605Smrg 107848b8605Smrg cache = CALLOC_STRUCT(util_cache); 108b8e80941Smrg if (!cache) 109848b8605Smrg return NULL; 110848b8605Smrg 111848b8605Smrg cache->hash = hash; 112848b8605Smrg cache->compare = compare; 113848b8605Smrg cache->destroy = destroy; 114848b8605Smrg 115848b8605Smrg make_empty_list(&cache->lru); 116848b8605Smrg 117848b8605Smrg size *= CACHE_DEFAULT_ALPHA; 118848b8605Smrg cache->size = size; 119848b8605Smrg 120848b8605Smrg cache->entries = CALLOC(size, sizeof(struct util_cache_entry)); 121b8e80941Smrg if (!cache->entries) { 122848b8605Smrg FREE(cache); 123848b8605Smrg return NULL; 124848b8605Smrg } 125848b8605Smrg 126848b8605Smrg ensure_sanity(cache); 127848b8605Smrg return cache; 128848b8605Smrg} 129848b8605Smrg 130848b8605Smrg 131b8e80941Smrg/** 132b8e80941Smrg * Try to find a cache entry, given the key and hash of the key. 133b8e80941Smrg */ 134848b8605Smrgstatic struct util_cache_entry * 135848b8605Smrgutil_cache_entry_get(struct util_cache *cache, 136848b8605Smrg uint32_t hash, 137848b8605Smrg const void *key) 138848b8605Smrg{ 139848b8605Smrg struct util_cache_entry *first_unfilled = NULL; 140848b8605Smrg uint32_t index = hash % cache->size; 141848b8605Smrg uint32_t probe; 142848b8605Smrg 143848b8605Smrg /* Probe until we find either a matching FILLED entry or an EMPTY 144848b8605Smrg * slot (which has never been occupied). 145848b8605Smrg * 146848b8605Smrg * Deleted or non-matching slots are not indicative of completion 147848b8605Smrg * as a previous linear probe for the same key could have continued 148848b8605Smrg * past this point. 149848b8605Smrg */ 150848b8605Smrg for (probe = 0; probe < cache->size; probe++) { 151848b8605Smrg uint32_t i = (index + probe) % cache->size; 152848b8605Smrg struct util_cache_entry *current = &cache->entries[i]; 153848b8605Smrg 154848b8605Smrg if (current->state == FILLED) { 155848b8605Smrg if (current->hash == hash && 156848b8605Smrg cache->compare(key, current->key) == 0) 157848b8605Smrg return current; 158848b8605Smrg } 159848b8605Smrg else { 160848b8605Smrg if (!first_unfilled) 161848b8605Smrg first_unfilled = current; 162848b8605Smrg 163848b8605Smrg if (current->state == EMPTY) 164848b8605Smrg return first_unfilled; 165848b8605Smrg } 166848b8605Smrg } 167848b8605Smrg 168848b8605Smrg return NULL; 169848b8605Smrg} 170848b8605Smrg 171b8e80941Smrgstatic inline void 172848b8605Smrgutil_cache_entry_destroy(struct util_cache *cache, 173848b8605Smrg struct util_cache_entry *entry) 174848b8605Smrg{ 175848b8605Smrg void *key = entry->key; 176848b8605Smrg void *value = entry->value; 177848b8605Smrg 178848b8605Smrg entry->key = NULL; 179848b8605Smrg entry->value = NULL; 180848b8605Smrg 181848b8605Smrg if (entry->state == FILLED) { 182848b8605Smrg remove_from_list(entry); 183848b8605Smrg cache->count--; 184848b8605Smrg 185b8e80941Smrg if (cache->destroy) 186848b8605Smrg cache->destroy(key, value); 187848b8605Smrg 188848b8605Smrg entry->state = DELETED; 189848b8605Smrg } 190848b8605Smrg} 191848b8605Smrg 192848b8605Smrg 193b8e80941Smrg/** 194b8e80941Smrg * Insert an entry in the cache, given the key and value. 195b8e80941Smrg */ 196848b8605Smrgvoid 197848b8605Smrgutil_cache_set(struct util_cache *cache, 198848b8605Smrg void *key, 199848b8605Smrg void *value) 200848b8605Smrg{ 201848b8605Smrg struct util_cache_entry *entry; 202848b8605Smrg uint32_t hash; 203848b8605Smrg 204848b8605Smrg assert(cache); 205848b8605Smrg if (!cache) 206848b8605Smrg return; 207848b8605Smrg hash = cache->hash(key); 208848b8605Smrg entry = util_cache_entry_get(cache, hash, key); 209848b8605Smrg if (!entry) 210848b8605Smrg entry = cache->lru.prev; 211848b8605Smrg 212848b8605Smrg if (cache->count >= cache->size / CACHE_DEFAULT_ALPHA) 213848b8605Smrg util_cache_entry_destroy(cache, cache->lru.prev); 214848b8605Smrg 215848b8605Smrg util_cache_entry_destroy(cache, entry); 216848b8605Smrg 217848b8605Smrg#ifdef DEBUG 218848b8605Smrg ++entry->count; 219848b8605Smrg#endif 220848b8605Smrg 221848b8605Smrg entry->key = key; 222848b8605Smrg entry->hash = hash; 223848b8605Smrg entry->value = value; 224848b8605Smrg entry->state = FILLED; 225848b8605Smrg insert_at_head(&cache->lru, entry); 226848b8605Smrg cache->count++; 227848b8605Smrg 228848b8605Smrg ensure_sanity(cache); 229848b8605Smrg} 230848b8605Smrg 231848b8605Smrg 232b8e80941Smrg/** 233b8e80941Smrg * Search the cache for an entry with the given key. Return the corresponding 234b8e80941Smrg * value or NULL if not found. 235b8e80941Smrg */ 236848b8605Smrgvoid * 237848b8605Smrgutil_cache_get(struct util_cache *cache, 238848b8605Smrg const void *key) 239848b8605Smrg{ 240848b8605Smrg struct util_cache_entry *entry; 241848b8605Smrg uint32_t hash; 242848b8605Smrg 243848b8605Smrg assert(cache); 244848b8605Smrg if (!cache) 245848b8605Smrg return NULL; 246848b8605Smrg hash = cache->hash(key); 247848b8605Smrg entry = util_cache_entry_get(cache, hash, key); 248848b8605Smrg if (!entry) 249848b8605Smrg return NULL; 250848b8605Smrg 251848b8605Smrg if (entry->state == FILLED) 252848b8605Smrg move_to_head(&cache->lru, entry); 253848b8605Smrg 254848b8605Smrg return entry->value; 255848b8605Smrg} 256848b8605Smrg 257848b8605Smrg 258b8e80941Smrg/** 259b8e80941Smrg * Remove all entries from the cache. The 'destroy' function will be called 260b8e80941Smrg * for each entry's (key, value). 261b8e80941Smrg */ 262848b8605Smrgvoid 263848b8605Smrgutil_cache_clear(struct util_cache *cache) 264848b8605Smrg{ 265848b8605Smrg uint32_t i; 266848b8605Smrg 267848b8605Smrg assert(cache); 268848b8605Smrg if (!cache) 269848b8605Smrg return; 270848b8605Smrg 271b8e80941Smrg for (i = 0; i < cache->size; ++i) { 272848b8605Smrg util_cache_entry_destroy(cache, &cache->entries[i]); 273848b8605Smrg cache->entries[i].state = EMPTY; 274848b8605Smrg } 275848b8605Smrg 276848b8605Smrg assert(cache->count == 0); 277848b8605Smrg assert(is_empty_list(&cache->lru)); 278848b8605Smrg ensure_sanity(cache); 279848b8605Smrg} 280848b8605Smrg 281848b8605Smrg 282b8e80941Smrg/** 283b8e80941Smrg * Destroy the cache and all entries. 284b8e80941Smrg */ 285848b8605Smrgvoid 286848b8605Smrgutil_cache_destroy(struct util_cache *cache) 287848b8605Smrg{ 288848b8605Smrg assert(cache); 289848b8605Smrg if (!cache) 290848b8605Smrg return; 291848b8605Smrg 292848b8605Smrg#ifdef DEBUG 293b8e80941Smrg if (cache->count >= 20*cache->size) { 294848b8605Smrg /* Normal approximation of the Poisson distribution */ 295848b8605Smrg double mean = (double)cache->count/(double)cache->size; 296848b8605Smrg double stddev = sqrt(mean); 297848b8605Smrg unsigned i; 298b8e80941Smrg for (i = 0; i < cache->size; ++i) { 299848b8605Smrg double z = fabs(cache->entries[i].count - mean)/stddev; 300848b8605Smrg /* This assert should not fail 99.9999998027% of the times, unless 301848b8605Smrg * the hash function is a poor one */ 302848b8605Smrg assert(z <= 6.0); 303848b8605Smrg } 304848b8605Smrg } 305848b8605Smrg#endif 306848b8605Smrg 307848b8605Smrg util_cache_clear(cache); 308848b8605Smrg 309848b8605Smrg FREE(cache->entries); 310848b8605Smrg FREE(cache); 311848b8605Smrg} 312848b8605Smrg 313848b8605Smrg 314b8e80941Smrg/** 315b8e80941Smrg * Remove the cache entry which matches the given key. 316b8e80941Smrg */ 317848b8605Smrgvoid 318848b8605Smrgutil_cache_remove(struct util_cache *cache, 319848b8605Smrg const void *key) 320848b8605Smrg{ 321848b8605Smrg struct util_cache_entry *entry; 322848b8605Smrg uint32_t hash; 323848b8605Smrg 324848b8605Smrg assert(cache); 325848b8605Smrg if (!cache) 326848b8605Smrg return; 327848b8605Smrg 328848b8605Smrg hash = cache->hash(key); 329848b8605Smrg 330848b8605Smrg entry = util_cache_entry_get(cache, hash, key); 331848b8605Smrg if (!entry) 332848b8605Smrg return; 333848b8605Smrg 334848b8605Smrg if (entry->state == FILLED) 335848b8605Smrg util_cache_entry_destroy(cache, entry); 336848b8605Smrg 337848b8605Smrg ensure_sanity(cache); 338848b8605Smrg} 339848b8605Smrg 340848b8605Smrg 341848b8605Smrgstatic void 342848b8605Smrgensure_sanity(const struct util_cache *cache) 343848b8605Smrg{ 344848b8605Smrg#ifdef DEBUG 345848b8605Smrg unsigned i, cnt = 0; 346848b8605Smrg 347848b8605Smrg assert(cache); 348848b8605Smrg for (i = 0; i < cache->size; i++) { 349848b8605Smrg struct util_cache_entry *header = &cache->entries[i]; 350848b8605Smrg 351848b8605Smrg assert(header); 352848b8605Smrg assert(header->state == FILLED || 353848b8605Smrg header->state == EMPTY || 354848b8605Smrg header->state == DELETED); 355848b8605Smrg if (header->state == FILLED) { 356848b8605Smrg cnt++; 357848b8605Smrg assert(header->hash == cache->hash(header->key)); 358848b8605Smrg } 359848b8605Smrg } 360848b8605Smrg 361848b8605Smrg assert(cnt == cache->count); 362848b8605Smrg assert(cache->size >= cnt); 363848b8605Smrg 364848b8605Smrg if (cache->count == 0) { 365848b8605Smrg assert (is_empty_list(&cache->lru)); 366848b8605Smrg } 367848b8605Smrg else { 368848b8605Smrg struct util_cache_entry *header = cache->lru.next; 369848b8605Smrg 370848b8605Smrg assert (header); 371848b8605Smrg assert (!is_empty_list(&cache->lru)); 372848b8605Smrg 373848b8605Smrg for (i = 0; i < cache->count; i++) 374848b8605Smrg header = header->next; 375848b8605Smrg 376848b8605Smrg assert(header == &cache->lru); 377848b8605Smrg } 378848b8605Smrg#endif 379848b8605Smrg 380848b8605Smrg (void)cache; 381848b8605Smrg} 382