# CUDA, Supercomputing for the Masses: Part 9

### Introducing SWIG

An excellent software development tool that connects modules written in C and C++ to a wide variety of high-level programming languages is SWIG which supports Perl, PHP, Python, Tcl, Java, C#, Common Lisp, Octave, R and many more (see www.swig.org/compat.html#SupportedLanguages for more languages.

Here are some links to get you started for three common languages. Check out the web for your favorite if not listed below:

The following is a simple Python example, contributed by a colleague at NVIDIA, which demonstrates the simplicity and speed of calling a CUDA kernel from Python. This example actually implements a useful method for financial applications -- namely matrix exponentiation. Unfortunately, the reasoning behind why such a method is useful is beyond the scope of this article. See the discussion starting on page 19 in the paper at http://arxiv.org/pdf/0710.1606 for more information. Be forewarned, this paper is quite dense.

In the spirit of this article, this example module makes efficient use of the GPU. The reason it performs so well is because this module lets Python programmers call SGEMM, a high flop per data item level-3 BLAS routine in the NVIDIA CUBLAS library. It also demonstrates that it is possible to map variables -- in this case an array -- very efficiently between Python and CUDA.

The full listing for the Python code exponentiationTest.py is:

```#! /usr/bin/env python

import copy
import numpy
import FastMatrixExp

# Read input matrix using a user defined function
b = copy.copy(a)

steps = 100

# Matrix exponentiation using CPU SGEMM
for i in range(steps):
a = numpy.dot(a,a)

# Matrix exponentiation using CUBLAS SGEMM
FastMatrixExp.matrixMulLoop([steps,b])

numpy.testing.assert_array_almost_equal(a, b, decimal = 6)
print 'Error = %f' % numpy.linalg.norm(a-b)

```

Within the exponentiationTest.py, a custom module is imported with the line:

```
import FastMatrixExp

```

The reader is required to define its own Python method to input a matrix into variable a, which is then duplicated in variable b for purposes of comparing the speed and accuracy of the CPU and GPU:

```
# Read input matrix using a user defined function
b = copy.copy(a)

```

Matrix a is then raised to the power specified in the variable steps (specifically 100) on the host processor with this code snippet:

```
steps = 100

# Matrix exponentiation using CPU SGEMM
for i in range(steps):
a = numpy.dot(a,a)

```

After which the SGEMM routine from the CUBLAS library is called from Python and utilized on the GPU to perform the matrix exponentiation with the following:

```
# Matrix exponentiation using CUBLAS SGEMM
FastMatrixExp.matrixMulLoop([steps,b])

```

Both the GPU and CPU generated results are then checked to see if they are equal within a reasonable tolerance via a numpy comparision as seen below. (Numpy is an excellent numerical Python package that has matrix operations.

```
numpy.testing.assert_array_almost_equal(a, b, decimal = 6)
print 'Error = %f' % numpy.linalg.norm(a-b)

```

The following is the SWIG interface code:

```%module FastMatrixExp

%{
#include <oldnumeric.h>
#include <cublas.h>
%}

%include exception.i

/* Matrix multiplication loop for fast matrix exponentiation. */

%typemap(python,in) (int steps, float *u, int n)
{
\$1 = PyInt_AsLong(PyList_GetItem(\$input,0));
\$2 = (float *)(((PyArrayObject *)PyList_GetItem(\$input,1))->data);
\$3 = ((PyArrayObject *)PyList_GetItem(\$input,1))->dimensions[0];
}

extern void matrixMulLoop(int steps, float *u, int n);

%{
void matrixMulLoop(int steps, float *u, int n)
{
int i;
float *ud;
cublasStatus status;

/* Allocate memory and copy u to the device. */
status = cublasAlloc(n*n, sizeof(float), (void **)&ud);
status = cublasSetMatrix(n, n, sizeof(float), (void *)u,n, (void *)ud, n);

for(i=0; i<steps; i++)
cublasSgemm('n','n',n,n,n,1.0f,ud,n,ud,n,0.0f,ud,n);

/* Copy u back to the host and free device memory. */
status = cublasGetMatrix(n, n, sizeof(float), (void *)ud,n, (void *)u, n);
status = cublasFree((void *)ud);
}
%}

%init
%{
import_array();
cublasStatus status;
status = cublasInit();
%}

```

The module name, `FastMatrixExp`, is defined in the first line of CUBLAS.i:

```#module FastMatrixExp
```

The iterated calls to `cublasSgemm` occur in the following C subroutine, which is defined between the `%{` and `%}` for SWIG:

```%{
void matrixMulLoop(int steps, float *u, int n)
{
int i;
float *ud;
cublasStatus status;

/* Allocate memory and copy u to the device. */
status = cublasAlloc(n*n, sizeof(float), (void **)&ud);
status = cublasSetMatrix(n, n, sizeof(float), (void *)u,n, (void *)ud, n);

for(i=0; i<steps; i++)
cublasSgemm('n','n',n,n,n,1.0f,ud,n,ud,n,0.0f,ud,n);

/* Copy u back to the host and free device memory. */
status = cublasGetMatrix(n, n, sizeof(float), (void *)ud,n, (void *)u, n);
status = cublasFree((void *)ud);
}
%}

```

To gain a greater understanding of the remaining parts of the SWIG file, I recommend consulting the SWIG documentation. You can also find out more about SWIG in David Beazley's article SWIG and Automated C/C++ Scripting Extensions, and Daniel Blezek's article Rapid Prototyping with SWIG.

For more advanced numerical packages that combine Python and CUDA, checkout pystream or GPUlib (which can be downloaded after submitting an email request).

Rob Farber is a senior scientist at Pacific Northwest National Laboratory. He has worked in massively parallel computing at several national laboratories and as co-founder of several startups. He can be reached at rmfarber@gmail.com.

### More Insights

 To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.

# First C Compiler Now on Github

The earliest known C compiler by the legendary Dennis Ritchie has been published on the repository.

# HTML5 Mobile Development: Seven Good Ideas (and Three Bad Ones)

HTML5 Mobile Development: Seven Good Ideas (and Three Bad Ones)

# Building Bare Metal ARM Systems with GNU

All you need to know to get up and running... and programming on ARM

# Amazon's Vogels Challenges IT: Rethink App Dev

Amazon Web Services CTO says promised land of cloud computing requires a new generation of applications that follow different principles.

# How to Select a PaaS Partner

Eventually, the vast majority of Web applications will run on a platform-as-a-service, or PaaS, vendor's infrastructure. To help sort out the options, we sent out a matrix with more than 70 decision points to a variety of PaaS providers.

More "Best of the Web" >>