Using the Darwin cluster
Darwin Cluster WikiSetting up passwordless SSH
Darwin specifications
Logging in
Compiling MPI and OpenMP programs
Running MPI programs
Timing your runs
MPI example
OpenMP example
Julia example
Emacs setup
Julia MPI
Setting up passwordless SSH
Being able to move among nodes without entering a password will make your life much more enjoyable.- Run ssh-keygen on a Unix machine you typically use (can be Athena, or a Darwin cluster head node). Accept the default settings and leave the passphrase blank. This creates files in ~/.ssh
- Append the contents of ~/.ssh/id_rsa.pub to the file ~/.ssh/authorized_keys on each machine you want to be able to connect to. The Darwin cluster nodes share a filesystem, so you only need to do this once on one of the head nodes.
- Copy the file ~/.ssh/id_rsa (private key) to the same location on each machine you want to connect from. Again, once this file is in ~/.ssh on Darwin you are all set for the cluster.
- The file id_rsa needs to have strict permissions. If you get errors about this, run chmod 400 id_rsa.
scp file user@machine:path
Darwin specifications
- Darwin compute cluster
- Head node: beagle.darwinproject.mit.edu
- Nodes: 128
- Per-node CPU: 2 x 2-core 3.00GHz Intel(R) Xeon(TM), 4MB L2 cache
- Per-node memory: 8 GB
- Darwin visualization cluster
- Head node: evolution.darwinproject.mit.edu
- Nodes: 60
- Per-node CPU: 2 x 2-core 2.66GHz Intel(R) Xeon(TM), 4MB L2 cache
- Per-node memory: 6 GB
The top command is useful to see how much CPU and memory everybody's jobs are using. In top, hit "M" to sort by memory use. Hit "u" and type your username to see just your processes.
Logging In
ssh to beagle.darwinproject.mit.edu or evolution.darwinproject.mit.edu with your athena username and password.If you are on a windows machine, you can download SecureCRT or Putty from MIT, MIT certificate required). Or you can use any other SSH client.
Compiling MPI and OpenMP programs
For MPI programs, use mpicc for C programs, mpiCC for C++ programs, mpif77 for fortran programs, as follows:mpicc mytest.c -o test
or,
mpiCC mytest.cc -o test
or,
mpif77 mytest.f -o test
For OpenMP programs you need to use the Intel Fortran/C Compilers. Do the following on beagle:
source /opt/intel/cc/9.1.051/bin/iccvars.sh
then,
icc -O -openmp -o test mytest.cc
or,
ifc -O -openmp -o test mytest.f
Running MPI programs
After compiling MPI programs, use qsub and mpirun
to execute:
echo '/opt/openmpi/bin/mpirun -np # /path/to/yourMPIProgram' | qsub -pe mpich_mx #
where # is the number of processors and yourMPIProgram is the MPI executable to be run. qsub is the interface to the Sun Grid Engine batch
queue, which ensures that the cluster is shared fairly.
Anything printed to standard out will be available in a file in your home
directory called STDIN.oID where ID is the job ID.
STDIN refers to the fact that the job description was provided
on standard input via a pipe instead of in a shell script file. The
standard error stream is in a similar file, named with an e instead
of the o.
When using a private cluster, one can specify machines to use manually
using a hostfile, as follows:
mpirun -np # -machinefile hostfile ./yourMPIProgram
"hostfile" is a text file listing all the hosts you want to use. It might
look like this:
node-1 node-2 node-3 node-4
Look at /etc/hosts to see the names of the compute nodes.
Timing your runs
You can use the command time to time your runs. For example,time ./myprog
returns something like
real 0m0.958s
user 0m0.180s
sys 0m0.170s
real is the wall clock time elapsed.
Timing MPI programs is similar,
time mpirun -np 4 ./hello++
This method is not very accurate. For accurate timing, use the function MPI_WTime
MPI example
#include "mpi.h" #include "unistd.h" #include "stdio.h" int main(int argc, char **argv) { char hostname[256]; int size,rank; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); gethostname(hostname, sizeof(hostname)); printf("Hi, I am %d of %d and my hostname is %s\n", rank, size, hostname); MPI_Finalize(); }
OpenMP example
#include <math.h> #include <stdio.h> #define N 16384 #define M 10 double dotproduct(int, double *); double dotproduct(int i, double *x) { double temp=0.0, denom; int j; for (j=0; j<N; j++) { // zero based!! denom = (i+j)*(i+j+1)/2 + i+1; temp = temp + x[j]*(1/denom); } return temp; } int main() { double *x = new double[N]; double *y = new double[N]; double eig = sqrt(N); double denom,temp; int i,j,k; for (i=0; i<N; i++) { x[i] = 1/eig; } for (k=0;k<M;k++) { y[i]=0; // compute y = Ax #pragma omp parallel for shared(y) for (i=0; i<N; i++) { y[i] = dotproduct(i,x); } // find largest eigenvalue of y eig = 0; for (i=0; i<N; i++) { eig = eig + y[i]*y[i]; } eig = sqrt(eig); printf("The largest eigenvalue after %2d iteration is %16.15e\n",k+1, eig); // normalize for (i=0; i<N; i++) { x[i] = y[i]/eig; } } }
Julia example
A regularly-updated copy of Julia is available on Darwin under /home/bezanson/julia. One of Julia's charming features is that it can be run by anyone, from anywhere, without any install or setup. Type /home/bezanson/julia/julia to run it. There is also a world-writable directory /home/bezanson/julia/data in case that is useful.You can add processors to Julia's pool from the prompt as follows:
julia> @time @parallel (+) for i=1:10000000; randn(); end elapsed time: 1.0429379940032959 seconds -842.00907574328687133 julia> @time @parallel (+) for i=1:10000000; randn(); end elapsed time: 0.58234810829162598 seconds 430.07946679243082144 julia> addprocs_sge(2) ok julia> @time @parallel (+) for i=1:10000000; randn(); end elapsed time: 3.28881287574768066 seconds 2124.42978527200511962 julia> @time @parallel (+) for i=1:10000000; randn(); end elapsed time: 0.31914687156677246 seconds 283.82680807441192883
Here we summed 10000000 normal-random numbers using a parallel for loop. addprocs_sge requests nodes from the Sun Grid Engine batch queue. Julia can also start processes via SSH, provided you have passwordless access to the nodes in question, using addprocs_ssh with a cell array of machine names. However, one should not do this on a shared cluster managed by a batch queue.
Note one minor annoyance: due to Julia's Just-In-Time (JIT) compilation model, things take longer the first time you do them. The extra delay is typically about 1-3 seconds. As the code cache warms up over a session, these delays become shorter and rarer.
(Optional!) Feel free to check out and build your own copy of Julia from github. We recommend this in order to stay up to date and make it easy to send patches. If you'd like to get a little deeper into Julia and possibly even contribute changes, fixes, example code, etc. you should make your own github account (if you don't have one already).
Emacs setup
An emacs mode for Julia is available. Copy /home/bezanson/.emacs to your home directory, or add the following to your .emacs file:(require 'julia-mode "/home/bezanson/julia/contrib/julia-mode.el")
Julia MPI
There are MPI bindings available for Julia. See /home/bezanson/julia-mpi/examples for examples. Use a command like the following to run a Julia MPI program:mpirun -np # /home/bezanson/.julia/mpi/juliampi sourcefile.jl
You will need to add /home/bezanson/bin to your path, or make a link to /home/bezanson/julia/julia in some directory in your path, such as $HOME/bin.
The MPI bindings are maintained by Lucas Wilcox in a separate github repository.