\chapter{Introduction}

Throughout the history of computing a primary concern for practitioners has been
the speed at which results can be computed. Due to this, an active area of
research has been the acceleration of computing. The strongest driver for the
increase in the performance of computers has historically been the approximate
doubling of the number of transistors in any given integrated circuit every two
years \cite{moore1965cramming}. This doubling along with Dennard Scaling powered
the steady increase in single core processor performance 
\cite{dennard1974design}. However, heat and power problems have forced
chip manufacturers to develop processors with a larger number of slower cores to
use the extra transistors each year \cite{esmaeilzadeh2011dark}. While both Moore's
law and Dennard Scaling have improved the computational power of chips, another
path to improving the performance of programs has been the addition of
specialized hardware to perform computationally expensive tasks. This
specialized hardware often takes the form of a coprocessor. 

An early example of coprocessors is the Data-Synchronizer Unit, also known as IO
channels, first found in the IBM 709 and 7090 \cite{bashe1981architecture}. 
Overtime other coprocessors were developed for a variety of problems, most notably
floating point coprocessors (FPUs). Due to the extremely slow speed of software
implementations for floating point math, FPUs became a critical component for 
scientific and computer graphics programs.  For computer graphics programs in 
particular, FPUs were unable to handle the large amount of floating point operations
done for each frame of animation.This gave birth to a new breed of coprocessors 
called graphics processing units (GPUs). The manufacturers of GPUs used the increase 
of transistors year-over-year to focus on parallel computing rather than increasing
the performance of a single computing core as CPU manufacturers did\cite{nickolls2010gpu}. This
focus on parallel execution of floating point math over general computation has
allowed GPUs to outpace CPUs in computational throughput. While CPU manufacturers
allocated swathes of silicon to things like branch prediction, GPU manufactures
concentrated on both things like higher core count and memory bandwidth 
\cite{owens2008gpu}. These two features originally added to assist with graphics
also give GPUs extremely high throughput for floating point operations. However this
throughput comes at a cost, the highly parallel nature of the hardware
requires a different approach to programming to deal with the trade-offs
inherent in the hardware.

When designing software to work around these trade-offs, two approaches can be
considered. The first approach is to program for the hardware itself. This
approach requires the most knowledge about the underlying hardware and must be
specialized to the specific GPU used\cite{nvidia2013tuning}. The underlying hardware
can vary greatly in capability. For instance, the presence of certain atomic
operations or advanced thread management\cite{nvidia2013guide}. The other
approach is to use a higher-level framework to abstract from the hardware
\cite{nvidia2014thrust}. The benefit to this approach is that the framework can 
represent the common idioms and patterns that exist in the programming language
used. Both approaches offer a set of trade-offs which will be explored later in
this thesis.

This thesis will present two applications which will explore the use of these two
approaches for using the GPU as an accelerator. For the first approach, the
application models the movement of sound through a room. This problem is
an example of a class of problems in physics which map well to the programming
model used on the GPU. The second approach is applied to a signal processing
problem. The application shows how the use of a framework can speed the
development of a solution while providing good levels of performance.

The structure of this document from here on out is as follows.
Chapter~\ref{chapter:background} will examine how the history of the GPU and the
underlying hardware of the GPU has shaped the nature of their use. 
Chapter~\ref{chapter:sound} will discuss the use of  the GPU as an accelerator 
for simulating and visualizing the movement of sound through rooms using the CUDA
programming model. Chapter~\ref{chapter:jitter} will explore how a framework
called thrust built upon the CUDA can use an existing programming model
to deliver better performance with minimal changes to the underlying code.
Chapter~\ref{chapter:conclusions} will finish with closing thoughts and ideas
for future work.
