On Wed, Jan 23, 2013 at 1:27 AM, Tom Hacohen <[email protected]> wrote: > On 22/01/13 13:21, Gustavo Sverzut Barbieri wrote: >> On Tue, Jan 22, 2013 at 7:57 AM, Cedric BAIL <[email protected]> wrote: >>> Hello, >>> >>> I have been chasing source of memory consumption in EFL since a few >>> weeks now. There is one source that I didn't hunt yet, callbacks. In >>> some small elementary_test they easily get over 400KB of >>> Evas_Func_Node. This func node are not that big, but they are still a >>> list with a function pointer, two integer and a data pointer. >>> When we look at our usage, in a lot of place, we do have the same >>> pattern. We register a set of callbacks for always the same event with >>> the function pointer and priority. The only thing that change is the >>> data pointer. >>> Instead of using a list, we could use an array, that would reduce >>> our memory use, but still, not enough. Maybe overall, it wouldn't even >>> b a win if we use an Eina_Inarray or an Eina_Array as they do require >>> two additional integer, so the base structure when you have no >>> callbacks will be bigger. >>> So what we could do is provide an API to register a static const >>> array of function pointer and event like an callback class. This >>> pattern would match our use in Edje, Elementary and even Terminology. >>> One "class" of callback per object, instead of n instance of callbacks >>> per object. That should really reduce the memory we use for that. >>> I don't want to push this new API in Evas, because we have that >>> pattern with edje signal, smart callback and object callback. I think >>> it should go to Eo and we should move our code to use such API. >>> >>> Any comments, though on that subject. >> >> Given the nature of it, I guess it's easier to solve like: >> >> evas_object_event_callback: >> 1 - dynamically allocate an array of pointers with size as the >> number of elements in EVAS_CALLBACK_* enum: when unused, pointer-size >> bytes. When used pointer-size * (elements-in-EVAS_CALLBACK_ + 1) >> 2 - for each callback, place in the aforementioned array another >> inarray of pairs {cb, data}. You can avoid your extra integer cost for >> inarray by implementing something manual, it won't hurt that much the >> integer, but seems you're bugged about that. The size would be 2 * >> pointer-size >> >> right now we use 4 pointers per node (prev, next, cb, data), plus some >> information that due alignment should take an extra pointer-size >> (type, priority, delete_me). So 5 pointer-size at least, but on my >> machine (32 bits) it's 28 bytes or 7 pointers. >> >> We can avoid the 'deleted' bit by making cb = NULL in the structure. >> If we use inarray (allocated size != used size), we can just swap >> deleted elements to the end as well when we cleanup, avoiding >> allocations at all. Problem is how to handle the priority part without >> loosing much info, I'll count it as an extra-pointer-size. >> >> Expected gains: >> >> = empty = >> now: 1 * pointer-size >> new: 1 * pointer-size >> >> = 1 event of 1 type = >> now: 1 * pointer-size + 1 * (7 * pointer-size) = 8 * pointer-size >> new: 1 * pointer-size + 34 * pointer-size + 1 * (3 * pointer-size) = >> 38 * pointer-size >> >> = 10 events of 5 types (50 events) = >> now: 1 * pointer-size + 50 * (7 * pointer-size) = 351 * pointer-size >> new: 1 * pointer-size + 34 * pointer-size + 50 * (3 * pointer-size) = >> 185 * pointer-size
Most common case is to have n callbacks for n differents type. There is very little chance that the same events get ten different callbacks. So let see the math : = 2 events of 10 types = now: 1 * pointer-size + 20 * (7 * pointer-size) = 141 * pointer-size new: 1 * pointer-size + 34 * pointer-size + 20 * (3 * pointer-size) = 95 * pointer-size Overall, the win is quite small (30%). This would mean we go from 400K to 280K, not enough in my opinion. >> equation: 1 + N * 7 = 35 + N * 3; N * 7 - N * 3 = 35 - 1; N * >> 4 = 34; N = 8.5 >> >> then it will pay off, but takes a reasonable amount of events (9). The >> additional benefit is avoiding memory fragmentation and it would >> reduce search for events as you know just events of a given type would >> be in the array slot. >> >> >> For evas_object_smart_callback we could optimize if the smart class >> declares its signals and just emits that, in this case we can use a >> similar approach to the above. > > I was thinking about adding static general purpose arrays for the first > X callbacks. The thing is, that we don't really have that many callbacks > per object, probably ~10 or less. So it'll be beneficial to: > 1. Test my hypothesis. > 2. Use an array for the first X events. > > It'll be a major save for most of the cases. I was thinking about the same idea and just maybe use an array for all events. No need to complexify more that piece of code. In that case, I think the common case would be : = 2 events of 10 types defined in 3 different place 2 * pointer-size + 3 * (2 * pointer-size) = 8 * pointer-size > I think we should probably implement all the options suggested and see > which one works best in real life applications. All the callback > handling code is now shared in just one place, so it shouldn't be too > annoying to do. I think we should start by implementing that static batch setting function and see if we have anything left to win after that. -- Cedric BAIL ------------------------------------------------------------------------------ Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS, MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft MVPs and experts. ON SALE this month only -- learn more at: http://p.sf.net/sfu/learnnow-d2d _______________________________________________ enlightenment-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/enlightenment-devel
