[ANN] Process-Specific Variables

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

[ANN] Process-Specific Variables

"Martin v. Löwis"
I'd like to announce the first release of Process-Specific Variables,
from

http://www.squeaksource.com/ProcessLocalStorage.html

Process-specific variables are variables that are neither global
nor specific to an object (like instance variables) or to a class.
Instead, they can have a different value in the context of each
Process.

New variables are declared by inheriting from a base class, similar
to the way WADynamicVariable of Seaside works.

There are two kinds of process-specific variables:
- ProcessLocalVariable is the base class for process-specific
   read-write variables. They are similar to thread-local storage
   (TLS) available in various operating systems. Reading and writing
   uses #value and #value:
- DynamicVariable is the base class of dynamically-scoped read-only
   variables. They are similar to the dynamic scoping in LISP.
   They can be read using #value, and set for the duration of a block
   with #value:during:

The implementation uses a per-process dictionary which is keyed by
the variable class.

Comments are welcome,

Martin


Reply | Threaded
Open this post in threaded view
|

RE: [ANN] Process-Specific Variables

Sebastian Sastre-2
Martin,

        I'm sure you are able to think about the aplicability of
Process-Specific Variables. Can you elaborate some examples? I'm pretty sure
I'm not the only one that is not up to date with that and I think it will
help to understand the practical consequences of using them facilitating the
ponderation of it's value.

        thanks,

Sebastian Sastre

> -----Mensaje original-----
> De: [hidden email]
> [mailto:[hidden email]] En
> nombre de "Martin v. Löwis"
> Enviado el: Martes, 13 de Marzo de 2007 16:03
> Para: [hidden email]
> Asunto: [ANN] Process-Specific Variables
>
> I'd like to announce the first release of Process-Specific
> Variables, from
>
> http://www.squeaksource.com/ProcessLocalStorage.html
>
> Process-specific variables are variables that are neither
> global nor specific to an object (like instance variables) or
> to a class.
> Instead, they can have a different value in the context of
> each Process.
>
> New variables are declared by inheriting from a base class,
> similar to the way WADynamicVariable of Seaside works.
>
> There are two kinds of process-specific variables:
> - ProcessLocalVariable is the base class for process-specific
>    read-write variables. They are similar to thread-local storage
>    (TLS) available in various operating systems. Reading and writing
>    uses #value and #value:
> - DynamicVariable is the base class of dynamically-scoped read-only
>    variables. They are similar to the dynamic scoping in LISP.
>    They can be read using #value, and set for the duration of a block
>    with #value:during:
>
> The implementation uses a per-process dictionary which is
> keyed by the variable class.
>
> Comments are welcome,
>
> Martin
>
>


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] Process-Specific Variables

Andreas.Raab
I haven't looked at the code so I'm guessing but from the description it
sounds as if you'd be doing something like:

        ProcessLocalVariable subclass: #MyGlobalVar

and then something like:

        MyGlobalVar value. "retrieve its value"
        MyGlobalVar value: aValue. "set the value"

except that the value of the variable is only valid in the scope of the
current process.

The idea of having a "class per variable" is actually intriguing to me -
I had never thought of it that way but it makes for some interesting
implications. And with a trivial modification to the compiler would
allow you to do something like, e.g.,

        MyGlobalVar. "retrieve value"
        MyGlobalVar := aValue. "set the value"

Cheers,
   - Andreas

Sebastian Sastre wrote:

> Martin,
>
> I'm sure you are able to think about the aplicability of
> Process-Specific Variables. Can you elaborate some examples? I'm pretty sure
> I'm not the only one that is not up to date with that and I think it will
> help to understand the practical consequences of using them facilitating the
> ponderation of it's value.
>
> thanks,
>
> Sebastian Sastre
>
>> -----Mensaje original-----
>> De: [hidden email]
>> [mailto:[hidden email]] En
>> nombre de "Martin v. Löwis"
>> Enviado el: Martes, 13 de Marzo de 2007 16:03
>> Para: [hidden email]
>> Asunto: [ANN] Process-Specific Variables
>>
>> I'd like to announce the first release of Process-Specific
>> Variables, from
>>
>> http://www.squeaksource.com/ProcessLocalStorage.html
>>
>> Process-specific variables are variables that are neither
>> global nor specific to an object (like instance variables) or
>> to a class.
>> Instead, they can have a different value in the context of
>> each Process.
>>
>> New variables are declared by inheriting from a base class,
>> similar to the way WADynamicVariable of Seaside works.
>>
>> There are two kinds of process-specific variables:
>> - ProcessLocalVariable is the base class for process-specific
>>    read-write variables. They are similar to thread-local storage
>>    (TLS) available in various operating systems. Reading and writing
>>    uses #value and #value:
>> - DynamicVariable is the base class of dynamically-scoped read-only
>>    variables. They are similar to the dynamic scoping in LISP.
>>    They can be read using #value, and set for the duration of a block
>>    with #value:during:
>>
>> The implementation uses a per-process dictionary which is
>> keyed by the variable class.
>>
>> Comments are welcome,
>>
>> Martin
>>
>>
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] Process-Specific Variables

Giovanni Corriga
Il giorno mar, 13/03/2007 alle 12.33 -0700, Andreas Raab ha scritto:

> I haven't looked at the code so I'm guessing but from the description it
> sounds as if you'd be doing something like:
>
> ProcessLocalVariable subclass: #MyGlobalVar
>
> and then something like:
>
> MyGlobalVar value. "retrieve its value"
> MyGlobalVar value: aValue. "set the value"
>
> except that the value of the variable is only valid in the scope of the
> current process.

Isn't this similar to what DynamicBindings does?

        Giovanni


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] Process-Specific Variables

"Martin v. Löwis"
In reply to this post by Sebastian Sastre-2
Sebastian Sastre schrieb:
> I'm sure you are able to think about the aplicability of
> Process-Specific Variables. Can you elaborate some examples? I'm pretty sure
> I'm not the only one that is not up to date with that and I think it will
> help to understand the practical consequences of using them facilitating the
> ponderation of it's value.

It's in the wider field of context-oriented/context-aware programming.
Application code (in particular server applications) often have the same
code operating in various contexts, and methods need to find out what
context they operate in.

To give a few examples:
- KomHttpServer includes HttpRequest>>current, which always gives the
   "current" HTTP request. This is set in a process-specific way when
   the request is read from the wire, then all processing methods can
   access it (in the context of a Process), even though they don't
   get the request object as a parameter. This is implemented using the
   DynamicBindings package.
- Seaside offers WACurrentSession>>value, which always provides you
   with the current Seaside session object (related to, but not identical
   with the HTTP request: the session object will store data that
   wasn't transmitted in the last request, but accumulated throughout
   the session). Again, in Seaside, you "always" need to know what
   the "current session" is, but don't want to pass this as a
   parameter.
   At the same time, this can't be a global variable, since multiple
   processes may simulatenously process requests.
- In a transaction environment, there is often a need to know what
   the "current" transaction is.
- In testing, it may be interesting to know whether code is run
   "in" the tester, i.e. whether it was invoked through the test
   runner or not.

These are all examples for dynamic variables: somebody sets it
for a process, then runs some code that only reads it, and then
it should get unset (revert to the previous value).

Process-local variables differ in that a value "persists" even
after the code setting it completes. For an introduction, see

http://en.wikipedia.org/wiki/Thread-local_storage

In Squeak, the only example I could find that may want to use
it is, again, in Seaside:
- WASpotProfiler>>profile: currently reads

        | time value |
        time := Time millisecondsToRun: [value := aBlock value].
        (readings at: Processor activeProcess ifAbsentPut: [OrderedCollection
new]) add: time.
        ^ value

   With process-local variables that could change to

         time := Time millisecondsToRun: [value := aBlock value].
        WAReadings value add: time.
         ^value

   Here, I use the feature that the process-local variables as
   I defined them allow the definition of a default value,
   which would be OrderedCollection new in the case of WAReadings.
   Of course, one would also need a way to gather totals across
   all processes (I'm uncertain why WASpotProfiler collects
   them per-process).

- In VisualWorks, a similar mechanism is available; they use
   process-local variables to record the "current debugger"
   per Process, and to inject values into a process from the
   outside.

- Also in VW, they have per-process UI managers.

- In the GNU C library, thread-local storage is used to reduce
   contention in memory management. Each thread has its own
   memory arena from which memory is allocated, and global
   synchronization is only performed when the arena is exhausted.

- Also in the C library, the value of errno (the last error
   that occurred) is thread-specific. It can't be a dynamic
   variable, since it is set by the callee, and read by the
   caller.

- A random-number generator may store its state in a thread-local
   object, in order to provide a repeatable sequence of pseudo-
   random number on a per-thread basis (rather than having
   other threads interfere by picking numbers out of that sequence).


In reviewing code from other languages, it seems that they often
use thread-local variables as the foundation for implementing
dynamic variables on top of it. I believe there is a use for
both of them, so I included them both.

HTH,
Martin

Reply | Threaded
Open this post in threaded view
|

Re: [ANN] Process-Specific Variables

"Martin v. Löwis"
In reply to this post by Andreas.Raab
Andreas Raab schrieb:
> I haven't looked at the code so I'm guessing but from the description it
> sounds as if you'd be doing something like:
>
>     ProcessLocalVariable subclass: #MyGlobalVar
>
> and then something like:
>
>     MyGlobalVar value. "retrieve its value"
>     MyGlobalVar value: aValue. "set the value"

Exactly so.

> except that the value of the variable is only valid in the scope of the
> current process.

Right. If no value was set, the variable will get a #default message,
to which it can either provide a value, or raise an error. The default
for default is nil.

> The idea of having a "class per variable" is actually intriguing to me -
> I had never thought of it that way but it makes for some interesting
> implications. And with a trivial modification to the compiler would
> allow you to do something like, e.g.,
>
>     MyGlobalVar. "retrieve value"
>     MyGlobalVar := aValue. "set the value"

The tricky part is to still allow access to the class, e.g. for
further subclassing, browsing, etc, if desired.

Anyway, if there is interest, I'm happy to contribute it to the Squeak
project, in some form.

Regards,
Martin


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] Process-Specific Variables

Andreas.Raab
In reply to this post by Giovanni Corriga
Giovanni Corriga wrote:
> Il giorno mar, 13/03/2007 alle 12.33 -0700, Andreas Raab ha scritto:
>> MyGlobalVar value. "retrieve its value"
>> MyGlobalVar value: aValue. "set the value"
>
> Isn't this similar to what DynamicBindings does?

Good question, I don't know (anyone knowing DynamicBindings care to
compare the approaches?) I've looked at the code in the meantime and it
does exactly what I thought it would ;-) though there was one thing that
surprised me: ProcessSpecificVariable caches the computed hash value,
which I assume it does for performance reasons. The reason this
surprises me is that I would not have expected this to have a
significant performance impact, maybe that's just a left-over?

But anyway, the idea is pretty cool, and I'm sure I can find uses for
it. If someone could compare/contrast with DynamicBindings this would be
greatly appreciated, too.

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: [ANN] Process-Specific Variables

"Martin v. Löwis"
In reply to this post by Giovanni Corriga
Giovanni Corriga schrieb:
>> except that the value of the variable is only valid in the scope of the
>> current process.
>
> Isn't this similar to what DynamicBindings does?

Indeed. I see two important differences, though:
- different (better?) implementation strategy: DynamicBinding is based
   on exceptions to find the innermost binding; this requires a stack
   walk for a matching exception handler. It then uses a linked list of
   dictionaries for lookup. So lookup time is typically linear with the
   stack depth, and then linear with the depth of the binding stack.
   My implementation offers constant-time lookup (if there are no
   dictionary collisions), as it has the current value always in the
   current process (getting the current process, getting a slot of it,
   fetching the reference to the global class, and passing that as
   a dictionary key are all constant-time).
- separation of process-local and dynamic variables: in DynamicBindings,
   you can rebind a variable at any point in time, and it uses the
   innermost binding (whereever that is). In my solution, dynamic
   variables can be only set, then read, but not written (i.e. rebound).
   Experiences with dynamic scoping in LISP show that they might be
   difficult to understand; I expect that making them read-only gives
   more readable code, as you don't need to worry that a function
   you call may change the value behind you.
   OTOH, process-local variables are read-write, but they don't have
   any nesting to them. This is, AFAICT, not directly supported in
   DynamicBinding, as you need to create at least one scope
   explicitly to establish per-process values. In process-local
   variables (called TLS elsewhere), every Process will have it own
   value for it right from the start, using a default mechanism.

Regards,
Martin



Reply | Threaded
Open this post in threaded view
|

Re: [ANN] Process-Specific Variables

"Martin v. Löwis"
In reply to this post by Andreas.Raab
Andreas Raab schrieb:
> Good question, I don't know (anyone knowing DynamicBindings care to
> compare the approaches?) I've looked at the code in the meantime and it
> does exactly what I thought it would ;-) though there was one thing that
> surprised me: ProcessSpecificVariable caches the computed hash value,
> which I assume it does for performance reasons. The reason this
> surprises me is that I would not have expected this to have a
> significant performance impact, maybe that's just a left-over?

It is indeed for performance reasons. Computing the hash alone,

1000000 timesRepeat:[C hash]

for some class C, on my machine, uses roughly 900ms to run
using the standard class hash, and uses 180ms to run using
the cached hash. A plain C yourself loop uses 120ms. So for
the hashing alone, the speedup is fairly dramatic (factor of
30, roughly). I haven't timed the impact on complete lookup
time for a variable (but could do so if there is interest).

In any case, that's a minor detail of the implementation;
taking it out has no effect other than slowing it a bit
and freeing 4 bytes per subclass.

> But anyway, the idea is pretty cool, and I'm sure I can find uses for
> it. If someone could compare/contrast with DynamicBindings this would be
> greatly appreciated, too.

See the message I just sent. In summary: DynamicBindings uses a stack
walk to find the innermost binding (using notifications). I couldn't
completely understand the implementation, as it has code like
'tmp _ thisContext. "..." tmp sender sender sender swapSender:
something' in it, but I still think that lookup should be fairly
expensive for a deep stack. I also don't like it that it mixes
nested scopes with allowing write access from any point in the
control flow.

Regards,
Martin