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

Reply via email to