\input{psfig}
\makeatletter
\long\def\unmarkedfootnote#1{{\long\def\@makefntext##1{##1}\footnotetext{#1}}}
\makeatother

\newcommand{\ignore}[1]{}

\documentstyle[11pt,fullpage,cmu-titlepage,picture]{cmu-art}
\include{caption}

\title{Computing the Pipelined Phase-Rotation FFT}

\author{
\begin{tabular}[c]{ c@{\extracolsep{2em}} c} 
 Langhorne P. Withers, Jr., John E. Whelchel 
& David R. O'Hallaron, Peter J. Lieu \\ 
\\
{E-Systems, Inc., Melpar Div.} & {School of Computer Science}\\
{7700 Arlington Boulevard}     & {Carnegie Mellon University}\\     
{Falls Church, VA 22046}       & {Pittsburgh, PA 15213}
\end{tabular}
}

\disclaimer{
Supported in part by the Advanced Research Projects Agency,
Information Science and Technology Office, under the title "Research
on Parallel Computing," ARPA Order No. 7330.  Work furnished in
connection with this research is provided under prime contract
MDA972--90--C--0035 issued by ARPA/CMO to Carnegie Mellon University,
and in part by the Air Force Office of Scientific Research under
Contract F49620--92--J--0131. Also supported in part by an E-Systems
IR\&D program.
}

\date{July 13, 1993}
\trnumber{CMU-CS-93-174}

\keywords{multicomputers, signal processing, Fast Fourier Transform}

\abstract{
The phase-rotation FFT is a new form of the FFT that replaces data
movement with multiplications by constant phasor multipliers.  The
result is an FFT that is extremely easy to pipeline: For the radix-$r$
case, the pipelined phase-rotation FFT consists of $r$ parallel data
channels. The only communication between the $r$ channels occurs
inside the DFT kernel.  This paper reports some fundamental new
improvements to the original phase-rotation FFT design, provides a
complete description of the algorithm directly in terms of the
parallel pipeline, and describes a radix-2 implementation on the iWarp
computer system that perfectly balances computation and communication
to run at the full-bandwidth of the communications links, regardless
of the input data set size.
}


\begin{document}
\bibliographystyle{acm}
\maketitle

\section {Introduction}
The Fast Fourier Transform (FFT) is an important algorithm with many
applications in signal processing and scientific computing.  The
Whelchel phase-rotation FFT~\cite{whelchel90} derives from the Pease
constant-geometry FFT~\cite{pease68}, which itself derives from the
original Cooley-Tukey FFT~\cite{cooley65} expressed in terms of
Kronecker products.

The phase-rotation FFT of radix $r$ is designed for a pipeline of $r$
parallel data channels.  At each time step, in each stage, the
pipeline carries the next $r$ data points, one from each channel, into
a Discrete Fourier Transform (DFT) kernel.  Unlike earlier pipelined
FFT's~\cite{mcclellan78,corinthios71}, the phase-rotation FFT has the
key property that no data is switched across channels, except
within the DFT kernel and at the input and output.

The phase-rotation FFT extends easily to higher radices, reducing
memory and latency while preserving the high throughput and parallel
shuffling simplicity of lower radix versions.  The phase-rotation FFT
has also been extended to a vector-radix, multidimensional
parallel-pipeline FFT with the same qualities of the one-dimensional
algorithm, and without transposes~\cite{withers91}.

This paper describes the results of a project to implement the
phase-rotation FFT on a parallel computer system.  There are three
main results:
\begin{itemize}

\item The digit-reversing shuffle step in the original version
of the phase-rotation FFT~\cite{whelchel90} is a potential pipeline
bottleneck because it requires communication between the data
channels. We describe a new version that corrects this problem by
using a parallel-pipeline digit-reversing step.

\item The structure of the phase-rotation FFT is extremely
simple. However, we learned that generating the appropriate twiddles
and shuffle indices from the original matrix
formulation~\cite{whelchel90} is quite difficult, even for the
designers of the algorithm! To try to help the implementer, we have
reformulated the phase-rotation FFT. We present a new set of recipes
for generating the twiddles and shuffle indices directly in terms of
the parallel pipeline.

\item Finally, we describe an implementation of the phase-rotation
FFT on the iWarp, a private-memory multicomputer system developed by
Intel and Carnegie Mellon~\cite{iwarp,iwarpcomm}. We describe a
mapping strategy for an $N$-point radix-2 phase-rotation FFT that
perfectly balances computation and communication to run at the full 40
Mbytes/sec rate of the iWarp physical links, regardless of the size of
the input data sets.
\end{itemize}

Section~\ref{sec:basic} introduces the phase-rotation concept.
Section~\ref{sec:phasedef} formally defines the improved FFT
algorithm. Section~\ref{sec:recipes} gives the recipes for generating
the twiddles and shuffle indices in terms of the parallel pipeline.
Finally, Section~\ref{sec:implementation} describes the full-bandwidth
implementation on iWarp.

\section{The basic idea} 
\label{sec:basic}
This section introduces the concept of the phase-rotation FFT.
Starting with the Pease constant-geometry FFT, we informally derive 
the pipelined phase-rotation FFT, identifying the key insights along
the way.

\subsection{Constant-geometry FFT}
Figure~\ref{fig:phase}(a) shows the flowgraph for a radix-$r$
$N$-point decimation-in-frequency (DIF) constant-geometry FFT, with
$r=2$ and $N=r^n=8$. There are $n$ stages. Each stage contains $N/r$
{\em kernels}. Each kernel is an operator that performs an $r$-point
DFT.  For radix 2, each kernel inputs two complex numbers and outputs
two complex numbers. (For simplicity, twiddles are not explicitly
shown in the flowgraph.)
\begin{figure}
\centering
\makebox{
\scaledpict 50mm by 29mm (phase scaled 1000)
}
\caption{Derivation of the phase-rotation FFT. {\rm (a) Initial constant-geometry FFT. (b) Pipelined constant geometry FFT. (c) Pipelined FFT based on cyclic rotations. (d) Pipelined phase-rotation FFT.}
} 
\label{fig:phase}
\end{figure}

Each stage in the constant-geometry FFT performs an identical perfect
stride-by-$s$ shuffle of its data vector, where $s = N/r$.  If the
data vector is regarded as an $s \times r$ array, stored in
column-major order, then the perfect shuffle simply transposes it into
an $r \times s$ array.  For example, the following transpose is a
stride-by-4 perfect shuffle, for $N=8$ points and radix $r=2$:
\begin{center}
\begin{tabular} {l c c c}                      
$\left[ 
\begin{array} {c c} 
 0 & 4 \\
 1 & 5 \\
 2 & 6 \\
 3 & 7 
 \end{array} \right]$
&
 $\stackrel{T}{\longrightarrow}$
&
 $\left[ \begin{array} {c c c c} 
 0 & 1 & 2 & 3 \\
 4 & 5 & 6 & 7
\end{array} \right]$\\ 
\end{tabular} 
\end{center}
The data items in example above, labeled by their indices in the
original column vector, are regarded as equivalent to a $4 \times 2$
array composed by a stride-by-4 unstacking of the 8-point column
vector.  After the transpose, the $2 \times 4$ array is equivalent to
a new 8-point column vector composed by a stride-by-2 stacking.  As we
shall see, this transpose creates difficulties when we try to pipeline
the constant-geometry FFT. And it is precisely these difficulties that
the phase-rotation FFT addresses.

\subsection{Pipelining the FFT}
Each stage of the constant-geometry FFT can be computed on a single
processor by pipelining the data.  For example,
Figure~\ref{fig:phase}(b) shows the pipeline for a single stage with
radix $r=2$.  The pipeline consists of a sequence of operators
connected by {\em pipeline segments}. Each pipeline segment consists
of $r$ parallel {\em channels}. Each channel carries a {\em stream} of
$N/r$ data points, which are labeled in this example by their indices
from the original column vectors in Figure~\ref{fig:phase}(a). For
each pipeline segment, the $r$ data points in the same position in
each stream are known as an $r$-{\em frame}, or simply, a {\em frame}.
For example, in Figure~\ref{fig:phase}(b), the first frame in the
pipeline segment between ${\bf S}$ and ${\bf F}$ is (0,4), the second
frame is (1,5), and so on.

At each time step, the $r$ twiddle operators (${\bf T}$) collectively
read a frame (one complex number per operator), perform an
element-wise complex multiplication, and write the resulting frame.
Notice that each stream is operated on independently.  Similarly, the
kernel operator (${\bf F}$) reads a frame, computes the radix-$r$
kernel, and writes the resulting frame.  In this case, the streams are
not independent; each data item in the output frame is a function of
every data point in the input frame.

The twiddle and kernel operators pipeline nicely because during each
time step they independently read and write a single number.  However,
the pipelined shuffle operator (${\bf S}$) is less well behaved.  To
produce one output frame, the shuffle operator must read and store the
$r$ data points from each stream. Thus, ${\bf S}$ requires $r$ memory
cycles to produce each frame. (Notice that ${\bf S}$ transposes the
data directly into an $r \times s$ pipeline segment; even starting
with data already in an $r \times s$ pipeline, ${\bf S}$ still
performs ``row-to-column'' motions.)  This is an example of the {\em
memory-bank conflict} discussed in
\cite[pp.31-32]{vanloan92}.  The conflict is clear in
Figure~\ref{fig:phase}(b).  To assemble its first output frame, ${\bf
S}$ must read both 0 and 4 from the upper stream to its left.  Then it
must read 1 and 5 from the lower stream, and so on.

We would like to replace the troublesome perfect shuffle operation
with a {\em parallel-pipeline shuffle}, where each stream is read and
written independently and in parallel. The next section describes the
insights that make this possible.

\subsection{The phase-rotation concept}
This section describes how to replace the perfect shuffle by a
parallel-pipeline shuffle, so that we can access the data streams in
parallel.  The basic idea is to rotate the data within frames, and
then compensate for these motions by phase rotations of the twiddle
factors.

We begin with a ``detour'' around the perfect shuffle. That is, we
find a sequence of three simpler shuffles that is equivalent to the
perfect shuffle. This idea is shown in Figure~\ref{fig:decomp}.  Each
radix-2 pipeline segment is represented as matrix. Each row in the
matrix is a stream and each column is a frame.  Notice that the frames
(columns) are arranged left-to-right in reverse-time order in the matrix.
\ignore{
First, we find that rotating the input data frames spreads the data
points for each perfect-shuffle output frame across the pipeline
segment, out of one stream into all of them.  The set of data points
comprising each output frame is then ready to be accessed in parallel.
We call this sequence of rotations (or cyclic shifts) ${\bf
C}_{slow}$.  Second, we retrieve the data points now accessible in
parallel.  This parallel-pipeline shuffle is called
${\overline{\overline{\bf S}}}$.  Note that no data points need to be
transferred between streams at this step.  Next, we find that this
step leaves the right data points in every frame, but not in the right
order. The last step is to rotate these data frames again, to put them
in the same order that the perfect shuffle would.  This set of
rotations is called ${\bf C}_{fast}$.  Note that ${\bf C}_{slow}$ and
${\bf C}_{fast}$ change the number of rotations per frame at different
paces, one slow and one fast.
}
When represented in matrix form, the shuffle operator ${\bf S}$ in
Figure~\ref{fig:phase}(b) can be factored into the double matrix
product 
\begin{equation}
{\bf S} = {\bf C}_{fast} {\overline{\overline{\bf S}}} {\bf C}_{slow}
\label{eqn:decomp}
\end{equation}
where ${\overline{\overline{\bf S}}}$ is a {\em parallel-pipeline
shuffle} that shuffles independently along each input stream, and
${\bf C}_{slow}$ and ${\bf C}_{fast}$ are frame-wise (i.e., involving
only data items in a single frame) cyclic rotations.  We will formally
define ${\overline{\overline{\bf S}}}$, ${\bf C}_{slow}$, and ${\bf
C}_{fast}$ in Section~\ref{sec:phasedef}. 
For now, we will rely on the
example in Figure~\ref{fig:decomp} to get the idea across.

\begin{figure}
\centering
\makebox{
\begin{tabular} {l c c c}                      
& 
 $\left[ \begin{array} {c c c c} 
 0 & 2 & 4 & 6 \\
 1 & 3 & 5 & 7
 \end{array} \right]$ 
&
 $\stackrel{{\bf S}}{\longrightarrow}$ 
&
 $\left[ \begin{array} {c c c c} 
 0 & 1 & 2 & 3 \\
 4 & 5 & 6 & 7
 \end{array} \right]$ 
\\ 
&
\\
& 
$\downarrow \; {\bf C}_{slow}$ & & $\uparrow \; {\bf C}_{fast}$ 
\\ 
& 
\\
&
 $\left[ \begin{array} {c c c c} 
 0 & 2 & 5 & 7 \\
 1 & 3 & 4 & 6             %% needs hand-drawn circles, squares 
 \end{array} \right]$ 
&
 $\stackrel{ \overline{\overline{\bf S}} }{\longrightarrow}$ 
&
 $\left[ \begin{array} {c c c c} 
 0 & 5 & 2 & 7 \\
 4 & 1 & 6 & 3             %% needs hand-drawn circles, squares 
\end{array} \right]$ 
\end{tabular} 
}
\caption{Replacing the perfect shuffle with three simpler shuffles.}
\label{fig:decomp}
\end{figure}
The first step in Figure~\ref{fig:decomp} is a set of cyclic
rotations, called ${\bf C}_{slow}$, which rotates each frame.  These
rotations are frame-wise in the sense that only data points contained
in the same frame are rotated across the streams.  Notice that in the
radix-2 case, half of the rotations leave the corresponding frame
unchanged.  The next step is a parallel-pipeline shuffle
$\overline{\overline{\bf S}}$, which permutes the data in each stream.
Notice that no data points need to be transferred between streams in
this step.  The last step is another set of frame-wise cyclic
rotations, called ${\bf C}_{fast}$, which leave the data in the same
order that the perfect shuffle would.  Note that, although it is
difficult to see in the radix-2 case, ${\bf C}_{slow}$ and ${\bf
C}_{fast}$ change the number of rotations per frame at different
paces, one slow and one fast.  
If we apply (\ref{eqn:decomp}) to each stage of the pipelined FFT in
Figure~\ref{fig:phase}(b), replacing each perfect shuffle with
three simpler shuffles, we get a pipelined FFT based on cyclic
rotations, which is shown in Figure~\ref{fig:phase}(c).  

The basic frame-wise rotation in Figure~\ref{fig:phase}(c) that is
applied at slow-varying, and then fast-varying rates, is represented
by the $r \times r$ cyclic (circular) shift permutation matrix ${\bf
C}_{r}$, made by permuting the rows of the identity matrix down by one
row, and moving the bottom row up to the top. For example,
\begin{eqnarray*}
{\bf C}_{4} = \left(
\begin{array}{ c c c c }
0&0&0&1\\
1&0&0&0\\
0&1&0&0\\
0&0&1&0
\end{array} \right)\;\;.
\end{eqnarray*}
The key insight of the phase-rotation FFT is that the cyclic shift
theorem for the DFT can be applied to the cyclic shift operators in
Figure~\ref{fig:phase}(c).  In matrix form, the cyclic shift theorem for
a DFT is the relation
\begin{equation}
{\bf F}_{r}{\bf C}_{r} = {\bf D}_{r}{\bf F}_{r},
\label{eqn:shifttheorem}
\end{equation} 
where 
${\bf D}_{r}= diag( 1, \omega, \omega^{2}, ..., \omega^{r-1} )$
is a set of twiddles, and the DFT matrix of size $r$ is
\begin{displaymath}
{\bf F}_{r} = \frac {1}{\sqrt{r}} ( \omega^{jk})_{j,k=0}^{r-1} ,
\end{displaymath}
where $\omega = e^{-\frac{2 \pi i}{r}}$.  For the pipelined FFT,
(\ref{eqn:shifttheorem}) says that phasor multipliers after a DFT
kernel give the same effect as physical data rotations before the DFT
kernel.  Likewise, physical rotations after the kernel are equivalent
to phasor multipliers before it. The meaning of
(\ref{eqn:shifttheorem}) is shown graphically in
Figure~\ref{fig:theorem} for a pipelined radix-2 kernel.
\begin{figure}
\centering
\makebox{
\scaledpict 50mm by 29mm (theorem scaled 1000)
}
\caption{Interpretation of ${\bf F}_{r}{\bf C}_{r} = {\bf D}_{r}{\bf F}_{r}$}
\label{fig:theorem}
\end{figure}

Now the data rotations in Figure~\ref{fig:phase}(c) can be replaced by
constant phasor multipliers.  These phasors can then be absorbed by
the twiddle factors on either side of the kernel, leaving only a
parallel-pipeline shuffle.  The result is the pipelined phase-rotation
FFT, which is shown in Figure~\ref{fig:phase}(d).  This completes our
informal derivation of the phase-rotation FFT.

The structure of the phase-rotation FFT in Figure~\ref{fig:phase}(d)
is quite similar to the original pipelined FFT in
Figure~\ref{fig:phase}(b). The twiddle operators ($D^\prime$) are
identical to the original twiddle operators ($T$), except now the
twiddles incorporate the original twiddles, phasors for the ${\bf
C}_{fast}$ operator from the previous stage, and phasors for the ${\bf
C}_{slow}$ operator from the next stage. The kernel operators are
identical as well. The important difference is that the troublesome
perfect shuffle operator has now been replaced by a parallel-pipeline
shuffle that requires no communication across the streams.

There are several other important properties of the phase-rotation FFT
in Figure~\ref{fig:phase}(d).  First, there are no additional
multiplications or additions, compared to the original pipelined FFT
in Figure~\ref{fig:phase}(a).  Second, the only internal
communication across streams occurs at the kernel, and this
communication is constrained, in that only data points within a single
frame need to be switched across channels, and the switching is fixed
for all frames.

\section{Improved phase-rotation FFT}
\label{sec:phasedef}
In this section we give a formal definition of an improved version of
the original phase-rotation FFT described in \cite{whelchel90}. The
new version replaces the digit-reversing permutation in the original
phase rotation FFT with a parallel-pipeline shuffle, followed by a
frame-wise cyclic rotation.  The advantage of this new approach is
that during the digit-reversing step at the end, all communication
between streams is limited to data points within a single frame.

For radix $r$ and $N=r^n$ points ($n>1$), the 1-dimensional
phase-rotation FFT is a matrix factorization of the $N$-point DFT
matrix ${\bf F}_{N}$.  Starting with the Pease constant-geometry
factorization, we replace its perfect shuffles ${\bf S}$ by ${\bf S} =
{\bf C}_{fast} \overline{\overline{{\bf S}}} {\bf C}_{slow}$.
Similarly, at the left end we replace the radix-$r$
index-digit-reversing permutation ${\bf Q} = {\bf Q}_{N,r}$ of $N$
data points by ${\bf Q} = {\bf C}_{slow}^T \overline{\overline{\bf
Q}}{\bf C}_{slow}$, where $\overline{\overline{\bf Q}}$ is another
parallel-pipeline shuffle that will be defined formally in
Section~\ref{sec:recipes}. The phase-rotation FFT is then defined by:
\begin{eqnarray}
{\bf F}_{N} &=& {\bf Q} \cdot 
\prod_{j=1}^{n} \left( {\bf F}{\bf S}{\bf T}_{j} \right)
 = \cdots 
\left( \mbox{ \small
\begin{tabular}[c]{c} 
\small vigorous\\
\small algebraic\\
\small shuffling
\end{tabular}  } 
\right) \cdots 
\nonumber\\ 
%&=& 
%\left( \prod_{j=1}^{n-1} {\bf F}
%{\bf C}_{fast} \overline{\overline{{\bf S}}} 
% {\bf C}_{slow} {\bf T}_{j} \right) {\bf F}{\bf S}{\bf Q} 
% = \cdots \nonumber\\
&=& {\bf C}_{slow}^T \cdot \overline{\overline{\bf Q}}{\bf D}_{fast}^{\prime} 
\left[  
\prod_{j=1}^{n} 
\left( {\bf F} \overline{\overline{{\bf S}}}{\bf D}_{j}^{\prime} \right) 
\right]
\cdot {\bf C}_{slow} . 
\label{eqn:phase} 
\end{eqnarray}
%
Let $s = N/r$ as before, and $r^{\prime} = N/r^2$.  ${\bf F}$ is a
direct (tensor, Kronecker) product ${\bf I}_{s} \otimes {\bf F}_{r} =
\mbox{diag}({\bf F}_{r}, {\bf F}_{r}, ...,{\bf F}_{r})$.  We interpret
this as a kernel DFT ${\bf F}_{r}$ operating on $s$ successive
frames of $r$ points placed in the pipeline.  For $j=1:n$, the other
parts of (\ref{eqn:phase}) are defined by
\begin{eqnarray}
{\bf C}_{slow} &=&  \bigoplus_{k=0}^{r-1} 
   \left( {\bf I}_{r^{\prime}} \otimes {\bf C}_{r}^{k} \right ) \nonumber\\ 
{\bf C}_{fast} &=&  {\bf I}_{r^{\prime}} \otimes 
   \left(   \bigoplus_{k=0}^{r-1} ({\bf C}_{r}^{T})^{k} \right ) \nonumber\\ 
\omega_j &=& exp \left({-\frac{2 \pi i}{r^{j}}} \right) \nonumber\\
{\bf D}_{r} &=& 
 diag( 1, \omega_{1}, \omega_{1}^{2}, ..., \omega_{1}^{r-1} ) 
 \nonumber\\ 
{\bf D}_{r^{j+1}} &=& 
 diag( 1, \omega_{j+1}, \omega_{j+1}^{2}, ..., \omega_{j+1}^{r^{j}-1} ) 
 \nonumber\\ 
{\bf D}_{slow}^{-1} &=&  \bigoplus_{k=0}^{r-1} 
   \left( {\bf I}_{r^{\prime}} \otimes {\bf D}_{r}^{-k} \right) 
   \nonumber\\ 
{\bf D}_{slow}^{\prime} &=&
              {\bf C}_{fast}^T {\bf D}_{slow}^{-1} {\bf C}_{fast} \nonumber\\
{\bf D}_{slow}^{\prime \prime} &=& 
     \overline{\overline{{\bf S}}}^T 
     {\bf D}_{slow}^{\prime} 
     \overline{\overline{{\bf S}}} \nonumber\\
{\bf D}_{fast}^{-1}  &=&  {\bf I}_{r^{\prime}} \otimes 
   \left(   \bigoplus_{k=0}^{r-1} {\bf D}_{r}^{-k} \right) 
   \nonumber\\ 
{\bf D}_{fast}^{\prime} &=&
              {\bf C}_{slow}^T {\bf D}_{fast}^{-1}  {\bf C}_{slow} \nonumber\\
{\tilde{\bf T}}_{j} &=& {\bf I}_{ \frac{N}{r^{(j+1)}} } \otimes 
   \left(  \bigoplus_{k=0}^{r-1}{\bf D}_{r^{j+1}}^{k} \right) \nonumber\\
%
{\bf T}_{j} &=& {\bf S}^{j\;T}{\tilde{\bf T}}_{j}{\bf S}^{j} \nonumber\\
{\bf T}_{j}^{\prime} &=& 
                 {\bf C}_{slow} {\bf T}_{j} {\bf C}_{slow}^T \nonumber\\
{\bf D}_{1}^{\prime} &=&      
     \left( \overline{\overline{{\bf S}}}^T 
            {\bf D}_{slow}^{-1} 
            \overline{\overline{{\bf S}}} \right) \cdot 
{\bf T}_{1}^{\prime}{\bf D}_{fast}^{-1}  \nonumber\\
{\bf D}_{j}^{\prime} &=& 
   {\bf D}_{slow}^{\prime \prime} {\bf T}_{j}^{\prime} {\bf D}_{fast}^{-1} \;\;,
\;\;\;\; j=2:n-1 \nonumber\\ 
{\bf D}_{n}^{\prime} &=& 
{\bf D}_{slow}^{\prime \prime} {\bf T}_{n}^{\prime} = 
{\bf D}_{slow}^{\prime \prime} \;\;. 
\label{eqn:phasederivation}
\end{eqnarray}
The direct sums are of the form 
\begin{displaymath}
\bigoplus_{k=0}^{r-1} {\bf A}_{k} =
\mbox{diag}( {\bf A}_{0}, {\bf A}_{1},..., {\bf A}_{r-1} ), 
\end{displaymath}
and ${\bf A}^T$ denotes the transpose of ${\bf A}$. 
See \cite{withers91} for more on the basic definitions and relations
used to derive (\ref{eqn:phase}), as well as the generalization to
higher dimension FFT's.

Note that the stages in (\ref{eqn:phase}) are counted in reverse time
order by the index $j$. This is in keeping with the fact that
(\ref{eqn:phase}) is a decimation-in-frequency (DIF) version of the FFT.
The transpose of (\ref{eqn:phase}), with the product
$\prod_{j=n}^{1}$, is the decimation-in-time (DIT) version of the
phase-rotation FFT.

A ${\bf C}_{slow}$ shuffle and its inverse remain at the input and
output ends of the pipeline, respectively.  As we have seen, ${\bf
C}_{slow}$ is a completely frame-wise rotation.  It rotates
(commutates) the data within each successive frame (column $r$-vector)
of the $r \times s$ pipeline segment for a stage.  There is also an
implicit frame-wise broadcast within each FFT kernel engine, when an
$r$-point DFT is somehow computed.  So in the phase-rotation FFT, data
motion is all parallel, except for frame-wise motions at I/O and at
every FFT kernel.  The simplicity of the phase-rotation FFT is that no
data point ever moves both down and across the pipeline in one
time-step.

\section{Pipeline recipes}
\label{sec:recipes}
While the structure of the pipelined phase-rotation FFT is extremely
simple, experience has taught us that generating the appropriate
twiddles and shuffle indices from the matrix formulations of
(\ref{eqn:phase}) and (\ref{eqn:phasederivation}) is difficult and
confusing.  To address this problem, we have developed a collection of
recipes for generating the phase-rotation twiddles and shuffle indices
off-line.  The recipes are defined for any 1D phase-rotation FFT of $N
= r^n$ points.  Following \cite{vanloan92}, they are written in a {\sc
Matlab}-like format.

As we saw in (\ref{eqn:phase}), the pipelined phase-rotation FFT
performs a typical ``twiddle, shuffle, kernel'' cycle at each stage.
Only the twiddles vary from stage to stage, and there is a
digit-reversing shuffle equivalent at the end.  To implement this FFT using
parallel $r \times s$ pipeline segments (one per stage), we insert the
$N$-vector of input data ${\bf x}$ into the pipeline as an $r \times
s$ array $X$: the first $r$ points of ${\bf x}$ go into the first
frame (column) $X$, the second $r$ points go into the second frame,
and so on.  We must also have a shuffle address and a twiddle factor
ready for each point in the pipeline.  In other words, we would like
to fill one $r \times s$ copy $A$ of the pipeline segment with
addresses, and another copy $D$ with twiddles.

Then the processors in each stage of the pipeline 
will know what to do at each time-step $t=0$:$s-1$. 
Using the current frame of addresses, 
they will fetch the current $r$-frame of data $X(0$:$r-1,A(0$:$r-1,t))$ and 
the current $r$-frame of twiddles $D(0$:$r-1,A(0$:$r-1,t))$ 
(pointwise in parallel), 
multiply these two frames pointwise, 
then do an $r$-point DFT ${\bf F}_r$ of the twiddled data frame.  
That is how each stage 
${\bf F} \overline{\overline{{\bf S}}}{\bf D}_{j}^{\prime}$ 
is implemented in the parallel pipeline. 

%% With this information in hand, the behavior of the processors that
%% execute each stage, 

The twiddle and shuffle recipes in this section are ``in place'' in
the sense that they work inside the $r \times s$ pipeline segments
that will contain the desired addresses and twiddles. They are not
``in place'' in the usual sense, as we will freely use an input and an
output copy of a pipeline segment.  This approach avoids constructing
and operating with large $N \times N$ matrices (each containing only
$N$ non-zero elements).  Each parallel-pipeline function recipe is
given a name similar to that of the $N \times N$ matrix factor in the
FFT (\ref{eqn:phase}) that it effectively implements.

\subsection{Shuffle recipes}
\label{sec:shufflerecipes}
As a convention, pipeline addresses (pipeline array row and column
indices) run 0:$r-1$ and 0:$s-1$, respectively.  To do
parallel-pipeline shuffles, we only need the horizontal (column)
addresses, since the data inside each pipe will only jump within that
stream (row).  The cross-stream shuffles, Cslow and Cfast, are
implemented using $\pi_{r}$, a cyclic rotation of a frame (a vertical
slice of the parallel pipeline) that has the effect of ${\bf y}_r =
{\bf C}_r{\bf x}_r$.  $\pi_{r}$ takes a column $r$-vector ${\bf x}_r =
(x_0, x_1, x_2, ..., x_{r-1})^T \mapsto {\bf y}_r = (x_{r-1}, x_0,
x_1, ..., x_{r-2})^T$.
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $Y$ = Cslow$( X )$ \\
\>    $col = 0$\\
\>    for $k = 1:r$\\
\>    \>  for $j = 1:r^{\prime}$\\
\>    \>    \>  $Y(:,col) = \pi_{r}^{k} (X(:,col))$\\
\>    \>    \>  $col = col + 1$\\
\>    \>  end \\
\>    end
\end{tabbing}       
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $Y$ = Cfast$( X )$ \\
\>    $col = 0$\\
\>    for $j = 1:r$\\
\>    \>  for $k = 1:r^{\prime}$\\
\>    \>    \>  $Y(:,col) = \pi_{r}^{k} (X(:,col))$\\
\>    \>    \>  $col = col + 1$\\
\>    \>  end \\
\>    end
\end{tabbing}       
The inverses of Cslow and Cfast are formed by simply reversing
$\pi_{r}$.  Next, we define some perfect shuffles.
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $Y$ = S$( X ) \;\;$ !stride by $s$\\
\>    $col = 0$\\
\>    for $row = 0:r-1$\\
\>    \>  for $k1 = 0:r:s-r$\\
\>    \>    \>  $k2 = k1+r-1$\\
\>    \>    \>  $Y(row,k1:k2) = X(:,col)$\\
\>    \>    \>  $col = col + 1$\\
\>    \>  end \\
\>    end
\end{tabbing}       
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $Y$ = S$^{-1}( X )\;\;$ !stride by $r$\\
\>    $col = 0$\\
\>    for $row = 0:r-1$\\
\>    \>  for $k1 = 0:r:s-r$\\
\>    \>    \>  $k2 = k1+r-1$\\
\>    \>    \>  $Y(:,col) = X(row,k1:k2)$\\
\>    \>    \>  $col = col + 1$\\
\>    \>  end \\
\>    end 
\end{tabbing}       
To implement the parallel-pipeline shuffles, 
$\overline{\overline{{\mbox{S}}}}$, 
$\overline{\overline{{\mbox{S}}}}^{-1}$, and 
$\overline{\overline{{\mbox{Q}}}}$, 
we will use the parallel-pipeline addresses $A$, which are 
computed by the following function:
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $A$ = 
           $\overline{\overline{\mbox{S}}}$\_addresses$(r,s)$ \\
\>    ${\bf a} = ( 0, r^{\prime}, ..., (r-1)r^{\prime})^T$  \> \> \>\\
\>    $col = 0$\\
\>    for $j = 1:r^{\prime}$\\
\>    \>  for $k = 1:r$\\
\>    \>    \>  $A(:,col) = {\bf a}$\\
\>    \>    \>  $col = col + 1$\\
\>    \>    \>  ${\bf a} = \pi_{r}({\bf a})$ \> \\
\>    \>  end \\
\>    \>  ${\bf a} = {\bf a} + {\bf 1}_{r}$ \\ %% \;\;\;(mod\;\;\; r)$ \> \> \\
\>    end 
\end{tabbing}       
Looking closely, one can see Cfast$^{-1}$ at work producing the
addresses $A$ in the last function.  The addresses $A$ can also be
generated by loading a pipeline segment with simple $r \times r$
address blocks $B_{rr}$, and then applying Cfast$^{-1}$ to the
pipeline segment.  The first block to load is $B_{rr} =$
diag$(0$:$r^{\prime}$:$s-1)*{\bf 1}_{rr}$, where ${\bf 1}_{rr}$ is the
$r \times r$ matrix whose entries are all 1's.  The next block is
always $B_{rr} = B_{rr} + {\bf 1}_{rr}$, until the pipeline segment
contains $r^{\prime}$ blocks and is full.
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $Y = \overline{\overline{{\mbox{S}}}}( X )$ \\
\>    $A$ = $\overline{\overline{{\mbox{S}}}}$\_addresses$(r,s)$ \\
\>    for $row = 0:r-1$\\
\>    \>  $Y(row,:) = X(row,A(row,:))$ \\
\>    end 
\end{tabbing}       
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $Y = \overline{\overline{\mbox{S}}}^{-1}( X )$ \\
\>    $A$ = $\overline{\overline{{\mbox{S}}}}$\_addresses$(r,s)$ \\
\>    $[AA,I] =$ sort($A$)  \\
\>    for $row = 0:r-1$\\
\>    \>  $Y(row,:) = X(row,I(row,:))$ \\
\>    end 
\end{tabbing}       
In the above functions, sort($A$) sorts each row of an array $A$ in
ascending order. It returns the row-sorted array $AA$ and the
corresponding array of addresses $I$ where the successive row elements
were found in $A$.  After we have sorted the addresses $A$ for
$\overline{\overline{{\mbox{S}}}}$, $I$ has the addresses for
$\overline{\overline{\mbox{S}}}^{-1}$.

The pipeline addresses for $\overline{\overline{\mbox{Q}}}$ are
obtained by block-perfect shuffles (along the length of the pipeline)
of the addresses for $\overline{\overline{\mbox{S}}}$:
\begin{tabbing}
ttttabbb \=tab\=tab\=tab\=tab\=tab\=12345123451234512\= \kill
\>    {\bf function} $Y = \overline{\overline{\mbox{Q}}}( X, n )$ \\ 
\>    $A$ = $\overline{\overline{{\mbox{S}}}}$\_addresses$(r,s)$ \\
\\
\>    if $n > 2$ \\ 
\>    \>  for $ns = (n-2):-1:1 \;$ \\
%%                                 !perfect shuffle index exponent 
\>    \>    \>  $stride= r^ns$\\ 
\>    \>    \>  $block = r^{n-2-ns}\;\;\;$ ! block length \\ 
\>    \>    \>  $col2=0$\\ 
\>    \>    \>  for $k_1=1:stride$\\ 
\>    \>    \>  \> $col1 = (k_1-1)*block$\\ 
\>    \>    \>  \> for $k=1:r$\\  
\>    \>    \>  \> \> for $j=1:block$\\
\>    \>    \>  \> \> \> $B(:,col2)=A(:,col1)$\\
\>    \>    \>  \> \> \> $col1 = col1 + 1$\\
\>    \>    \>  \> \> \> $col2 = col2 + 1$\\
\>    \>    \>  \> \> end\\
\>    \>    \>  \> \> $col1 = col1 + (stride-1)*block$\\ 
\>    \>    \>  \> end\\
\>    \>    \>  end\\
\>    \>    \>  $A=B$\\
\>    \>  end\\
\>    end \\ 
\\
\>    for $row = 0:r-1$\\
\>    \>  $Y(row,:) = X(row,A(row,:))$ \\
\>    end  
\end{tabbing}       

\subsection{Twiddle recipes}
\label{sec:twiddlerecipes}
Every twiddle matrix ${\bf D}$ is diagonal, so it operates on a data
vector as a point-to-point vector multiply. Given some permutation
matrix ${\bf P}$, a new twiddle matrix ${\bf PDP}^T$ is equivalent to
a rediagonalizing of the vector shuffle of the diagonal of ${\bf D}$,
that is, ${\bf PDP}^T$ = diag$({\bf P}*$diag$({\bf D}))$.  (This is a
{\sc Matlab} notation: diag() puts the diagonal of a matrix in a
vector, and puts a vector in the diagonal of a matrix.)  Since we want
to perform shuffles within pipeline arrays, we reshape the twiddle
$N$-vector diag$({\bf D})$ as an $r \times s$ pipeline array $D$, just
as we originally reshaped the data vector.  Then we shuffle the
pipelined twiddles, to effect the equivalent of the vector shuffle
${\bf P}*$diag$({\bf D})$.  So we interpret the ${\bf PDP}^T$ operator
as an in-pipeline shuffle of the pipelined twiddles $D$, which are
then in position to operate on the pipelined data $X$ directly by
point-to-point multiplication, $Y = D.*X$. (As mentioned, the data will
actually be twiddled frame-by-frame in the pipelined implementation.)

We will interpret the twiddles expressed in (\ref{eqn:phasederivation}) this
way.  Each twiddle function below returns an $r \times s$ array $D$ of
twiddle factors (the actual twiddling of the data is not included):
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $D_{slow}$ = Dslow\_twiddles$( r, s )$ \\ 
\>    $\omega_{j} = exp(-2\pi i /r)$\\ 
\>    $t = 0$\\ 
\>    for $j = 0:(r-1)$\\
\>    \>  for $k = 0:(r^{\prime}-1)$\\
\>    \>    \>  $D_{slow}(:,t) = 
      (1, \omega_r^k, \omega_r^{2k}, ..., \omega_r^{(r-1)k})^T$ \\ 
\>    \>    \>  $t = t + 1$\\
\>    \>  end \\
\>    end 
\end{tabbing}       
\begin{tabbing}
ttttabbb \=tab\=tabbb \=tabbb1234512345123451234512\= \kill
\>    {\bf function} $D_{fast}$ = Dfast\_twiddles$( r, s )$ \\ 
\>    $\omega_{j} = exp(-2\pi i /r)$\\ 
\>    $t = 0$\\ 
\>    for $k = 0:(r^{\prime}-1)$\\
\>    \>  for $j = 0:(r-1)$\\
\>    \>    \>  $D_{fast}(:,t) = 
      (1, \omega_r^j, \omega_r^{2j}, ..., \omega_r^{(r-1)j})^T$ \\ 
\>    \>    \>  $t = t + 1$\\
\>    \>  end \\
\>    end 
\end{tabbing}       
The inverses of $D_{slow}$ and $D_{fast}$ are just their complex
conjugates, and are generated simply by replacing $\omega_{j}$ by
$\omega_{j}^{-1}$.
For stages $j = 1$:$n$ (counted down from $n$), we generate pipelined 
twiddles $\tilde{T}_j$ by 
\begin{tabbing}
ttttabbb \=tab\=tab\=tab\=1234512345123451234512\= \kill
\>    {\bf function} $\tilde{T}_j$ = 
                     $\tilde{\mbox{T}}$\_twiddles$( r, s, j )$ \\ 
\>    $\omega_{j} = exp(2\pi i /r^{j+1})$\\ 
\>    $\omega_{j}^{\prime} = \omega_{r^{j+1}}^r$\\ 
\>    for $k = 0:(r-1) \;\;$ ! direct sum loop\\ 
\>    \>  $t_1 = k \cdot r^{j-1}$\\ 
\>    \>  for $p = 0:(r-1)$\\ 
\>    \>    \>  $\tilde{T}_j(p,t_1) = \omega_{j}^{kp} $\\ 
\>    \>  end \\ 
\>    \>  $t_1 = t_1 + 1$\\ 
\>    \>  $t_2 = t_1 + r^{j-1}$\\ 
\>    \>  for $t = t_1:t_2\;\;$ ! fill next column from last \\ 
\>    \>    \>  $\tilde{T}_j(:,t) = \omega_{j}^{\prime k} \cdot 
                 \tilde{T}_j(:,t-1)$ \\ 
\>    \>  end \\ 
\>    end\\ 
\\
\>   if $j < n$ \\
\>    \>    $t_2 = r^j$\\
\>    \>    for $k = 0:(N/r^{j+1}) \;\;$ \\
\>    \>    \>  $t_1 = t_2$\\
\>    \>    \>  $t_2 = k \cdot r^j$\\
\>    \>    \>  $t = 0$\\
\>    \>    \>  for $t_0 = t_1:t_2$\\ 
\>    \>    \>    \>$\tilde{T}_j(:,t_0) = \tilde{T}_j(:,t)\;\;$ ! copy columns\\ 
\>    \>    \>    \>$t = t + 1$\\ 
\>    \>    \>  end \\ 
\>    \>    end\\ 
\>    end 
\end{tabbing}       
The rest of the twiddle arrays can now be defined in terms of the
shuffles:
\begin{tabbing}
ttttabbb \=tab\=tabbbb\=tabbb \=tabbb1234512345123451234512\= \kill
\>    $D_{slow}^{\prime}$ \> \> = S$^{-1}( D_{slow}^{-1} )$ \\
\>    $D_{slow}^{\prime \prime}$ \> \> = Cslow$( D_{slow}^{\prime} )$ \\
\\
\>    $D_{fast}^{\prime}$ \> \> =  Cslow$( D_{fast}^{-1} )$ \\
\\
\>    $T_j$ \> \> = S$^{-1}( \tilde{T}_j )$ \\
\>    $T_j^{\prime}$ \> \> = Cslow$( T_j )$ \\
\\
\>    $D_1^{\prime}$ \> = 
           $\overline{\overline{\mbox{S}}}(D_{slow}^{-1}) 
                                  .* T_1^{\prime}.*D_{fast}^{-1}$\\
\>    if $1<j<n$\\
\>    \> $D_j^{\prime}$ \> = 
         $D_{slow}^{\prime \prime}.* T_j^{\prime}.*D_{fast}^{-1}$\\ 
\>    end \\ 
\>    $D_n^{\prime}$ \> = $D_{slow}^{\prime \prime}$ 
\end{tabbing}       

\section{Implementation issues} 
\label{sec:implementation}
In this section we describe issues that arise when the phase-rotation
FFT is implemented on a real parallel system.  In particular, we
describe implementation approaches for the radix-2 FFT on the iWarp
system. The main result is a scalable implementation of the pipelined
phase-rotation FFT that runs at the full 40 Mbytes/second rate of the
iWarp physical links.

\subsection{iWarp}
The iWarp is a private-memory multicomputer developed jointly by
Intel and Carnegie Mellon~\cite{iwarp,iwarpcomm}.  iWarp
systems are 2-dimensional tori of iWarp nodes, ranging in size from 4
to 1024 nodes. Each node consists of an iWarp {\em component}, up to 16
Mbytes of off-chip local memory, and a set of 8 unidirectional
communication {\em links} that physically connect the node to four
neighboring nodes.

The iWarp component is a VLSI chip that contains a {\em processing
agent} and a {\em communication agent}. The processing agent is a
general-purpose load-store microprocessor, centered around a $128
\times 32$-bit register file, that runs at a maximum rate of 20
MFLOPs. The local memory is accessed at a rate of 160 Mbytes/sec.
Each link runs at 40 Mbytes/sec, for a maximum aggregate bandwidth of
320 Mbytes/sec per node.

The key feature of the iWarp is its communication system, which is
summarized in Figure~\ref{fig:pathways}.  Each communication agent
contains a set of 20 hardware FIFO {\em queues}. Each queue can hold
up to 8 32-bit words.  iWarp nodes communicate with other nodes using
unidirectional point-to-point structures called {\em pathways}. Each
pathway is a sequence of queues. Pathways can be created and destroyed
dynamically at runtime.  Figure~\ref{fig:pathways} shows a pair of
such pathways.
\begin{figure}
\centering
\makebox{
\psfig{figure=pathways.eps}
}
\caption{iWarp communication concepts.}
\label{fig:pathways}
\end{figure}

Data traveling along a pathway passes from queue to queue {\em
automatically}, without disturbing the computations on intermediate
nodes. For example, in Figure~\ref{fig:pathways}, data items traveling
over the pair of pathways do not disturb the computation on node 1.
The latency from queue to queue is small, ranging from 100-300
nanoseconds.

Multiple pathways can share the same link. For example, in
Figure~\ref{fig:pathways}, two pathways share the link from node 1 to
node 2. In this case, the pathways share the link bandwidth in a
round-robin fashion, one word at a time.  If only one pathway is
sending data over a link, then it gets the entire link bandwidth.
If multiple pathways are sending data over a link, then the link can
be utilized at the full 40 Mbytes/sec, and each pathway is guaranteed a
proportional fraction of the bandwidth.

User programs can directly access the queues, one word at a time, by
reading and writing special registers in the register file called {\em
gates}.  To an iWarp instruction, a gate is just another register in
the register file. The important point is that a program can read or
write a word in a queue with the latency of a register access. A
single instruction can read and write up to 4 words from queues, with
a maximum aggregate bandwidth of 160 Mbytes/sec.  Gates can be
accessed directly from user-level C programs.

\subsection{Mapping strategies on iWarp}
The problem is to develop a mapping of the flowgraph in
Figure~\ref{fig:phase}(d) to an iWarp array. The objective is a
pipelined radix-2 FFT that runs at the maximum 40 Mbytes/sec rate of
an iWarp communication link.

The simplest mapping strategy is to assign each flowgraph node to a
unique processor node of a linear array, route the flowgraph arcs
through this array, and then embed the resulting linear array in the
iWarp torus. This approach, called the PHASE5 mapping because it uses
5 iWarp nodes for each FFT stage, is shown in
Figure~\ref{fig:mappings}(a).
\begin{figure}
\centering
\makebox{
\psfig{figure=mappings.eps}
}
\caption{Strategies for mapping one stage of the FFT onto a linear array. \rm{(a) PHASE5 mapping. (b) PHASE3 mapping.}}
\label{fig:mappings}
\end{figure}

Each iWarp node in PHASE5 executes a small program that implements its
flowgraph operator. Each twiddle node ($D^\prime$) repeatedly reads a
complex number from its input pathway (via the gates), multiplies it
by the appropriate twiddle (precomputed off-line using the recipes in
Section~\ref{sec:twiddlerecipes}), and sends the result to its output
pathway (again, via the gates).  Each shuffle operator
($\overline{\overline{S}}$) repeatedly reads a complex data item from
its input pathway, stores it in memory, and uses the appropriate
shuffle index (again precomputed off-line using the recipes in
Section~\ref{sec:shufflerecipes}) to send an appropriate
double-buffered data point to the output pathway. The kernel node
($F$) repeatedly reads two complex numbers from its input pathways,
performs the radix-2 DFT kernel operation, and outputs two complex
numbers to its output pathways.

Another approach, the PHASE3 mapping, combines the twiddle and shuffle
operators on a single node, as shown in Figure~\ref{fig:mappings}(b),
so that each stage requires 3 nodes instead of 5 nodes.  As we shall
see, the communication and computation throughputs of the two mappings
are are identical. The advantage of the PHASE5 mapping is its
simplicity. Each node is assigned exactly one operator from the
flowgraph.  The advantage of the PHASE3 mapping is that it is more
node-efficient, requiring fewer nodes per stage than the PHASE5
mapping.

Figure~\ref{fig:phasenet} shows a working implementation of a
16K-point radix-2 phase-rotation FFT on a 64-node iWarp array at
Carnegie Mellon. The large squares are iWarp nodes, labeled with the
corresponding operator and stage number. The small squares are queues.
The arrows are iWarp pathways. The implementation is based on the
PHASE3 mapping from Figure~\ref{fig:mappings}(b). Each of the 14 FFT
stages uses 3 nodes, and there are an additional 3 nodes for the
digit-reversing-equivalent step at the end.
\begin{figure}
\centering
\makebox{
\psfig{figure=phasenet.eps}
}
\caption{16K pipelined phase-rotation FFT on iWarp}
\label{fig:phasenet}
\end{figure}

\subsection{Performance}
While the details are beyond the scope of this paper, each node
program in the PHASE3 and PHASE5 mappings performs each of its
computations in at most 8 clocks. At the peak rate of 40 Mbytes/sec,
each link can produce and consume a 32-bit floating point number every
2 clocks.  Further, each data point in the pipeline is a complex
number consisting of 2 32-bit floating point words. As a result, each
pathway requires exactly half of the available link bandwidth.  Since
each link is shared by two pathways, and since the iWarp communication
agent gives each pathway an equal share of the link bandwidth, without
disturbing the computations on intermediate nodes, each link is fully
utilized. The result is a radix-2 FFT that runs at the full 40
Mbytes/sec rate of an iWarp link, regardless of the number of points
in the FFT! Since each sample consists of 8 bytes, the FFT runs at a
constant rate of
$40 \mbox{Mbytes/sec} \times 8 \mbox{bytes/samples} = 5 \mbox{Msamples/sec}$.
Given enough nodes, the same approach will produce arbitrarily large
FFT's at this rate.  Perhaps even more important, this approach achieves
the same performance on smaller FFT's.

Another way to characterize the performance of the PHASE3 and PHASE5
mappings is by its computational throughput, expressed as millions of
floating point operations per second (MFLOPS). The standard formula
for computing the computational throughtput of FFT's is $5N \log N$
floating-point operations per N-point FFT~\cite{carlson92}. Since each
node program executes its computation in at most 8 clocks, and since
each clock is $50$ nanoseconds, the performance of each stage of both
the PHASE3 and PHASE5 mappings is $25 \log N \mbox{MFLOPS}$.  So the
16K FFT from Figure~\ref{fig:phasenet} achieves a measured performance
of $25 \times 14 = 350$ MFLOPS (single precision) on iWarp.  As a
point of comparison, a highly optimized 16K-point FFT has been
measured at 237 MFLOPS (double precision)~\cite[p.114]{carlson92} on a
single-processor Cray Y-MP.  The numbers are not directly comparable
because of the different floating-point precisions, but they do
suggest that the absolute performance of the phase rotation FFT on
iWarp is quite good.

\section{Concluding remarks}
We have described an improved version of the Whelchel pipelined
phase-rotation FFT, developed recipes for generating the appropriate
twiddles and shuffle indices off-line and directly in terms of the
parallel pipeline, outlined mapping approaches for the radix-2 case on
the iWarp parallel computer, and presented measured performance
results of an implementation on iWarp.

The improvement on the original phase-rotation FFT is significant in
that it eliminates a potential pipeline bottleneck during the digit
reversing step at the end.  The twiddle and shuffle recipes should be
helpful to the programmer who wants to implement the pipelined phase
rotation FFT. The iWarp implementation validates a simple and
realistic approach for building scalable pipelined FFT's on a
programmable parallel system. Further, the implementation demonstrates
that, given a balanced parallel computer architecture with word-level
access to the communication links, it is possible to build FFT's that
run at the full link bandwidth of the links, even when the FFT's are
relatively small.

\section*{Acknowledgements}
We would like to thank Tom Warfel and LeeAnn Tzeng for their help with
the iWarp implementation, and Doug Noll and Doug Smith for discussions
that led to the more node-efficient mapping.

\small
\bibliography{/afs/cs/project/iwarp/member/droh/bib/compiler,/afs/cs/project/iwarp/member/droh/bib/defs,/afs/cs/project/iwarp/member/droh/bib/me,/afs/cs/project/iwarp/member/droh/bib/refs}

\end{document}

    
