AM_CFLAGS = @WIN32_CFLAGS@
-bin_PROGRAMS = evas_cserve evas_cserve_test
+bin_PROGRAMS = evas_cserve evas_cserve_tool
evas_cserve_SOURCES = \
evas_cserve_main.c
evas_cserve_LDADD = \
$(top_builddir)/src/lib/libevas.la
-evas_cserve_test_LDFLAGS =
+evas_cserve_tool_LDFLAGS =
-evas_cserve_test_SOURCES = \
-evas_cserve_test_main.c
+evas_cserve_tool_SOURCES = \
+evas_cserve_tool.c
-evas_cserve_test_LDADD = \
+evas_cserve_tool_LDADD = \
$(top_builddir)/src/lib/libevas.la
-evas_cserve_test_LDFLAGS =
+evas_cserve_tool_LDFLAGS =
endif
#include "Evas.h"
#include "evas_cs.h"
#include <signal.h>
+#include <sys/time.h>
+#include <time.h>
+#ifdef _WIN32
+# include <windows.h>
+#endif
// fixme:'s
//
-// add ops to get/set cache size, check time and cache time (both)
-// add ops to get internal state (both)
+// 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)
//
time_t modtime;
time_t last_stat;
} file;
+ struct {
+ int load1saved, load2saved;
+ double load1, load2;
+ } stats;
Lopt load_opts;
struct {
int w, h;
static int cache_usage = 0;
static int cache_max_usage = 1 * 1024 * 1024;
static int cache_item_timeout = -1;
-static int cache_item_timeout_check = 10;
+static int cache_item_timeout_check = -1;
static Mem *stat_mem = NULL;
static int stat_mem_num = 0;
static Eina_List *stat_mems = NULL;
+#ifndef _WIN32
+static double
+get_time(void)
+{
+ struct timeval timev;
+
+ gettimeofday(&timev, NULL);
+ return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
+}
+#else
+static double
+get_time(void)
+{
+ return (double)GetTickCount()/1000.0;
+}
+#endif
+
+
+static int stats_dirty = 0;
+static int saved_loads = 0;
+static double saved_load_time = 0;
+static double saved_load_lifetime = 0;
+
+static int saved_loaddatas = 0;
+static double saved_loaddata_time = 0;
+static double saved_loaddata_lifetime = 0;
+
+static int saved_memory = 0;
+static int saved_memory_peak = 0;
+static int alloced_memory = 0;
+static int alloced_memory_peak = 0;
+static int real_memory = 0;
+static int real_memory_peak = 0;
+
+static Eina_Bool
+stats_hash_image_cb(const Eina_Hash *hash __UNUSED__,
+ const void *key __UNUSED__,
+ void *data, void *fdata __UNUSED__)
+{
+ Img *img = data;
+
+ saved_load_time += img->stats.load1 * img->stats.load1saved;
+ saved_loaddata_time += img->stats.load2 * img->stats.load2saved;
+ if (img->ref > 1)
+ saved_memory += img->image.w * img->image.h * sizeof(DATA32) * (img->ref - 1);
+ if (img->mem)
+ {
+ alloced_memory += img->image.w * img->image.h * sizeof(DATA32);
+ real_memory += (((img->image.w * img->image.h * sizeof(DATA32)) + 4095) >> 12) << 12;
+ }
+ return 1;
+}
+
+static void
+stats_calc(void)
+{
+ Img *img;
+ Eina_List *l;
+
+ if (!stats_dirty) return;
+ stats_dirty = 0;
+ saved_loads = 0;
+ saved_load_time = 0;
+ saved_loaddatas = 0;
+ saved_loaddata_time = 0;
+ saved_memory = 0;
+ alloced_memory = 0;
+ real_memory = 0;
+
+ if (active_images)
+ eina_hash_foreach(active_images, stats_hash_image_cb, NULL);
+ EINA_LIST_FOREACH(cache_images, l, img)
+ {
+ saved_loads += img->stats.load1saved;
+ saved_load_time += img->stats.load1 * img->stats.load1saved;
+ saved_loaddatas += img->stats.load2saved;
+ saved_loaddata_time += img->stats.load2 * img->stats.load2saved;
+ if (img->mem)
+ {
+ alloced_memory += img->image.w * img->image.h * sizeof(DATA32);
+ real_memory += (((img->image.w * img->image.h * sizeof(DATA32)) + 4095) >> 12) << 12;
+ }
+ }
+ if (saved_memory > saved_memory_peak)
+ saved_memory_peak = saved_memory;
+ if (real_memory > real_memory_peak)
+ real_memory_peak = real_memory;
+ if (alloced_memory > alloced_memory_peak)
+ alloced_memory_peak = alloced_memory;
+}
+
+static void
+stats_update(void)
+{
+ stats_dirty = 1;
+}
+
+static void
+stats_lifetime_update(Img *img)
+{
+ saved_load_lifetime += img->stats.load1 * img->stats.load1saved;
+ saved_loaddata_lifetime += img->stats.load2 * img->stats.load2saved;
+}
+
static void
stat_clean(Mem *m)
{
int ret;
Image_Entry *ie;
int err = 0;
+ double t;
ret = stat(file, &st);
if (ret < 0) return NULL;
+ t = get_time();
ie = evas_cache_image_request(cache, file, key, load_opts, &err);
+ t = get_time() - t;
if (!ie) return NULL;
img = (Img *)ie;
+ img->stats.load1 = t;
img->key = eina_stringshare_add(bufkey);
img->file.modtime = st.st_mtime;
img->file.file = eina_stringshare_add(file);
static void
img_loaddata(Img *img)
{
+ double t;
+
// fixme: load img data
+ t = get_time();
evas_cache_image_load_data((Image_Entry *)img);
+ t = get_time() - t;
+ img->stats.load2 = t;
if (img->image.data)
msync(img->image.data, img->image.w * img->image.h * sizeof(DATA32), MS_SYNC | MS_INVALIDATE);
img->usage +=
static void
img_free(Img *img)
{
+ stats_lifetime_update(img);
+ stats_update();
eina_stringshare_del(img->key);
eina_stringshare_del(img->file.file);
eina_stringshare_del(img->file.key);
img = eina_hash_find(active_images, buf);
if ((img) && (img_ok(img)))
{
+ img->stats.load1saved++;
img->ref++;
+ stats_update();
return img;
}
{
if (img_ok(img))
{
+ img->stats.load1saved++;
img->ref++;
cache_images = eina_list_remove_list(cache_images, l);
eina_hash_direct_add(active_images, img->key, img);
+ stats_update();
return img;
}
}
msg.mem.id = img->mem->id;
msg.mem.offset = img->mem->offset;
msg.mem.size = img->mem->size;
+ img->stats.load2saved++;
+ stats_update();
}
else
msg.mem.id = msg.mem.offset = msg.mem.size = 0;
Op_Loaddata *rep;
Op_Loaddata_Reply msg;
Img *img;
-// fixme: handle loadopts on loaddata
-// RGBA_Image_Loadopts lopt = {0, 0.0, 0, 0};
rep = (Op_Loaddata *)data;
img = rep->handle;
- img_loaddata(img);
+ if (img->mem)
+ {
+ img->stats.load2saved++;
+ stats_update();
+ }
+ else
+ img_loaddata(img);
memset(&msg, 0, sizeof(msg));
if (img->mem)
{
img_forcedunload(img);
}
break;
+ case OP_GETCONFIG:
+ {
+ Op_Getconfig_Reply msg;
+
+ msg.cache_max_usage = cache_max_usage;
+ msg.cache_item_timeout = cache_item_timeout;
+ msg.cache_item_timeout_check = cache_item_timeout_check;
+ evas_cserve_client_send(c, OP_GETCONFIG, sizeof(msg), (unsigned char *)(&msg));
+ }
+ break;
+ case OP_SETCONFIG:
+ {
+ Op_Setconfig *rep;
+
+ rep = (Op_Setconfig *)data;
+ cache_max_usage = rep->cache_max_usage;
+ cache_item_timeout = rep->cache_item_timeout;
+ cache_item_timeout_check = rep->cache_item_timeout_check;
+ cache_clean();
+ }
+ break;
+ case OP_GETSTATS:
+ {
+ Op_Getstats_Reply msg;
+
+ stats_calc();
+ msg.saved_memory = saved_memory;
+ msg.wasted_memory = (real_memory - alloced_memory);
+ msg.saved_memory_peak = saved_memory_peak;
+ msg.wasted_memory_peak = (real_memory_peak - alloced_memory_peak);
+ msg.saved_time_image_header_load = saved_load_lifetime + saved_load_time;
+ msg.saved_time_image_data_load = saved_loaddata_lifetime + saved_loaddata_time;
+ evas_cserve_client_send(c, OP_GETSTATS, sizeof(msg), (unsigned char *)(&msg));
+ }
+ break;
+ case OP_GETINFO:
+ {
+// get a list of all images in active hash and cache list, and their info like
+// file + key
+// width, height and alpha flag
+// refcount
+// data loaded flag
+// active ot cached
+// last active timestamp
+// dead
+// mod time
+// last checked mod time time
+// memory footprint
+// Op_Getstats_Reply msg;
+ }
+ break;
default:
break;
}
+++ /dev/null
-#include "evas_cs.h"
-
-int
-main(int argc, char **argv)
-{
- evas_init();
-
- printf("evas_cserve_init = %i\n", evas_cserve_init());
-
- {
- Image_Entry *ie;
- RGBA_Image_Loadopts lopt = { 0, 0.0, 0, 0};
-
- ie = malloc(sizeof(Image_Entry));
- if (evas_cserve_image_load(ie, argv[1], NULL, &lopt))
- {
- printf("load ok\n");
- if (evas_cserve_image_data_load(ie))
- {
- Mem *m;
-
- m = ie->data2;
- printf("first pixel: %08x\n", *((int *)m->data));
- printf("load data ok\n");
-// evas_cserve_image_free(ie);
- }
- }
- }
-
- evas_cserve_shutdown();
- evas_shutdown();
- return 0;
-}
--- /dev/null
+#include "evas_cs.h"
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ evas_init();
+ if (!evas_cserve_init())
+ {
+ printf("ERROR: Cannot connect to cserve. abort\n");
+ exit(-1);
+ }
+
+ for (i = 1; i < argc; i++)
+ {
+ if ((!strcmp(argv[i], "-h")) ||
+ (!strcmp(argv[i], "-help")) ||
+ (!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"
+ );
+ exit(0);
+ }
+ else if ((!strcmp(argv[i], "getconfig")))
+ {
+ Op_Getconfig_Reply config;
+
+ if (!evas_cserve_config_get(&config))
+ {
+ printf("ERROR: cannot fetch config.\n");
+ exit(-1);
+ }
+ printf("csize: %i\n", config.cache_max_usage / 1024);
+ printf("ctime: %i\n", config.cache_item_timeout);
+ printf("ctimecheck: %i\n", config.cache_item_timeout_check);
+ printf("-OK-\n");
+ }
+ else if ((!strcmp(argv[i], "setconfig")) && (i < (argc - 3)))
+ {
+ Op_Setconfig config;
+
+ i++;
+ config.cache_max_usage = atoi(argv[i]) * 1024;
+ i++;
+ config.cache_item_timeout = atoi(argv[i]);
+ i++;
+ config.cache_item_timeout_check = atoi(argv[i]);
+ if (!evas_cserve_config_set(&config))
+ {
+ printf("ERROR: cannot set config.\n");
+ exit(-1);
+ }
+ }
+ else if ((!strcmp(argv[i], "getstats")))
+ {
+ Op_Getstats_Reply stats;
+
+ if (!evas_cserve_stats_get(&stats))
+ {
+ printf("ERROR: cannot fetch stats.\n");
+ exit(-1);
+ }
+ printf("saved_memory: %i Kb\n", stats.saved_memory / 1024);
+ printf("wasted_memory: %i Kb\n", stats.wasted_memory / 1024);
+ printf("saved_memory_peak: %i Kb\n", stats.saved_memory_peak / 1024);
+ printf("wasted_memory_peak: %i Kb\n", stats.wasted_memory_peak / 1024);
+ printf("saved_time_image_header_load: %1.3f sec\n", stats.saved_time_image_header_load);
+ printf("saved_time_image_data_load: %1.3f sec\n", stats.saved_time_image_data_load);
+ printf("-OK-\n");
+ }
+ }
+/*
+ {
+ Image_Entry *ie;
+ RGBA_Image_Loadopts lopt = { 0, 0.0, 0, 0};
+
+ ie = malloc(sizeof(Image_Entry));
+ if (evas_cserve_image_load(ie, argv[1], NULL, &lopt))
+ {
+ printf("load ok\n");
+ if (evas_cserve_image_data_load(ie))
+ {
+ Mem *m;
+
+ m = ie->data2;
+ printf("first pixel: %08x\n", *((int *)m->data));
+ printf("load data ok\n");
+// evas_cserve_image_free(ie);
+ }
+ }
+ }
+ */
+ evas_cserve_shutdown();
+ evas_shutdown();
+ return 0;
+}
};
//// for comms
-// for clients to connect to cserve
-EAPI Eina_Bool evas_cserve_init(void);
-EAPI int evas_cserve_use_get(void);
-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_free(Image_Entry *ie);
-
-// for the server
-EAPI Server *evas_cserve_server_add(void);
-EAPI void evas_cserve_server_del(Server *s);
-EAPI void evas_cserve_client_send(Client *c, int opcode, int size, unsigned char *data);
-EAPI void evas_cserve_server_message_handler_set(Server *s, int (*func) (void *fdata, Server *s, Client *c, int opcode, int size, unsigned char *data), void *data);
-EAPI void evas_cserve_server_wait(Server *s, int timeout);
-
-//// for memory
-// for server
-EAPI Mem *evas_cserve_mem_new(int size, const char *name);
-EAPI void evas_cserve_mem_free(Mem *m);
-
-// for client
-EAPI Mem *evas_cserve_mem_open(int pid, int id, const char *name, int size, int write);
-EAPI void evas_cserve_mem_close(Mem *m);
-
-// for both
-EAPI Eina_Bool evas_cserve_mem_resize(Mem *m, int size);
-EAPI void evas_cserve_mem_del(int pid, int id);
-
-
enum
{
OP_NOP, // 0
OP_PRELOAD, // 5
OP_FORCEDUNLOAD, // 6
+ OP_GETCONFIG, // 7
+ OP_SETCONFIG, // 8
+ OP_GETSTATS, // 9
+ OP_GETINFO, // 10
+
OP_INVALID // 6
};
{
void *handle;
} Op_Forcedunload;
+typedef struct
+{
+ int cache_max_usage;
+ int cache_item_timeout;
+ int cache_item_timeout_check;
+} Op_Getconfig_Reply;
+typedef struct
+{
+ int cache_max_usage;
+ int cache_item_timeout;
+ int cache_item_timeout_check;
+} Op_Setconfig;
+typedef struct
+{
+ int saved_memory;
+ int wasted_memory;
+ int saved_memory_peak;
+ int wasted_memory_peak;
+ double saved_time_image_header_load;
+ double saved_time_image_data_load;
+} Op_Getstats_Reply;
+
+
+// for clients to connect to cserve
+EAPI Eina_Bool evas_cserve_init(void);
+EAPI int evas_cserve_use_get(void);
+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_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);
+EAPI Eina_Bool evas_cserve_stats_get(Op_Getstats_Reply *stats);
+
+// for the server
+EAPI Server *evas_cserve_server_add(void);
+EAPI void evas_cserve_server_del(Server *s);
+EAPI void evas_cserve_client_send(Client *c, int opcode, int size, unsigned char *data);
+EAPI void evas_cserve_server_message_handler_set(Server *s, int (*func) (void *fdata, Server *s, Client *c, int opcode, int size, unsigned char *data), void *data);
+EAPI void evas_cserve_server_wait(Server *s, int timeout);
+
+//// for memory
+// for server
+EAPI Mem *evas_cserve_mem_new(int size, const char *name);
+EAPI void evas_cserve_mem_free(Mem *m);
+
+// for client
+EAPI Mem *evas_cserve_mem_open(int pid, int id, const char *name, int size, int write);
+EAPI void evas_cserve_mem_close(Mem *m);
+
+// for both
+EAPI Eina_Bool evas_cserve_mem_resize(Mem *m, int size);
+EAPI void evas_cserve_mem_del(int pid, int id);
#endif
Op_Load msg;
Op_Load_Reply *rep;
unsigned char *buf;
- char fbuf[PATH_MAX], wd[PATH_MAX];
+ char fbuf[PATH_MAX], wdb[PATH_MAX];
int flen, klen;
int opcode;
int size;
msg.lopt.h = lopt->h;
if (file[0] != '/')
{
- if (getcwd(wd, sizeof(wd)))
+ if (getcwd(wdb, sizeof(wdb)))
{
- snprintf(fbuf, "%s/%s", wd, file);
+ snprintf(fbuf, sizeof(buf), "%s/%s", wdb, file);
file = fbuf;
}
}
- if (!realpath(file, wd)) file = wd;
+ if (!realpath(file, wdb)) file = wdb;
flen = strlen(file) + 1;
klen = strlen(key) + 1;
buf = malloc(sizeof(msg) + flen + klen);
ie->data1 = NULL;
}
+EAPI Eina_Bool
+evas_cserve_config_get(Op_Getconfig_Reply *config)
+{
+ Op_Getconfig_Reply *rep;
+ int opcode;
+ int size;
+ if (csrve_init > 0) server_reinit();
+ else return 0;
+ if (!cserve) return 0;
+ if (!server_send(cserve, OP_GETCONFIG, 0, NULL)) return 0;
+ rep = (Op_Getconfig_Reply *)server_read(cserve, &opcode, &size);
+ if ((rep) && (opcode == OP_GETCONFIG) && (size == sizeof(Op_Getconfig_Reply)))
+ {
+ memcpy(config, rep, sizeof(Op_Getconfig_Reply));
+ return 1;
+ }
+ return 0;
+}
+
+EAPI Eina_Bool
+evas_cserve_config_set(Op_Setconfig *config)
+{
+ if (csrve_init > 0) server_reinit();
+ else return 0;
+ if (!cserve) return 0;
+ if (!server_send(cserve, OP_SETCONFIG, sizeof(Op_Setconfig), (unsigned char *)config)) return 0;
+ return 1;
+}
+
+EAPI Eina_Bool
+evas_cserve_stats_get(Op_Getstats_Reply *stats)
+{
+ Op_Getstats_Reply *rep;
+ int opcode;
+ int size;
+ if (csrve_init > 0) server_reinit();
+ else return 0;
+ if (!cserve) return 0;
+ if (!server_send(cserve, OP_GETSTATS, 0, NULL)) return 0;
+ rep = (Op_Getstats_Reply *)server_read(cserve, &opcode, &size);
+ if ((rep) && (opcode == OP_GETSTATS) && (size == sizeof(Op_Getstats_Reply)))
+ {
+ memcpy(stats, rep, sizeof(Op_Getstats_Reply));
+ return 1;
+ }
+ return 0;
+}
+
#endif