Algorithmic skeleton
Encyclopedia
In computing
Computing
Computing is usually defined as the activity of using and improving computer hardware and software. It is the computer-specific part of information technology...

, algorithmic skeletons (a.k.a. Parallelism Patterns) are a high-level parallel programming model
Parallel programming model
A parallel programming model is a concept that enables the expression of parallel programs which can be compiled and executed. The value of a programming model is usually judged on its generality: how well a range of different problems can be expressed and how well they execute on a range of...

 for parallel and distributed computing.

Algorithmic skeletons take advantage of common programming patterns to hide the complexity of parallel and distributed applications. Starting from a basic set of patterns (skeletons), more complex patterns can be built by combining the basic ones.

Overview

The most outstanding feature of algorithmic skeletons, which differentiates them from other high-level parallel programming models, is that orchestration and synchronization of the parallel activities is implicitly defined by the skeleton patterns. Programmers do not have to specify the synchronizations between the application's sequential parts. This yields two implications. First, as the communication/data access patterns are known in advance, cost models can be applied to schedule skeletons programs. Second, that algorithmic skeleton programming reduces the number of errors when compared to traditional lower-level parallel programming models (Threads, MPI).

History

Algorithmic skeletons were first introduced by Cole in 1989. Several frameworks have been proposed by different research groups using different techniques such as functional, imperative, custom and object oriented languages. A recent survey of algorithmic skeleton frameworks can be found in.

Well-known skeleton patterns

This section describes some well known Algorithmic Skeleton patterns. Additionally, the patterns signature in the Skandium library is provided for clarity.
  • FARM is also known as master-slave. Farm represents task replication where the execution of different tasks by the same farm are replicated and executed in parallel.


Farm(Skeleton skeleton){...}
  • PIPE represents staged computation. Different tasks can be computed simultaneously on different pipe stages. A pipe can have a variable number of stages, each stage of a pipe may be a nested skeleton pattern. Note that an n-stage pipe can be composed by nesting n-1 2-stage pipes.


Pipe(Skeleton stage1, Skeleton stage2){...}
  • FOR represents fixed iteration, where a task is executed a fixed number of times. In some implementations the executions may take place in parallel.


For(Skeleton skeleton, int times){...}
  • WHILE represents conditional iteration, where a given skeleton is executed until a condition is met.


public While(Skeleton skeleton, Condition

condition){...}

  • IF represents conditional branching, where the execution choice between two skeleton patterns is decided by a condition.


If(Condition

condition, Skeleton trueCase, Skeleton falseCase){...}

  • MAP represents split, execute, merge computation. A task is divided into sub-tasks, sub-tasks are executed in parallel according to a given skeleton, and finally sub-task's results are merged to produce the original task's result.


Map(Split split, Skeleton skeleton, Merge merge){...}
  • D&C represents divide and conquer parallelism. A task is recursively sub-divided until a condition is met, then the sub-task is executed and results are merged while the recursion is unwound.


DaC(Condition

condition, Split split, Skeleton skeleton, Merge merge){...}

  • SEQ does not represent parallelism, but it is often used a convenient tool to wrap code as the leafs of the skeleton nesting.


public Seq(Execute execute){...}

Example program

The following example is based on the Java Skandium library for parallel programming.

The objective is to implement an Algorithmic Skeleton based parallel version of the QuickSort algorithm using the Divide and Conquer pattern. Notice that the high-level approach hides Thread management from the programmer.


// 1. Define the skeleton program
Skeleton sort = new DaC(
new ShouldSplit(threshold, maxTimes),
new SplitList,
new Sort,
new MergeList);

// 2. Input parameters
Future future = sort.input(new Range(generate(...)));

// 3. Do something else here.
// ...

// 4. Block for the results
Range result = future.get;

  1. The first thing is to define a new instance of the skeleton with the functional code that fills the pattern (ShouldSplit, SplitList, Sort, MergeList). The functional code is written by the programmer without parallelism concerns.
  2. The second step is the input of data which triggers the computation. In this case Range is a class holding an array and two indexes which allow the representation of a subarray. For every data entered into the framework a new Future object is created. More than one Future can be entered into a skeleton simultaneously.
  3. The Future allows for asynchronous computation, as other tasks can be performed while the results are computed.
  4. We can retrieve the result of the computation, blocking if necessary (i.e. results not yet available).


The functional codes in this example correspond to four types Condition, Split, Execute, and Merge.


public class ShouldSplit implements Condition{

int threshold, maxTimes, times;

public ShouldSplit(int threshold, int maxTimes){
this.threshold = threshold;
this.maxTimes = maxTimes;
this.times = 0;
}

@Override
public synchronized boolean condition(Range r){
return r.right - r.left > threshold &&
times++ < this.maxTimes;
}
}


The ShouldSplit class implements the Condition interface. The function receives an input, Range r in this case, and returning true or false. In the context of the Divide and Conquer where this function will be used, this will decide whether a sub-array should be subdivided again or not.

The SplitList class implements the split interface, which in this case divides an (sub-)array into smaller sub-arrays. The class uses a helper function partition(...) which implements the well known QuickSort pivot and swap scheme.


public class SplitList implements Split{

@Override
public Range[] split(Range r){

int i = partition(r.array, r.left, r.right);

Range[] intervals = {new Range(r.array, r.left, i-1),
new Range(r.array, i+1, r.right)};

return intervals;
}
}


The Sort class implements and Execute interface, and is in charge of sorting the sub-array specified by Range r. In this case we simply invoke Java's default (Arrays.sort) method for the given sub-array.


public class Sort implements Execute {

@Override
public Range execute(Range r){

if (r.right <= r.left) return r;

Arrays.sort(r.array, r.left, r.right+1);

return r;
}
}


Finally, once a set of sub-arrays are sorted we merge the sub-array parts into a bigger array with the MergeList class which implements a Merge interface.


public class MergeList implements Merge{

@Override
public Range merge(Range[] r){

Range result = new Range( r[0].array, r[0].left, r[1].right);

return result;
}
}

ASSIST

ASSIST is a programming environment which provides programmers with a structured coordination language. The coordination language can express parallel programs as an arbitrary graph of software modules. The module graph describes how a set of modules interact with each other using a set of typed data streams. The modules can be sequential or parallel. Sequential modules can be written in C, C++, or Fortran; and parallel modules are programmed with a special ASSIST parallel module (parmod).

AdHoc, a hierarchical and fault-tolerant Distributed Shared Memory (DSM) system is used to interconnect streams of data between processing elements by providing a repository with: get/put/remove/execute operations. Research around AdHoc has focused on transparency, scalability, and fault-tolerance of the data repository.

While not a classical skeleton framework, in the sense that no skeletons are provided, ASSIST's generic parmod can be specialized into classical skeletons such as: farm, map, etc. ASSIST also supports autonomic control of parmodss, and can be subject to a performance contract by dynamically adapting the number of resources used.

CO2P3S

CO2P3S (Correct Object-Oriented Pattern-based Parallel Programming System), is a pattern oriented development environment, which achieves parallelism using threads in Java.

CO2P3S is concerned with the complete development process of a parallel application. Programmers interact through a programming GUI to choose a pattern and its configuration options. Then, programmers fill the hooks required for the pattern, and new code is generated as a framework in Java for the parallel execution of the application. The generated framework uses three levels, in descending order of abstraction: patterns layer, intermediate code layer, and native code layer. Thus, advanced programmers may intervene the generated code at multiple levels to tune the performance of their applications. The generated code is mostly type safe, using the types provided by the programmer which do not require extension of superclass, but fails to be completely type safe such as in the reduce(..., Object reducer) method in the mesh pattern.

The set of patterns supported in CO2P3S corresponds to method-sequence, distributor, mesh, and wavefront. Complex applications can be built by composing frameworks with their object references. Nevertheless, if no pattern is suitable, the MetaCO2P3S graphical tool addresses extensibility by allowing programmers to modify the pattern designs and introduce new patterns into CO2P3S.

Support for distributed memory architectures in CO2P3S was introduced in later. To use a distributed memory pattern, programmers must change the pattern’s memory option from shared to distributed, and generate the new code. From the usage perspective, the distributed memory version of the code requires the management of remote exceptions.

Calcium & Skandium

Calcium is greatly inspired by Lithium and Muskel. As such, it provides algorithmic skeleton programming as a Java library. Both task and data parallel skeletons are fully nestable; and are instantiated via parametric skeleton objects, not inheritance.

Calcium supports the execution of skeleton applications on top of the ProActive
ProActive
ProActive is Java grid middleware for parallel, distributed, and multi-threaded computing. It is developed by the OW2 Consortium, including INRIA, CNRS, University of Nice Sophia Antipolis, and ActiveEon...

 environment
for distributed cluster like infrastructure. Additionally, Calcium has three distinctive features for algorithmic skeleton programming. First, a performance tuning model which helps programmers identify code responsible for performance bugs. Second, a type system for nestable skeletons which is proven to guaranty subject reduction properties and is implemented using Java Generics. Third, a transparent algorithmic skeleton file access model, which enables skeletons for data intensive applications.

Skandium is a complete re-implementation of Calcium for multi-core computing. Programs written on Skandium may take advantage of shared memory to simplify parallel programming.

Eden

Eden is a parallel programming language for distributed memory environments, which extends Haskell. Processes are defined explicitly to achieve parallel programming, while their communications remain implicit. Processes communicate through unidirectional channels, which connect one writer to exactly one reader. Programmers only need to specify which data a processes depends on. Eden’s process model provides direct control over process granularity, data distribution and communication topology.

Eden is not a skeleton language in the sense that skeletons are not provided as language constructs. Instead, skeletons are defined on top of Eden’s lower-level process abstraction, supporting both task and data parallelism. So, contrary to most other approaches, Eden lets the skeletons be defined in the same language and at the same level, the skeleton instantiation is written: Eden itself. Because Eden is an extension of a functional language, Eden skeletons are higher order functions. Eden introduces the concept of implementation skeleton, which is an architecture independent scheme that describes a parallel implementation of an algorithmic skeleton.

eSkel

The Edinburgh Skeleton Library (eSkel) is provided in C and runs on top of MPI. The first version of eSkel was described in, while a later version is presented in.

In, nesting-mode and interaction-mode for skeletons are defined. The nesting-mode can be either transient or persistent, while the interaction-mode can be either implicit or explicit. Transient nesting means that the nested skeleton is instantiated for each invocation and destroyed
Afterwards, while persistent means that the skeleton is instantiated once and the same skeleton instance will be invoked throughout the application. Implicit interaction means that the flow of data between skeletons is completely defined by the skeleton composition, while explicit means that data can be generated or removed from the flow in a way not specified by the skeleton composition. For example, a skeleton that produces an output without ever receiving an input has explicit interaction.

Performance prediction for scheduling and resource mapping, mainly for pipe-lines, has been
explored by Benoit et al. They provided a performance model for each mapping,
based on process algebra, and determine the best scheduling strategy based on the results of the
model.

More recent works have addressed the problem of adaptation on structured parallel programming, in particular for the pipe skeleton.

HDC

Higher-order Divide and Conquer (HDC) is a subset of the functional language Haskell
Haskell (programming language)
Haskell is a standardized, general-purpose purely functional programming language, with non-strict semantics and strong static typing. It is named after logician Haskell Curry. In Haskell, "a function is a first-class citizen" of the programming language. As a functional programming language, the...

. Functional programs are presented as polymorphic higher-order functions, which can be compiled into C/MPI, and linked with skeleton implementations. The language focus on divide and conquer paradigm, and starting from a general kind of divide and conquer skeleton, more specific cases with efficient implementations are derived. The specific cases correspond to: fixed recursion depth, constant recursion degree, multiple block recursion, elementwise operations, and
correspondent communications

HDC pays special attention to the subproblem’s granularity and its relation with the number of
Available processors. The total number of processors is a key parameter for the performance of the
skeleton program as HDC strives to estimate an adequate assignment of processors for each part
of the program. Thus, the performance of the application is strongly related with the estimated
number of processors leading to either exceeding number of subproblems, or not enough parallelism
to exploit available processors.

HOC-SA

HOC-SA is an Globus Incubator project.

HOC-SA stands for Higher-Order Components-Service Architecture.
Higher-Order Components (HOCs) have the aim of simplifying
Grid application development.

The objective of HOC-SA is to provide Globus users, who do not want to know about all the details of the Globus middleware (GRAM RSL documents, Web services and resource configuration etc.), with HOCs that provide a higher-level interface to the Grid than the core Globus Toolkit.

HOCs are Grid-enabled skeletons, implemented as components on top of the Globus Toolkit, remotely accessibly via Web Services.

JaSkel

JaSkel is a Java based skeleton framework providing skeletons such as farm, pipe and heartbeat. Skeletons are specialized using inheritance. Programmers implement the abstract methods for each skeleton to provide their application specific code. Skeletons in JaSkel are provided in both sequential, concurrent and dynamic versions. For example, the concurrent farm can be used in shared memory environments (threads), but not in distributed environments (clusters) where
the distributed farm should be used. To change from one version to the other, programmers must
change their classes’ signature to inherit from a different skeleton. The nesting of skeletons uses the basic Java Object class, and therefore no type system is enforced during the skeleton composition.

The distribution aspects of the computation are handled in JaSkel using AOP, more specifically
the AspectJ implementation. Thus, JaSkel can be deployed on both cluster and Grid like
infrastructures. Nevertheless, a drawback of the JaSkel approach is that the nesting of the skeleton strictly relates to the deployment infrastructure. Thus, a double nesting of farm yields a better performance than a single farm on hierarchical infrastructures. This defeats the purpose of using AOP to separate the distribution and functional concerns of the skeleton program.

Lithium & Muskel

Lithium and its successor Muskel are skeleton frameworks developed at University of Pisa, Italy. Both of them provide nestable skeletons to the programmer as Java libraries.The evaluation of a skeleton application follows a formal definition of operational semantics introduced by Aldinucci and Danelutto, which can handle both task and data parallelism. The semantics describe both functional and parallel behavior of the skeleton language using a labeled transition system. Additionally, several performance optimization are applied such as: skeleton rewriting techniques [18, 10], task lookahead, and server-to-server lazy binding.

At the implementation level, Lithium exploits macro-data flow to achieve parallelism. When the input stream receives a new parameter, the skeleton program is processed to obtain a macro-data flow graph. The nodes of the graph are macro-data flow instructions (MDFi) which represent the sequential pieces of code provided by the programmer. Tasks are used to group together several MDFi, and are consumed by idle processing elements from a task pool. When the computation of the graph is concluded, the result is placed into the output stream and thus delivered back to the user.

Muskel also provides non-functional features such as Quality of Service (QoS); security between task pool and interpreters; and resource discovery, load balancing, and fault tolerance when interfaced with Java / Jini Parallel Framework (JJPF), a distributed execution framework. Muskel also provides support for combining structured with unstructured programming and recent research has addressed extensibility.

Mallba

Mallba is a library for combinatorial optimizations supporting exact, heuristic and hybrid search strategies. Each strategy is implemented in Mallba as a generic skeleton which can be used by prodiving the required code. On the exact search algorithms Mallba provides branch-and-bound and dynamic-optimization skeletons. For local search heuristics Mallba supports: hill climbing, metropolis, simulated annealing, and tabu search; and also population based heuristics derived from evolutionary algorithms such as genetic algorithms, evolution strategy, and others (CHC). The hybrid skeletons combine strategies, such as: GASA, a mixture of genetic algorithm and
simulated annealing, and CHCCES which combines CHC and ES.

The skeletons are provided as a C++ library and are not nestable but type safe. A custom
MPI abstraction layer is used, NetStream, which takes care of primitive data type marshalling,
synchronization, etc. A skeleton may have multiple lower-level parallel implementations depending
on the target architectures: sequential, LAN, and WAN. For example: centralized master-slave,
distributed master-slave, etc.

Mallba also provides state variables which hold the state of the search skeleton. The state links the search with the environment, and can be accessed to inspect the evolution of the search and
decide on future actions. For example, the state can be used to store the best solution found so
far, or α, β values for branch and bound pruning.

Compared with other frameworks, Mallba’s usage of skeletons concepts is unique. Skeletons
are provided as parametric search strategies rather than parametric parallelization patterns.

Muesli

The Muenster Skeleton Library Muesli is a C++ template library which re-implements many of the ideas and concepts introduced in Skil, e.g. higher order functions, currying, and polymorphic types http://www.wi.uni-muenster.de/pi/forschung/Skeletons/index.html. It is build on top of MPI
Message Passing Interface
Message Passing Interface is a standardized and portable message-passing system designed by a group of researchers from academia and industry to function on a wide variety of parallel computers...

 1.2 and OpenMP
OpenMP
OpenMP is an API that supports multi-platform shared memory multiprocessing programming in C, C++, and Fortran, on most processor architectures and operating systems, including Linux, Unix, AIX, Solaris, Mac OS X, and Microsoft Windows platforms...

 2.5 and supports, unlike many other skeleton libraries, both task and data parallel skeletons. Skeleton nesting (composition) is similar to the two tier approach of P3L, i.e. task parallel skeletons can be nested arbitrarily while data parallel skeletons cannot, but may be used at the leaves of a task parallel nesting tree. C++ templates are used to render skeletons polymorphic, but no type system is enforced. However, the library implements an automated serialization mechanism inspired by such that, in addition to the standard MPI data types, arbitrary user-defined data types can be used within the skeletons. The supported task parallel skeletons are Branch & Bound, Divide & Conquer, Farm, and Pipe, auxiliary skeletons are Filter, Final, and Initial. Data parallel skeletons, such as fold (reduce), map, permute, zip, and their variants are implemented as higher order member functions of a distributed data structure. Currently, Muesli supports distributed data structures for arrays, matrices, and sparse matrices.

As a unique feature, Muesli’s data parallel skeletons automatically scale both on single- as well as on multi-core, multi-node cluster architectures. Here, scalability across nodes and cores is ensured by simultaneously using MPI and OpenMP, respectively. However, this feature is optional in the sense that a program written with Muesli still compiles and runs on a single-core, multi-node cluster computer without changes to the source code, i.e. backward compatibility is guaranteed. This is ensured by providing a very thin OpenMP abstraction layer such that the support of multi-core architectures can be switched on/off by simply providing/omitting the OpenMP compiler flag when compiling the program. By doing so, virtually no overhead is introduced at runtime.

P3L, SkIE, SKElib

P3L (Pisa Parallel Programming Language) is a skeleton based coordination language. P3L provides skeleton constructs which are used to coordinate the parallel or sequential execution of C code. A compiler named Anacleto is provided for the language. Anacleto uses implementation templates to compile P3 L code into a target architecture. Thus, a skeleton can have several templates each optimized for a different architecture. A template implements a skeleton on a specific architecture and provides a parametric process graph with a performance model. The performance model can then be used to decide program transformations which can lead to performance optimizations.

A P3L module corresponds to a properly defined skeleton construct with input and output
streams, and other sub-modules or sequential C code. Modules can be nested using the two tier
model, where the outer level is composed of task parallel skeletons, while data parallel skeletons
may be used in the inner level [64]. Type verification is performed at the data flow level, when the programmer explicitly specifies the type of the input and output streams, and by specifying the
flow of data between sub-modules.

SkIE (Skeleton-based Integrated Environment) is quite similar to P3L, as it is also based on a coordination language, but provides advanced features such as debugging tools, performance analysis, visualization and graphical
user interface. Instead of directly using the coordination language, programmers interact with a
graphical tool, where parallel modules based on skeletons can be composed.

SKELib builds upon the contributions of P3L and SkIE by inheriting, among others, the template system. It differs from them because a coordination language is no longer used, but instead skeletons are provided as a library in C, with performance similar as the one achieved in P3L. Contrary to Skil, another C like skeleton framework, type safety is not addressed in SKELib.

PAS and EPAS

PAS (Parallel Architectural Skeletons) is a framework for skeleton programming developed in C++
and MPI. Programmers use an extension of C++ to write their skeleton applications1 . The code is then passed through a Perl script which expands the code to pure C++ where skeletons are specialized through inheritance.

In PAS, every skeleton has a Representative (Rep) object which must be provided by the
programmer and is in charge of coordinating the skeleton’s execution. Skeletons can be nested in
a hierarchical fashion via the Rep objects. Besides the skeleton’s execution, the Rep also explicitly
manages the reception of data from the higher level skeleton, and the sending of data to the sub-skeletons. A parametrized communication/synchronization protocol is used to send and receive
data between parent and sub-skeletons.

An extension of PAS labeled as SuperPas and later as EPAS addresses skeleton extensibility concerns. With the EPAS tool, new skeletons can be added to PAS. A Skeleton Description Language (SDL) is used to describe the skeleton pattern by specifying the topology with respect to a virtual processor grid. The SDL can then be compiled into native C++ code, which can be used as any other skeleton.

SBASCO

SBASCO (Skeleton-BAsed Scientific COmponents) is a programming environment oriented towards efficient development of parallel and distributed numerical applications. SBASCO aims at integrating two programming models: skeletons and components with a custom composition language. An application view of a component provides a description of its interfaces (input and
output type); while a configuration view provides, in addition, a description of the component’s
internal structure and processor layout. A component’s internal structure can be defined using
three skeletons: farm, pipe and multi-block.

SBASCO’s addresses domain decomposable applications through its multi-block skeleton. Domains are specified through arrays (mainly two dimensional), which are decomposed into sub-arrays with possible overlapping boundaries. The computation then takes place in an iterative BSP like fashion. The first stage consists of local computations, while the second stage performs boundary exchanges. A use case is presented for a reaction-diffusion problem in.

Two type of components are presented in. Scientific Components (SC) which provide the functional code; and Communication Aspect Components (CAC) which encapsulate non-functional behavior such as communication, distribution processor layout and replication. For example, SC components are connected to a CAC component which can act as a manager at runtime by dynamically re-mapping processors assigned to a SC. A use case showing improved performance when using CAC components is shown in.

SCL

The Structured Coordination Language (SCL) was one of the first languages introduced for skeleton programming. SCL is considered a base language, and was designed to be integrated with a host language, for example Fortran. In SCL, skeletons are classified into three types: configuration, elementary and computation. Configuration skeletons abstract patterns for commonly used data structures such as distributed arrays (ParArray). Elementary skeletons correspond to data parallel skeletons such as map, scan, and fold. Computation skeletons which abstract the control flow and correspond mainly to task parallel skeletons such as farm, SPMD, and iterateUntil.

SKiPPER & QUAFF

SKiPPER is a domain specific skeleton library for vision applications which provides skeletons in CAML, and thus relies on CAML for type safety. Skeletons are presented in two ways: declarative and operational. Declarative skeletons are directly used by programmers, while their operational versions provide an architecture specific target implementation. From the
runtime environment, CAML skeleton specifications, and application specific functions (provided in C by the programmer), new C code is generated and compiled to run the application on the target architecture. One of the interesting things about SKiPPER is that the skeleton program can be executed sequentially for debugging.

Different approaches have been explored in SKiPPER for writing operational skeletons: static
data-flow graphs, parametric process networks, hierarchical task graphs, and tagged-token data-
flow graphs.

QUAFF is a more recent skeleton library written in C++ and MPI. QUAFF relies on template-based meta-programming techniques to reduce runtime overheads and perform skeleton expansions and optimizations at compilation time. Skeletons can be nested and sequential functions are stateful. Besides type checking, QUAFF takes advantage of C++ templates to generate, at
compilation time, new C/MPI code. QUAFF is based on the CSP-model, where the skeleton program is described as a process network and production rules (single, serial, par, join).

SkeTo

The SkeTo project is a C++ library which achieves parallelization using MPI. SkeTo is different to other skeleton libraries because instead of providing nestable parallelism patterns, SkeTo provides parallel skeletons for parallel data structures such as: lists, trees, and matrices. The data structures are typed using templates, and several parallel operations can be invoked on them. For example the list structure provides parallel operations such as: map, reduce, scan, zip, shift, etc...

Additional research around SkeTo has also focused on optimizations strategies by transforma-
tion, and more recently domain specific optimizations. For example, SkeTo provides a fusion transformation which merges two successive function invocations into a single one, thus decreasing the function call overheads and avoiding the creation of intermediate data structures
passed between functions.

Skil

Skil is an imperative language for skeleton programming. Skeletons are not
directly part of the language but are implemented with it. Skil uses a subset of C language which provides functional language like features such as higher order functions, curring and polymorphic types. When Skil is compiled, such features are eliminated and a regular C code is produced. Thus, Skil transforms polymorphic high order functions into monomorphic first order C functions. Skil does not support nestable composition of skeletons. Data parallelism is achieved using specific data parallel structures, for example to spread arrays among available processors. Filter skeletons can be used.

Frameworks comparison

  • Activity Years is the known activity years span. The dates represented in this column correspond to the first and last publication date of a related article in a scientific journal or conference proceeding. Note that a project may still be active beyond the activity span, and that we have failed to find a publication for it beyond the given date.
  • Programming Language is the interface with which programmers interact to code their skeleton applications. These languages are diverse, encompassing paradigms such as: functional languages, coordination languages, markup languages, imperative languages, object oriented languages, and even graphical user interfaces. Inside the programming language, skeletons have been provided either as language constructs or libraries. Providing skeletons as language construct implies the development of a custom domain specific language and its compiler. This was clearly the stronger trend at the begging of skeleton research. The more recent trend is to provide skeletons as libraries, in particular with object oriented languages such as C++ and Java.

  • Execution Language is the language in which the skeleton applications are run or compiled. It was recognized very early that the programming languages (specially in the functional cases), were not efficient enough to execute the skeleton programs. Therefore, skeleton programming languages were simplified by executing skeleton application on other languages. Transformation processes were introduced to convert the skeleton applications (defined in the programming language) into an equivalent application on the target execution language. Different transformation processes were introduced, such as code generation or instantiation of lowerlevel skeletons (sometimes called operational skeletons) which were capable of interacting with a library in the execution language. The transformed application also gave the opportunity to introduce target architecture code, customized for performance, into the transformed application. Table 1 shows that a favorite for execution language has been the C language.

  • Distribution Library provides the functionality to achieve parallel/distributed computations. The big favorite in this sense has been MPI, which is not surprising since it integrates well with the C language, and is probably the most used tool for parallelism in cluster computing. The dangers of directly programming with the distribution library are, of course, safely hidden away from the programmers who never interact with the distribution library. Recently, the trend has been to develop skeleton frameworks capable of interacting with more than one distribution library. For example, CO2 P3 S can use Threads, RMI or Sockets; Mallba can use Netstream or MPI; or JaSkel which uses AspectJ to execute the skeleton applications on different skeleton frameworks.

  • Type Safety refers to the capability of detecting type incompatibility errors in skeleton program. Since the first skeleton frameworks were built on functional languages such as Haskell, type safety was simply inherited from the host language. Nevertheless, as custom languages were developed for skeleton programming, compilers had to be written to take type checking into consideration; which was not as difficult as skeleton nesting was not fully supported. Recently however, as we begun to host skeleton frameworks on object oriented languages with full nesting, the type safety issue has resurfaced. Unfortunately, type checking has been mostly overlooked (with the exception of QUAFF), and specially in Java based skeleton frameworks.

  • Skeleton Nesting is the capability of hierarchical composition of skeleton patterns. Skeleton Nesting was identified as an important feature in skeleton programming from the very beginning, because it allows the composition of more complex patterns starting from a basic set of simpler patterns. Nevertheless, it has taken the community a long time to fully support arbitrary nesting of skeletons, mainly because of the scheduling and type verification difficulties. The trend is clear that recent skeleton frameworks support full nesting of skeletons.

  • File Access is the capability to access and manipulate files from an application. In the past, skeleton programming has proven useful mostly for computational intensive applications, where small amounts of data require big amounts of computation time. Nevertheless, many distributed applications require or produce large amounts of data during their computation. This is the case for astrophysics, particle physics, bio-informatics, etc. Thus, providing file transfer support that integrates with skeleton programming is a key concern which has been mostly overlooked.

  • Skeleton Set is the list of supported skeleton patterns. Skeleton sets vary greatly from one framework to the other, and more shocking, some skeletons with the same name have different semantics on different frameworks. The most common skeleton patterns in the literature are probably farm, pipe, and map.

Non-object oriented Algorithmic Skeleton Frameworks
Activity Years Programming Language Execution Language Distribution Library Type Safe Skeleton Nesting File Access Skeleton Set
ASSIST 2004–2007 Custom Control Language C++ TCP/IP + ssh/scp yes no explicit seq, parmod
SBSACO 2004–2006 Custom Composition Language C++ MPI yes yes no farm, pipe, multi-block
eSkel 2004–2005 C C MPI no ? no pipeline, farm, deal, butterfly, hallowSwap
HDC 2004–2005 Haskell subset C MPI yes ? no dcA, dcB, dcD, dcE, dcF, map, red, scan, filter
SKELib 2000-2000 C C MPI no no no farm, pipe
SkiPPER 1999–2002 CAML C SynDex yes limited no scm, df, tf, intermem
SkIE 1999-1999 GUI/Custom Control Lang. C++ MPI yes limited no pipe,farm, map, reduce, loop
Eden 1997–2011 Haskell extension Haskell PVM/MPI yes yes no map,farm,workpool,nr,dc,pipe,iterUntil,torus,ring
P3L 1995–1998 Custom Control Lang. C MPI yes limited no map,reduce,scan,comp,pipe,farm,seq,loop
Skil 1995–1998 C subset C ? yes no no pardata,map,fold
SCL 1993–1995 Custom Control Lang. Fortran CS Tools yes limited no map,scan,fold,farm,SPMD,iterateUntil

Object oriented Algorithmic Skeleton Frameworks
Activity Years Programming Language Execution Language Distribution Library Type Safe Skeleton Nesting File Access Skeleton Set
Skandium 2009–2010 Java Java Threads yes yes no seq, pipe, farm, for, while, map, d&c, fork
Calcium 2006–2008 Java Java ProActive yes yes yes seq, pipe, farm, for, while, map, d&c, fork
QUAFF 2006–2007 C++ C MPI yes yes no seq, pipe, farm, scm, pardo
JaSkel 2006–2007 Java Java/AspectJ MPP / RMI no yes no farm, pipeline, heartbeat
Muskel 2005–2008 Java Java RMI no yes no farm, pipe, seq, + custom MDF Graphs
HOC-SA 2004–2008 Java Java Globus, KOALA no no no farm, pipeline, wavefront
SkeTo 2003–2010 C++ C++ MPI yes no no list, matrix, tree
Mallba 2002–2007 C++ C++ NetStream / MPI yes no no exact, heuristic, hybrid
Muesli 2002–2010 C++ C++ MPI / OpenMP yes yes no data parallel: fold, map, permute, scan, zip, and variants. task parallel: branch & bound, divide & conquer, farm, pipe. auxiliary: filter, final, initial
Alt 2002–2003 Java/GworkflowDL Java Java RMI yes no no map, zip, reduction, scan, dh, replicate, apply, sort
(E)PAS 1999–2005 C++ extension C++ MPI no yes no singleton, replication, compositional, pipeline, divideconquer, dataparallel
Lithium 1999–2004 Java Java RMI no yes no pipe, map, farm, reduce
CO2P3S 1999–2003 GUI/Java Java (generated) Threads / RMI / Sockets partial no no method-sequence, distributor, mesh, wavefront
The source of this article is wikipedia, the free encyclopedia.  The text of this article is licensed under the GFDL.
 
x
OK