//
// add ops to get internal cache state (both)
// preload - make it work (both)
-// monitor /proc/meminfo and if mem low - free items until cache empty (server)
+
//
// pants!
{
Image_Entry ie;
int ref;
+ int dref;
int usage;
Mem *mem;
const char *key;
} image;
Eina_Bool dead : 1;
Eina_Bool active : 1;
+ Eina_Bool useless : 1;
};
// config
static Eina_Hash *active_images = NULL;
static Eina_List *cache_images = NULL;
static int cache_usage = 0;
-static int cache_max_usage = 1 * 1024 * 1024;
+static int cache_max_usage = 1 * 1024;
+static int cache_max_adjust = 0;
static int cache_item_timeout = -1;
static int cache_item_timeout_check = -1;
static Mem *stat_mem = NULL;
}
#endif
+static int mem_total = 0;
+static int mem_free = 0;
+static int mem_buffers = 0;
+static int mem_cached = 0;
+
+static void
+meminfo_check(void)
+{
+ FILE *f;
+ char buf[1024];
+ int v;
+
+ f = fopen("/proc/meminfo", "r");
+ if (!f) return;
+ if (!fgets(buf, sizeof(buf), f)) goto done;
+ v = 0; if (sscanf(buf, "%*s %i %*s", &v) != 1) goto done;
+ mem_total = v;
+ if (!fgets(buf, sizeof(buf), f)) goto done;
+ v = 0; if (sscanf(buf, "%*s %i %*s", &v) != 1) goto done;
+ mem_free = v;
+ if (!fgets(buf, sizeof(buf), f)) goto done;
+ v = 0; if (sscanf(buf, "%*s %i %*s", &v) != 1) goto done;
+ mem_buffers = v;
+ if (!fgets(buf, sizeof(buf), f)) goto done;
+ v = 0; if (sscanf(buf, "%*s %i %*s", &v) != 1) goto done;
+ mem_cached = v;
+ done:
+ fclose(f);
+}
static int stats_dirty = 0;
static int saved_loads = 0;
{
double t;
- // fixme: load img data
t = get_time();
evas_cache_image_load_data((Image_Entry *)img);
t = get_time() - t;
static void
cache_clean(void)
{
- while ((cache_usage > cache_max_usage) && (cache_images))
+ while ((cache_usage > ((cache_max_usage + cache_max_adjust) * 1024)) && (cache_images))
{
Img *img;
Eina_List *l;
}
static void
+mem_cache_adjust(void)
+{
+ int pval = cache_max_adjust;
+ int max = 0;
+
+ if (mem_total <= 0) return;
+ if ((mem_free + mem_cached + mem_buffers) < mem_total)
+ cache_max_adjust += mem_total - (mem_free + mem_cached + mem_buffers);
+
+ max = (mem_free / 8) - cache_max_usage;
+ if (max < 0) max = 0;
+ if (max > cache_max_usage) max = cache_max_usage;
+ cache_max_adjust = max - cache_max_usage;
+
+ if (cache_max_adjust < -cache_max_usage)
+ cache_max_adjust = -cache_max_usage;
+ if (pval != cache_max_adjust) cache_clean();
+}
+
+static void
img_cache(Img *img)
{
eina_hash_del(active_images, img->key, img);
cache_images = eina_list_prepend(cache_images, img);
img->cached = t_now;
cache_usage += img->usage;
- if (cache_usage > cache_max_usage)
+ if (cache_usage > ((cache_max_usage + cache_max_adjust) * 1024))
cache_clean();
}
}
static void
+img_unloaddata(Img *img)
+{
+ if ((img->dref <= 0) && (img->useless))
+ {
+ Image_Entry *ie = (Image_Entry *)img;
+
+ evas_cserve_mem_free(img->mem);
+ img->mem = NULL;
+ img->image.data = NULL;
+ img->dref = 0;
+
+ ie->flags.loaded = 0;
+ ie->allocated.w = 0;
+ ie->allocated.h = 0;
+ }
+}
+
+static void
+img_useless(Img *img)
+{
+ img->useless = 1;
+ if (img->dref <= 0) img_unloaddata(img);
+}
+
+static void
img_forcedunload(Img *img)
{
img->dead = 1;
evas_cserve_client_send(c, OP_LOADDATA, sizeof(msg), (unsigned char *)(&msg));
}
break;
+ case OP_UNLOADDATA:
+ {
+ Op_Unloaddata *rep;
+ Img *img;
+
+ rep = (Op_Unloaddata *)data;
+ img = rep->handle;
+ img->dref--;
+ img_unloaddata(img);
+ }
+ break;
+ case OP_USELESSDATA:
+ {
+ Op_Unloaddata *rep;
+ Img *img;
+
+ rep = (Op_Unloaddata *)data;
+ img = rep->handle;
+ img->dref--;
+ img_useless(img);
+ }
+ break;
case OP_PRELOAD:
{
Op_Preload *rep;
else if ((!strcmp(argv[i], "-csize")) && (i < (argc - 1)))
{
i++;
- cache_max_usage = atoi(argv[i]) * 1024;
+ cache_max_usage = atoi(argv[i]);
}
else if ((!strcmp(argv[i], "-ctime")) && (i < (argc - 1)))
{
if (exit_flag) break;
t = time(NULL);
t_next = t - last_check;
- if ((t_next) > cache_item_timeout_check)
+ if ((t_next) >= cache_item_timeout_check)
{
t_next = cache_item_timeout_check;
last_check = t;
cache_timeout(t);
+ meminfo_check();
+ mem_cache_adjust();
}
if ((t_next <= 0) && (cache_item_timeout_check > 0))
t_next = 1;
}
error:
- printf("clean shutdown\n");
if (stat_mem)
{
stat_clean(stat_mem);
(!strcmp(argv[i], "--help")))
{
printf("Options:\n"
- "\t-h This help\n"
- "\tgetconfig Get configuration values\n"
- "\tsetconfig csize ctimeout ctimecheck Set the config values\n"
- "\tgetstats Get current cache statistics\n"
+ "\t-h This help\n"
+ "\tgetconfig Get configuration values\n"
+ "\tsetconfig CSIZE CTIME CTIMECHECK Set the config values\n"
+ "\tgetstats Get current cache statistics\n"
);
exit(0);
}
printf("ERROR: cannot fetch config.\n");
exit(-1);
}
- printf("csize: %i\n", config.cache_max_usage / 1024);
+ printf("csize: %i\n", config.cache_max_usage);
printf("ctime: %i\n", config.cache_item_timeout);
printf("ctimecheck: %i\n", config.cache_item_timeout_check);
printf("-OK-\n");
Op_Setconfig config;
i++;
- config.cache_max_usage = atoi(argv[i]) * 1024;
+ config.cache_max_usage = atoi(argv[i]);
i++;
config.cache_item_timeout = atoi(argv[i]);
i++;
OP_LOAD, // 2
OP_UNLOAD, // 3
OP_LOADDATA, // 4
- OP_PRELOAD, // 5
- OP_FORCEDUNLOAD, // 6
+ OP_UNLOADDATA, // 5
+ OP_USELESSDATA, // 6
+ OP_PRELOAD, // 7
+ OP_FORCEDUNLOAD, // 8
- OP_GETCONFIG, // 7
- OP_SETCONFIG, // 8
- OP_GETSTATS, // 9
- OP_GETINFO, // 10
+ OP_GETCONFIG, // 9
+ OP_SETCONFIG, // 10
+ OP_GETSTATS, // 11
+ OP_GETINFO, // 12
- OP_INVALID // 6
+ OP_INVALID // 13
};
typedef struct
typedef struct
{
void *handle;
+} Op_Unloaddata;
+typedef struct
+{
+ void *handle;
} Op_Loaddata;
typedef struct
{
EAPI void evas_cserve_shutdown(void);
EAPI Eina_Bool evas_cserve_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt);
EAPI Eina_Bool evas_cserve_image_data_load(Image_Entry *ie);
+EAPI void evas_cserve_image_unload(Image_Entry *ie);
+EAPI void evas_cserve_image_useless(Image_Entry *ie);
EAPI void evas_cserve_image_free(Image_Entry *ie);
EAPI Eina_Bool evas_cserve_config_get(Op_Getconfig_Reply *config);
EAPI Eina_Bool evas_cserve_config_set(Op_Setconfig *config);
if (ie->data1 == NULL) return;
memset(&msg, 0, sizeof(msg));
msg.handle = ie->data1;
- if (ie->data2) evas_cserve_mem_close(ie->data2);
- ie->data2 = NULL;
+ if (ie->data2) evas_cserve_image_unload(ie);
server_send(cserve, OP_UNLOAD, sizeof(msg), (unsigned char *)(&msg));
ie->data1 = NULL;
}
+EAPI void
+evas_cserve_image_unload(Image_Entry *ie)
+{
+ Op_Unloaddata msg;
+
+ if (csrve_init > 0) server_reinit();
+ else return;
+ if (!cserve) return;
+ if (ie->data1 == NULL) return;
+ memset(&msg, 0, sizeof(msg));
+ msg.handle = ie->data1;
+ if (ie->data2) evas_cserve_mem_close(ie->data2);
+ ie->data2 = NULL;
+ server_send(cserve, OP_UNLOADDATA, sizeof(msg), (unsigned char *)(&msg));
+}
+
+EAPI void
+evas_cserve_image_useless(Image_Entry *ie)
+{
+ Op_Unloaddata msg;
+
+ if (csrve_init > 0) server_reinit();
+ else return;
+ if (!cserve) return;
+ if (ie->data1 == NULL) return;
+ memset(&msg, 0, sizeof(msg));
+ msg.handle = ie->data1;
+ if (ie->data2) evas_cserve_mem_close(ie->data2);
+ ie->data2 = NULL;
+ server_send(cserve, OP_USELESSDATA, sizeof(msg), (unsigned char *)(&msg));
+}
+
EAPI Eina_Bool
evas_cserve_config_get(Op_Getconfig_Reply *config)
{
evas_cache_image_preload_cancel(ie, NULL);
if (!ie->flags.loaded) return;
- if (!ie->info.module) return;
+ if ((!ie->info.module) && (!ie->data1)) return;
if (!ie->file) return;
+
ie->flags.loaded = 0;
if ((im->cs.data) && (im->image.data))
}
im->cs.data = NULL;
+#ifdef EVAS_CSERVE
+ if (ie->data1)
+ {
+ evas_cserve_image_useless(ie);
+ im->image.data = NULL;
+ ie->allocated.w = 0;
+ ie->allocated.h = 0;
+ return;
+ }
+#endif
+
if (im->image.data && !im->image.no_free)
free(im->image.data);
im->image.data = NULL;
#define MAX_SCALEITEMS 32
#define MIN_SCALE_USES 3
-#define MIN_SCALE_AGE_GAP 5000
-#define MIN_SCALECACHE_SIZE 3200
+//#define MIN_SCALE_AGE_GAP 5000
+#define MAX_SCALECACHE_DIM 3200
#define FLOP_ADD 4
#define MAX_FLOP_COUNT 16
#define FLOP_DEL 1
-//#define SCALE_CACHE_SIZE 10 * 1024 * 1024
-#define SCALE_CACHE_SIZE 0
+#define SCALE_CACHE_SIZE 4 * 1024 * 1024
+//#define SCALE_CACHE_SIZE 0
typedef struct _Scaleitem Scaleitem;
RGBA_Image *im, *parent_im;
int src_x, src_y, src_w, src_h;
int dst_w, dst_h;
- int smooth, populate_me, flop;
+ int flop;
+ int size_adjust;
+ Eina_Bool forced_unload : 1;
+ Eina_Bool smooth : 1;
+ Eina_Bool populate_me : 1;
};
#ifdef SCALECACHE
// printf(" 0- %i\n", sci->dst_w * sci->dst_h * 4);
LKL(cache_lock);
evas_common_rgba_image_free(&sci->im->cache_entry);
- cache_size -= sci->dst_w * sci->dst_h * 4;
+ if (!sci->forced_unload)
+ cache_size -= sci->dst_w * sci->dst_h * 4;
+ else
+ cache_size -= sci->size_adjust;
cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
LKU(cache_lock);
}
if (sci->im)
{
evas_common_rgba_image_free(&sci->im->cache_entry);
- cache_size -= sci->dst_w * sci->dst_h * 4;
+ if (!sci->forced_unload)
+ cache_size -= sci->dst_w * sci->dst_h * 4;
+ else
+ cache_size -= sci->size_adjust;
// printf(" 1- %i\n", sci->dst_w * sci->dst_h * 4);
cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
}
sci->usage = 0;
sci->usage_count = 0;
sci->flop += FLOP_ADD;
- cache_size -= sci->dst_w * sci->dst_h * 4;
+ if (!sci->forced_unload)
+ cache_size -= sci->dst_w * sci->dst_h * 4;
+ else
+ cache_size -= sci->size_adjust;
// printf(" 2- %i\n", sci->dst_w * sci->dst_h * 4);
cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
memset(sci, 0, sizeof(Eina_Inlist));
{
if (!sci->im)
{
- if ((sci->dst_w < MIN_SCALECACHE_SIZE) &&
- (sci->dst_h < MIN_SCALECACHE_SIZE))
+ if ((sci->dst_w < MAX_SCALECACHE_DIM) &&
+ (sci->dst_h < MAX_SCALECACHE_DIM))
{
if (sci->flop <= MAX_FLOP_COUNT)
{
RGBA_Image *im = (RGBA_Image *)ie;
Scaleitem *sci;
int didpop = 0;
+ int dounload = 0;
/*
static int i = 0;
}
if (sci->populate_me)
{
+ int size, osize, used;
+
+ size = dst_region_w * dst_region_h;
+ if (((dst_region_w > 640) || (dst_region_h > 640)) &&
+ (size > (480 * 480)))
+ {
+ Eina_List *l;
+ Scaleitem *sci2;
+
+ dounload = 1;
+ osize = sci->parent_im->cache_entry.w * sci->parent_im->cache_entry.h;
+ used = 0;
+ EINA_LIST_FOREACH(im->cache.list, l, sci2)
+ {
+ if (sci2->im) used += sci2->dst_w * sci2->dst_h;
+ }
+ if ((size < osize) && (used == 0))
+ sci->size_adjust = 0;
+ else
+ {
+ osize -= used;
+ if (osize < 0) osize = 0;
+ size -= osize;
+ sci->size_adjust = size * 4;
+ }
+ }
+ else
+ {
+ size *= sizeof(DATA32);
+ if ((cache_size + size) > max_cache_size)
+ {
+ sci->populate_me = 0;
+ im->cache.populate_count--;
+ }
+ }
+ }
+ if (sci->populate_me)
+ {
// printf("##! populate!\n");
sci->im = evas_common_image_new
(dst_region_w, dst_region_h, im->cache_entry.flags.alpha);
{
if (yy & 0x1)
{
- if (xx & 0x1) *pp = 0;
+ if (xx & 0x1) *pp = 0x882288ff;
}
else
{
- if (!(xx & 0x1)) *pp = 0;
+ if (!(xx & 0x1)) *pp = 0x882288ff;
}
pp++;
}
}
#endif
}
- cache_size += sci->dst_w * sci->dst_h * 4;
+ if (dounload)
+ {
+ sci->forced_unload = 1;
+ cache_size += sci->size_adjust;
+ }
+ else
+ {
+ cache_size += sci->dst_w * sci->dst_h * 4;
+ }
// printf(" + %i @ flop: %i (%ix%i)\n",
// sci->dst_w * sci->dst_h * 4, sci->flop,
// sci->dst_w, sci->dst_h);
// im,
// (int)im->cache.orig_usage,
// (int)im->cache.newest_usage);
- if ((im->cache_entry.flags.loaded) && (!im->cs.no_free) &&
- (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888))
+ if ((dounload) ||
+ ((im->cache_entry.flags.loaded) &&
+ ((!im->cs.no_free)
+#ifdef EVAS_CSERVE
+ || (ie->data1)
+#endif
+ ) &&
+ (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)))
{
- if (im->cache.orig_usage <
- (im->cache.newest_usage / 20))
- evas_common_rgba_image_unload(&im->cache_entry);
+ if ((dounload) || (im->cache.orig_usage <
+ (im->cache.newest_usage / 20)))
+ {
+ evas_common_rgba_image_unload(&im->cache_entry);
+ }
}
LKU(im->cache.lock);
}