
% Template for a simple journal or conference style article

\documentstyle[12pt,fullpage]{article}
\begin{document}
\pagestyle{plain}
\title{\bf CIS 629 : Cray - 1}
\author {Sameer S. Shende}
\maketitle
\vspace*{.3in}
\begin{enumerate}
\item
Vector chaining is a mechanism used in machines like Cray - 1 to concurrently execute two (or more) vector operations where the output of the first ALU is directed to the second ALU to improve the performance.
In the absence of vector chaining the output of one ALU is stored in a vector and only one vector operation can execute. After the vector operation has completed the second phase of computation can begin by reading the vector operands.
Chaining can be used to store the output of the first state in the vector register and concurrently start the execution  of the second operation while the first one is still executing. This way, as the first output (first element of the first vector operation) is produced and stored in the vector register, the second vector operation can start with this as one of its operands. This way the output of the first stage can be thought of as being fed to the second stage which lags behind the first stage by a certain number of cycles.
Thus, vector chaining avoids the waiting time associated with operations which
need to "wait" for the complete input operands prior to execution.
In fact the compilers are specially  "looking out" for vector instructions 
which have a dependency (output of one required as input of the next) and chain the instructions together for a better throughput. The delay associated with 
each of the instructions is crucial in determining the rate at which the final
output (of the chained instructions) can be obtained. If both the instructions
are vector multiply instructions like
	V1 = V2 * V3
	V4 = V1 * V5
Then as the first vector stage produces the results they are fed in at the
same rate in the second stage and if it takes 6 clock cycles to execute the
multiply instruction, after a fixed startup time the complete chain will 
produce the output vector (V4) periodically (every cycle).

If the second instruction is add (which takes fewer clock cycles than multiply)
then the add unit would idle for some cycles waiting for the output of the
first stage and although the output of the final stage would occur periodically, the rate of production of the output would depend upon the first stage (the slower of the two stages in the chain).
Vector chaining can be applied to all kinds of vector operations, whether it
is between two vector operands or between scalar and vector operands. It can also be applied to memory to vector or vector to memory. So, the advantage of
using chaining is that multiple stages of the program can execute simultaneously with different kinds of instructions thereby keeping a lot of ALUs "busy" and maximising the throughput.

\item Gantt charts for the execution of 
	V0 = V1 + V2
	V3 = V0 + V4


\item It is not possible to implement chaining on a machine that has memory 
vectors (like CDC 205). A machine that does not have a vector register has to access the memory location explicitly to get the data. To access a vector in
Cray-1, a special hardware counter keeps track of which element in the vector
is currently being accessed. Such a counter is absent in the memory. To access
a memory location to fetch the results of the first phase of computation in
a chain there's no way to determine that the first phase is over. This is 
critical when the second stage in the pipeline is faster than the 
first (multiply followed by add) and the second stage does not know when the
output of the first stage has been put in the memory. This problem is avoided
when the output of the first stage is put in the vector register which 
supplies one of the operands to the second stage of computation.

\item In Cray-1 the memory was organised into 16 memory banks (interleaved memory) which contained
successive addresses. Thus, if a vector of length 16 was to be accessed, and
the stride was 1, then each memory bank would have one reference and it would
be fetched very fast. If the stride was set to 16, then all memory references
to a vector of length 16 would be directed to only 1 memory bank and it would 
take a significant time for processing all the memory requests which would be 
queued at the bank. Similarly for a stride of 8 if a vector of length 16 was to
be accessed two memory banks would get the alternate references and the performance would be bad. However, if the pattern to be accessed was not linear 
(e.g. diagonal in the matrix, or a column in a square matrix), it would be beneficial to have such strides. So, the strides should be set appropriately depending
upon the elements to be accessed and the stride of 1 would be commonly used 
for getting consecutive elements of a one dimensional array.

\item The Cray-1 did not have a cache because it was a vector machine and
cache gives a performance boost to scalar applications. It however did have 
eight 64 bit scalar registers which were backed up by sixty four 64-bit scalar
T registers, and eight 63-element (64 bits per element) vector registers and
four instruction buffers of 64 16 bit instructions each. This amounts to 4888
bytes of storage for data/address and 512 bytes of instruction storage which is
like a cache. The problems associated with a cache are that in the case of a 
vector operation, often a single vector could fill the entire cache. It 
was not feasible to store only parts of different vectors. The operation of
a cache involves extraction of a tag from a memory reference, comparison of
the tag with k  elements (in the case of a set associative cache) and 
generating a cache hit or a miss. This was a lengthy operation. Also, the
hardware was responsible for the replacement decision (LRU, OPT policy).In the
case of Cray-1, the program had to keep track of the registers (essentially
the onus was on the compiler) but the advantage was that the element to be 
accessed was in the registers and buffers and it was removed (flushed out) 
explicitly by the program - so there was no uncertainty involved. Cache can 
be divided into data cache and instruction (read only) cache. Because the 
access pattern of a vector processor is different from a scalar processor,
the vectors had to be stored in the vector registers. For the instruction
cache, Cray-1 did the instruction look aheads and stored the instructions 
in the four instruction buffers which served the function of a cache. Thus, 
the scalar and vector registers (with scalar backup registers) could be
accessed quickly by the 12 ALUs. Also, interleaved memory implementation 
provided a fast access to vectors.  
	
The performance of Cray-1 could have been boosted by an instruction cache
however because it served the same function as an instruction buffer and
the reference pattern of instructions would be similar in both the vector and
the scalar case. 

Cray-1 had a high processor memory bandwidth (320 M W/s or 2.56 GB/s which
is quite impressive for a machine built in 1978 compared to 1.2 GB/s peak
memory bandwidth of an SGI Power challenge built in 1994!). So, the Cray-1
performed very well in its time because of the large vector/scalar and address 
storage built into the CPU and so it could do without the cache memory. 

\item To implement a data cache for a machine like the Cray-1 the primary
consideration would be how to treat the vectors (scalar implementation is
fairly straight forward). Since all the vector does not have to be accessed
at the same time, the length of the pipeline could be used as a measure to
cache the vector. For example if an add pipeline took 6 pair of operands 
at a time (in different stages) then it would be wise to get maybe 12 pairs
of operands in advance in the cache. If the entire vector was taken into 
consideration then the whole cache could be filled by just a couple of vectors.
If one decided to cache parts of many vectors, then depending on the access
pattern (starting index of the vector), the vectors would need to be stored.
Essentially the problems associated with data cache for a vector processor 
are that of the cache size. Recent multiprocessors (SGI PowerChallenge) 
feature cache sizes of 4MB. Such sizes are appropriate for vector processors.
The applications which access few arrays repeatedly would benefit from 
such a cache. The replacement policy would also need to be examined and 
possibly an entire least recently used "vector" could be flushed out (vector
LRU implementation). 

\end{enumerate}

\end{document}

% ------------ end of document ----------------------

% here are some templates of different environments you can cut and paste:

\begin{figure}
\vspace{3in}
\caption{}
\end{figure}

\begin{itemize}
\item
...
\end{itemize}

\begin{enumerate}
\item
...
\end{enumerate}

