Alchemi v0.6.1 Documentation

Table of Contents

1. Introduction & Concepts
2. Constructing Grids
3. Installation, Configuration & Operation
4. Grid Programming


1. Introduction & Concepts

This documentation shows you how to use the Alchemi .NET Grid Computing Framework to:

This chapter gives you an introduction to how Alchemi implements the concept of grid computing and discusses concepts required for using Alchemi. Some key features of the framework are highlighted along the way.

What is a Grid?

Here is a definition from http://www.gridcomputing.com:

A grid is a type of parallel and distributed system that enables the sharing, selection, and aggregation of geographically distributed "autonomous" resources dynamically at runtime depending on their availability, capability, performance, cost, and users' quality-of-service requirements.
Thus, at the most basic level, a grid can be viewed as an aggregation of multiple machines (each with one or more CPUs) abstracted to behave as one "virtual" machine with multiple CPUs.

Grid implementations differ in the way they implement this abstraction. One of the key differentiating features of Alchemi is the way it abstracts the grid, with the aim to make the process of developing grid software as easy as possible. The next section expands on this.

Developing Grid Software

Generally speaking, software suited to grid computing has the following features:

Course-Grained Abstraction : Grid Jobs

Traditional grid implementations have only offered a high-level abstraction of the "virtual machine", where the smallest unit of parallel execution is a process (typically referred to as a job, with many jobs constituting a task).

In this scenario, writing software to run on a grid involves dealing with processes, an approach that can be complicated and inflexible.

Fine-Grained Abstraction : Grid Threads

Alchemi on the other hand, primarily offers a more low-level (and hence more powerful) abstraction of the underlying grid by providing a programming model that is object-oriented and that imitates traditional multi-threaded programming.

The smallest unit of parallel execution in this case is a grid thread (object), where a grid thread is very similar to a "normal" thread. A grid application is defined simply as an application that is to be executed on a grid and that consists of a number of grid threads executing in parallel.

Note: Hereafter, applications and threads can be taken to mean grid applications and grid threads respectively, unless stated otherwise.

The developer deals only with application and thread objects and any other custom objects, allowing him/her to concentrate on the application itself without worrying about the "plumbing" details. Furthermore, abstraction at this level allows the use of programming language constructs such as events between local and remote code.

All of this is offered via the Alchemi API.

The fact that a) objects are much easier to deal with than processes combined with b) a programming model that is familiar to developers and c) the use of language constructs across local and remote code makes this a superior approach to the one described in the previous section.

The additional benefit of this approach is that it does not limit the developer to applications that are completely or "embarrassingly" parallel. Indeed, it allows development of grid applications where inter-thread communication is required.

Note: While Alchemi currently only supports completely parallel threads, support for inter-thread communication is planned for future releases.

Grids Jobs vs. Grid Threads

While Alchemi supports the execution of grid jobs, this support is present for the following reasons:

Development via the Alchemi API is preferred due to its ease of use, power and flexibility and should be used for all new applications, while the "grid job" model should be used for grid-enabling existing applications or writing cross-platform applications.

The ".NET" in ".NET Grid Computing Framework" & Cross-Platform Support

Alchemi is written for the .NET CLR. Hence all machines running any Alchemi software component must have the .NET Framework installed. Note: While Alchemi has only been tested on Windows, it is conceivable that it could run on Unix-class operating systems as well.

Additionally, the Alchemi API is closely tied in with the .NET CLR and thus can only be used by .NET applications.

However, as mentioned previously, Alchemi does offer support for execution of cross-platform applications via web services. Thus, using the "grid job" model one can write:

Grid Components

Grids are constructed using three types of distributed components (or nodes). (I refer to distributed in the context of standard distributed systems i.e. usually, but not necessarily residing in separate machines.) These are named according to their roles with respect to a grid application. All components are installed using Windows installers.

Manager

The Manager manages the execution of grid applications and provides services associated with managing thread execution. It is deployed as an executable.

An optional sub-component of the Manager is the Cross Platform Manager, which is deployed as a web service.

Executor

The Executor executes individual grid threads and provides services associated with executing threads. It is deployed as an executable.

An Executor can be configured to be dedicated (meaning the Manager initiates thread execution directly) or non-dedicated (meaning that thread execution is initiated by the Executor on a volunteer basis via a screen saver or some other user-defined options.)

Owner

The Owner owns an application and provides services associated with the ownership of an application (and its constituent threads).

The Owner is implicitly created by the Alchemi API.

Traditional Multiple-Processor Paradigm vs. Grid Paradigm

To clarify the concepts discussed so far, consider the following analogies between traditional multithreaded programming and grid programming:

Multiprocessor Machine Grid
Operating System Alchemi
Processor Executor
OS Services (High-Level) Owner
OS Services (Low-Level) Manager
Process Grid Application
Thread Grid Thread
System API Alchemi API


2. Constructing Grids

Uni-Level Grids

The simplest grid consists of one Manager. Multiple Executors are configured to connect to the Manager. One or more Owners can execute applications on the grid by connecting to the Manager.

cg1.gif
Fig 2.1. A uni-level grid deployment.

Multi-Level Grids

Multi-level grids are created by connecting Managers hierarchically. The key to accomplishing this is in Alchemi's inherent architecture, which allows a Manager to behave like an Executor towards a higher level Manager.

cg2.gif
Fig 2.2. A multi-level grid deployment.

The higher-level Owner has access to the entire computing power of the grid, while the lower-level Owner only has access to the computing power managed by the lower-level Manager.

Grids can be scaled to an infinite number of levels in this fashion.

Cross Platform Grids

Alchemi provides a cross-platform web service interface to the Manager. This can be used by software written on other platforms to extend Alchemi grids.

cg3.gif
Fig 2.3. A cross platform grid deployment.


3. Installation, Configuration & Operation

Common Requirements

Manager

The Manager should be installed on a stable and reasonably capable machine. The Manager requires:

Note: SQL Server / MSDE do not necessarily need to installed be on the same machine as the Manager.

If using SQL Server, ensure that SQL Server authentication is enabled. Otherwise, follow these instructions to install and prepare MSDE 2000 for Alchemi.

Make a note of the system administrator (sa) password in either case.

Installation

mgr0.gif

Fig 3.1. Database installation during Manager installation.

Configuration

The Manager is configured from the application itself.

The Manager can be run from the desktop or Start -> Programs -> Alchemi -> Alchemi Manager. The database configuration settings used during installation automatically appear when the Manager is first started.

For a stand-alone Manager (for a uni-level grid or the highest-level multi-level grid Manager) you only need to designate the "OwnPort" setting, which is the port that Manager listens on for all communication:

mgr1.gif

Fig 3.2. Stand-alone Manager configuration.

For an intermediate (lower-level) Manager that is part of a multi-level grid you need to check the "Intermediate" box and specify the higher-level Manager's host and port.

Since the Manager behaves like an Executor towards the higher-level Manager, you also need to specify whether it is a dedicated or non-dedicated "Executor" by checking/uncheckig the "Dedicated" box.

mgr2.gif

Fig 3.3. Intermediate Manager configuration.

Operation

Click the "Start" button to start the Manager.

mgr3.gif

Fig 3.4. Manager operation.

Cross Platform Manager

The Cross Platform Manager (XPManager) requires:

Installation

Configuration

If the XPManager is installed on a different machine that the Manager, or if the default port of the Manager is changed, the web service's configuration must be modified. The XPManager is configured via the ASP.NET Web.config file located in the installation directory (wwwroot\Alchemi\CrossPlatformManager by default):

<appSettings> <add key="ManagerUri" value="tcp://localhost:9000/Alchemi_Node" /> </appSettings>

Operation

The XPManager web service URL is of the format:

http://[host_name]/[installation_path]

The default is therefore:

http://[host_name]/Alchemi/CrossPlatformManager

The web service communicates with the Manager. The Manager must therefore be running and started for the web service to work.

Executor

Installation

ex1.gif

Fig 3.5. Alchemi screen saver.

Configuration

The Executor is configured from the application itself.

The Executor can be run from the desktop or Start -> Programs -> Alchemi -> Alchemi Executor.

ex2.gif

Fig 3.5. Executor configuration.

You need to configure 2 aspects of the Executor:

Operation

ex3.gif

Fig 3.5. Executor connected to a Manager.

ex4.gif

Fig 3.6. Non-dedicated execution.

Verifying Grid Installation

You can verify successful setup of a grid by running a sample application on it. The Alchemi SDK contains a sample application "PiCalculator" that calculates the value of Pi to 100 digits.

Configure PiCalculator to point to a Manager:

Run it:

picalc.gif

Fig 3.6. "PiCalculator" running on a grid.


4. Grid Programming

Introduction

Certain types of software are more suited to a grid environment than others. In order to design and develop effective grid applications, one must appreciate some aspects of grid software.

Firstly, the application should be able to be broken up into a number of parallel threads (i.e. threads that do not require constant communication among themselves). Having said that, it should be noted that limited synchronisation mechanisms are indeed available.

Secondly, the application must be computationally intensive with a high 'compute time' vs. 'communication time' ratio.

Reasons for these should be clear to the reader, given the nature of grids.

Grid applications typically employ the parameter sweep model. Examples of applications are (source):

Grid Application Performance

A key decision in designing a grid application is how the application will be parallelised in order to maximise performance (minimise execution time). i.e. the number of threads vs. the workload of each thread.

There is a certain amount of overhead in running a grid thread (network data transfer, setting up and destroying threads etc.) as opposed to running a "normal" thread. Clearly, total overhead can be minimised by having a low number of threads with high computational workload.

On the other hand, a high number of threads running in parallel will result in better utilisation of the grid, leading to faster total execution time for the application.

Given these two opposing factors, one needs to find a balance between the number of threads and each thread's workload. Some specific factors that will affect this decision are a) the size of the grid and b) importance of performance.

Development Environment

Follow these steps to set up a development environment:

Grid Programming Tutorial

This tutorial provides a basic introduction to grid programming. Familiarity with VS.NET and C# is assumed.

Let's pretend that multiplying two integers is a very computationally intensive process. Since we need to multiply ten sets of integers, we decide to write a grid application.

To start off,

There are essentially two parts to a grid application:

The grid code can be compiled separately from the local code as one or more .dlls or it can be compiled as part of the local code executable. In the tutorial, all code is in one file, Tutorial.cs.

Grid Thread Class

To write a grid thread class, we derive a new class from the Alchemi.Core.GThread class and override the void Start() method. We must also add the Serializable attribute to it:

[Serializable] public class MultiplierThread : GThread { public override void Start() { } }

Listing 4.1. Grid thread skeleton

We now add the following bits to make the grid thread perform a multiplication between two integers:

using System; using Alchemi.Core; namespace Alchemi.Examples.Tutorial { [Serializable] public class MultiplierThread : GThread { private int _A; private int _B; private int _Result; public int Result { get { return _Result; } } public MultiplierThread(int a, int b) { _A = a; _B = b; } public override void Start() { _Result = _A * _B; } } ...

Listing 4.2. Grid thread implementation

Create Grid Application

The Main() method of the console application is as follows:

... class MultiplierApplication { static GApplication ga; [STAThread] static void Main(string[] args) { Console.WriteLine("[enter] to start grid application ..."); Console.ReadLine(); // create grid application ga = new GApplication("localhost", 9099); // add GridThread module (this executable) as a dependency ga.Manifest.Add(new ModuleDependency(typeof(MultiplierThread).Module)); // create and add 10 threads to the application for (int i=0; i<10; i++) { // create thread MultiplierThread thread = new MultiplierThread(i, i+1); // set the thread finish callback method thread.FinishCallback = new GThreadFinish(ThreadFinished); // add thread to application ga.Threads.Add(thread); } // set the application finish callback method ga.FinishCallback = new GApplicationFinish(ApplicationFinished); // start application ga.Start(); Console.ReadLine(); } ...

Listing 4.3. Grid application Main() method

First, a GApplication object is created. The Alchemi Manager host and port are supplied in the constructor. Next, a ModuleDepencency using the module (.dll) of the grid thread is created and added to the Manifest of the application, signaling it as a dependency for all threads.

Ten threads are then created. A ThreadFinished delegate is set for each thread (this delegate is called when the thread finishes executing) and the thread is added to the application.

Finally, the ApplicationFinished delegate is set for the application (this delegate is called when the application finishes executing), and the application is started.

We can now add the two delegate (callback) methods:

... static void ThreadFinished(GThread th) { // cast GThread back to MultiplierThread MultiplierThread thread = (MultiplierThread) th; if (thread.RemoteExecutionException == null) { // thread executed OK Console.WriteLine( "thread # {0} finished with result '{1}'", thread.Id, thread.Result); } else { // an exception occured Console.WriteLine( "thread # {0} finished with error '{1}'", thread.Id, thread.RemoteExecutionException); } } static void ApplicationFinished() { Console.WriteLine("\napplication finished"); Console.WriteLine("\n[enter] to continue ..."); } } }

Listing 4.4. Grid application delegates

Run It

prog1.gif

Fig 4.1. Tutorial grid application

Advanced Grid Programming

The tutorial only demonstrates basic features of the Alchemi API. This section contains some notes on other features.

Multiple Classes & Dependencies

The tutorial demonstrates only one module dependency (GridThread.dll) containing only one class (MultiplierThread). You can have multiple GThread-inherited classes. The GThread-inherited class(es) can use other classes as well.

You need only ensure that all modules are added to the Manifest as dependencies.

Multiple Thread Delegates

The tutorial only uses one ThreadFinished delegate for all threads, but you can specify a different one for each thread.

On-The-Fly Execution

In the tutorial, all threads are added to the application and it is then started. An optional scenario is on-the-fly execution. This is useful for real-time or "service" applications where information about all threads to be executed is not known beforehand. Please note the following for using on-the-fly execution.

prog2.gif

Fig. 4.2. Example of on-the-fly execution

Thread Priorities

You can request a priority by setting the Priority property for a thread before it is executed. The highest priority is 0 (default) with larger integers denoted lower priorities. Note: The requested priority is not guaranteed to be met.

Thread Synchronisation

Even though inter-thread communication is not possible (in this version), limited thread synchronisation - using the results of a thread for a subsequent thread - can still be coded into the ThreadFinish and/or AppliationFinish callback methods. It should be clear to the reader how this could be achieved.

Grid Job Model : Grid-Enabling Existing Applications

Alchemi supports the traditional job model i.e. jobs within tasks, where each job is a process with input and output files.

It should be noted that in Alchemi:

This means that any tools or code that work with grid applications and grid threads will also work with taks and jobs respectively.

There are two options available for grid-enabling, running and monitoring existing applications:

Using the Alchemi API for 'Job Model' Applications

The JobAPI example ([SDK]\Examples\JobAPI example demonstrates the use of the Alchemi API for tasks/jobs. The solution contains two projects: Reverse (a simple console application that reverses the text of a file specified as a command-line argument and displays the results) and GridReverser (a console application that demonstrates the grid-enabling of Reverse).

Here is the complete listing of GridReverser.cs:

using System; using System.Xml; using System.IO; using Alchemi.Core; using Alchemi.Core.Utility; namespace Alchemi.Examples.CrossPlatformDemo { class GridReverser { static GApplication ga; [STAThread] static void Main(string[] args) { Console.WriteLine("Press [enter] to start ..."); Console.ReadLine(); try { ga = new GApplication("localhost", 9099); ga.Manifest.Add(new EmbeddedFileDependency("Reverse.exe", @"..\..\..\Reverse\bin\Debug\Reverse.exe")); GJob job1 = new GJob(); job1.InputFiles.Add(new EmbeddedFileDependency("input1.txt", @"..\..\input1.txt")); job1.RunCommand = "Reverse input1.txt"; job1.OutputFiles.Add(new EmbeddedFileDependency("out.txt")); ga.AddThread(job1, 0, new GThreadFinish(JobFinished)); ga.Start(); ga.FinishCallback = new GApplicationFinish(ApplicationFinished); } catch (Exception e) { Console.WriteLine(e); } Console.WriteLine("Started .. Waiting for jobs to finish ..\n"); Console.ReadLine(); } public static void JobFinished(GThread thread) { GJob job = (GJob) thread; Console.WriteLine("Finished job {0}", job.Id); foreach (FileDependency fd in job.OutputFiles) { Directory.CreateDirectory("job_" + job.Id); fd.UnPack(Path.Combine("job_" + job.Id, fd.FileName)); Console.WriteLine("Unpacked file {0} for job {1}", fd.FileName, job.Id); } } public static void ApplicationFinished() { ga.Stop(); } } }

Listing 4.5. GridReverser

The Manager Console Interface (MCI)

The MCI is a console application ([SDK]\alchemi_mci.exe) that can be used to monitor grid applications/threads. It can also be used to submit tasks/jobs and retrieve their results.

Its use is demonstrated here by a simple example. The files required for this example can be found in [SDK]\Examples\MCIUsage.

The file test.xml contains an example representation of a task:

<task> <manifest> <embedded_file name="Reverse.exe" location="Reverse.exe" /> </manifest> <job id="0"> <input> <embedded_file name="input1.txt" location="input1.txt" /> </input> <work run_command="Reverse.exe input1.txt > result1.txt" /> <output> <embedded_file name="result1.txt"/> </output> </job> <job id="1"> <input> <embedded_file name="input2.txt" location="input2.txt" /> </input> <work run_command="Reverse input2.txt > result2.txt" /> <output> <embedded_file name="result2.txt"/> </output> </job> </task>

Listing 4.6. Example task representation.

The MCI must be started with the host and port of an Alchemi Manager:

mci_1.gif

The following screenshot shows how the MCI can be used to submit a task, monitor its jobs and retrieve results:

mci_2.gif

There are other commands you can use as well; invoke alchemi_mci.exe without any arguments for help.

The Mandelbrot Set Generator Example

The Mandelbrot set generator example can be found in [SDK]\Examples\Mandelbrot:

mandel.gif

Cross-Platform Development : The Cross-Platform Manager Web Service

[todo]