Skip to content

Schedule.h|cpp refactored to class templates for performance and reuse #6902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 60 commits into
base: master
Choose a base branch
from

Conversation

dok-net
Copy link
Contributor

@dok-net dok-net commented Dec 12, 2019

The interrupt/signal safe linked list in Schedule.h|cpp can very well be used as a universal queue or event delegate (c# terminology ;-) ) class.
This PR also supersedes cores/esp8266/CallbackList.h.

The new Delegate.h class template provides compelling performance improvements in cases where std::function is repeatedly constructed during execution, which is quite slow. While a simple seek&replace drop-in for std::function in APIs, call sites can in turn be refactored; basically, the binding via lambda capture or std::bind is substituted for by using the C-function pointer style Delegate constructor's obj argument.

Performance comparisons:

Using C function pointer or std::function

One assignment and one call via bool(*f)(Foo*, int) : 108 cycles; call only: 31 cycles.
One assignment and one call via std::function<bool(int)> : 1360 cycles; call only: 34 cycles.

Using Delegate<bool(int), Foo*>

One assignment from bound C++-style Callable and one call: 1435 cycles; call only: 46 cycles.
One assignment from C-function pointer plus obj, and one call: 151 cycles; call only: 30 cycles.

@hreintke
Copy link
Contributor

@dok-net :
How should I use MultiDelegate as replacement for CallBackList ?

@dok-net dok-net force-pushed the schedule_w_delegate branch from 560d917 to e35d6fb Compare December 12, 2019 19:51
@dok-net
Copy link
Contributor Author

dok-net commented Dec 12, 2019

@hreintke I've tried for a few minutes to wrap Multidelegate as the experimental::CBListImplementation::CallBackList, but I think there's no need to mimic the interface exactly - right?
To get started on what you functionally need, I believe the two specializations used in Schedule.h|cpp provide that right match - execute exactly once, or forever until some condition applies, upon which the callback signals via it's false return value. So instead of resetting the std::shared_ptr returned from add, give the actual Delegate instances access to a corresponding predicate and have them return that.

struct SomeClass {
    void doSomething(int) const {};
    bool active = true; // for event handling sample
};
SomeClass obj;
// the function type void(int) passes an int value to all callbacks:
using CallbackOnceFuncT = Delegate<void(int), SomeClass>;
using CallOnceQueue = MultiDelegate< CallbackOnceFuncT, true >;
CallOnceQueue q;
q.add([obj](int i) { obj.doSomething(i); }); // construction very expensive.
// fast add, 712 fewer CPU cycles:
q.add({ [](SomeClass obj, int i) { obj.doSomething(i); }, obj });
// the function type bool(int) passes an int value to all event handlers.
// return false from the event handler to get it removed from the event multiplexer:
using EventHandlerFuncT = Delegate<bool(int), SomeClass>;
using EventHandlers = MultiDelegate< EventHandlerFuncT >;
EventHandlers ev;
ev.add([obj](int i) { obj.doSomething(i); return obj.active; }); // construction very expensive.
// fast add, 670 fewer CPU cycles:
ev.add({ [](SomeClass obj, int i) { obj.doSomething(i); return obj.active; }, obj });
q(42);
ev(42);

Instead of the active field in SomeClass, you might instead derive from EventHandlerFuncT and keep and retrieve that "remove" flag there - see Schedule.cpp's class mRecFuncT : public Delegate<bool(), void*>, which overwrites bool operator()().

@hreintke
Copy link
Contributor

@dok-net :
First impression, did not get into all details of your remark.

Main functionality of CallBacklist is that it prevents executing the callback when the Object that registered the callback is already destructed.
Because of that, the deletion from the list cannot be dependent on returning false.
When the returned CallBackHandler add(cbFunctionT af, bool ad = true) goes out of scope, the callback is deleted before executing it.

Do not (yet) see that possibility in (Multi)Delegate.
Maybe the std::list<CallBackHandler> callBackEventList; can be replaced my MultiDelegate but need to get more in the details to be sure.

@dok-net dok-net force-pushed the schedule_w_delegate branch 4 times, most recently from 6680cae to ff4bdd6 Compare December 17, 2019 16:17
@dok-net dok-net force-pushed the schedule_w_delegate branch 5 times, most recently from 36b3353 to e7a2b49 Compare December 25, 2019 10:43
@dok-net dok-net force-pushed the schedule_w_delegate branch 3 times, most recently from 2c11ba9 to ad94655 Compare January 22, 2020 08:30
@dok-net dok-net force-pushed the schedule_w_delegate branch 2 times, most recently from d523639 to 2eec43a Compare February 5, 2020 07:16
@dok-net dok-net force-pushed the schedule_w_delegate branch 3 times, most recently from 3e24043 to 24b446f Compare February 13, 2020 21:39
@dok-net dok-net force-pushed the schedule_w_delegate branch 5 times, most recently from c08978d to 8ef1041 Compare March 1, 2020 16:54
@dok-net dok-net force-pushed the schedule_w_delegate branch 3 times, most recently from 8ef1041 to ce88779 Compare March 10, 2020 18:21
dok-net added 29 commits June 28, 2021 12:48
…ATTR attribute.

This affects the unnamed namespace or static non-member functions.
…uto-remove. Invoke returns result of last Delegate call.

Caveat: breaks use of event multiplexer with auto-remove; WIP: add iterators.
…ent operators, needing a lot

of code duplication, this commit provides that.
@dok-net dok-net force-pushed the schedule_w_delegate branch from 78d2073 to 3458547 Compare June 28, 2021 10:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants