About the non-use of Announcer in Bloc

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
53 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Henrik Sperre Johansen

On 31 Aug 2016, at 10:10 , Glenn Cavarlé <[hidden email]> wrote:

In Bloc the constraint is to propagate more than 2000 events/second without
to decrease fps

That's only a small part of the picture though, how many listeners are there per each event?
And how large do you think the overhead specific to delivery guards is compared to the constraint propagation handlers?

On my machine (an old 2011 MBP), the following gives throughput on the order of 300k-600k deliveries per second (very variable, due to the amount of garbage generated from copying subs, I presume) 

#(1 10 100 1000) collect: [ :listeners | 

a := Announcer new. 
b := Object new.
"Single message send in handler"
listeners timesRepeat: [a when: Announcement do: [ :a | a yourself ] for: b.].
"announcement creation overhead not included"
ann := Announcement new.
[a announce: ann] bench].

Cheers, 
Henry

And with a registry tuned for delivery, yet maintaining the guards (attached)/exception/error handling properties, 900k -> 2.5M

#(1 10 100 1000) collect: [ :listeners | 

a := Announcer new. 
b := Object new.
a instVarNamed: 'registry' put: DeliveringSubscriptionRegistry new. 
"Single message send in handler"
listeners timesRepeat: [a when: Announcement do: [ :a | a yourself ] for: b.].
"announcement creation overhead not included"
ann := Announcement new.
[a announce: ann] bench.].



DeliveringSubscriptionRegistry.st (3K) Download Attachment
signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier


2016-08-31 18:01 GMT+02:00 Henrik Johansen <[hidden email]>:

On 31 Aug 2016, at 10:10 , Glenn Cavarlé <[hidden email]> wrote:

In Bloc the constraint is to propagate more than 2000 events/second without
to decrease fps

That's only a small part of the picture though, how many listeners are there per each event?
And how large do you think the overhead specific to delivery guards is compared to the constraint propagation handlers?

On my machine (an old 2011 MBP), the following gives throughput on the order of 300k-600k deliveries per second (very variable, due to the amount of garbage generated from copying subs, I presume)

So close to 3 times the performance of entry-level celeron for laptops today (if I take the lowest of the 15" MBP of early 2011).
 

#(1 10 100 1000) collect: [ :listeners | 

a := Announcer new. 
b := Object new.
"Single message send in handler"
listeners timesRepeat: [a when: Announcement do: [ :a | a yourself ] for: b.].
"announcement creation overhead not included"
ann := Announcement new.
[a announce: ann] bench].

Cheers, 
Henry

And with a registry tuned for delivery, yet maintaining the guards (attached)/exception/error handling properties, 900k -> 2.5M

#(1 10 100 1000) collect: [ :listeners | 

a := Announcer new. 
b := Object new.
a instVarNamed: 'registry' put: DeliveringSubscriptionRegistry new. 
"Single message send in handler"
listeners timesRepeat: [a when: Announcement do: [ :a | a yourself ] for: b.].
"announcement creation overhead not included"
ann := Announcement new.
[a announce: ann] bench.].

Thanks for the numbers. We need those to optimise what really matters :)

Thierry

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

stepharo
In reply to this post by Thierry Goubier
Hi thierry

I think that if we would have a tool to show us the activity I'm quite
sure that we would find bugs

or mistaken behavior.

could you send the scripts you did?

Stef


Le 30/8/16 à 22:36, Thierry Goubier a écrit :

> Numbers for the discussion:
>
> No activity, empty desktop:
> announcements            608/minute
> subscribe add/remove        9/minute
>
> Activity, AltBrowser:
> announcements            1109/minute
> subscribe add/remove        207/minute
>
> Activity, Nautilus:
> announcements            2488/minute
> subscribe add/remove        716/minute
>
> Empirically the same processus in both environments: open two system
> browser, in one, find the Announcer class, browse through a few of the
> methods, select basicSubscribe: and ask for senders.
>
> Tracing done with Metalinks during one minute.
>
> Not exactly what I would have expected, especially the ratio subscribe
> add/remove and announcements.
>
> Thierry
>
> Le 30/08/2016 à 17:36, Henrik Johansen a écrit :
>>
>>> On 30 Aug 2016, at 5:16 , Thierry Goubier
>>> <[hidden email]> wrote:
>>>
>>>
>>> I have the same concern with an Announcer optimized for certain use
>>> cases, in the fact that the announcer creator is the one choosing
>>> the 'kind of' optimisation it would target, hoping that the
>>> listeners will conform to that use case...
>>
>>
>> There simply is no silver bullet that will give unbeatable
>> performance in all scenarios; and focusing on improving one facet of
>> the default implementation will inevitably lead to either - the loss
>> of some important property (general thread-safety if removing the
>> mutex protection, ability to unsubscribe in handler if removing the
>> copy operation and extending the delivery mutex protection, etc.) -
>> greatly degenerated performance for another facet (like #remove for
>> OC's).
>>
>> That said, the current implementation is very geared towards decent,
>> balanced subscribe/unsubscribe performance, at the expense of
>> delivery speed. I've said it before, and still think, that offering
>> at least one other implementation emphasizing delivery speed over
>> subscription/unsubscription performance, in the same way the original
>> implementation did (and/or changing the default Announcer to switch
>> between the two dynamically based on heuristics) *would* be a
>> valuable addition to the general library.
>>
>> Cheers, Henry
>>
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

stepharo
In reply to this post by Glenn Cavarlé

> To me, Announcer is really usefull and efficient when it is used as an event
> bus that can be shared between multiple objects.
> For instance, it seems to be useless to use an Announcer in NewValueHolder
> because it cannot be shared and it is only used internally to register
> handlers and to propagate only the same event (ValueChanged) to them. What
> is the gain of using a full featured Announcer in this case?
I particularly like these two points and I would really like to have a
confirmation
because in that case this is really a place for improvements.


> In Bloc the constraint is to propagate more than 2000 events/second without
> to decrease fps, so we cannot afford to x4 the time to process events even
> if Announcer is safer and better tested.
>
> Regards,
> Glenn.

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

stepharo
In reply to this post by Denis Kudriashov



Le 31/8/16 à 11:23, Denis Kudriashov a écrit :

2016-08-31 10:10 GMT+02:00 Glenn Cavarlé <[hidden email]>:
Hi all (I was out for some days),

Hi Glenn
 

What i see is that Bloc EventRegistry:
1) is not thread safe (no mutex + #select:thenDo:)
2) doesn't allow handler removal from the handler list currently used in the
thenDo: loop
3) is used specifically for a one-to-many communication (1 BlElement -> X
handlers)

The (1) doesn't seem to be a problem in Bloc during UI event processing
because a new event handler, even if it is added from another thread, would
be taken into account for the next event.

Problem that concurrent modification of OrderedCollection could just fail. You will got debugger.
 
I note that it is really not
recommended (at all) to update an UI element elsewhere than in the UI thread
and it is like that in all other UI frameworks i know.

Does it means that I should not subscribe on UI events from different (not UI) processes?
How to do this if it is needed? 
Should I always put subscription code into #defer: message (analogue)? 
In that case what to do if I need to be sure that I really subscribe on event and only after this continue my business logic process?
 

The (2) is a very specific use case and i don't know if it is a real need in
Bloc because this implies that an element has 2 handlers for the same event
and one of them has to remove the other before it is executed and during the
same event processing (maybe more a conception issue than a common use
case...). In other cases, no problem for handler removal.

Very simple example: I want one shot handler for MouseMove to highlight element once to see that my mouse was moved around.
So my handler will highlight target element and unsubscribe it immediately.
Problem that if you do it on OrderedCollection during iteration you could skip one of the handlers. And probably some failures are also possible (debugger again).

Of course you could say users do not do all of this. But what the alternative? And if people will do this by "incident" it will be very difficult to discover reasons.
 

But maybe i miss some specific cases in (1) and in (2).

To me, Announcer is really usefull and efficient when it is used as an event
bus that can be shared between multiple objects.
For instance, it seems to be useless to use an Announcer in NewValueHolder
because it cannot be shared and it is only used internally to register
handlers and to propagate only the same event (ValueChanged) to them. What
is the gain of using a full featured Announcer in this case?

But in practice we never share any announcer instance.
Really? You lost me on that sentence. SystemAnnouncer current is shared by all the tools no?

We always hide it inside owner object. ValueHolder is not specific example.
Also ValueHolder is kind of active model for UI application which could be shared between different views. And when it will be modified in one view another view will be updated automatically.
 

In Bloc the constraint is to propagate more than 2000 events/second without
to decrease fps, so we cannot afford to x4 the time to process events even
if Announcer is safer and better tested.

I wondering what the source of this constraint? Does Morphic follows it? I guess not, but all Pharo works quite well with it. 


Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier
In reply to this post by stepharo
Hi Stef,


2016-09-01 8:13 GMT+02:00 stepharo <[hidden email]>:
Hi thierry

I think that if we would have a tool to show us the activity I'm quite sure that we would find bugs

or mistaken behavior.

Yes. I did some checks on Morphic and AltBrowser after getting the numbers, to see if I wasn't
doing something wrong with my code.

could you send the scripts you did?

Later today. I don't have access now to the laptop where I did it.

Thierry
 

Stef


Le 30/8/16 à 22:36, Thierry Goubier a écrit :

Numbers for the discussion:

No activity, empty desktop:
announcements            608/minute
subscribe add/remove        9/minute

Activity, AltBrowser:
announcements            1109/minute
subscribe add/remove        207/minute

Activity, Nautilus:
announcements            2488/minute
subscribe add/remove        716/minute

Empirically the same processus in both environments: open two system browser, in one, find the Announcer class, browse through a few of the methods, select basicSubscribe: and ask for senders.

Tracing done with Metalinks during one minute.

Not exactly what I would have expected, especially the ratio subscribe add/remove and announcements.

Thierry

Le 30/08/2016 à 17:36, Henrik Johansen a écrit :

On 30 Aug 2016, at 5:16 , Thierry Goubier
<[hidden email]> wrote:


I have the same concern with an Announcer optimized for certain use
cases, in the fact that the announcer creator is the one choosing
the 'kind of' optimisation it would target, hoping that the
listeners will conform to that use case...


There simply is no silver bullet that will give unbeatable
performance in all scenarios; and focusing on improving one facet of
the default implementation will inevitably lead to either - the loss
of some important property (general thread-safety if removing the
mutex protection, ability to unsubscribe in handler if removing the
copy operation and extending the delivery mutex protection, etc.) -
greatly degenerated performance for another facet (like #remove for
OC's).

That said, the current implementation is very geared towards decent,
balanced subscribe/unsubscribe performance, at the expense of
delivery speed. I've said it before, and still think, that offering
at least one other implementation emphasizing delivery speed over
subscription/unsubscription performance, in the same way the original
implementation did (and/or changing the default Announcer to switch
between the two dynamically based on heuristics) *would* be a
valuable addition to the general library.

Cheers, Henry







Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Denis Kudriashov
In reply to this post by stepharo

2016-09-01 8:18 GMT+02:00 stepharo <[hidden email]>:

But in practice we never share any announcer instance.
Really? You lost me on that sentence. SystemAnnouncer current is shared by all the tools no?

Yes, you are right. I forgot this big monster :). 
Now I look at senders of #announcer and there are many places with chain like "aSomebody announcer when:send:..." or also "aSomebody somebodyElse announcer when:send:...". So forgot my words :)
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Denis Kudriashov

2016-09-01 9:57 GMT+02:00 Denis Kudriashov <[hidden email]>:
Really? You lost me on that sentence. SystemAnnouncer current is shared by all the tools no?

Yes, you are right. I forgot this big monster :). 
Now I look at senders of #announcer and there are many places with chain like "aSomebody announcer when:send:..." or also "aSomebody somebodyElse announcer when:send:...". So forgot my words :)

But these places are definitely smell.
Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier
In reply to this post by Thierry Goubier
Hi Stef,

here is the script I use:

| c1 c2 c3 n1 n2 n3 l1 l2 l3 |
c1 := c2 := c3 := 0.
n1 := (Announcer>>#announce:) ast.
n2 := #(subscribe:do: subscribe:send:to: basicSubscribe:) collect: [ :e | (Announcer>>e) ast ].
n3 := #(unsubscribe: removeSubscription:) collect: [ :e | (Announcer>>e) ast ].
l1 := MetaLink new metaObject: [ c1 := c1 + 1 ]; selector: #value.
l2 := MetaLink new metaObject: [ c2 := c2 + 1 ]; selector: #value.
l3 := MetaLink new metaObject: [ c3 := c3 + 1 ]; selector: #value.
[ n1 link: l1. n2 do: [ :e | e link: l2 ]. n3 do: [ :e | e link: l3 ].
(Duration minutes: 1) wait.
n1 removeLink: l1. n2 do: [ :e | e removeLink: l2 ]. n3 do: [ :e | e removeLink: l3 ].
{ 'announce' -> c1. 'subscribe' -> c2.  'unsubscribe' -> c3 } inspect ] forkAt: Processor userBackgroundPriority

Images intégrées 1

2016-09-01 9:28 GMT+02:00 Thierry Goubier <[hidden email]>:
Hi Stef,


2016-09-01 8:13 GMT+02:00 stepharo <[hidden email]>:
Hi thierry

I think that if we would have a tool to show us the activity I'm quite sure that we would find bugs

or mistaken behavior.

Yes. I did some checks on Morphic and AltBrowser after getting the numbers, to see if I wasn't
doing something wrong with my code.

could you send the scripts you did?

Later today. I don't have access now to the laptop where I did it.

Thierry
 

Stef


Le 30/8/16 à 22:36, Thierry Goubier a écrit :

Numbers for the discussion:

No activity, empty desktop:
announcements            608/minute
subscribe add/remove        9/minute

Activity, AltBrowser:
announcements            1109/minute
subscribe add/remove        207/minute

Activity, Nautilus:
announcements            2488/minute
subscribe add/remove        716/minute

Empirically the same processus in both environments: open two system browser, in one, find the Announcer class, browse through a few of the methods, select basicSubscribe: and ask for senders.

Tracing done with Metalinks during one minute.

Not exactly what I would have expected, especially the ratio subscribe add/remove and announcements.

Thierry

Le 30/08/2016 à 17:36, Henrik Johansen a écrit :

On 30 Aug 2016, at 5:16 , Thierry Goubier
<[hidden email]> wrote:


I have the same concern with an Announcer optimized for certain use
cases, in the fact that the announcer creator is the one choosing
the 'kind of' optimisation it would target, hoping that the
listeners will conform to that use case...


There simply is no silver bullet that will give unbeatable
performance in all scenarios; and focusing on improving one facet of
the default implementation will inevitably lead to either - the loss
of some important property (general thread-safety if removing the
mutex protection, ability to unsubscribe in handler if removing the
copy operation and extending the delivery mutex protection, etc.) -
greatly degenerated performance for another facet (like #remove for
OC's).

That said, the current implementation is very geared towards decent,
balanced subscribe/unsubscribe performance, at the expense of
delivery speed. I've said it before, and still think, that offering
at least one other implementation emphasizing delivery speed over
subscription/unsubscription performance, in the same way the original
implementation did (and/or changing the default Announcer to switch
between the two dynamically based on heuristics) *would* be a
valuable addition to the general library.

Cheers, Henry








Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Denis Kudriashov
Hi Thierry.

2016-09-01 10:21 GMT+02:00 Thierry Goubier <[hidden email]>:
(Duration minutes: 1) wait.

Just to mention our nice language: it could be written as:

 1 minutes wait

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Sven Van Caekenberghe-2
In reply to this post by Thierry Goubier

> On 01 Sep 2016, at 10:21, Thierry Goubier <[hidden email]> wrote:
>
> Hi Stef,
>
> here is the script I use:
>
> | c1 c2 c3 n1 n2 n3 l1 l2 l3 |
> c1 := c2 := c3 := 0.
> n1 := (Announcer>>#announce:) ast.
> n2 := #(subscribe:do: subscribe:send:to: basicSubscribe:) collect: [ :e | (Announcer>>e) ast ].
> n3 := #(unsubscribe: removeSubscription:) collect: [ :e | (Announcer>>e) ast ].
> l1 := MetaLink new metaObject: [ c1 := c1 + 1 ]; selector: #value.
> l2 := MetaLink new metaObject: [ c2 := c2 + 1 ]; selector: #value.
> l3 := MetaLink new metaObject: [ c3 := c3 + 1 ]; selector: #value.
> [ n1 link: l1. n2 do: [ :e | e link: l2 ]. n3 do: [ :e | e link: l3 ].
> (Duration minutes: 1) wait.
> n1 removeLink: l1. n2 do: [ :e | e removeLink: l2 ]. n3 do: [ :e | e removeLink: l3 ].
> { 'announce' -> c1. 'subscribe' -> c2.  'unsubscribe' -> c3 } inspect ] forkAt: Processor userBackgroundPriority

Well, this is really cool code !

> <image.png>
>
> 2016-09-01 9:28 GMT+02:00 Thierry Goubier <[hidden email]>:
> Hi Stef,
>
>
> 2016-09-01 8:13 GMT+02:00 stepharo <[hidden email]>:
> Hi thierry
>
> I think that if we would have a tool to show us the activity I'm quite sure that we would find bugs
>
> or mistaken behavior.
>
> Yes. I did some checks on Morphic and AltBrowser after getting the numbers, to see if I wasn't
> doing something wrong with my code.
>
> could you send the scripts you did?
>
> Later today. I don't have access now to the laptop where I did it.
>
> Thierry
>  
>
> Stef
>
>
> Le 30/8/16 à 22:36, Thierry Goubier a écrit :
>
> Numbers for the discussion:
>
> No activity, empty desktop:
> announcements            608/minute
> subscribe add/remove        9/minute
>
> Activity, AltBrowser:
> announcements            1109/minute
> subscribe add/remove        207/minute
>
> Activity, Nautilus:
> announcements            2488/minute
> subscribe add/remove        716/minute
>
> Empirically the same processus in both environments: open two system browser, in one, find the Announcer class, browse through a few of the methods, select basicSubscribe: and ask for senders.
>
> Tracing done with Metalinks during one minute.
>
> Not exactly what I would have expected, especially the ratio subscribe add/remove and announcements.
>
> Thierry
>
> Le 30/08/2016 à 17:36, Henrik Johansen a écrit :
>
> On 30 Aug 2016, at 5:16 , Thierry Goubier
> <[hidden email]> wrote:
>
>
> I have the same concern with an Announcer optimized for certain use
> cases, in the fact that the announcer creator is the one choosing
> the 'kind of' optimisation it would target, hoping that the
> listeners will conform to that use case...
>
>
> There simply is no silver bullet that will give unbeatable
> performance in all scenarios; and focusing on improving one facet of
> the default implementation will inevitably lead to either - the loss
> of some important property (general thread-safety if removing the
> mutex protection, ability to unsubscribe in handler if removing the
> copy operation and extending the delivery mutex protection, etc.) -
> greatly degenerated performance for another facet (like #remove for
> OC's).
>
> That said, the current implementation is very geared towards decent,
> balanced subscribe/unsubscribe performance, at the expense of
> delivery speed. I've said it before, and still think, that offering
> at least one other implementation emphasizing delivery speed over
> subscription/unsubscription performance, in the same way the original
> implementation did (and/or changing the default Announcer to switch
> between the two dynamically based on heuristics) *would* be a
> valuable addition to the general library.
>
> Cheers, Henry
>
>
>
>
>
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

Thierry Goubier
In reply to this post by Denis Kudriashov


2016-09-01 10:29 GMT+02:00 Denis Kudriashov <[hidden email]>:
Hi Thierry.

2016-09-01 10:21 GMT+02:00 Thierry Goubier <[hidden email]>:
(Duration minutes: 1) wait.

Just to mention our nice language: it could be written as:

 1 minutes wait

Thanks. Didn't find that one when searching through the code. Recovering the userBackgroundPriority message by code browsing and search wasn't too obvious either.

 Thierry

Reply | Threaded
Open this post in threaded view
|

Re: About the non-use of Announcer in Bloc

stepharo
In reply to this post by Thierry Goubier

this is really cool :)


Le 1/9/16 à 10:21, Thierry Goubier a écrit :
Hi Stef,

here is the script I use:

| c1 c2 c3 n1 n2 n3 l1 l2 l3 |
c1 := c2 := c3 := 0.
n1 := (Announcer>>#announce:) ast.
n2 := #(subscribe:do: subscribe:send:to: basicSubscribe:) collect: [ :e | (Announcer>>e) ast ].
n3 := #(unsubscribe: removeSubscription:) collect: [ :e | (Announcer>>e) ast ].
l1 := MetaLink new metaObject: [ c1 := c1 + 1 ]; selector: #value.
l2 := MetaLink new metaObject: [ c2 := c2 + 1 ]; selector: #value.
l3 := MetaLink new metaObject: [ c3 := c3 + 1 ]; selector: #value.
[ n1 link: l1. n2 do: [ :e | e link: l2 ]. n3 do: [ :e | e link: l3 ].
(Duration minutes: 1) wait.
n1 removeLink: l1. n2 do: [ :e | e removeLink: l2 ]. n3 do: [ :e | e removeLink: l3 ].
{ 'announce' -> c1. 'subscribe' -> c2.  'unsubscribe' -> c3 } inspect ] forkAt: Processor userBackgroundPriority

Images intégrées 1

2016-09-01 9:28 GMT+02:00 Thierry Goubier <[hidden email]>:
Hi Stef,


2016-09-01 8:13 GMT+02:00 stepharo <[hidden email]>:
Hi thierry

I think that if we would have a tool to show us the activity I'm quite sure that we would find bugs

or mistaken behavior.

Yes. I did some checks on Morphic and AltBrowser after getting the numbers, to see if I wasn't
doing something wrong with my code.

could you send the scripts you did?

Later today. I don't have access now to the laptop where I did it.

Thierry
 

Stef


Le 30/8/16 à 22:36, Thierry Goubier a écrit :

Numbers for the discussion:

No activity, empty desktop:
announcements            608/minute
subscribe add/remove        9/minute

Activity, AltBrowser:
announcements            1109/minute
subscribe add/remove        207/minute

Activity, Nautilus:
announcements            2488/minute
subscribe add/remove        716/minute

Empirically the same processus in both environments: open two system browser, in one, find the Announcer class, browse through a few of the methods, select basicSubscribe: and ask for senders.

Tracing done with Metalinks during one minute.

Not exactly what I would have expected, especially the ratio subscribe add/remove and announcements.

Thierry

Le 30/08/2016 à 17:36, Henrik Johansen a écrit :

On 30 Aug 2016, at 5:16 , Thierry Goubier
<[hidden email]> wrote:


I have the same concern with an Announcer optimized for certain use
cases, in the fact that the announcer creator is the one choosing
the 'kind of' optimisation it would target, hoping that the
listeners will conform to that use case...


There simply is no silver bullet that will give unbeatable
performance in all scenarios; and focusing on improving one facet of
the default implementation will inevitably lead to either - the loss
of some important property (general thread-safety if removing the
mutex protection, ability to unsubscribe in handler if removing the
copy operation and extending the delivery mutex protection, etc.) -
greatly degenerated performance for another facet (like #remove for
OC's).

That said, the current implementation is very geared towards decent,
balanced subscribe/unsubscribe performance, at the expense of
delivery speed. I've said it before, and still think, that offering
at least one other implementation emphasizing delivery speed over
subscription/unsubscription performance, in the same way the original
implementation did (and/or changing the default Announcer to switch
between the two dynamically based on heuristics) *would* be a
valuable addition to the general library.

Cheers, Henry









123