00001 /* Part of the culibs project, <http://www.eideticdew.org/culibs/>. 00002 * Copyright (C) 2006--2007 Petter Urkedal <urkedal@nbi.dk> 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef CUFLOW_CACHE_H 00019 #define CUFLOW_CACHE_H 00020 00021 #include <cuflow/fwd.h> 00022 #include <cu/thread.h> 00023 #include <cu/clos.h> 00024 #include <cu/inherit.h> 00025 #include <cu/dlink.h> 00026 00027 CU_BEGIN_DECLARATIONS 00028 /** \defgroup cuflow_cache_h cuflow/cache.h: Function Call Cache (unfinished) 00029 ** @{ \ingroup cuflow_x_mod 00030 **/ 00031 00032 #define CUFLOWP_CACHE_LOG2_BIN_COUNT 5 00033 #define CUFLOWP_CACHE_BIN_COUNT (1 << CUFLOWP_CACHE_LOG2_BIN_COUNT) 00034 00035 /** Returns a function code identifying slot number \a index in a cache which 00036 ** takes a key of \a key_wsize words size. */ 00037 #define CUFLOW_FNCODE(index, key_wsize) (((index) << 16) + (key_wsize)) 00038 00039 /** The key size in words of \a code. */ 00040 #define CUFLOW_FNCODE_KEY_SIZEW(code) ((code) & 0xffff) 00041 00042 #define CUFLOW_FNCODE_SLOT(code) ((code) >> 16) 00043 00044 #define CUFLOWP_CACHEOBJ_HDR(obj) ((cuflowP_cacheobjhdr_t)(obj) - 1) 00045 00046 typedef struct cuflowP_cachebin *cuflowP_cachebin_t; 00047 typedef struct cuflow_cache *cuflow_cache_t; 00048 typedef struct cuflowP_cacheobjhdr *cuflowP_cacheobjhdr_t; 00049 typedef struct cuflow_cacheobj *cuflow_cacheobj_t; 00050 00051 struct cuflowP_cachebin 00052 { 00053 cu_mutex_t mutex; 00054 size_t cap; 00055 size_t size; 00056 size_t access_since_pruned; 00057 cuflow_cacheobj_t *link_arr; 00058 }; 00059 00060 struct cuflow_cache 00061 { 00062 cu_inherit (cu_dlink); 00063 cuflow_cacheconf_t conf; 00064 struct cuflowP_cachebin bin_arr[CUFLOWP_CACHE_BIN_COUNT]; 00065 cuflow_cacheobj_t (**fn_arr)(cuflow_cacheobj_t key); 00066 }; 00067 00068 struct cuflowP_cacheobjhdr 00069 { 00070 cuflow_cacheobj_t next; 00071 unsigned int access_ticks; 00072 unsigned long access_function; 00073 unsigned long gain; 00074 }; 00075 00076 /** The base struct for both cache keys and cache objects. Typically use is to 00077 ** \ref cu_inherit_h this in the cache key, and cu_inherit the cache key in 00078 ** the full cache object. This contains one field, \e fncode, which must be 00079 ** assigned an integer obtaind with \ref CUFLOW_FNCODE, which identifies the 00080 ** callback and key size. */ 00081 struct cuflow_cacheobj 00082 { 00083 /** The function code, identifying the slot number of the cache callback 00084 * and the size of the key, including this struct. */ 00085 cu_word_t fncode; 00086 }; 00087 00088 /** Creates a cache with a unique set of callbacks stored in \a fn_arr. 00089 ** Normally a cache is called at program initialisation and kept for the 00090 ** lifetime of the program, but if you want to despose of a cache, call \ref 00091 ** cuflow_cache_deinit, since \a cache will be linked into \a conf. */ 00092 void 00093 cuflow_cache_init(cuflow_cache_t cache, cuflow_cacheconf_t conf, 00094 cuflow_cacheobj_t (**fn_arr)(cuflow_cacheobj_t key)); 00095 00096 /** Unlink \a cache from it's configuration. */ 00097 void cuflow_cache_deinit(cuflow_cache_t cache); 00098 00099 /** Return a pointer into the data area of a newly allocated cache object. The 00100 ** cache callbacks must use this to allocate objects and must call \ref 00101 ** cuflow_cacheobj_set_gain before returning them. */ 00102 cuflow_cacheobj_t 00103 cuflow_cacheobj_alloc(size_t full_size, cuflow_cacheobj_t key); 00104 00105 /** Set the gain of \a obj to \a gain. The gain is an estimate of 00106 ** <i>C</i>/<i>S</i> where <i>C</i> is the cost of computing the retured 00107 ** object in CPU cycles, and <i>S</i> is the size of the returned object in 00108 ** bytes including a fixed overhead of about 5 words. The <i>C</i> may 00109 ** include cost of using other resources multiplied with suitable constants to 00110 ** make them cycle-equivanent according to the desired resource utilization. 00111 ** 00112 ** These quastities are hard to determine precisely. Available CPU clocks are 00113 ** typically not precise enough to measure <i>C</i>, and computing <i>S</i> 00114 ** may be expensive for tree-structures or even ambiguous when sharing is 00115 ** involved. Therefore, rule of thumb estimates will have to do. Some 00116 ** suggestions: 00117 ** 00118 ** - If the complexity of the computation is linear in the size of \a obj, 00119 ** then <i>C</i>/<i>S</i> can be taken to be a constant. Note that there is 00120 ** no need to know the size of \a obj, since it cancels out. 00121 ** - If the complexity of the computation is quadratic, make an estimate of 00122 ** the final size of \a obj and multiply with a constant to get \a gain. 00123 ** Assuming that the size can be computed in linear time, the real 00124 ** computiation will dominate for sufficiently large input. Alternatively, 00125 ** time the computation and use the square root to estimate the object size. 00126 ** If the time is not granular enough, then neglect the quadratic behaviour. 00127 **/ 00128 CU_SINLINE void 00129 cuflow_cacheobj_set_gain(cuflow_cacheobj_t obj, float gain) 00130 { CUFLOWP_CACHEOBJ_HDR(obj)->gain = gain; } 00131 00132 /** Return the computed object with key-part equal to \a key. \a key may be a 00133 ** stack object or static storage. The callback and key size is determined 00134 ** from \e fncode. The callback is only called if \a cache does not already 00135 ** contain the requested object. */ 00136 cuflow_cacheobj_t 00137 cuflow_cache_call(cuflow_cache_t cache, cu_word_t fncode, 00138 cuflow_cacheobj_t key); 00139 00140 /** Template macro for creating the type definitions of a cached function, 00141 ** suited for use with the \c cuflow_cachetab command. \a NAME is the 00142 ** function name to be passed as the first argument of the CACHENAME_call 00143 ** macro that is generated by <tt>cuflow_cachetab -p CACHENAME ...</tt>. */ 00144 #define cuflow_cached_edcl(NAME, key_struct, value_struct) \ 00145 struct NAME##_key \ 00146 { \ 00147 cu_inherit (cuflow_cacheobj); \ 00148 cuPP_splice key_struct \ 00149 }; \ 00150 struct NAME##_obj \ 00151 { \ 00152 struct NAME##_key key; \ 00153 cuPP_splice value_struct \ 00154 }; \ 00155 typedef struct NAME##_key NAME##_key_t; \ 00156 typedef struct NAME##_obj NAME##_obj_t 00157 00158 /** When cache header generated by \c cuflow_cachetab is included, this gives 00159 ** the function index of \a NAME. */ 00160 #define cuflow_cached_fncode(NAME) \ 00161 CUFLOW_FNCODE(NAME##_index, sizeof(NAME##_key_t)/sizeof(cu_word_t)); 00162 00163 /** This is the template for the prototype of the definition of the \a NAME 00164 ** cached function. This should be followed by a function body surrounded by 00165 ** <tt>{ }</tt>, which receives a parameter \e key. The function body shall 00166 ** return an object allocated with \ref cuflow_cached_new and tagged with \ref 00167 ** cuflow_cacheobj_set_gain. A previous \ref cuflow_cached_edcl must be 00168 ** issued. */ 00169 #define cuflow_cached_edef(NAME) \ 00170 NAME##_obj_t *NAME##_fn(NAME##_key_t *key) 00171 00172 /** Allocate an object suitable for returning from the cache function with name 00173 ** \a NAME. The returned value is a struct containing the members declared in 00174 ** the \e value_struct parameter of the corresponding \ref cuflow_cached_edcl. 00175 ** If \a extra_size is not 0, this number of extra bytes will be allocated 00176 ** after the \e value_struct fields. */ 00177 #define cuflow_cached_new(NAME, extra_size) \ 00178 ((NAME##_obj_t *) \ 00179 cuflow_cacheobj_alloc(sizeof(struct NAME##_obj) + (extra_size), \ 00180 (cuflow_cacheobj_t)(key))) 00181 00182 /** @} */ 00183 CU_END_DECLARATIONS 00184 00185 #endif