| ||||||||||||||||||||
| ||||||||||||||||||||
|
||||||||||||||||||||
|
Parallel programming has been notoriously difficult as it often involves sharing data and processing power across multiple CPUs, memory systems and interconnectors. Hardware is generally non-standard: varying from multiple processors sharing memory, multiple processors with dedicated memory, multiple processors with shared and dedicated memory, or even distributed across multiple Linux desktops. Differing platforms come with differing software, APIs and idiosyncrasies. This all combines to create high costs, steep learning curves and a lack of portability between applications. CxC from Engineered Intelligence is aimed at removing many of these issues by creating a language dedicated to parallel programming. All programming is done using the CxC language, but the compiled executable can be run on a variety of hardware platforms including a standard Windows machine. The design goal of CxC was to create a powerful parallel programming language for scientists (or non-parallel programming experts!). The CxC LanguageThe CxC is an intriguing language, combining aspects of C/C++ with several parallel programming paradigms. Data and processing power is automatically assigned by the runtime, which means virtually all of the pains of splitting up data and the complex message passing systems of MPI/PVM are gone. Programs are split into controllers which in turn have a specified number of units. These controllers are connected via the specified topology, and all controllers are run by their associated programs. While this might initially sound complicated, it means all your code can be succinctly described within one source file. Personally, I found CxC's topology feature one of its best. Take a look at these two code snippets from EI's neural network and a cellular automata examples: topology xor_topo { output_unit[0] -> hidden_unit[*]; hidden_unit[i] -> input_unit[*]; } This states that the only output unit should connect to every hidden unit, and each hidden unit should be connected to every input unit. Now look at a more complicated example for the cellular automata: topology Link1 { InputUnit[0]->CAUnit[*][*]; } topology Link2 { CAUnit[i][j] <-> CAUnit[i][ (j+1) % HEIGHT ]; CAUnit[i][j] <-> CAUnit[(i+1) % WIDTH][ j ]; CAUnit[i][j] <-> CAUnit[(i+1) % WIDTH][ (j+1) % HEIGHT ]; CAUnit[i][j] <-> CAUnit[(i-1) % WIDTH][ (j+1) % HEIGHT ]; } This application requires two topologies: one for handling input, and another to designate the relationship between cellular automata cells. Within Link1, the input unit connects with every cellular automata unit. Link2 states that for CAUnit[i][j] it connects to the unit below it, to its right, below-right and below-left. Note how these links are bidirectional (specified by <-> operator), therefore each cell has access to its immediate 8 neighbours. Not only is this system nothing short of ingenious for understanding how your units communicate, it greatly aids debugging since you can clearly check the topology controlling your entire program without trawling through all your source files. Program FlowCxC also natively supports numerous features that allows you to control how the program executes. Two keywords, barrier and syncup, are used to synchronize different programs or units. Looking again at the neural network example: program input { srand(time()); switch(id()) { case 0: // ... case 1: // ... } barrier; } program hidden { // ... for (i=0; i<count(weight); i++) weight[i] = rand(10000)/5000.0-1.0; barrier; for (j=0; j<100; j++) { input.fanin( oi ); syncup; net = dot(input, weight); oh = 1/(1+pow(exp(1.0), -net)); } } barrier is used to synchronize all controllers, whereas syncup is used to synchronize all units within the specified controller. So in our example, the layers would initialize simultaneously (if on a multiprocessor machine), but would then wait for all other controllers when barrier was reached. Within the hidden layer program, syncup will ensure that each hidden unit has received input before continuing. For comparison, the barrier keyword in pthreads would take about 8 lines of code to lock mutexes, create a conditional wait, broadcast messages when barriers have been reached, and unlocking the mutex again. These language features make CxC an excellent time-saver. Compile-Once, Run-Anywhere?When CxC compiles a program, it generates a RUN file. This RUN file is loaded by the CxC runtime, which then utilizes the required hardware, creating virtual processors and interconnects as required. The same RUN file can be loaded on many different platforms. CxC though has added layers that allow external code such as C or FORTRAN libraries to be linked in. Similarly, CxC can be called from external programs to add parallel implementation to existing code. CxC seems to lie somewhere between the Java runtime and platform-specific binaries in an attempt to get the best of both worlds. PerformanceSurely all this has an overhead? CxC actually has very little overhead given the advantages gained in development time. Engineered Intelligence's figures show that for their Navier-Stokes benchmark, CxC has a 10% overhead on Linux and and 4% for IRIX (no figures for Windows). More information can be found at EI's Technology page. CxC Editor & DocumentationCxC comes with a powerful source editor (shown below). The editor is extremely fully-featured, with a lot of functionality that would make it a good general text editor: spell-checking, hex mode, OEM/ANSI conversions, word count, replace in files, FTP functionality, bookmarks, macros and a lot more.
The documentation provided with CxC is also excellent. It is split primarily into two documents, the Programmer's Guide and Reference Manual, with nearly 250 pages between them. The Programming Guide is well-written, splitting much of its time between parallal programming theory, example case-studies and program source code. I felt some of the programs could have been broken down and explained a little more thoroughly, but on the whole the book goes to great pains to explain how to get the best from CxC. The Reference Manual is a lot more theoretical, but covers every aspect of CxC in minute detail. I would have liked to have seen the documentation available in some other form beyond PDF, since Adobe Acrobat's dire search functionality made it hard to pinpoint the information I needed sometimes. Faults?It is actually very hard to fault any aspect of CxC. There are occassional language quirks such as a mixture of C and C++ style syntax. For example: int i; long init:value_array; // ... value_array.fanin( value ); In CxC, all variables must be declared at the top of functions, C-style. Yet, the value_array declaration (tying it to the init topology) and use of fanin as an object method makes the syntax look very object-orientated. While this isn't really a fault per se (CxC is its own language), this mixture of styles can be confusing for beginner and seasoned programmers alike. There were a few minor annoyances within the editor too, most notably the lack of keyboard shortcuts for the Build and Run commands. Overall though, CxC's compiler and editor stands to be some of most interesting and impressive technology I've seen in a while. ConclusionCxC is an extremely exciting technology, with superb language features, extensive documentation, strong performance, multi-platform executables and a powerful editor, there is extremely little to fault.
Submitted: 13/12/2004 Article content copyright © James Matthews, 2004.
|
|
|||||||||||||||||||
All content copyright © 1998-2007, Generation5 unless otherwise noted.
- Privacy Policy - Legal - Terms of Use -