[Pharo-project] Ideas for CompiledMethod proxies?

Mariano Martinez Peck marianopeck at gmail.com
Sat Nov 20 16:40:15 CET 2010


On Fri, Nov 19, 2010 at 11:03 PM, Eliot Miranda <eliot.miranda at gmail.com>wrote:

> Hi Mariano,
>
>     it strikes me that the class and selector are implicit in method
> dictionaries.  So if you use a zero-sized object to replace a method (one
> word in memory if you make it an instance of a compact class) you can find
> its class and selector by searching all method dictionaries in the class
> hierarchy.  In an image with approximately 90,000 methods on a 2.66GHz Core
> i7 it takes Cog 15 milliseconds on average to locate a method in the
> hierarchy:
>
> | cms |
> cms := CompiledMethod allInstances.
> cms := (1 to: cms size by: 100) collect: [:i| cms at: i].
> { Time millisecondsToRun:
> [cms do:
>  [:cm|
> [:exit|
> ProtoObject withAllSubclasses do:
>  [:c|
> c selectorsAndMethodsDo: [:s :m| m == cm ifTrue: [exit value]]]]
> valueWithExit]].
>  cms size } #(13371 917)
> 13371 / 917.0 14.58124318429662
> CompiledMethod instanceCount 91696
>
> So one thing might be to use a zero-sized object.
>
> Of course you could use a one instance variable object whose instance
> variable was the class and then things would be /much/ faster, with only one
> method dictionary to search.
>
>
Thanks Eliot for the idea. I didn't think about searching the method in the
whole hierarchy because I thought it was going to be much slower. And its
true, storing a pointer to the class will be fast enought.

So...taking into account all the answers I think I should discard the idea
of using the SAME proxy instance for everybody and using fileName patterns
to guess the file. It seems there is no way. So...if I need an instance per
proxy, now let's see how to make this object as small as possible. In the
case you told me, the object will be zero sized and if the class is compact,
then it would be just one word.
But the "search" will take some time.....if I store the class pointer, then
it would be 8 bytes per proxy...

This is why I liked the Levente solution (I answer after to him).


> Or perhaps you could use a 4-byte byte array and keep the identity hash of
> the class and the identity hash of the selector in two 16-bit values in the
> 4-byte array, but this wouldn't get you anything over and above the one
> instance variable object pointing to the class.
>

Exactly. The only thing here is that since I have both, class and selector,
and don't need to do the search in the class method dict.


> However, if you are talking abut optimizing a closed world then this does
> hold water.  One thing you can do if you *really* want to save space is
> eliminate symbols, replacing them by integers.  The lookup machinery should
> be able to deal with a SmallInteger selector, and if it doesn't it has a
> bug.  This is a space saving technique I first heard about in the ActiveBook
> which used my BrouHaHa VM and ParcPlace's Smalltalk-80 v2.3 back in the 80's
> to produce an early tablet computer.  So the idea is to number classes and
> selectors and use the selector numbers to replace symbols.  Now the byte
> array makes sense because if you have < 64k symbols and < 64k classes you
> have the class and the selector directly.
>

exactly!


If you were clever you could put the selector numbering in the compiler and
> keep the symbol table externally in a file, mapping selector number to
> symbol there-in.  Obviously the tricky thing is in eliminating or
> implementing asSymbol in perform: usage.
>

ahhhhh  ok, I got the idea :)

Thanks Eliot for the help.


>  Sometimes you see horror show code like
>     self perform: (self opPrefix, self opSuffix) asSymbol
> which makes it /really/ hard to find implementors and senders (and IMO
> people who write this kind of thing should be shot, and IIRC there is stuff
> like this in the change notification code, ARGH!!!).
>
> HTH
> Eliot
>
> On Fri, Nov 19, 2010 at 12:47 PM, Mariano Martinez Peck <
> marianopeck at gmail.com> wrote:
>
>> Hi. I am developing kind of proxies for unused compiled methods. I want to
>> detect them, put a proxy instead of them, and swap them to disk. Then, in
>> case they are used, I put back the original ones. With this, I want to
>> realease memory. This is why I need the proxy objects to be as small as
>> possibles.
>>
>> Right now, I do something like this:
>>
>> aProxy := CompiledMethodProxyReferenceStreamWithFileName installOn:
>> ClassWith1Var selector: #foo.
>>
>> this will instantiate the proxy, do the ClassWith1Var methodAt: #foo put:
>> proxy, write the original compiledMethod that was in #foo into a file,
>> etc....
>>
>> and then if I do "ClassWith1Var new foo", then using the #run:with:in  I
>> load the file from disk and I put back the original method. To know WHICH
>> file I have to load, I have to store the fileName in the proxy object.
>>
>> In addition, if I DON'T execute the compiled method, but instead I send a
>> message, for example:
>>
>> (ClassWith1Var >> #foo) literals
>>
>> this has to do the same: load and put back the original compiled method.
>> To do this, I use the doesNotUnderstand:.
>>
>> This is easy to do if I store the fileName in the proxy instance. Right
>> now, I am using as fileName this:  CLASS >> SELECTOR. For example, in this
>> case, the file would be named "ClassWith1Var >> #foo"
>>
>> Now.....with this solution, I need create an proxy instance for each
>> compiled method, and these instances have also another instance for the
>> filename. If I could use the same proxy instance for everybody, the amount
>> of memory released would be muuuuch more. So I thought that maybe from the
>> context I can "guess" the filename if I use conventions.
>>
>> For example, if you do "ClassWith1Var new foo" then in the #run:with:in I
>> receive all the information to KNOW that the fileName should be
>> "ClassWith1Var >> #foo". So, no problem here.
>>
>> But for the second case, suppose "(ClassWith1Var >> #foo) literals", I
>> don't see a way to know this.  In this case, #literals is intercepted by the
>> doesNotUnderstand: of my proxy, and here I should load back the original
>> compiled method from disk. The problem is that I cannot know in which CLASS
>> and SELECTOR this proxy was put. The only way I know to do this, is to store
>> the class + selector in the proxy instance....but it is the same...I will
>> need an instance per compiled method. In such case is even easier to
>> directly store the fileName.
>>
>> Anyway, if someone has a solution or advice on this, I would be
>> appreciated that. I tried with thisContext, but it didn't help me.
>>
>> Thanks
>>
>> Mariano
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.gforge.inria.fr/pipermail/pharo-project/attachments/20101120/7e0efd6a/attachment.htm>


More information about the Pharo-project mailing list