Dynamic protocol performance

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

Dynamic protocol performance

Zulq Alam-2
Apologies for the long post. There have been so many lately. I wanted to
share my progress and thoughts about dynamic protocol performance.

There are four really troublesome dynamic protocols:

   DPLong          reads all sources
   DPUncommented   reads all sources
   DPSupplied      lengthy analysis, no caching
   DPRequired      lengthy analysis, no caching

When you browse to a class or a browser refreshes, each dynamic protocol
is (re)calculated to determine whether it should be listed. It is then
recalculated when selected. If the protocol is cacheable, the cache will
be used when populated. Refreshes can be triggered by browsing, class
changes or do-its and print-its (many of these unrelated).

I've uploaded a package to SqueakSource which should help
(DynamicProtocols-za.69). On the basis that it is better to list an
empty protocol I allow protocols to define a pain threshold. If the
target class has more selectors than this pain threshold, the protocol
is always displayed and only calculated when accessed.

To help determine whether a protocol has been calculated, protocol names
now include the number of methods they contain, e.g. "-- long (?) --" or
"-- override (3) --". A "?" means the number of selectors is above the
pain threshold and the protocol will be calculated on access.

I've also had a stab at the required protocol (the worst offender):

| selectors  |
selectors := Set new.
aClass allSuperclasses reverseDo:
   [:eachSuperclass |
   eachSuperclass selectorsAndMethodsDo:
     [:eachSelector :eachMethod |
     selectors remove: eachSelector ifAbsent: [].
     eachMethod isRequired
       ifTrue: [selectors add: eachSelector]]].
selectors removeAllFoundIn: aClass selectors.
^ selectors

This is faster than using Behaviour>>#requiredSelectors but also gives
completely different results! I have either misunderstood what
"required" means or something isn't right with one or the other.

For example, "AColorSelectorMorph requiredSelectors" answers 16
selectors that are not required, many are not even from the same hierarchy.

Anyway, the pain thresholds probably needs some adjustment but it all
seems useable in my image. I'd be interested to hear how it works for
others and any comments on changes.

Thanks,
Zulq.


Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

JuanjoE
Hello, first of all, sorry for my english. I'll try to make me  
understand.

I like the idea behind dynamic protocols, but in fact, I have it  
deactivated in my working image.

The first thing that is annoying to me is the progress bar. I think  
that in this particular case it makes the feel of a more slow  
function. I make a clik on a class and i see a little window that  
appear and dissapear. perhaps is better to no show anything.

The other think that I'm thinking, I don't know if it is possible with  
the OB design, but can you make the calculations in an asynchronic way?
So if I click on a class, I see the normal protocols without stopping  
my work and in less than a second a few extra protocols appear. I  
don't know, it's an idea.

Regards
-------------------------------------------
La vida es como un partido de ajedrez contra uno mismo. Siempre ganás,
siempre perdés.

On 06/02/2008, at 21:06, Zulq Alam wrote:

> Apologies for the long post. There have been so many lately. I  
> wanted to share my progress and thoughts about dynamic protocol  
> performance.
>
> There are four really troublesome dynamic protocols:
>
>  DPLong          reads all sources
>  DPUncommented   reads all sources
>  DPSupplied      lengthy analysis, no caching
>  DPRequired      lengthy analysis, no caching
>
> When you browse to a class or a browser refreshes, each dynamic  
> protocol is (re)calculated to determine whether it should be listed.  
> It is then recalculated when selected. If the protocol is cacheable,  
> the cache will be used when populated. Refreshes can be triggered by  
> browsing, class changes or do-its and print-its (many of these  
> unrelated).
>
> I've uploaded a package to SqueakSource which should help  
> (DynamicProtocols-za.69). On the basis that it is better to list an  
> empty protocol I allow protocols to define a pain threshold. If the  
> target class has more selectors than this pain threshold, the  
> protocol is always displayed and only calculated when accessed.
>
> To help determine whether a protocol has been calculated, protocol  
> names now include the number of methods they contain, e.g. "-- long  
> (?) --" or "-- override (3) --". A "?" means the number of selectors  
> is above the pain threshold and the protocol will be calculated on  
> access.
>
> I've also had a stab at the required protocol (the worst offender):
>
> | selectors  |
> selectors := Set new.
> aClass allSuperclasses reverseDo:
>  [:eachSuperclass |
>  eachSuperclass selectorsAndMethodsDo:
>    [:eachSelector :eachMethod |
>    selectors remove: eachSelector ifAbsent: [].
>    eachMethod isRequired
>      ifTrue: [selectors add: eachSelector]]].
> selectors removeAllFoundIn: aClass selectors.
> ^ selectors
>
> This is faster than using Behaviour>>#requiredSelectors but also  
> gives completely different results! I have either misunderstood what  
> "required" means or something isn't right with one or the other.
>
> For example, "AColorSelectorMorph requiredSelectors" answers 16  
> selectors that are not required, many are not even from the same  
> hierarchy.
>
> Anyway, the pain thresholds probably needs some adjustment but it  
> all seems useable in my image. I'd be interested to hear how it  
> works for others and any comments on changes.
>
> Thanks,
> Zulq.
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Damien Cassou-3
In reply to this post by Zulq Alam-2
Hi Zulq,

thank you very much for your work. Let me try to explain what the
DynamicProtocol #required means. The documentation on the class says:
«I contain all selectors you have to implement in order to make your
class concrete». This takes into account:

- #subclassResponsibilites methods
- messages you send but for which there is no implementation (even if
you do not implement a #subclassResponsibility)
- required methods comming from traits.

I think RequiredSelectors does its job well (the algorithm is complex
and is the subject of an scientific article). We probably have to use
it in some way. Maybe we just have to set up an interest on this
class, I don't know.


Good luck

On Feb 7, 2008 12:06 AM, Zulq Alam <[hidden email]> wrote:

> Apologies for the long post. There have been so many lately. I wanted to
> share my progress and thoughts about dynamic protocol performance.
>
> There are four really troublesome dynamic protocols:
>
>    DPLong          reads all sources
>    DPUncommented   reads all sources
>    DPSupplied      lengthy analysis, no caching
>    DPRequired      lengthy analysis, no caching
>
> When you browse to a class or a browser refreshes, each dynamic protocol
> is (re)calculated to determine whether it should be listed. It is then
> recalculated when selected. If the protocol is cacheable, the cache will
> be used when populated. Refreshes can be triggered by browsing, class
> changes or do-its and print-its (many of these unrelated).
>
> I've uploaded a package to SqueakSource which should help
> (DynamicProtocols-za.69). On the basis that it is better to list an
> empty protocol I allow protocols to define a pain threshold. If the
> target class has more selectors than this pain threshold, the protocol
> is always displayed and only calculated when accessed.
>
> To help determine whether a protocol has been calculated, protocol names
> now include the number of methods they contain, e.g. "-- long (?) --" or
> "-- override (3) --". A "?" means the number of selectors is above the
> pain threshold and the protocol will be calculated on access.
>
> I've also had a stab at the required protocol (the worst offender):
>
> | selectors  |
> selectors := Set new.
> aClass allSuperclasses reverseDo:
>    [:eachSuperclass |
>    eachSuperclass selectorsAndMethodsDo:
>      [:eachSelector :eachMethod |
>      selectors remove: eachSelector ifAbsent: [].
>      eachMethod isRequired
>        ifTrue: [selectors add: eachSelector]]].
> selectors removeAllFoundIn: aClass selectors.
> ^ selectors
>
> This is faster than using Behaviour>>#requiredSelectors but also gives
> completely different results! I have either misunderstood what
> "required" means or something isn't right with one or the other.
>
> For example, "AColorSelectorMorph requiredSelectors" answers 16
> selectors that are not required, many are not even from the same hierarchy.
>
> Anyway, the pain thresholds probably needs some adjustment but it all
> seems useable in my image. I'd be interested to hear how it works for
> others and any comments on changes.
>
> Thanks,
> Zulq.
>
>
>


--
Damien Cassou


Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Damien Cassou-3
In reply to this post by JuanjoE
On Feb 7, 2008 3:21 AM, Juan José Evangelista <[hidden email]> wrote:
> The first thing that is annoying to me is the progress bar. I think
> that in this particular case it makes the feel of a more slow
> function. I make a clik on a class and i see a little window that
> appear and dissapear. perhaps is better to no show anything.


There was no progress bar before and I think it was even more
annoying: your image was very slow and you never knew why. Now, you
know this is because of DynamicProtocols.


> The other think that I'm thinking, I don't know if it is possible with
> the OB design, but can you make the calculations in an asynchronic way?
> So if I click on a class, I see the normal protocols without stopping
> my work and in less than a second a few extra protocols appear. I
> don't know, it's an idea.

--
Damien Cassou


Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Daniel Vainsencher-3
In reply to this post by Damien Cassou-3


Damien Cassou wrote:
[snip]
> I think RequiredSelectors does its job well (the algorithm is complex
> and is the subject of an scientific article). We probably have to use
> it in some way. Maybe we just have to set up an interest on this
> class, I don't know.
>  
This is exactly right. Nathanael has written very efficient code for
calculating the required methods of all subclasses of a class at once,
but it is not efficient enough to always calculate the whole image.
Running it on a particular class as needed is very inefficient. By
registering interest in every class in every category being displayed at
the moment, we allow the Model Extension mechanism to calculate exactly
what is needed by running Nathanael's code only on what needs to be
updated, in as large a batch as possible. This allows all queries to be
answered from one unified cache for all active browsers and tools, that
is updated as efficiently as possible, and only when necessary (relevant
code is changed).

Daniel

>
> Good luck
>
> On Feb 7, 2008 12:06 AM, Zulq Alam <[hidden email]> wrote:
>  
>> Apologies for the long post. There have been so many lately. I wanted to
>> share my progress and thoughts about dynamic protocol performance.
>>
>> There are four really troublesome dynamic protocols:
>>
>>    DPLong          reads all sources
>>    DPUncommented   reads all sources
>>    DPSupplied      lengthy analysis, no caching
>>    DPRequired      lengthy analysis, no caching
>>
>> When you browse to a class or a browser refreshes, each dynamic protocol
>> is (re)calculated to determine whether it should be listed. It is then
>> recalculated when selected. If the protocol is cacheable, the cache will
>> be used when populated. Refreshes can be triggered by browsing, class
>> changes or do-its and print-its (many of these unrelated).
>>
>> I've uploaded a package to SqueakSource which should help
>> (DynamicProtocols-za.69). On the basis that it is better to list an
>> empty protocol I allow protocols to define a pain threshold. If the
>> target class has more selectors than this pain threshold, the protocol
>> is always displayed and only calculated when accessed.
>>
>> To help determine whether a protocol has been calculated, protocol names
>> now include the number of methods they contain, e.g. "-- long (?) --" or
>> "-- override (3) --". A "?" means the number of selectors is above the
>> pain threshold and the protocol will be calculated on access.
>>
>> I've also had a stab at the required protocol (the worst offender):
>>
>> | selectors  |
>> selectors := Set new.
>> aClass allSuperclasses reverseDo:
>>    [:eachSuperclass |
>>    eachSuperclass selectorsAndMethodsDo:
>>      [:eachSelector :eachMethod |
>>      selectors remove: eachSelector ifAbsent: [].
>>      eachMethod isRequired
>>        ifTrue: [selectors add: eachSelector]]].
>> selectors removeAllFoundIn: aClass selectors.
>> ^ selectors
>>
>> This is faster than using Behaviour>>#requiredSelectors but also gives
>> completely different results! I have either misunderstood what
>> "required" means or something isn't right with one or the other.
>>
>> For example, "AColorSelectorMorph requiredSelectors" answers 16
>> selectors that are not required, many are not even from the same hierarchy.
>>
>> Anyway, the pain thresholds probably needs some adjustment but it all
>> seems useable in my image. I'd be interested to hear how it works for
>> others and any comments on changes.
>>
>> Thanks,
>> Zulq.
>>
>>
>>
>>    
>
>
>
>  
> ------------------------------------------------------------------------
>
>
>  



Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Zulq Alam-2
In reply to this post by Damien Cassou-3
Damien Cassou wrote:

> - messages you send but for which there is no implementation (even if
> you do not implement a #subclassResponsibility)

Ahh.. OK, thanks. So these are implicitly required. Mostly I would be
interested in the explicit case and rarely in the implicit case.

I think it would be better to make two protocols, "explicitly required"
and "implicitly required" (maybe with better names). What do you think?

The performance of the implicit protocol wont be proportional to the
number of selectors and will be bad so it could specify a pain threshold
of 0. Therefore, it's calculation would always be deferred.

> I think RequiredSelectors does its job well (the algorithm is complex
> and is the subject of an scientific article). We probably have to use
> it in some way. Maybe we just have to set up an interest on this
> class, I don't know.

Declaring interest wont help with initial access. Here the only options
you have are to (a) optimize #requiredSelectors, (b) never do it, (c) do
it asynchronously, (d) do it only when you really must. I have gone for
option (d) for simplicity. I may have a look at (a) when I get some time.

Thanks,
Zulq.


Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Zulq Alam-2
In reply to this post by JuanjoE
Juan José Evangelista wrote:
>
> The first thing that is annoying to me is the progress bar. I think that
> in this particular case it makes the feel of a more slow function. I
> make a clik on a class and i see a little window that appear and
> dissapear. perhaps is better to no show anything.
>

I intend to remove this once sufficient improvements have been made. In
the package I have uploaded it has already been removed to aid testing.

> The other think that I'm thinking, I don't know if it is possible with
> the OB design, but can you make the calculations in an asynchronic way?

I considered this. Basically, I don't know how to do this with the OB
infrastructure. Instead I settled for delaying calculation of slow
protocols until they are clicked on.

For instance, if I browse to Morph in my image I quickly see:

-- long (?) --
-- uncommented (?) --
-- debugging (1) --
-- supplied (?) --
-- override (43) --
-- supersend (10) --
-- local (1213) --

The ?'s indicate that the protocol is slow and has not been calculated
yet. It will only slow me down if I click on one of them, i.e. if I am
interested in finding methods which are long, uncommented, supplied or
required.

If the class is small, say less than 20 selectors, then the protocols
are calculated as before. This needs some tuning.

As someone who is interested in dynamic protocols, what do you think of
this?

Thanks,
Zulq.



Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Zulq Alam-2
In reply to this post by Zulq Alam-2
Zulq Alam wrote:

> Declaring interest wont help with initial access.

I am wrong about this. Even cold access is improved by declaring interest.

class := PluggableListMorph.
class withAllSuperclasses do: [:e | LocalSends current clearOut: e].
"LocalSends current
   lostInterest: nil
   inAll: class withAllSuperclasses."


Time millisecondsToRun: [class requiredSelectors]. " 3481 "

LocalSends current
   noteInterestOf: nil
   inAll: PluggableListMorph withAllSuperclasses.

Time millisecondsToRun: [class requiredSelectors]. " 333 "

I think 333 is still noticeable.


Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

SergeStinckwich
In reply to this post by Zulq Alam-2
Zulq Alam a écrit :

> Juan José Evangelista wrote:
>>
>> The first thing that is annoying to me is the progress bar. I think
>> that in this particular case it makes the feel of a more slow
>> function. I make a clik on a class and i see a little window that
>> appear and dissapear. perhaps is better to no show anything.
>>
>
> I intend to remove this once sufficient improvements have been made. In
> the package I have uploaded it has already been removed to aid testing.
>
>> The other think that I'm thinking, I don't know if it is possible with
>> the OB design, but can you make the calculations in an asynchronic way?
>
> I considered this. Basically, I don't know how to do this with the OB
> infrastructure. Instead I settled for delaying calculation of slow
> protocols until they are clicked on.
>
> For instance, if I browse to Morph in my image I quickly see:
>
> -- long (?) --
> -- uncommented (?) --
> -- debugging (1) --
> -- supplied (?) --
> -- override (43) --
> -- supersend (10) --
> -- local (1213) --
>
> The ?'s indicate that the protocol is slow and has not been calculated
> yet. It will only slow me down if I click on one of them, i.e. if I am
> interested in finding methods which are long, uncommented, supplied or
> required.
>
> If the class is small, say less than 20 selectors, then the protocols
> are calculated as before. This needs some tuning.
>
> As someone who is interested in dynamic protocols, what do you think of
> this?


I think this is the way to go in the right way. The list should be
updated asynchronously when the user is not interacting with the UI.
Maybe, if you click on a dynamic protocol and when the list is very time
consuming to build, the methods should appears progressively.

--
Serge Stinckwich
http://doesnotunderstand.free.fr/


Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Damien Cassou-3
In reply to this post by Zulq Alam-2
On Feb 7, 2008 10:32 AM, Zulq Alam <[hidden email]> wrote:
> Damien Cassou wrote:
>
> > - messages you send but for which there is no implementation (even if
> > you do not implement a #subclassResponsibility)
>
> Ahh.. OK, thanks. So these are implicitly required. Mostly I would be
> interested in the explicit case and rarely in the implicit case.


This is because you are used to not having this information I guess.
Imagine, you code a method #m and, during its writing, you notice you
want another method #m2 to do part of the job. You can code #m and
send #m2, then, in your browser on the Dynamic Protocol Required, you
can click on the method #m2 and start coding it.


> I think it would be better to make two protocols, "explicitly required"
> and "implicitly required" (maybe with better names). What do you think?


I think it will be confusing but you may have a different opinion.
Just implement what you prefer.


> The performance of the implicit protocol wont be proportional to the
> number of selectors and will be bad so it could specify a pain threshold
> of 0. Therefore, it's calculation would always be deferred.

I agree.

> > I think RequiredSelectors does its job well (the algorithm is complex
> > and is the subject of an scientific article). We probably have to use
> > it in some way. Maybe we just have to set up an interest on this
> > class, I don't know.
>
> Declaring interest wont help with initial access. Here the only options
> you have are to (a) optimize #requiredSelectors, (b) never do it, (c) do
> it asynchronously, (d) do it only when you really must. I have gone for
> option (d) for simplicity. I may have a look at (a) when I get some time.
>
> Thanks,
> Zulq.
>
>
>



--
Damien Cassou

Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Damien Cassou-3
In reply to this post by Zulq Alam-2
On Feb 7, 2008 10:47 AM, Zulq Alam <[hidden email]> wrote:

> Juan José Evangelista wrote:
> >
> > The first thing that is annoying to me is the progress bar. I think that
> > in this particular case it makes the feel of a more slow function. I
> > make a clik on a class and i see a little window that appear and
> > dissapear. perhaps is better to no show anything.
> >
>
> I intend to remove this once sufficient improvements have been made. In
> the package I have uploaded it has already been removed to aid testing.
>
> > The other think that I'm thinking, I don't know if it is possible with
> > the OB design, but can you make the calculations in an asynchronic way?
>
> I considered this. Basically, I don't know how to do this with the OB
> infrastructure. Instead I settled for delaying calculation of slow
> protocols until they are clicked on.
>
> For instance, if I browse to Morph in my image I quickly see:
>
> -- long (?) --
> -- uncommented (?) --
> -- debugging (1) --
> -- supplied (?) --
> -- override (43) --
> -- supersend (10) --
> -- local (1213) --
>
> The ?'s indicate that the protocol is slow and has not been calculated
> yet. It will only slow me down if I click on one of them, i.e. if I am
> interested in finding methods which are long, uncommented, supplied or
> required.
>
> If the class is small, say less than 20 selectors, then the protocols
> are calculated as before. This needs some tuning.
>
> As someone who is interested in dynamic protocols, what do you think of
> this?
I really appreciate your work on this project. I believe Dynamic
Protocols can be really appreciated if they are fast and easy to use.
In Visual Works, when we released them, a lot of people told us they
liked it and they start implementing their own protocols.


--
Damien Cassou


Reply | Threaded
Open this post in threaded view
|

Re: Dynamic protocol performance

Damien Cassou-3
In reply to this post by Zulq Alam-2
On Feb 7, 2008 12:21 PM, Zulq Alam <[hidden email]> wrote:

> Zulq Alam wrote:
>
> > Declaring interest wont help with initial access.
>
> I am wrong about this. Even cold access is improved by declaring interest.
>
> class := PluggableListMorph.
> class withAllSuperclasses do: [:e | LocalSends current clearOut: e].
> "LocalSends current
>    lostInterest: nil
>    inAll: class withAllSuperclasses."
>
>
> Time millisecondsToRun: [class requiredSelectors]. " 3481 "
>
> LocalSends current
>    noteInterestOf: nil
>    inAll: PluggableListMorph withAllSuperclasses.
>
> Time millisecondsToRun: [class requiredSelectors]. " 333 "
>
> I think 333 is still noticeable.


Does it still feels slow?


--
Damien Cassou