This page demonstrates the ease of use of Swift/T when constructing common application patterns.
Links:
-
Post to the Swift/T user list with questions about these examples.
-
These example scripts may be downloaded here (2KB).
1. Hello world
File: hello-world/hello-world.swift
import io;
printf("Hello world!");
2. Swift/T for shell users
Swift/T has a powerful shell interface in its app function syntax. Here are some advanced examples:
To pass a whole command line into a generic app function, use:
File: sh-c/sh-1.swift
import string;
app f(string commandline)
{
"sh" "-c" commandline;
}
tokens = ["/bin/echo","this","is","my","message"];
f(string_join(tokens," "));
producing:
this is my message
Programs that are found in different locations on different machines can be accessed like this:
File: sh-c/sh-2.swift
import string;
import sys;
// Program configuration
string program;
if (getenv("HOST") == "umbra")
{
program = "/bin/echo";
}
else
{
// something else
}
// End program configuration
app f(string arguments)
{
program arguments;
}
tokens = ["this","is","my","message"];
f(string_join(tokens," "));
You can put the "program configuration" section in a separate file and
import
it.
If you prefer, you could also put separate definitions of program
in
separate files and conditionally #include
them with STC support for the C preprocessor.
This script converts itself to octal in mtc.octal
.
File: mtc/mtc1.swift
app (file o) f(file i)
{
"od" "-b" i @stdout=o;
}
file x = input("mtc1.swift");
file y<"mtc1.octal">;
y = f(x);
This script splits itself into lines, where line i is in file out-
i .txt
File: mtc/mtc2.swift
import files;
import string;
app (file o) f(string s)
{
"/bin/echo" s @stdout=o;
}
string lines[] = file_lines(input("mtc2.swift"));
foreach line,i in lines
{
file y <sprintf("out-%i.txt",i)> = f(line);
}
Note that each /bin/echo
is eligible to run concurrently. See
Invocation for how to run with many
processes.
3. Swift/T for cluster users
It’s easy to launch these kinds of workloads on a cluster.
If using a plain host list:
File: mtc/hosts.txt
machine1.some.edu
machine2.some.edu
machine3.some.edu
machine4.some.edu
Just run with:
stc mtc1.swift
turbine -f hosts.txt -n 4 mtc1.tic
As shown, turbine
accepts an MPI hosts file and number of
processes, just like mpiexec
.
A shorter, equivalent form of that command sequence is:
swift-t -t f:hosts.txt -n 4 mtc1.swift
On a PBS system, run with:
swift-t -m pbs -n 4 mtc1.swift
Many other systems are supported!
4. Swift/T for MapReduce users
A simplified version of the MapReduce model is to just compute many things and assemble them together at the end.
This script splits itself into lines, then reassembles the original script.
File: mtc/mtc3.swift
import files;
import string;
import unix;
app (file o) g(string s)
{
"/bin/echo" s @stdout=o;
}
string lines[] = file_lines(input("mtc3.swift"));
file fragments[];
foreach line,i in lines
{
file y <sprintf("out-%i.txt",i)> = g(line);
fragments[i] = y;
}
file result <"assembled.txt"> = cat(fragments);
Note that leading whitespace is trimmed by file_lines()
, and cat()
is part of the Swift/T standard library in module unix
.
5. Swift/T for recursive algorithms
5.1. Fibonacci
This script computes the given Fibonacci number:
File: fib/fib.swift
import sys;
(int o) fib(int i)
{
if (i >= 2)
{
o = fib(i-1) + fib(i-2);
}
else if (i == 1)
{
o = 1;
}
else
{
o = 0;
}
}
int n = toint(argv("n"));
trace(fib(n));
Run it as:
File: fib/run.sh
#!/bin/sh -e
swift-t fib.swift -n=7
Each recursive call to fib()
is spawned as a concurrent task.
The sys
module provides the argv()
function, which provides a
handy key/value interface for input values.
5.2. Merge sort
This script implements a parallel merge sort. The data files are generated by
tclsh make-data.tcl
Each of the 8 files is already sorted, and a merged result will be
placed in sorted.txt
.
File: merge-sort/merge.swift
import string;
app (file o) sort(file i, file j)
{
// This uses the standard sort -m feature (merge)
"sort" "-mn" i j @stdout=o;
}
(file o) merge(int i, int j)
{
if (j-i == 1)
{
file fi = input(sprintf("data-%i.txt",i));
file fj = input(sprintf("data-%i.txt",j));
o = sort(fi, fj);
}
else
{
d = j - i + 1;
m = d %/ 2; // integer divide operator
o = sort(merge(i,i+m-1), merge(i+m,j));
}
}
file result <"sorted.txt"> = merge(0,7);
This code runs the sort
invocations concurrently, limited only by
available processors and data dependencies.
6. Swift/T for Python and Numpy users
Swift/T can run Python as an ordinary external program or via a
bundled interpreter! You can load Python packages, including
Python-wrapped native code- just set PYTHONPATH
and import
what
you need.
See this section for information about calling Python or Numpy: Swift/T Guide: Python
7. Swift/T for Tcl users
Swift/T is a great way to parallelize Tcl applications. You can run
tclsh
as an ordinary external program, or use the bundled Tcl
interpreter! (Swift/T always has a Tcl interpreter for basic
operation.) You can load Tcl packages, including Tcl-wrapped native
code- just set SWIFT_PATH
and package require
what you need.
File: swift-tcl/tcl.swift
import io;
@dispatch=WORKER
(int o) add(int i, int j) "turbine" "0.0"
[
"""
set i <<i>>
set j <<j>>
set o [ expr $i + $j ]
puts "tcl: o=$o"
set <<o>> $o
"""
];
i = 3;
j = 4;
o = add(i,j);
printf("o should be: %i", i+j);
printf("o is: %i", o);
Run this with:
swift-t -p gallery/swift-tcl/tcl.swift
(swift-t -p
turns off the C preprocessor and allows the triple-quote
syntax.)
It outputs:
o should be: 7
tcl: o=7
o is: 7
The @dispatch=WORKER
annotation allows add()
to run on any worker
process in the run. Multiple add()
s, or other functions, can run
concurrently. Swift automatically maintains ordering by managing data
dependencies from function outputs to inputs.
8. Static executables
This section demonstrates a complete, concrete example of the optional static executable feature. First, compose a Swift script.
File: static-exec/hello.swift
import io;
printf("HELLO");
Then, copy Turbine’s example manifest file and edit. This manifest has all comments removed for simplicity.
File: static-exec/hello.manifest
pkg_name = hello
pkg_version = 0.1
main_script = hello.tic
Then, build:
File: static-exec/build.sh
#!/bin/bash
set -eu
# Obtain the Turbine build configuration variables
TURBINE=/homes/wozniak/sfw/fusion/compute/turbine-static
source ${TURBINE}/scripts/turbine-build-config.sh
# Generate hello.tic
stc hello.swift
# Bundle hello.tic and Turbine into hello_main.c
mkstatic.tcl hello.manifest -c hello_main.c
# Compile hello_main.c and link as standalone, static executable
CFLAGS=-std=gnu99
gcc -c ${CFLAGS} ${TURBINE_INCLUDES} hello_main.c
mpicc -static -o hello.x hello_main.o ${TURBINE_LIBS} ${TURBINE_RPATH}