/[zanavi_public1]/navit/navit/cache.c
ZANavi

Contents of /navit/navit/cache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 27 - (show annotations) (download)
Mon Apr 9 21:27:36 2012 UTC (10 years, 7 months ago) by zoff99
File MIME type: text/plain
File size: 11022 byte(s)
lots of new stuff, tranlsations, bug fixes ...
1 /**
2 * ZANavi, Zoff Android Navigation system.
3 * Copyright (C) 2011-2012 Zoff <zoff@zoff.cc>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "glib_slice.h"
21 #ifdef DEBUG_CACHE
22 #include <stdio.h>
23 #endif
24 #include <string.h>
25 #include "debug.h"
26 #include "cache.h"
27
28 struct cache_entry
29 {
30 int usage;
31 int size;
32 struct cache_entry_list *where;
33 struct cache_entry *next;
34 struct cache_entry *prev;
35 int id[0];
36 };
37
38 struct cache_entry_list
39 {
40 struct cache_entry *first, *last;
41 int size;
42 };
43
44 struct cache
45 {
46 struct cache_entry_list t1, b1, t2, b2, *insert;
47 int size, id_size, entry_size;
48 int t1_target;
49 long misses;
50 long hits;
51 GHashTable *hash;
52 };
53
54 static void cache_entry_dump(struct cache *cache, struct cache_entry *entry)
55 {
56 int i, size;
57 //dbg(0,"Usage: %d size %d\n",entry->usage, entry->size);
58 if (cache)
59 size = cache->id_size;
60 else
61 size = 5;
62 for (i = 0; i < size; i++)
63 {
64 dbg(0, "0x%x\n", entry->id[i]);
65 }
66 }
67
68 static void cache_list_dump(char *str, struct cache *cache, struct cache_entry_list *list)
69 {
70 struct cache_entry *first = list->first;
71 dbg(0, "dump %s %d\n", str, list->size);
72 while (first)
73 {
74 cache_entry_dump(cache, first);
75 first = first->next;
76 }
77 }
78
79 static guint cache_hash4(gconstpointer key)
80 {
81 int *id = (int *) key;
82 return id[0];
83 }
84
85 static guint cache_hash20(gconstpointer key)
86 {
87 int *id = (int *) key;
88 return id[0] ^ id[1] ^ id[2] ^ id[3] ^ id[4];
89 }
90
91 static gboolean cache_equal4(gconstpointer a, gconstpointer b)
92 {
93 int *ida = (int *) a;
94 int *idb = (int *) b;
95
96 return ida[0] == idb[0];
97 }
98
99 static gboolean cache_equal20(gconstpointer a, gconstpointer b)
100 {
101 int *ida = (int *) a;
102 int *idb = (int *) b;
103
104 return (ida[0] == idb[0] && ida[1] == idb[1] && ida[2] == idb[2] && ida[3] == idb[3] && ida[4] == idb[4]);
105 }
106
107 struct cache *
108 cache_new(int id_size, int size)
109 {
110 struct cache *cache=g_new0(struct cache, 1);
111
112 cache->id_size = id_size / 4;
113 cache->entry_size = cache->id_size * sizeof(int) + sizeof(struct cache_entry);
114 cache->size = size;
115
116 dbg(0, "_c size=%d\n", size);
117
118 switch (id_size)
119 {
120 case 4:
121 cache->hash = g_hash_table_new(cache_hash4, cache_equal4);
122 break;
123 case 20:
124 cache->hash = g_hash_table_new(cache_hash20, cache_equal20);
125 break;
126 default:
127 dbg(0, "cache with id_size of %d not supported\n", id_size);
128 g_free(cache);
129 cache = NULL;
130 }
131 return cache;
132 }
133
134 static void cache_insert_mru(struct cache *cache, struct cache_entry_list *list, struct cache_entry *entry)
135 {
136 entry->prev = NULL;
137 entry->next = list->first;
138 entry->where = list;
139 if (entry->next)
140 entry->next->prev = entry;
141 list->first = entry;
142 if (!list->last)
143 list->last = entry;
144 list->size += entry->size;
145 if (cache)
146 g_hash_table_insert(cache->hash, (gpointer) entry->id, entry);
147 }
148
149 static void cache_remove_from_list(struct cache_entry_list *list, struct cache_entry *entry)
150 {
151 if (entry->prev)
152 entry->prev->next = entry->next;
153 else
154 list->first = entry->next;
155 if (entry->next)
156 entry->next->prev = entry->prev;
157 else
158 list->last = entry->prev;
159 list->size -= entry->size;
160 }
161
162 static void cache_remove(struct cache *cache, struct cache_entry *entry)
163 {
164 // dbg(1,"remove 0x%x 0x%x 0x%x 0x%x 0x%x\n", entry->id[0], entry->id[1], entry->id[2], entry->id[3], entry->id[4]);
165 g_hash_table_remove(cache->hash, (gpointer)(entry->id));
166 g_slice_free1(entry->size, entry);
167 }
168
169 static struct cache_entry *
170 cache_remove_lru_helper(struct cache_entry_list *list)
171 {
172 struct cache_entry *last = list->last;
173 if (!last)
174 return NULL;
175 list->last = last->prev;
176 if (last->prev)
177 last->prev->next = NULL;
178 else
179 list->first = NULL;
180 list->size -= last->size;
181 return last;
182 }
183
184 static struct cache_entry *
185 cache_remove_lru(struct cache *cache, struct cache_entry_list *list)
186 {
187 struct cache_entry *last;
188 int seen = 0;
189 while (list->last && list->last->usage && seen < list->size)
190 {
191 last = cache_remove_lru_helper(list);
192 cache_insert_mru(NULL, list, last);
193 seen += last->size;
194 }
195 last = list->last;
196 if (!last || last->usage || seen >= list->size)
197 {
198 return NULL;
199 }
200 //dbg(1,"removing %d\n", last->id[0]);
201 cache_remove_lru_helper(list);
202 if (cache)
203 {
204 cache_remove(cache, last);
205 return NULL;
206 }
207 return last;
208 }
209
210 void *
211 cache_entry_new(struct cache *cache, void *id, int size)
212 {
213 struct cache_entry *ret;
214 size += cache->entry_size;
215 cache->misses += size;
216 ret = (struct cache_entry *) g_slice_alloc0(size);
217 ret->size = size;
218 ret->usage = 1;
219 memcpy(ret->id, id, cache->id_size * sizeof(int));
220 return &ret->id[cache->id_size];
221 }
222
223 void cache_entry_destroy(struct cache *cache, void *data)
224 {
225 struct cache_entry *entry = (struct cache_entry *) ((char *) data - cache->entry_size);
226 // dbg(1,"destroy 0x%x 0x%x 0x%x 0x%x 0x%x\n", entry->id[0], entry->id[1], entry->id[2], entry->id[3], entry->id[4]);
227 entry->usage--;
228 }
229
230 static struct cache_entry *
231 cache_trim(struct cache *cache, struct cache_entry *entry)
232 {
233 struct cache_entry *new_entry;
234 //dbg(1,"trim 0x%x 0x%x 0x%x 0x%x 0x%x\n", entry->id[0], entry->id[1], entry->id[2], entry->id[3], entry->id[4]);
235 //dbg(1,"Trim %x from %d -> %d\n", entry->id[0], entry->size, cache->size);
236 if (cache->entry_size < entry->size)
237 {
238 g_hash_table_remove(cache->hash, (gpointer)(entry->id));
239
240 new_entry = g_slice_alloc0(cache->entry_size);
241 memcpy(new_entry, entry, cache->entry_size);
242 g_slice_free1(entry->size, entry);
243 new_entry->size = cache->entry_size;
244
245 g_hash_table_insert(cache->hash, (gpointer) new_entry->id, new_entry);
246 }
247 else
248 {
249 new_entry = entry;
250 }
251
252 return new_entry;
253 }
254
255 static struct cache_entry *
256 cache_move(struct cache *cache, struct cache_entry_list *old, struct cache_entry_list *new)
257 {
258 struct cache_entry *entry;
259 entry = cache_remove_lru(NULL, old);
260 if (!entry)
261 return NULL;
262 entry = cache_trim(cache, entry);
263 cache_insert_mru(NULL, new, entry);
264 return entry;
265 }
266
267 static int cache_replace(struct cache *cache)
268 {
269 if (cache->t1.size >= MAX(1, cache->t1_target))
270 {
271 //dbg(1,"replace 12\n");
272 if (!cache_move(cache, &cache->t1, &cache->b1))
273 cache_move(cache, &cache->t2, &cache->b2);
274 }
275 else
276 {
277 //dbg(1,"replace t2\n");
278 if (!cache_move(cache, &cache->t2, &cache->b2))
279 cache_move(cache, &cache->t1, &cache->b1);
280 }
281 #if 0
282 if (! entry)
283 {
284 cache_dump(cache);
285 exit(0);
286 }
287 #endif
288 return 1;
289 }
290
291 void cache_flush(struct cache *cache, void *id)
292 {
293 struct cache_entry *entry = g_hash_table_lookup(cache->hash, id);
294 if (entry)
295 {
296 cache_remove_from_list(entry->where, entry);
297 cache_remove(cache, entry);
298 }
299 }
300
301 void cache_flush_data(struct cache *cache, void *data)
302 {
303 struct cache_entry *entry = (struct cache_entry *) ((char *) data - cache->entry_size);
304 if (entry)
305 {
306 cache_remove_from_list(entry->where, entry);
307 cache_remove(cache, entry);
308 }
309 }
310
311 void *
312 cache_lookup(struct cache *cache, void *id)
313 {
314 struct cache_entry *entry;
315
316 //dbg(1,"get %d\n", ((int *)id)[0]);
317 entry = g_hash_table_lookup(cache->hash, id);
318 if (entry == NULL)
319 {
320 cache->insert = &cache->t1;
321 #ifdef DEBUG_CACHE
322 fprintf(stderr,"-");
323 #endif
324 //dbg(1,"not in cache\n");
325 return NULL;
326 }
327
328 // dbg(1,"found 0x%x 0x%x 0x%x 0x%x 0x%x\n", entry->id[0], entry->id[1], entry->id[2], entry->id[3], entry->id[4]);
329 if (entry->where == &cache->t1 || entry->where == &cache->t2)
330 {
331 cache->hits += entry->size;
332 #ifdef DEBUG_CACHE
333 if (entry->where == &cache->t1)
334 {
335 fprintf(stderr,"h");
336 }
337 else
338 {
339 fprintf(stderr,"H");
340 }
341 #endif
342 // dbg(1,"in cache %s\n", entry->where == &cache->t1 ? "T1" : "T2");
343 cache_remove_from_list(entry->where, entry);
344 cache_insert_mru(NULL, &cache->t2, entry);
345 entry->usage++;
346 return &entry->id[cache->id_size];
347 }
348 else
349 {
350 if (entry->where == &cache->b1)
351 {
352 #ifdef DEBUG_CACHE
353 fprintf(stderr,"m");
354 #endif
355 //dbg(1,"in phantom cache B1\n");
356 cache->t1_target = MIN(cache->t1_target + MAX(cache->b2.size / cache->b1.size, 1), cache->size);
357 cache_remove_from_list(&cache->b1, entry);
358 }
359 else if (entry->where == &cache->b2)
360 {
361 #ifdef DEBUG_CACHE
362 fprintf(stderr,"M");
363 #endif
364 //dbg(1,"in phantom cache B2\n");
365 cache->t1_target = MAX(cache->t1_target - MAX(cache->b1.size / cache->b2.size, 1), 0);
366 cache_remove_from_list(&cache->b2, entry);
367 }
368 else
369 {
370 //dbg(0,"**ERROR** invalid where\n");
371 }
372 cache_replace(cache);
373 cache_remove(cache, entry);
374 cache->insert = &cache->t2;
375 return NULL;
376 }
377 }
378
379 void cache_insert(struct cache *cache, void *data)
380 {
381 struct cache_entry *entry = (struct cache_entry *) ((char *) data - cache->entry_size);
382 //dbg(1,"insert 0x%x 0x%x 0x%x 0x%x 0x%x\n", entry->id[0], entry->id[1], entry->id[2], entry->id[3], entry->id[4]);
383 if (cache->insert == &cache->t1)
384 {
385 if (cache->t1.size + cache->b1.size >= cache->size)
386 {
387 if (cache->t1.size < cache->size)
388 {
389 cache_remove_lru(cache, &cache->b1);
390 cache_replace(cache);
391 }
392 else
393 {
394 cache_remove_lru(cache, &cache->t1);
395 }
396 }
397 else
398 {
399 if (cache->t1.size + cache->t2.size + cache->b1.size + cache->b2.size >= cache->size)
400 {
401 if (cache->t1.size + cache->t2.size + cache->b1.size + cache->b2.size >= 2 * cache->size)
402 cache_remove_lru(cache, &cache->b2);
403 cache_replace(cache);
404 }
405 }
406 }
407 cache_insert_mru(cache, cache->insert, entry);
408 }
409
410 void *
411 cache_insert_new(struct cache *cache, void *id, int size)
412 {
413 void *data = cache_entry_new(cache, id, size);
414 cache_insert(cache, data);
415 return data;
416 }
417
418 void cache_stats(struct cache *cache)
419 {
420 unsigned long c_ratio = 0;
421 if ((cache->hits + cache->misses) > 0)
422 {
423 c_ratio = (long) (cache->hits) * (long) (100L);
424 //dbg(0,"1 c_ratio=%lu\n", c_ratio);
425 c_ratio = c_ratio / (long) (cache->hits + cache->misses);
426 //dbg(0,"2 c_ratio=%lu\n", c_ratio);
427
428 dbg(0, "hits %d misses %lu hitratio %d size %d entry_size %d id_size %d T1 target %d\n", cache->hits, cache->misses, c_ratio, cache->size, cache->entry_size, cache->id_size, cache->t1_target);
429 // dbg(0,"T1:%d B1:%d T2:%d B2:%d\n", cache->t1.size, cache->b1.size, cache->t2.size, cache->b2.size);
430
431 // if numbers are too big, reset them
432 if ((cache->hits > 1000000000) || (cache->misses > 1000000000))
433 {
434 cache->hits = 0;
435 cache->misses = 0;
436 }
437 }
438 }
439
440 void cache_dump(struct cache *cache)
441 {
442 struct cache_entry *first;
443 first = cache->t1.first;
444 cache_stats(cache);
445 cache_list_dump("T1", cache, &cache->t1);
446 cache_list_dump("B1", cache, &cache->b1);
447 cache_list_dump("T2", cache, &cache->t2);
448 cache_list_dump("B2", cache, &cache->b2);
449 dbg(0, "dump end\n");
450 }
451

   
Visit the ZANavi Wiki