Efficient thread-local shared variables
reinz at desk.org
Tue Oct 24 08:02:47 UTC 2006
> 2) Use message lookup, e.g., send a message. This is simple to
> describe but not necessarily simple to implement correctly. Here is
> how the simulation would look like:
I have experimented with this in VisualWorks (to implement a new
namespace system, not per-process pools) with great results regarding
speed. The two concepts I needed (stolen from Forth) where Vocabulary
(a Dictionary) and SearchOrder (a stack of those dictionaries). My
breakthrough came when I realized that my search rules in a
SearchOrder where the same as those the VM uses when doing method
So I implemented a Vocabulary 'instance' as a pair of a anonymous
class and a singleton instance of that class, lookup is done by
sending a message to the instance (fast), insertion/removal is done
by adding/removing methods in the class (slow).
The methods are very simple: they return their first literal, where
the literal slot holds the value to be returned from the dictionary
for the key assigned as that method's selector.
> ProtoObject>>lookup: sharedBinding
> "Look up the value of the given shared binding in the currently
> executing process."
> ^[Processor activeProcess scope perform: sharedBinding key]
> on: MessageNotUnderstood do:[:ex| ex return: nil].
In my scheme you can get rid of the cost of this exception handler by
reimplementing #doesNotUnderstand: on the anonymous class so it
raises a KeyNotFound error (or returns nil as your snippet suggests).
In VW #doesNotUnderstand: is fully supported by the VM optimizations
(ICs, PICs, hoisting etc..) making lookup misses a fast path, I don't
know whether Squeak does the same in the case of #doesNotUnderstand:,
you may want to measure that.
^Processor activeScope perform: sharedBinding key
> One problem here is that the key needs to be unique within all
> possible keys which is a problem if there is a name conflict. This
> can be resolved by implicitly prefixing names with the place where
> they are defined so it's not such big of a deal conceptually but
> practically the impact of that change might be more visible.
This is where SearchOrder enters the picture (assuming your conflicts
arise because you don't model scoping).
SearchOrder is implemented by chaining Vocabularies through the
#superclass attribute of the anonymous class. The VM will run through
this chain when a miss happens on the first Vocabulary and the nice
thing is that it will probably optimize future lookup of this key (by
Implementing scoping is obviously more involved since you need to
know /where from/ the lookup is performed.
^(Procesor activeScopeFor: self class) perform: sharedBinding key
Perhaps you can make gains by cashing the per-process SearchOrders
belonging only to this calling scope in the sharedBinding?
^(sharedBinding scopeFor: Processor activeProcess) perform:
"we lost the 'self class' because the binding already 'knows' that"
That last snippet clearly wants to be implemented on sharedBinding
instead of ProtoObject ;-)
> The other problem is that the scope object needs to hold all the
> objects which means quite a number of them. OTOH, one could argue
> that in many ways "Smalltalk" is just an object with a few thousand
> iVars so having a class representing the namespace defined by
> Smalltalk may be quite reasonable.
In my scheme Smalltalk would be modeled by an anonymous class that
implements thousands of methods, each with one literal, no ivars are
So you are limited by the maximum number of methods a class may
implement. I guess that is infinite for our purposes, but if Squeak
does have an upper limit on the number of methods per class you can
work around that by splitting the oversized Vocabularies into
multiple Vocabularies that are placed adjacent in the SearchOrder.
I don't actively follow this list, so please CC reinz at desk.org if you
have any questions.
Furthermore I'm vain, so please credit me if you decide to run with
More information about the Squeak-dev