summaryrefslogtreecommitdiff
path: root/image
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2011-09-06 22:01:47 +0000
committerVincent Sanders <vince@netsurf-browser.org>2011-09-06 22:01:47 +0000
commite471efa0967586c7a7ab1060572ebcec0b02269f (patch)
tree7b58538cd547b21e4d143560fde252132ea7ff6e /image
parent95dfffb3dfcb060682c9e47f557a534369d23904 (diff)
downloadnetsurf-e471efa0967586c7a7ab1060572ebcec0b02269f.tar.gz
netsurf-e471efa0967586c7a7ab1060572ebcec0b02269f.tar.bz2
make the image_cache cleaner less brain dead
svn path=/trunk/netsurf/; revision=12766
Diffstat (limited to 'image')
-rw-r--r--image/image.c26
-rw-r--r--image/image_cache.c153
-rw-r--r--image/image_cache.h21
3 files changed, 139 insertions, 61 deletions
diff --git a/image/image.c b/image/image.c
index fb8197b28..d65ae8a67 100644
--- a/image/image.c
+++ b/image/image.c
@@ -38,6 +38,22 @@
#include "utils/config.h"
+/** low water mark for speculative pre-conversion */
+
+/* Experimenting by visiting every page from default page in order and
+ * then netsurf homepage
+ *
+ * 0 : Cache hit/miss/speculative miss/fail 604/147/ 0/0 (80%/19%/ 0%/ 0%)
+ * 2048 : Cache hit/miss/speculative miss/fail 622/119/ 17/0 (82%/15%/ 2%/ 0%)
+ * 4096 : Cache hit/miss/speculative miss/fail 656/109/ 25/0 (83%/13%/ 3%/ 0%)
+ * 8192 : Cache hit/miss/speculative miss/fail 648/104/ 40/0 (81%/13%/ 5%/ 0%)
+ * ALL : Cache hit/miss/speculative miss/fail 775/ 0/161/0 (82%/ 0%/17%/ 0%)
+*/
+#define SPECULATE_SMALL 4096
+
+/* the time between cache clean runs in ms */
+#define CACHE_CLEAN_TIME (10 * 1000)
+
/**
* Initialise image content handlers
*
@@ -46,8 +62,14 @@
nserror image_init(void)
{
nserror error;
-
- error = image_cache_init();
+ struct image_cache_parameters image_cache_parameters = {
+ .bg_clean_time = CACHE_CLEAN_TIME,
+ .limit = (8 * 1024 * 1024),
+ .hysteresis = (2 * 1024 * 1024),
+ .speculative_small = SPECULATE_SMALL
+ };
+
+ error = image_cache_init(&image_cache_parameters);
if (error != NSERROR_OK)
return error;
diff --git a/image/image_cache.c b/image/image_cache.c
index 796d833f3..b13073a6e 100644
--- a/image/image_cache.c
+++ b/image/image_cache.c
@@ -64,53 +64,61 @@ struct image_cache_entry_s {
* sensibly.
*/
struct image_cache_s {
- cache_age current_age; /** the "age" of the current operation */
- struct image_cache_entry_s *entries; /* cache objects */
+ /** Cache parameters */
+ struct image_cache_parameters params;
+
+ /** The "age" of the current operation */
+ cache_age current_age;
+
+ /* The objects the cache holds */
+ struct image_cache_entry_s *entries;
- /* Statistics for replacement algorithm */
+
+ /* Statistics for management algorithm */
/** total size of bitmaps currently allocated */
size_t total_bitmap_size;
- /** Max size of bitmaps allocated at any one time */
+ /** Total count of bitmaps currently allocated */
+ int bitmap_count;
+
+ /** Maximum size of bitmaps allocated at any one time */
size_t max_bitmap_size;
+ /** The number of objects when maximum bitmap usage occoured */
int max_bitmap_size_count;
- int bitmap_count;
+ /** Maximum count of bitmaps allocated at any one time */
int max_bitmap_count;
+ /** The size of the bitmaps when teh max count occoured */
size_t max_bitmap_count_size;
- int miss_count; /* bitmap was not available at plot time required conversion */
- int specultive_miss_count; /* bitmap was available but never actually required conversion */
- int hit_count; /* bitmap was available at plot time required no conversion */
- int fail_count; /* bitmap was not available at plot time, required conversion which failed */
-
- int total_unrendered; /* bitmap was freed without ever being required for redraw */
-
- int total_extra_conversions; /* counts total number of conversions of images, after the first */
- int total_extra_conversions_count; /* counts total number of images with more than one conversion */
- int peak_conversions; /* bitmap with most conversions was converted this many times */
- unsigned int peak_conversions_size; /* bitmap with most conversions this size */
+ /** Bitmap was not available at plot time required conversion */
+ int miss_count;
+ /** Bitmap was available at plot time required no conversion */
+ int hit_count;
+ /** Bitmap was not available at plot time and required
+ * conversion which failed.
+ */
+ int fail_count;
+
+ /* Cache entry freed without ever being redrawn */
+ int total_unrendered;
+ /** Bitmap was available but never required - wasted conversions */
+ int specultive_miss_count;
+
+ /** Total number of additional (after the first) conversions */
+ int total_extra_conversions;
+ /** counts total number of images with more than one conversion */
+ int total_extra_conversions_count;
+
+ /** Bitmap with most conversions was converted this many times */
+ int peak_conversions;
+ /** Size of bitmap with most conversions */
+ unsigned int peak_conversions_size;
};
static struct image_cache_s *image_cache = NULL;
-/** low water mark for speculative pre-conversion */
-
-/* Experimenting by visiting every page from default page in order and
- * then netsurf homepage
- *
- * 0 : Cache hit/miss/speculative miss/fail 604/147/ 0/0 (80%/19%/ 0%/ 0%)
- * 2048 : Cache hit/miss/speculative miss/fail 622/119/ 17/0 (82%/15%/ 2%/ 0%)
- * 4096 : Cache hit/miss/speculative miss/fail 656/109/ 25/0 (83%/13%/ 3%/ 0%)
- * 8192 : Cache hit/miss/speculative miss/fail 648/104/ 40/0 (81%/13%/ 5%/ 0%)
- * ALL : Cache hit/miss/speculative miss/fail 775/ 0/161/0 (82%/ 0%/17%/ 0%)
-*/
-#define SPECULATE_SMALL 4096
-
-/* the time between cache clean runs in ms */
-#define CACHE_CLEAN_TIME (10 * 1000)
-
/** Find the cache entry for a content
*/
@@ -229,6 +237,42 @@ static void image_cache__free_entry(struct image_cache_entry_s *centry)
free(centry);
}
+/** Cache cleaner */
+static void image_cache__clean(struct image_cache_s *icache)
+{
+ struct image_cache_entry_s *centry = icache->entries;
+
+ while (centry != NULL) {
+ if ((icache->current_age - centry->redraw_age) >
+ icache->params.bg_clean_time) {
+ /* only consider older entries, avoids active entries */
+ if ((icache->total_bitmap_size >
+ (icache->params.limit - icache->params.hysteresis)) &&
+ (random() > (RAND_MAX / 2))) {
+ image_cache__free_bitmap(centry);
+ }
+ }
+ centry=centry->next;
+ }
+}
+
+/** Cache background scheduled callback. */
+static void image_cache__background_update(void *p)
+{
+ struct image_cache_s *icache = p;
+
+ /* increment current cache age */
+ icache->current_age += icache->params.bg_clean_time;
+
+ LOG(("Cache age %ds", icache->current_age / 1000));
+
+ image_cache__clean(icache);
+
+ schedule((icache->params.bg_clean_time / 10),
+ image_cache__background_update,
+ icache);
+}
+
/* exported interface documented in image_cache.h */
struct bitmap *image_cache_get_bitmap(struct content *c)
{
@@ -262,12 +306,20 @@ bool image_cache_speculate(struct content *c)
{
bool decision = false;
- if (c->size <= SPECULATE_SMALL) {
+ /* If the cache is below its target usage and the bitmap is
+ * small enough speculate.
+ */
+ if ((image_cache->total_bitmap_size < image_cache->params.limit) &&
+ (c->size <= image_cache->params.speculative_small)) {
+#ifdef IMAGE_CACHE_VERBOSE
LOG(("content size (%d) is smaller than minimum (%d)", c->size, SPECULATE_SMALL));
+#endif
decision = true;
}
+#ifdef IMAGE_CACHE_VERBOSE
LOG(("returning %d", decision));
+#endif
return decision;
}
@@ -284,33 +336,20 @@ struct bitmap *image_cache_find_bitmap(struct content *c)
return centry->bitmap;
}
-static void image_cache__clean(void *p)
-{
- struct image_cache_s *icache = p;
- struct image_cache_entry_s *centry = icache->entries;
-
- /* increment current cache age */
- icache->current_age += CACHE_CLEAN_TIME;
-
- LOG(("Running cache clean at cache age %ds", icache->current_age / 1000));
-
- LOG(("Brain dead cache cleaner removing all bitmaps not redraw in last %ds", CACHE_CLEAN_TIME / 1000));
- while (centry != NULL) {
- if ((icache->current_age - centry->redraw_age) > CACHE_CLEAN_TIME) {
- image_cache__free_bitmap(centry);
- }
- centry=centry->next;
- }
-
- schedule((CACHE_CLEAN_TIME / 10), image_cache__clean, icache);
-}
-
/* exported interface documented in image_cache.h */
-nserror image_cache_init(void)
+nserror
+image_cache_init(const struct image_cache_parameters *image_cache_parameters)
{
image_cache = calloc(1, sizeof(struct image_cache_s));
+ if (image_cache == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ image_cache->params = *image_cache_parameters;
- schedule((CACHE_CLEAN_TIME / 10), image_cache__clean, image_cache);
+ schedule((image_cache->params.bg_clean_time / 10),
+ image_cache__background_update,
+ image_cache);
return NSERROR_OK;
}
@@ -320,7 +359,7 @@ nserror image_cache_fini(void)
{
int op_count;
- schedule_remove(image_cache__clean, image_cache);
+ schedule_remove(image_cache__background_update, image_cache);
op_count = image_cache->hit_count +
image_cache->miss_count +
diff --git a/image/image_cache.h b/image/image_cache.h
index c0ccfac90..568f3e951 100644
--- a/image/image_cache.h
+++ b/image/image_cache.h
@@ -43,8 +43,25 @@
typedef struct bitmap * (image_cache_convert_fn) (struct content *content);
-/** Initialise the image cache */
-nserror image_cache_init(void);
+struct image_cache_parameters {
+ /** How frequently the background cache clean process is run (ms) */
+ unsigned int bg_clean_time;
+
+ /** The target upper bound for the image cache size */
+ size_t limit;
+
+ /** The hysteresis allowed round the target size */
+ size_t hysteresis;
+
+ /** The speculative conversion "small" size */
+ size_t speculative_small;
+};
+
+/** Initialise the image cache
+ *
+ * @param image_cache_parameters The control parameters for the image cache
+ */
+nserror image_cache_init(const struct image_cache_parameters *image_cache_parameters);
nserror image_cache_fini(void);
/** adds an image content to be cached.