This page demonstrates the ease of use of Swift/T when constructing common application patterns.

Links:

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}