This page demonstrates the ease of use of Swift/T when constructing common application patterns.
Links:
-
Post to the ExM 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
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
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
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
The sys
module provides the argv()
function, which provides a
handy key/value interface for input values.
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}