Hello,
I know there are some Self experts in this mailing list, that's why I am asking a question related to it there. What would be the best strategy to have variables not accessed by using their index, but rather by sending messages correspondong to their accessors/mutators.
I feel that an efficient implementation would require new bytecode, therefore hardcoding this in the VM.
Markus Denker has an implementation that use an object-as-compiled trick to delay the recompilation of a method, but the assumption was not to modify the VM.
Anyone can confirm or infirm what I wrote ?
Cheers, Alexandre
Alex,
What is your intent? To hide instance variables only? This can be done "simply" using the subclass creation protocole. I worked on something like that in the ClassTalk system. In this context since instance variable names aren't (easily) available to developers, they have no choice except using accessors.
No extra-byte code is introduced. The only overhead is that you replace a direct access to an IV with an message.
Noury Le 21 juin 05, à 16:29, Alexandre Bergel a écrit :
Hello,
I know there are some Self experts in this mailing list, that's why I am asking a question related to it there. What would be the best strategy to have variables not accessed by using their index, but rather by sending messages correspondong to their accessors/mutators.
I feel that an efficient implementation would require new bytecode, therefore hardcoding this in the VM.
Markus Denker has an implementation that use an object-as-compiled trick to delay the recompilation of a method, but the assumption was not to modify the VM.
Anyone can confirm or infirm what I wrote ?
Cheers, Alexandre
-- _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;: Alexandre Bergel http://www.iam.unibe.ch/~bergel ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
-------------------------------------------------------------- Dr. Noury Bouraqadi - Enseignant/Chercheur Ecole des Mines de Douai - Dept. G.I.P http://csl.ensm-douai.fr/noury
European Smalltalk Users Group Board http://www.esug.org
Squeak: an Open Source Smalltalk http://www.squeak.org --------------------------------------------------------------
Am 21.06.2005 um 16:29 schrieb Alexandre Bergel:
Hello,
I know there are some Self experts in this mailing list, that's why I am asking a question related to it there. What would be the best strategy to have variables not accessed by using their index, but rather by sending messages correspondong to their accessors/mutators.
I feel that an efficient implementation would require new bytecode, therefore hardcoding this in the VM.
Markus Denker has an implementation that use an object-as-compiled trick to delay the recompilation of a method, but the assumption was not to modify the VM.
Anyone can confirm or infirm what I wrote ?
I'm not quite sure what you actually want to achieve ...
Tweak's compiler supports a variation of "implicit self", so "foo" is actually compiled into "self foo", but only if "foo" was declared as field (in contrast to Self, which uses implicit self universally). Fields are the Tweak-equivalent of an instance variable. Similarly, "foo := <expr>" is compiled as "self foo: (<expr>)".
So this compiler change lets you use entities looking like instance variables in the code that are actually referenced by message sends. Is that what you need?
- Bert -
Am 21.06.2005 um 18:29 schrieb Bert Freudenberg:
Am 21.06.2005 um 16:29 schrieb Alexandre Bergel:
Hello,
I know there are some Self experts in this mailing list, that's why I am asking a question related to it there. What would be the best strategy to have variables not accessed by using their index, but rather by sending messages correspondong to their accessors/ mutators.
Do you really need the message send or just the "name" instead of offset? These are two different things... the offset is needed for e.g. Traits with state, but sends only for stuff like persistance.
I feel that an efficient implementation would require new bytecode, therefore hardcoding this in the VM.
If you want message sends for instance access, you don't need new bytecodes. you just need to change the compiler to emit a send for instance var access. (For the new compiler, this is quite trivial to do), or use Geppetto to reify instance var access.
Of course, this is slow. So if you just want to late-bind the name to the offset, then it would be faster to have bytecode for accessing instVars by name. This would be slower than doing offsets, but nevertheless much faster then sends, as no lookup needs to be done, no method needs to be executed.
The third idea is that the offsets rarely change even when developing and they are (mostly) constant at runtime. So with some form of runtime-translator, you could have the smalltalk compiler generate sends, and then have the "jit" to replace the sends on first call with offsets. All offset changing opereations (those that now force recompilation of the class hierarchy) would then just invalidate the cache. This approach would cost mostly memory, runtime would be as good as offsets, after the sytem "warms up".
Marcus
Sorry to not have given more information about what I try to achieve. I have been working on adding state to traits. The idea is that the offset for a variable is not constant anymore. For instance, let's assume the following:
T1 defines v1 "offset of v1 = 1" T2 defines v2 "offset of v2 = 1" T3 uses T2 + T1 "offset of v2 = 1 and v1 = 2"
Currently I use the instVarName to access variable (note that I prefixed them like T1.v1). I have a running implementation, but accessing variable in this way is quite slow (about 1000 times slower).
Do you really need the message send or just the "name" instead of offset? These are two different things... the offset is needed for e.g. Traits with state, but sends only for stuff like persistance.
Actually I need to access variables through their names. However their offset is not constant (cf my previous example)
Of course, this is slow. So if you just want to late-bind the name to the offset, then it would be faster to have bytecode for accessing instVars by name. This would be slower than doing offsets, but nevertheless much faster then sends, as no lookup needs to be done, no method needs to be executed.
Ok, therefore having a new byte-code would make this solution usuable. I guess this is the way adopted by Self...
Thanks to all of you! Alexandre
Am 21.06.2005 um 21:14 schrieb Alexandre Bergel:
I guess this is the way adopted by Self...
Not really. Self is based of the idea to have a good, dynamically optimizing compiler. So they can just use message sends to describe instVarAccess. (Remember, there are only slots in Self which unify both mothods and instVars). But then the system can just inline everything, thus get rid of the send.
Marcus
Alexandre Bergel wrote:
Sorry to not have given more information about what I try to achieve. I have been working on adding state to traits. The idea is that the offset for a variable is not constant anymore. For instance, let's assume the following:
T1 defines v1 "offset of v1 = 1" T2 defines v2 "offset of v2 = 1" T3 uses T2 + T1 "offset of v2 = 1 and v1 = 2"
This looks like premature static optimization for me. What's wrong with just using messages? E.g., if all references to v1 and v2 are compiled into message sends (something the compiler can do trivially [*]) you can define the "offset" in any way you like in the leaf class (T3).
[*] And this is starting to look a *lot* like Tweak ;-)
Currently I use the instVarName to access variable (note that I prefixed them like T1.v1). I have a running implementation, but accessing variable in this way is quite slow (about 1000 times slower).
Really? What benchmark are you using? Given that a) sends are roughly 30x slower than byte codes (which is a loooong ways from 1000x slower) and that b) accessors do not require activations (which makes the difference a looooot less than the above factor of 30x) there doesn't seem to be a good reason for it being 1000x slower. A really dumb little test (not that useful but just to get a gross feeling for the situation) seems to indicate that the difference is nowhere near the general send/bytecode difference:
a) [1 to: 10000000 do:[:i| ]] timeToRun. => ~500 msecs
b) [1 to: 10000000 do:[:i| a := b + c]] timeToRun. => ~700 msecs
c) [1 to: 10000000 do:[:i| a := self b + self c]] timeToRun. => ~1500 msecs
d) [1 to: 10000000 do:[:i| self a: self b + self c]] timeToRun. => ~2880 msecs
Note the dramatic relative increase between c) and d) which I believe is caused by the activation required for the mutator. But it looks like we're not getting anywhere near the theoretical 30x difference in speed and clearly there is no 1000x slowdown anywhere in sight ;-)
Please say more about this - I'm interested in this for obvious reasons.
Cheers, - Andreas
Alexandre Bergel wrote:
Currently I use the instVarName to access variable (note that I prefixed them like T1.v1). I have a running implementation, but accessing variable in this way is quite slow (about 1000 times slower).
Andreas Raab responded:
Really? What benchmark are you using? Given that a) sends are roughly 30x slower than byte codes (which is a loooong ways from 1000x slower) and that b) accessors do not require activations (which makes the difference a looooot less than the above factor of 30x) there doesn't seem to be a good reason for it being 1000x slower.
I haven't seen Alex's code, but 1000x doesn't sound far fetched. If he's using #instVarNamed: it's more than just sending an accessor. It's a send with a full activation, which does several more full sends to ask the class for the names of its instance variables, iterate over them checking for equality, then call the primitive to fetch the value based on index. Slooow.
I'm liking the sound of Tweak's approach here. I imagine it's the kind of thing that Exupery could optimize nicely, so it could perform very well, but it would also be more dynamic than the current offset-based system.
Colin
Colin Putney wrote:
I haven't seen Alex's code, but 1000x doesn't sound far fetched. If he's using #instVarNamed: it's more than just sending an accessor. It's a send with a full activation, which does several more full sends to ask the class for the names of its instance variables, iterate over them checking for equality, then call the primitive to fetch the value based on index. Slooow.
Oh. Yes. #instVarNamed: ... oh dear. Yes, I see how this would be a 1000x slower ;-)
I'm liking the sound of Tweak's approach here. I imagine it's the kind of thing that Exupery could optimize nicely, so it could perform very well, but it would also be more dynamic than the current offset-based system.
Depends on how well Exupery does adaptive inlining. But if I had the choice I'd opt for more send performance before dealing with adaptive inlining - with an average of 300 cycles per send there is a lot of room for optimizations and optimizing sends in general would help out many other areas.
Cheers, - Andreas
Andreas Raab wrote:
Colin Putney wrote:
I'm liking the sound of Tweak's approach here. I imagine it's the kind of thing that Exupery could optimize nicely, so it could perform very well, but it would also be more dynamic than the current offset-based system.
Depends on how well Exupery does adaptive inlining. But if I had the choice I'd opt for more send performance before dealing with adaptive inlining - with an average of 300 cycles per send there is a lot of room for optimizations and optimizing sends in general would help out many other areas.
Agreed, which is why I like Tweak's approach. The key to optimizing Smalltalk is making sends fast, and if inst var access is just another send, that gets optimized as well. Exupery seems to be moving along nicely in this area - PICs are already done, and adaptive inlining is just the ultimate optimization of a send: remove it entirely.
In fact, Bryce's recent work on compiling specialized primitives seems like just the ticket here. He can generate inlined, class-specific implementations of #at: which have the offsets figured out at compile time. I suspect that accessing named instance variables would have a lot in common with that.
Colin
Colin Putney writes:
Agreed, which is why I like Tweak's approach. The key to optimizing Smalltalk is making sends fast, and if inst var access is just another send, that gets optimized as well. Exupery seems to be moving along nicely in this area - PICs are already done, and adaptive inlining is just the ultimate optimization of a send: remove it entirely.
The question is how to optimise sends. Dynamic inlining is probably the best way to avoid the cost of creating a new context and shuffling arguments. It also exposes more code for classical optimisations.
It wouldn't be hard to make self and super sends completely free by inlining them without a type check. The trick is to compile a method once for each receiver class which allows all self sends to be easily resolved at compile time. Exupery already compiles a different version of a method for each receiver, this is to specialise code for #at:. I think that Self used this trick.
Exupery currently treats #at:s as normal sends then inlines the primitive, this gets '820,512,820 bytecodes/sec; 14,907,050 sends/sec'. Using the at cache and special bytecodes only got 700 million bytecodes/second. Exupery is using a normal send and type checks, I'd rather optimise the general case first.
Bryce
On 21 juin 05, at 21:37, Andreas Raab wrote:
Alexandre Bergel wrote:
Sorry to not have given more information about what I try to achieve. I have been working on adding state to traits. The idea is that the offset for a variable is not constant anymore. For instance, let's assume the following: T1 defines v1 "offset of v1 = 1" T2 defines v2 "offset of v2 = 1" T3 uses T2 + T1 "offset of v2 = 1 and v1 = 2"
This looks like premature static optimization for me. What's wrong with just using messages? E.g., if all references to v1 and v2 are compiled into message sends (something the compiler can do trivially [*]) you can define the "offset" in any way you like in the leaf class (T3).
I can reply (but I may be I'm wrong I did not look at the implementation of alex). Our idea was ok let us try to have dictionary like semantics for state composition and how does it solve the problem to introduce state in traits. So we took really the most dummy approach just to get a feel of the model. Because we wanted to understand how the model should looks like. So our initial implementation is certainly not the best because this is a hack. But thanks for the discussion.
Traits with state breaks the flatenning property but this is fun to see a language with only traits :)
Stef
This looks like premature static optimization for me. What's wrong with just using messages? E.g., if all references to v1 and v2 are compiled into message sends (something the compiler can do trivially [*]) you can define the "offset" in any way you like in the leaf class (T3).
My first goal was to avoid having accessors to access variable. But you're right, this might probably be the way to go.
Currently I use the instVarName to access variable (note that I prefixed them like T1.v1). I have a running implementation, but accessing variable in this way is quite slow (about 1000 times slower).
I was comparing using direct variable access and using reflection through instVarNamed: However, when I measure this access again I obtain: o := Time now. Time millisecondsToRun: [1 to: 100000 do: [:i| o asSeconds]]. ==> 23 Time millisecondsToRun: [1 to: 100000 do: [:i| o instVarNamed: 'seconds']]. ==> 1968
Which is about 85 times slower.
you are right, probably we will go for generating accessor/mutator for each variable access.
Cheers, Alexandre
Alexandre Bergel writes:
This looks like premature static optimization for me. What's wrong with just using messages? E.g., if all references to v1 and v2 are compiled into message sends (something the compiler can do trivially [*]) you can define the "offset" in any way you like in the leaf class (T3).
My first goal was to avoid having accessors to access variable. But you're right, this might probably be the way to go.
A decent way to make some selectors only accessible to local methods would be another solution. I avoid accessors because they make it much harder to find encapsulation, a better way to control encapsulation would make accessors much less semantically offensive.
Theoretically, there is no performance cost to using accessors. If access local to the object then they can be optimised away. If access is not local then a type check or send is required.
Bryce
squeak-dev@lists.squeakfoundation.org