Compare commits

...

4 Commits

Author SHA1 Message Date
Marcel Hollerbach 9852b2b714 Revert "eo: make callback_add faster"
This reverts commit d34a0321cb.
2020-08-05 11:53:19 +02:00
Marcel Hollerbach 5dbc62a98b eo: event callback call optimization
a little overfiew to how eos event emission is working:
- In eo there are 2 types of events restart events and normal events.
  Normals are *always* emitted from callback_max to 0
  Restarts are emitted from the previous emissions current idx to 0. The
  previous emission will stop then
- To keep track of the previous event emissions for restarts there was
  an eina inlist.
- To keep track of other things in eo, there was an additional eo event
  stack frame (newly inserted events etc. etc.)

This commit now uses this event stack frame for implementing the details
about the restart events. This has the advatage that every
efl_object_data contains one byte less, and the up to date keeping of
the id's in the restart infrastructure is not needed anymore, making the
whole event emission code less instructions and faster.

How this now works:
- Every emission has a event emission frame, when the emission starts,
  the frame is added, next points to the next older event emission. In
  this event stack frame we are storing the current idx, the description
  and a few other things that are not really relevant at this point.
- when a restart event is started, this event stack is searched from the
  current frame up to the next one featuring the same event description.
  The event frame stack is then remembered, if the event emission is
  done, the current idx (normally 0 or something higher when callback
  was stopped) is then copyied back to the earlier frame.
- Based on the nature of the event frame stacks, the idx is updated
  every iteration. And for the restart events, we only need to know the
  next, which removes the need of permanently updating the idx in the
  current stack.
- The event frame stack is not allocated on the heap, hence more things
  in there does not matter at all.

Differential Revision: https://phab.enlightenment.org/D12097
2020-08-05 11:05:17 +02:00
Marcel Hollerbach 0cb7708c68 eo: evalulate special counts earlier
we have these special counts which are > 0 when there is a callback
subscribed. THey are currently evalulated in _callback_call. However,
we can also skip the entire call from inside eo_base_class as we are
having the fields there as well.

This way we are skipping the obj pointer lookup and vtable lookup.

Differential Revision: https://phab.enlightenment.org/D12079
2020-08-05 11:05:05 +02:00
Marcel Hollerbach d34a0321cb eo: make callback_add faster
I was researching for quite some time how eo events could be made
faster, while doing that i recognized that we are not utilizing the full
size of Efl_Object_Data, so we can do a little bit more hinting for how
our events are currently working.

In this commit a flag called single priority is inserted. This flag
ensures that the object only has one callback priority registered, which
gives us the possibility of skipping the binary search, the search
itself is not that bad, however, alone the loading of the instructions
takes time, so this way we can skip the search, *and* the instructions
for moving the array elements to later.

Differential Revision: https://phab.enlightenment.org/D12078
2020-08-05 11:04:51 +02:00
1 changed files with 27 additions and 45 deletions

View File

@ -38,6 +38,7 @@ struct _Efl_Event_Forwarder
struct _Efl_Event_Callback_Frame
{
const Efl_Event_Description *desc;
Efl_Event_Callback_Frame *next;
unsigned int idx;
unsigned int inserted_before;
@ -65,8 +66,6 @@ struct _Efl_Object_Data
Efl_Object_Extension *ext;
Eina_Inlist *current;
Efl_Event_Callback_Frame *event_frame;
Eo_Callback_Description **callbacks;
#ifdef EFL64
@ -238,9 +237,9 @@ _efl_invalidate(_Eo_Object *obj)
id = _eo_obj_id_get(obj);
efl_event_callback_call(id, EFL_EVENT_INVALIDATE, NULL);
pd = efl_data_scope_get(id, EFL_OBJECT_CLASS);
if (pd->event_cb_EFL_EVENT_INVALIDATE)
efl_event_callback_call(id, EFL_EVENT_INVALIDATE, NULL);
efl_invalidate(id);
@ -1576,7 +1575,8 @@ _efl_object_event_callback_priority_add(Eo *obj, Efl_Object_Data *pd,
_eo_callbacks_sorted_insert(pd, cb);
_special_event_count_inc(obj, pd, &(cb->items.item));
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)arr);
if (pd->event_cb_EFL_EVENT_CALLBACK_ADD)
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)arr);
return EINA_TRUE;
@ -1602,8 +1602,8 @@ _efl_object_event_callback_clean(Eo *obj, Efl_Object_Data *pd,
pd->need_cleaning = EINA_TRUE;
else
_eo_callback_remove(obj, pd, cb);
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_DEL, (void *)array);
if (pd->event_cb_EFL_EVENT_CALLBACK_DEL)
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_DEL, (void *)array);
}
EOLIAN static Eina_Bool
@ -1730,7 +1730,8 @@ _efl_object_event_callback_array_priority_add(Eo *obj, Efl_Object_Data *pd,
ev_array[i].priority = 0;
ev_array[i].func = NULL;
ev_array[i].user_data = NULL;
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, ev_array);
if (pd->event_cb_EFL_EVENT_CALLBACK_ADD)
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, ev_array);
return EINA_TRUE;
@ -2035,11 +2036,12 @@ _event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
Eina_Bool legacy_compare)
{
Eo_Callback_Description **cb;
Eo_Current_Callback_Description *lookup, saved;
Efl_Event_Callback_Frame *restart_lookup = NULL; //a pointer to a frame, which is high up the stack, which we use to restore
Efl_Event ev;
unsigned int idx;
Eina_Bool callback_already_stopped, ret;
Efl_Event_Callback_Frame frame = {
.desc = desc,
.next = NULL,
.idx = 0,
.inserted_before = 0,
@ -2069,7 +2071,6 @@ _event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
EVENT_STACK_PUSH(pd, &frame);
lookup = NULL;
callback_already_stopped = pd->callback_stopped;
pd->callback_stopped = EINA_FALSE;
ret = EINA_TRUE;
@ -2109,9 +2110,6 @@ restart_back:
(event_freeze_count || pd->event_freeze_count))
continue;
// Handle nested restart of walking list
if (lookup) lookup->current = idx - 1;
it->func((void *) (*cb)->func_data, &ev);
/* Abort callback calling if the func says so. */
if (pd->callback_stopped)
@ -2119,10 +2117,6 @@ restart_back:
ret = EINA_FALSE;
goto end;
}
// We have actually walked this list during a nested call
if (lookup &&
lookup->current == 0)
goto end;
}
}
else
@ -2133,9 +2127,6 @@ restart_back:
(event_freeze_count || pd->event_freeze_count))
continue;
// Handle nested restart of walking list
if (lookup) lookup->current = idx - 1;
(*cb)->items.item.func((void *) (*cb)->func_data, &ev);
/* Abort callback calling if the func says so. */
if (pd->callback_stopped)
@ -2143,23 +2134,18 @@ restart_back:
ret = EINA_FALSE;
goto end;
}
// We have actually walked this list during a nested call
if (lookup &&
lookup->current == 0)
goto end;
}
}
//copy back the idx that might have changed due to restarts, (theoretically only needed with restarts, condition made everything slower)
idx = frame.idx;
//adjust to event subscriptions that have been added in a event callback
idx += frame.inserted_before;
frame.inserted_before = 0;
}
end:
// Handling restarting list walking complete exit.
if (lookup) lookup->current = 0;
if (lookup == &saved)
{
pd->current = eina_inlist_remove(pd->current, EINA_INLIST_GET(lookup));
}
if (restart_lookup) restart_lookup->idx = 0;
EVENT_STACK_POP(pd);
@ -2169,26 +2155,22 @@ end:
return ret;
restart:
EINA_INLIST_FOREACH(pd->current, lookup)
restart_lookup = frame.next;
while (restart_lookup)
{
if (lookup->desc == desc) break;
if (restart_lookup->desc == desc) break;
restart_lookup = restart_lookup->next;
}
// This is the first event to trigger it, so register it here
if (!lookup)
{
// This following trick get us a zero allocation list
saved.desc = desc;
saved.current = 0;
lookup = &saved;
// Ideally there will most of the time be only one item in this list
// But just to speed up things, prepend so we find it fast at the end
// of this function
pd->current = eina_inlist_prepend(pd->current, EINA_INLIST_GET(lookup));
}
if (restart_lookup) {
idx = restart_lookup->idx - 1;
} else {
idx = 0;
}
if (!idx)
idx = pd->callbacks_count;
if (!lookup->current) lookup->current = pd->callbacks_count;
idx = lookup->current;
goto restart_back;
}