November 03, 2009

A First Attempt at Haiku

Normally I'm shy about my poetry but I think I can be brave enough to share 3 lines and 17 syllables.

Talking to my Project Manager last night, I said that a particularly gnarly problem would probably be solved by about 3 lines of code, but which 3 lines of code? He laughed and said that was going to be a piece of software haiku. He went to a neighbouring desk tossing out a line that he would like to see some haiku from me and this is what I produced in the 3 minutes he was away.

Code glows on white screen;
Incandescent thought laid bare,
Human to Machine.

I hope that you like it.

October 26, 2009

Octopussies...


Nope - I'm not referring to multiples of a James Bond Film - I'm referring instead to a family tradition.

My mother has for as long as I can remember given an 'Octopussy' to the young children of family and friends. An Octopussy is a friendly octopus crocheted out of wool:

To start the body:
  • Make a chain of 6 or 7 stitches and then form a circle using whatever colour wool you have to hand..
  • Using double crochet make a flat circle about 2 or 3 inches in diameter.
  • Continue adding rows to the circle without increasing the number of stitches and this will form a cup shape.
  • Change to white to continue in order to make a space for the eyes to be embroidered.
  • Continue until you have a nice wide band for the eyes.
Now make 8 thick crochet legs as long as you like:
  • Start trimming the edge with double crochet in a contrasting colour going through the middle of the chain.
  • Continue down to one end and crochet in the long strands.
  • Turn and do a second row of double crochet and turn again to give a 3 row 'foot'.
  • Continue until you reach the end that you started with.
  • Using the loose strands from each of the feet pull them through the flat circle at the base of the body and tie them off to attach the legs.
Finish the body;
  • Embroider the eyes.
  • Change colour from the white to whatever colour you like.
  • Continue with crochet decreasing with each row.
  • When you are close to the end stuff the body with a non-toxic filling (my mother uses a form of foam chips).
  • finish the top of the body and pull final thread through to lose it in the body.
  • Make a long chain with two or three strands of wool.
  • Pull the chain halfway through the top of the Octopussy placing a knot so that it cannot be shifted.
  • The chain can then be tied onto a convenient point so that the Octopussy cannot be thrown out of a pram or cot.
The Octopussy contains only wool, thread and stuffing so there are no small hard parts that can be pulled off and cause a hazard. It is very robust to chewing and is fully washable.

It also has the advantage of leaving the child with a friendly view of Octopi!

October 13, 2009

GPGPU Mandelbrot with OpenCL and Java

I've done a fair amount of learning since I last posted. OpenCL stopped being just a specification and now has a concrete implementation.

I upgraded my MacBook to Snow Leopard and got access to a fairly solid implementation. I say 'fairly' because it exhibits a few interesting quirks... I can pretty reliably get it to throw memory access errors even when I am doing nothing exotic. More about this if I can nail down why it is happening.

I've recently installed ATI Stream SDK 2.0 beta 2 to my 'Windows Beast' only to discover that beta 3 is the only one so far that works with the toolkit that I am using.

At present I am using OpenCL4Java to provide the Java bindings to OpenCL they are developing fast and have the advantage of using JNA so there needs to be no native installs past the OpenCL drivers.

It has proved both easier and harder than I expected - I hadn't realised how much C I had forgotten, but then again the syntactical similarities with Java made it easier for me to get to grips with.

I walked through the various examples and tinkered with them until I had at least a basic grip. For my first program I decided to use a nearly perfect algorithm for scaling on multiple threads, the Mandelbrot set. Pseudo code for the algorithm is widely disseminated but to be honest the OpenCL implementation is clear enough. I'll present my take here and with it I will highlight some of the interesting features of OpenCL.
__kernel mandelbrot(
const float deltaReal,
const float deltaImaginary,
const float realMin,
const float imaginaryMin,
const unsigned int maxIter,
const unsigned int magicNumber,
const unsigned int hRes,
__global int* outputi
)
{
int xId = get_global_id(0);
int yId = get_global_id(1);

float realPos = realMin + (xId * deltaReal);
float imaginaryPos = imaginaryMin + (yId * deltaImaginary);
float real = realPos;
float imaginary = imaginaryPos;
float realSquared = real * real;
float imaginarySquared = imaginary * imaginary;

int iter = 0;
while ( (iter < maxIter) && ((realSquared + imaginarySquared) < magicNumber) )
{
imaginary = (2 * (real * imaginary)) + imaginaryPos;
real = realSquared - imaginarySquared + realPos;
realSquared = real * real;
imaginarySquared = imaginary * imaginary;
iter++;
}
if(iter >= maxIter){
iter = 0;
}
outputi[(yId * hRes) + xId] = iter;
}
First thing I'll highlight is the fact that I've only non-pixel specific parameters - all pixel specific variables are calculated in the OpenCL program. At present I'm only using floats - the implementations have yet to support doubles.

The coordinates of the pixel / work group are retrieved using the OpenCL specific function : get_global_id(int dimension). Currently Open CL supports 1,2 and 3 dimensional coordinate spaces.

The OpenCL language is mainly derived from C99 and should be pretty easy for C/C++/Java developers to read. The main difference is exclusions - a lot of the default libraries and some control of flow instructions. There are a few additions such as the work group / unit functions and the '__kernel' keyword.

The OpenCL4Java source code is pretty simple:
package bbbob.gparallel.mandelbrot;
import com.nativelibs4java.opencl.*;
import static com.nativelibs4java.opencl.OpenCL4Java.*;
import com.nativelibs4java.util.NIOUtils;

import javax.imageio.ImageWriter;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.IOException;
import java.io.File;
import java.nio.IntBuffer;
import java.awt.image.BufferedImage;

public class Mandelbrot {
//boundary of view on mandelbrot set

public static void main(String[] args) throws IOException, CLBuildException {

//Setup variables for parameters

//Boundaries
float realMin = -2.25f; //-0.19920f; // -2.25
float realMax = 0.75f; //-0.12954f; // 0.75
float imaginaryMin = -1.5f; //1.01480f; // -1.5
float imaginaryMax = 1.5f; //1.06707f; // 1.5

//Resolution
int realResolution = 640; // TODO validate against device capabilities
int imaginaryResolution = 640;

//The maximum iterations to perform before returning and assigning 0 to a pixel (infinity)
int maxIter = 64;

//TODO describe what this number means...
int magicNumber = 4;

//Derive the distance in imaginary / real coordinates between adjacent pixels of the image.
float deltaReal = (realMax - realMin) / (realResolution-1);
float deltaImaginary = (imaginaryMax - imaginaryMin) / (imaginaryResolution-1);

//Setup output buffer
int size = realResolution * imaginaryResolution;
IntBuffer results = NIOUtils.directInts(size);

//TODO use an image object directly.
//CL.clCreateImage2D(context.get(), 0, OpenCLLibrary);
//TODO set up a Float4 array in order to be able to provide a colour map.
//This depends on whether we will be able to pass in a Float4 array as an argument in the future.

//Read the source file.
String src = readFully(
new InputStreamReader(Mandelbrot.class.getResourceAsStream("opencl/mandelbrot.cl")),
new StringBuilder()
).toString();

buildAndExecuteKernel(realMin, imaginaryMin, realResolution, imaginaryResolution, maxIter, magicNumber,
deltaReal, deltaImaginary, results, src);


outputResults(realResolution, imaginaryResolution, results);
}

private static void outputResults(int realResolution, int imaginaryResolution,
IntBuffer results) {
int[] outputResults = new int[realResolution * imaginaryResolution];

results.get(outputResults);
BufferedImage image = new BufferedImage(realResolution, imaginaryResolution, BufferedImage.TYPE_INT_RGB);
for(int y = 0; y < imaginaryResolution; y++){
int rowPos = y * imaginaryResolution;
for(int x = 0; x < realResolution; x++){
image.setRGB(x,y,outputResults[rowPos + x] * 32 );
}
}

try {
ImageWriter writer = ImageIO.getImageWritersByFormatName("gif").next();
ImageOutputStream stream = ImageIO.createImageOutputStream(new File("test.gif"));
writer.setOutput(stream);
writer.write(image);
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}


// for (int i = 0; i < outputResults.length; i++) {
// if((i % realResolution) == 0 ){
// System.out.print("\n");
// }
// int outputResult = outputResults[i];
// if(outputResult == 0){
// System.out.print("0");
// }else{
// System.out.print("" + outputResult % 10);
// }
// }
}

private static void buildAndExecuteKernel(float realMin, float imaginaryMin, int realResolution,
int imaginaryResolution, int maxIter, int magicNumber, float deltaReal,
float deltaImaginary, IntBuffer results, String src) throws CLBuildException {
//TODO build some intelligence into the mechanism for pulling out platforms and devices.
CLPlatform[] platforms = listPlatforms();
CLDevice[] devices = platforms[0].listGPUDevices(false);

//Create a context and program using the devices discovered.
CLContext context = platforms[0].createContext(devices);
CLProgram program = context.createProgram(src).build();

//Create a kernel instance from the mandelbrot kernel, passing in parameters.
CLKernel kernel = program.createKernel(
"mandelbrot",
deltaReal,
deltaImaginary,
realMin,
imaginaryMin,
maxIter,
magicNumber,
realResolution,
context.createIntBuffer(CLMem.Usage.Output, results, false)
);

//Enqueue and complete work using a 2D range of work groups corrsponding to individual pizels in the set.
//The work groups are 1x1 in size and their range is defined by the desired resolution. This corresponds
//to one device thread per pixel.
CLQueue queue = context.createDefaultQueue();
kernel.enqueueNDRange(queue, new int[]{realResolution, imaginaryResolution}, new int[]{1,1});
queue.finish();
}

public static CharSequence readFully(Reader reader, StringBuilder builder) throws IOException {

char[] buffer = new char[8192];
for (int readLen = reader.read(buffer); readLen >= 0; readLen = reader.read(buffer)){
builder.append(buffer, 0, readLen);
}
return builder;
}

}

I'm finding it pretty easy to work with OpenCL - now I need to identify some more complex problems to solve.

May 07, 2009

Balance in Business and Technical Architectures

I've worked in a number of organisations over the years. These organisations were many and varied but one pattern seemed to be repeated without fail.

The cycle of centralisation and de-centralisation.

This seems to be a very disruptive and expensive cycle.. The time and effort wasted on reorganising must detract from the company bottom line. I've spent some time trying to work out why this cycle happens and how to resolve it.

Both centralisation and de-centralisation has their positives and their negatives. Centralisation allows the rationalisation of processes and resources but increases the rigidity of the organisation, reducing its ability to respond to changing conditions. De-centralisation can make the company more flexible and agile but risks different segments of the organisation wasting resources through unnecessary competition.

The trouble seems to be that the people at the helm don't seem to understand the interplay of benefits and consequences. This may be due to the way that information about the organisation is presented to them. There is a belief that only simple messages can be delivered at the executive level and so they hear stark messages like 'We're too centralised, we must de-centralise' or 'We're too de-centralised we must de-centralise'. They aren't told the detail and texture.

When they hear these messages, they feel they must act decisively.

It may also be that the hardest thing in business is the same as the hardest thing in politics: Be seen to do nothing. Perhaps the only way out of this cycle is for the bosses to make smaller, more considered changes but to do that takes better communications and finer filters.

I wonder whether Service Oriented Architecture is an example of a potential business architecture that can be used to break this cycle. It balances by centralising the control of the interfaces between business units and systems, but de-centralises the system implementations. The technologies of the interfaces are centralised and controlled but the technologies of the implementations can be the ones most suited to their requirements.

Of course the SOA model can be centralised when someone imposes the implementation technologies on the business units.

I think that there is a balance that must be struck between centralisation and de-centralisation. When I find a large company that manages it I'll be fascinated to see how they achieve it.

April 14, 2009

I just thought that I would share with the world a little bit of my family history. I am a descendent of Samuel Boote (1844-1921) a reasonably well known Argentine photographer. One of our cousins kindly loaned me a copy of the genealogy tracing the descendents of Samuel's grandfather, also Samuel Boote (1788-1854). I've scanned the pages as images and felt that it would be a good idea to make them more widely available.

To that end I just want to post on my blog that I have these images available and publish the 3 pages that I feel that I can show without violating data protection laws as they only refer to the long-dead.

If anyone wishes to contact me regarding access to more of the genealogy please leave a comment.



February 10, 2009

Pair Programming Interviews

My current project has undergone an highly protracted round of interviews due in part to the hiring freeze that for some strange reason started in September.

This was my first set of interviews where I used pair programming as part of the interview process.

It was extremely effective. We used a highly simplified 'story' to test the candidate's design and coding skills. The story defined an UserManager middleware component that was used to register new users given a login and an e-mail address. The inputs were to be validated and an e-mail sent to the e-mail address containing an auto-generated password.

An empty Eclipse or IntelliJ project was provided with Spring, JUnit and all the mocking frameworks available as dependencies. A working Maven 2 build was implemented on the command line. The candidate was asked to provide an implementation of the middleware component and provide interfaces for all the dependencies that this component required.

There were two interviewers with the candidate, one acting as pair and the other as the product owner.

We were looking for a clear understanding of interface-implementation separation, understanding of how unit testing and dependency injection fitted together and a clear understanding of the IDE tooling and the various refactorings.

It was certainly effective. It was surprising how many candidates that seemed technically competent verbally were unable to make any headway with this exercise. A lot of candidates just couldn't handle the unfamiliar interview situation; others really had not learnt the tools of their trade and were unable to use the IDE to speed up their coding; other candidates had claimed TDD experience and were unable to write a decent unit test or use mocks; many candidates were unable to handle the design element, defining interfaces and making clear, logical decisions about contracts and responsibilities.

The successful candidates usually sketched out the domain either as interfaces in code or on paper, they asked good questions of their pair and the product owner and they always were very clear about what testing was needed. They also picked up the fact that the story was incomplete and asked about details of the validation.

A pair programming interview highlights the candidates technical skills but provides great insight into their characters and how they will fit into a team.