summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-04-01 20:29:04 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-04-01 20:33:52 +0900
commit57ce6419e5c257e6fee6809cdb9c63d39c0b0a98 (patch)
treec73294e6ef658054ffa83062292a0d741d9bc340
parent7f20ff52c9b51f8dc5a9c2bdba52d2622d9759a8 (diff)
downloadenlightenment-57ce6419e5c257e6fee6809cdb9c63d39c0b0a98.tar.gz
e icons: reduce mem usage (in x11) by a fair bit by de-duplicating
so i was profiling today .. leak hunting .. and i noticed. if you have enough appss open - eg terminology, e uses a huge amount of memory... for icons. terminology is 128x128 ... thats 64k per icon. open up a lot of terminology windows and we duplicate that 64k per every window on the wm sside because we get the data. it would apply for any app that sets a netwm icon. this can be come rather silly if you have like 100 terminals. it's worse with larger icons (eg 256x256 - 256k per icon). this puts in a simply list for shared icons and a lookup on fetch to de-duplicate and share icon data. this should drop memory usage nicely. @improvement
-rw-r--r--src/bin/e_client.c103
-rw-r--r--src/bin/e_client.h2
-rw-r--r--src/bin/e_comp_x.c22
3 files changed, 105 insertions, 22 deletions
diff --git a/src/bin/e_client.c b/src/bin/e_client.c
index 1d2436697f..e2a2bf652d 100644
--- a/src/bin/e_client.c
+++ b/src/bin/e_client.c
@@ -534,10 +534,9 @@ _e_client_free(E_Client *ec)
ec->stick_desks = eina_list_free(ec->stick_desks);
if (ec->netwm.icons)
{
- int i;
- for (i = 0; i < ec->netwm.num_icons; i++)
- free(ec->netwm.icons[i].data);
- E_FREE(ec->netwm.icons);
+ e_client_icon_free(ec->netwm.icons, ec->netwm.num_icons);
+ ec->netwm.icons = NULL;
+ ec->netwm.num_icons = 0;
}
E_FREE(ec->netwm.extra_types);
eina_stringshare_replace(&ec->border.name, NULL);
@@ -5023,3 +5022,99 @@ e_client_layout_cb_set(E_Client_Layout_Cb cb)
CRI("ATTEMPTING TO OVERWRITE EXISTING CLIENT LAYOUT HOOK!!!");
_e_client_layout_cb = cb;
}
+
+////////////////////////////////////////////
+static Eina_List *iconshare = NULL;
+
+typedef struct _E_Client_Icon_Entry E_Client_Icon_Entry;
+
+struct _E_Client_Icon_Entry
+{
+ Ecore_X_Icon *icons;
+ int num_icons;
+ int ref;
+};
+
+E_API Ecore_X_Icon *
+e_client_icon_deduplicate(Ecore_X_Icon *icons, int num_icons)
+{
+ int i;
+ Eina_List *l;
+ E_Client_Icon_Entry *ie;
+
+ // unless the rest of e uses border icons OTHER than icon #0
+ // then free the rest that we don't need anymore.
+ for (i = 1; i < num_icons; i++)
+ {
+ free(icons[i].data);
+ icons[i].data = NULL;
+ }
+ // lookup icon data in icons cache/share
+ EINA_LIST_FOREACH(iconshare, l, ie)
+ {
+ if ((ie->num_icons == num_icons) &&
+ (num_icons > 0) &&
+ (ie->icons[0].width == icons[0].width) &&
+ (ie->icons[0].height == icons[0].height) &&
+ (!memcmp(ie->icons[0].data, icons[0].data,
+ icons[0].width * icons[0].height * 4)))
+ {
+ // found so free the input icons
+ for (i = 0; i < num_icons; i++)
+ free(icons[i].data);
+ free(icons);
+ // ref the shared/cached one
+ ie->ref++;
+ iconshare = eina_list_promote_list(iconshare, l);
+ // and return that
+ return ie->icons;
+ }
+ }
+ // no hit - new entry to cache. add it
+ ie = calloc(1, sizeof(E_Client_Icon_Entry));
+ if (ie)
+ {
+ ie->icons = icons;
+ ie->num_icons = num_icons;
+ ie->ref = 1;
+ iconshare = eina_list_prepend(iconshare, ie);
+ }
+ return icons;
+}
+
+E_API void
+e_client_icon_free(Ecore_X_Icon *icons, int num_icons)
+{
+ int i;
+ Eina_List *l;
+ E_Client_Icon_Entry *ie;
+
+ // lookup in icon share cache
+ EINA_LIST_FOREACH(iconshare, l, ie)
+ {
+ if ((ie->num_icons == num_icons) &&
+ (num_icons > 0) &&
+ (ie->icons[0].width == icons[0].width) &&
+ (ie->icons[0].height == icons[0].height) &&
+ (!memcmp(ie->icons[0].data, icons[0].data,
+ icons[0].width * icons[0].height * 4)))
+ {
+ // found so deref
+ ie->ref--;
+ if (ie->ref <= 0)
+ {
+ // no refs left - free the icon from the share/cache
+ iconshare = eina_list_remove_list(iconshare, l);
+ for (i = 0; i < ie->num_icons; i++)
+ free(ie->icons[i].data);
+ free(ie->icons);
+ free(ie);
+ }
+ return;
+ }
+ }
+ // not found - so just free it ... odd - we should never be here
+ for (i = 0; i < num_icons; i++)
+ free(icons[i].data);
+ free(icons);
+}
diff --git a/src/bin/e_client.h b/src/bin/e_client.h
index 13d24fd56f..94ef059afb 100644
--- a/src/bin/e_client.h
+++ b/src/bin/e_client.h
@@ -827,6 +827,8 @@ E_API Eina_Bool e_client_has_xwindow(const E_Client *ec);
E_API Eina_Bool e_client_desk_window_profile_available_check(E_Client *ec, const char *profile);
E_API void e_client_desk_window_profile_wait_desk_set(E_Client *ec, E_Desk *desk);
E_API void e_client_layout_cb_set(E_Client_Layout_Cb cb);
+E_API Ecore_X_Icon *e_client_icon_deduplicate(Ecore_X_Icon *icons, int num_icons);
+E_API void e_client_icon_free(Ecore_X_Icon *icons, int num_icons);
YOLO E_API void e_client_focus_stack_set(Eina_List *l);
diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c
index 35831a8da7..2bff1106e7 100644
--- a/src/bin/e_comp_x.c
+++ b/src/bin/e_comp_x.c
@@ -3795,30 +3795,16 @@ _e_comp_x_hook_client_fetch(void *d EINA_UNUSED, E_Client *ec)
}
if (ec->netwm.fetch.icon)
{
- int i;
- if (ec->netwm.icons)
- {
- for (i = 0; i < ec->netwm.num_icons; i++)
- {
- free(ec->netwm.icons[i].data);
- ec->netwm.icons[i].data = NULL;
- }
- free(ec->netwm.icons);
- }
+ e_client_icon_free(ec->netwm.icons, ec->netwm.num_icons);
ec->netwm.icons = NULL;
ec->netwm.num_icons = 0;
if (ecore_x_netwm_icons_get(win,
&ec->netwm.icons,
&ec->netwm.num_icons))
{
- // unless the rest of e uses border icons OTHER than icon #0
- // then free the rest that we don't need anymore.
- for (i = 1; i < ec->netwm.num_icons; i++)
- {
- free(ec->netwm.icons[i].data);
- ec->netwm.icons[i].data = NULL;
- }
- ec->netwm.num_icons = 1;
+ if (ec->netwm.icons)
+ ec->netwm.icons = e_client_icon_deduplicate
+ (ec->netwm.icons, ec->netwm.num_icons);
ec->changes.icon = 1;
}
ec->netwm.fetch.icon = 0;