Monday, March 23, 2009

Concurrency

I'm depressed.

Over the last couple of weeks, I've been playing with various Smalltalk implementations. I always had this idea that some of them could use multiple CPU cores. As it turns out, none of them do it, and the ones that do concurrency don't do it well.

VisualWorks
is single-threaded. Squeak is single-threaded. Smalltalk/X didn't fully use two CPU cores. Smalltalk/MT should, but didn't. Huemul 0.7 tried... but crashed.

[update: Smalltalk/MT does use multiple cores as Peter Lount points out in the comments, but is severely limitied by the garbage collector.]

Igor's Hydra VM does concurrency the hard way: by making a completely separate VM in a separate thread but in the same process (using OS terminology here): VMs can communicate with each other, but each is single-threaded. Gemstone, I hear, can make multiple Gems which share a transacted memory, but each Gem is single threaded.

Surely it can't be that hard to make a VM that does fine-grained concurrency?

Smalltalk, the language, is ideally suited to concurrency. The language lends itself to creating concurrent abstractions and already has basic support, but there's no implementation which can take advantage of the CPU power.

Smalltalk VMs are not going to be running any faster if we don't start exploring concurrency. The free ride in MHz increases is about to end soon (in theory, anyway). Moreso, the best Smalltalk VM can only use quarter of the power of a quad-core CPU, and this unused potential will increase exponentially as the number of cores increases exponentially.

What am I going to do about it? Well, I'm going to be modifying the Process scheduler in Squeak to simulate multiple CPU cores. Individual Processes will have their speed throttled down so that using multiple forked processes will be required to get a speed increase. Then I will, eventually, start writing concurrent frameworks to take advantage of the "multiple cores". This way, if some smart alec makes me a nice concurrent VM, they have concurrent code to take advantage of it.

Thursday, March 12, 2009

Playing with Blocks

Today I learned about blocks. We Smalltalkers all know and love blocks: those bits of code in square brackets that we can do all sorts of dandy tricks with. So what evils are there?


Well, Evil Trick number one:

b := [ ^ Transcript show: 'In the block'; cr ].

... in another method:

b value.
Transcript show: 'After the block evaluation'; cr.

The latter message will not be printed on the transcript. When you evaluate a block that has a return statement in it (a "non-local" return), the current context is abruptly terminated and the method context where the block was defined is returned from.


Evil trick number two:

b := [ ^ 1 ].
[ b value ] fork.

This will cause >>cannotReturn: to be evaluated on the BlockContext. The block has a non-local return in it but it cannot return. The containing MethodContext of that block is not on the call stack, because the block is evaluated in another process which has its another stack. When a non-local return happens, the VM searches down the call stack until it finds the method that the block is defined in.

This will also happen if you get a block with a non-local return by calling a method that defines it and then evaluate that block after the method returns:

someMethod
^ [ ^ 1 ].

self someMethod value. "Fails"


Evil trick number three:

s := Semaphore new.
b := [ s wait ].
[ b value ] fork.
[ b value ] fork.

This will fail in Squeak, although it shouldn't. Squeak has an optimisation that prevents two concurrent evaluations of the same block. I'm not entirely sure why, but it certainly hinders concurrent programming in Squeak (that, and the fact that Squeak is single threaded).

It also happens if you get a block to evaluate itself:

b := [:block | block value: block].
b value: b


Evil trick number four:

[ |b| b := 'bar'] value.
[ |b| ^ b] value.

You would expect to get a nil, but in Squeak, you'll get a 'bar' instead. This is because block variables are defined in their method contexts rather than in their block contexts. This is what the community is complaining about when they complain about the lack of closure support. So, how do you fix it?

[ |b| b := 'bar'] value.
[ |b| ^ b] fixTemps value.

This version does not work: fixTemps disallows a block from doing non-local returns. How about:

| result |
[ |b| b := 'bar'] value.
[ |b| result := b] fixTemps value.
^ result.

Lame, but it actually works like it should. nil is returned.

Sunday, February 22, 2009

Low-level graphics in Squeak

It wasn't until I dug into how low-level graphics worked in Squeak that I realised how trivial it was.

To draw on the screen, use the global variable "Display". This is an instance of a subclass of Form. A Form is a bitmap. To draw on Forms, you use "BitBlt" instances, which represent drawing commands.

For handling events from the mouse and keyboard, you use the global variable Sensor, which is an instance of EventSensor. In a loop, you call EventSensor>>nextEvent to get the next event, which is either "nil" or the next keyboard or mouse event. Yes, you need to poll it, and if you don't want to use 100% CPU, then you need to suspend your thread for, say, 20ms on every iteration.

Except for the details, that's all you need to do to draw on the screen and handle events. There's plenty of example code in a stock Squeak image.

Now comes the tricky part: how do you wrestle control of these objects from Morphic? Well, as it turns out, Morphic wasn't designed in the resiliant, secure and reactive way I would have designed it. Morphic is single threaded! When you run your code, you're running it in the same Process that handles event handling and screen drawing! So if you never return from your event polling loop, Morphic never runs (unless a Transcript is open and you write something to it).

I find the single-threadedness of Morphic rather quaint.

Alternatively, you can use:
Project uiProcess suspend. "This suspends the Morphic process; make sure your code runs in another process!"
Project spawnNewProcess " If you terminated the Morphic process, this makes a fresh one. "

Sunday, February 8, 2009

SiteBrowser

Last night I started work on a new SiteBrowser. This time, it will only use the Subcanvas API to do drawing and event management.

Hopefully it won't take much more time before I can release SecureSqueak version 0.1. I think I'll revise the schedule to make lots more releases each with fewer new features.

In the meanwhile, Matthew Fulmer has sent a progress report about Squeak 4.0. I'm not sure if that should affect me. My current state of thinking is that I'll be making such vast changes to the kernel that it doesn't really matter which version I begin with.

Monday, January 19, 2009

Subcanvas progress

I'm always impressed by how quick you can get stuff working in Smalltalk and Squeak. I spent a couple of hours over the last weekend getting events working in Subcanvas. I haven't touched it for a month now as I've only just come back from a 3-week holiday with my family.

So now Subcanvas can process left mouse button clicks. I coded up a small demo where the mouse click handler drew small 5mm x 5mm squares on the screen. You can add a child canvas, and the events and redrawing works in the simple case.

Tuesday, November 25, 2008

Unicode in Squeak

(Excuse the odd formatting; blogger.com isn't liking my Unicode symbols in this post and is doing odd things with line heights)

Somebody on the Squeak mailing list asked about how to do an open Interval. I came up with:

1 to: ∞

I had added "∞" as a global variable equal to "Float infinity" and my example... just worked! When I was looking at the character table for the infinity sign, I came across a ton of other gems. These would be all quite possible in Squeak, and many of them trivial.

( (22 ÷ 7) ≈ (π ± ¼) ) → true or false, π and ¼ are constants and ± would return an object representing a numeric accuracy object of some sort.
((c ∪ d) ⊂ e) → true or false for collections c, d, and e.
(a ∧ b ∨ c) ¬ " The not-sign needs to come after expressions. "

1 … 3 → returns an interval. The ellipses is a single Unicode character.
2¹⁶ → 2 raisedTo: 16.
∅ → An empty, immutable Set instance.

There are loads of symbols available that would work as constants, method selectors, variables (greek letters anybody?) and so forth. Some of them won't work, such as using a dollar-sign for currency values. I'm not sure about '∃' and '∀' because of Smalltalk's message order; these two symbols are some odd prefix-type expression.

Another useful symbol would be some sort of concatenation operator, but (not being a proper mathematician) I don't know one. This operator would allow you to easily make a collection, e.g.

#a | ∅ " A new set containing #a. This could be implemented, but '|' is already used in Boolean operations. "
varA | varB | varC | ∅ " Shorthand for making a collection. Replace '∅' to change the type of collection. "

There's a Unicode character called a "Character tie": http://www.fileformat.info/info/unicode/char/2040/index.htm. Would this make a potential concatenation operator?:

varA ⁀ varB ⁀ varC ⁀ ∅ " Meh "

Tuesday, November 4, 2008

Subcanvas: first graphics.

A screenshot:


 
What is it? Well, it's an orange line, green rectangle, filled blue rectangle and small blue bit of text. The relevance here is that I've gotten some basic graphics output from Subcanvas.

The features that you aren't seeing here are:
  • The code for this is in a Package, and the classes are all in Namespaces. Namespaces really work! Although... I have found some more nasty bugs that destroy code.
  • The coordinates used are measured in micrometers. Those are 20mm by 20mm boxes on my screen, roughly.
My next steps are to add support for child canvases and keyboard / mouse event handling.