Автор работы: Пользователь скрыл имя, 05 Марта 2015 в 17:12, курсовая работа
Известно, что вычислительные задачи требуют значительного количества операций, а значит, и ресурсов. Долгое время одним из основных методов повышения производительности было увеличение тактовой частоты процессора. Однако, из-за фундаментальных ограничений при производстве интегральных схем (ограничения на потребляемую мощность и на тепловыделение, физический предел размера транзистора), рассчитывать на увеличение производительности за счет увеличения тактовой частоты процессора в дальнейшем не приходится.
Введение
Постановка задачи
Реализация
Результат
Сравнение производительности приложения на CPU и GPU
Выводы
Список литературы
Московский Авиационный Институт
(Национальный
Курсовая работа
Программирование графических процессоров
Выполнил студент
Проверил
Москва 2014
СОДЕРЖАНИЕ
Известно, что вычислительные задачи требуют значительного количества операций, а значит, и ресурсов. Долгое время одним из основных методов повышения производительности было увеличение тактовой частоты процессора. Однако, из-за фундаментальных ограничений при производстве интегральных схем (ограничения на потребляемую мощность и на тепловыделение, физический предел размера транзистора), рассчитывать на увеличение производительности за счет увеличения тактовой частоты процессора в дальнейшем не приходится.
Таким образом, столкнувшись с очевидной проблемой повышения быстродействия, производители начали предлагать процессоры с несколькими вычислительными ядрами вместо одного. Но и многоядерные процессоры, если все сводится к размещению большего числа классических простых ядер на одной подложке, нельзя воспринимать как решение всех проблем. Их чрезвычайно сложно программировать, и они могут быть эффективны только на приложениях, обладающих естественной многопоточностью. Кроме того, если все ядра подключены к общей шине, каждый процессор должен «видеть» целый и корректный образ памяти, что неизбежно ведет к необходимости для каждого процессора отслеживать обращения к памяти всех остальных процессоров для поддержания актуальности своих кешей. Подобная задача имеет квадратичную сложность от числа процессоров.
Наконец, оптимальным решением при написании вычислительных программ для обработки массивов данных явилось задействование вычислительных ресурсов видеокарт. По сравнению с традиционным конвейером обработки данных в центральном процессоре, выполнение вычислений общего характера в графическом процессоре дает существенные преимущества. Разработанная компанией NVIDIA архитектура параллельных вычислений CUDA предлагает сотни ядер, способных обрабатывать параллельные потоки, что позволяет обеспечить невероятную производительность целому спектру вычислительных приложений.
В настоящей работе рассмотрены примеры программ обработки массивов данных и выполнен анализ производительности работы программ в зависимости от размера массивов и процессора, осуществляющего вычисления.
Написать программу, которая должна выполнять вычисления для массива данных, и произвести оценку производительности работы программы при вычислениях на CPU и GPU.
Программа 1: инвертировать массив.
Программа 2: вычислить квадраты элементов массива.
Программа 3: вычислить функцию экспоненты.
Вычисление по каждой программе будет включать следующие последовательные этапы:
3. Реализация
Ниже для заданий представлены функции GPU
Инвертирование массива
__global__ void invArray(int* a, int* b, int count)
{
int id = blockIdx.x * blockDim.x + threadIdx.x;
if (id < count)
{
b[id] = a[count-1-id];
}
}
Вычисление квадратов элементов массива
__global__ void multArray(float* a, float*b, int count)
{
int id = blockIdx.x * blockDim.x + threadIdx.x;
if (id < count)
{
b[id] = a[id]*a[id];
}
}
Вычисление функции экспоненты
__global__ void expArray(float* a, float*b, int count)
{
int id = blockIdx.x * blockDim.x + threadIdx.x;
if (id < count)
{
b[id] = exp(a[id]);
}
}
4. Результат
Программа инвертирования массива
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
#include <helper_timer.h>
#include <fstream>
#include <string>
#include <stdio.h>
using namespace std;
__global__ void invArray(int* a, int* b, int count)
{
int id = blockIdx.x * blockDim.x + threadIdx.x;
if (id < count)
{
b[id] = a[count-1-id];
}
}
void invarrayCPU(int* datainput, int* dataoutput, int count )
{
for (int i = 0; i < count; i++)
{
dataoutput [i] = datainput [count-1-i];
}
}
int main()
{
int count = 1000;
int* data = new int [count];
int* res = new int[count];
int* dataGPU;
int* resGPU;
float time_gpu = 0, time_cpu = 0;
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
for(int i = 0; i < count; ++i)
{
data[i]=i;
}
//GPU
cudaMalloc((void**)&dataGPU, count*sizeof(int));
cudaMalloc((void**)&resGPU, count*sizeof(int));
cudaMemcpy(dataGPU, data, count*sizeof(int), cudaMemcpyHostToDevice);
cudaEventRecord(start, 0);
invArray<<<1024, 1024>>>(dataGPU, resGPU, count);
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time_
cudaMemcpy(res, resGPU, count*sizeof(float), cudaMemcpyDeviceToHost);
cudaFree(dataGPU);
cudaFree(resGPU);
int* res1 = new int[count];
StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
invarrayCPU(data, res1, count);
sdkStopTimer(&timer);
time_cpu=sdkGetTimerValue(&
std::cout<<"\n\ntime_cpu = "<<time_cpu<<"\ntime_gpu = "<<time_gpu<<'\n';
cin.get();
cudaDeviceReset();
return 0;
}
Программа вычисления квадратов элементов массива
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
#include <helper_timer.h>
#include <fstream>
#include <string>
#include <stdio.h>
using namespace std;
__global__ void multArray(float* a, float*b, int count)
{
int id = blockIdx.x * blockDim.x + threadIdx.x;
if (id < count)
{
b[id] = a[id]*a[id];
}
}
void multarrayCPU(float* datainput, float *dataoutput, int count )
{
for (int i = 0; i < count; i++)
{
dataoutput [i] = datainput [i] * datainput[i];
}
}
int main()
{
int count = 10;
float* data = new float [count];
float* res = new float[count];
float* dataGPU;
float* resGPU;
float time_gpu = 0, time_cpu = 0;
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
for(int i = 0; i < count; i++)
{
data[i]=float(i)*0.01f;
}
//GPU
cudaMalloc((void**)&dataGPU, count*sizeof(float));
cudaMalloc((void**)&resGPU, count*sizeof(float));
cudaMemcpy(dataGPU, data, count*sizeof(float), cudaMemcpyHostToDevice);
cudaEventRecord(start, 0);
multArray<<<1024,1024>>>(
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time_
cudaMemcpy(res, resGPU, count*sizeof(float), cudaMemcpyDeviceToHost);
cudaFree(dataGPU);
float* res1 = new float[count];
StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
multarrayCPU(data, res1, count);
sdkStopTimer(&timer);
time_cpu=sdkGetTimerValue(&
std::cout<<"\n\ntime_cpu = "<<time_cpu<<"\ntime_gpu = "<<time_gpu<<'\n';
cin.get();
cudaDeviceReset();
return 0;
}
Программа вычисления функции экспоненты
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
#include <helper_timer.h>
#include <fstream>
#include <string>
#include <stdio.h>
using namespace std;
__global__ void expArray(float* a, float*b, int count)
{
int id = blockIdx.x * blockDim.x + threadIdx.x;
if (id < count)
{
b[id] = exp(a[id]);
}
}
void exparrayCPU(float* datainput, float *dataoutput, int count )
{
for (int i = 0; i < count; i++)
{
dataoutput [i] = exp(datainput[i]);
}
}
int main()
{
int count = 1000000;
float* data = new float [count];
float* res = new float[count];
float* dataGPU;
float* resGPU;
float step = 0.01f;
cudaDeviceProp devProp;
cudaGetDeviceProperties(&
size_t maxThreads = devProp.maxThreadsPerBlock;
float time_gpu = 0, time_cpu = 0;
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
for(int i = 0; i < count; i++)
{
data[i]=float(i)*step;
}
//GPU
cudaMalloc((void**)&dataGPU, count*sizeof(float));
cudaMalloc((void**)&resGPU, count*sizeof(float));
cudaMemcpy(dataGPU, data, count*sizeof(float), cudaMemcpyHostToDevice);
cudaEventRecord(start, 0);
expArray<<<1024,1024>>>(
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time_
cudaMemcpy(res, resGPU, count*sizeof(float), cudaMemcpyDeviceToHost);
cudaFree(dataGPU);
float* res1 = new float[count];
StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
exparrayCPU(data, res1, count);
sdkStopTimer(&timer);
time_cpu=sdkGetTimerValue(&
std::cout<<"\n\ntime_cpu = "<<time_cpu<<"\ntime_gpu = "<<time_gpu<<'\n';
std::cout << maxThreads << '\n';
cin.get();
cudaDeviceReset();
return 0;
}
5. Сравнение производительности приложения на CPU и GPU
Вычисление осуществлялось на системах
CPU: IntelCore(TM) i7-3770 CPU @ 3.40 GHz, 16 GB
GPU: NVIDIA Quadro 4000, GDDR5, 2 GB
CPU: Intel(R) Xeon® CPU E5-2650.@ 2.00GHz, 128 GB
GPU: Tesla M2075 Dual-Slot GDDR5, 6GB
Ниже результаты производительности (в миллисекундах, в зависимости от размера массива):
для программы инвертирования массива
Количество элементов |
CPU Intel i7 |
GPU NVIDIA Quadro |
CPU Intel Xeon |
GPU Tesla |
10 |
0,000301858 |
0,182176 |
0 |
0,056352 |
1 000 |
0,00241487 |
0,181824 |
0,06 |
0,056672 |
10 000 |
0,0220357 |
0,179552 |
0,047 |
0,056352 |
100 000 |
0,221866 |
0,191424 |
0,495 |
0,059424 |
1 000 000 |
2,22953 |
0,2984 |
6,404 |
0,120224 |
для программы вычисления квадратов элементов массива
Количество элементов |
CPU Intel i7 |
GPU NVIDIA Quadro |
CPU Intel Xeon |
GPU Tesla |
10 |
0,000301858 |
0,18112 |
0,001 |
0,09072 |
1 000 |
0,00271673 |
0,181152 |
0,006 |
0,092512 |
10 000 |
0,0250542 |
0,181856 |
0,053 |
0,088992 |
100 000 |
0,246316 |
0,191616 |
0,557 |
0,060256 |
1 000 000 |
2,34212 |
0,31034 |
6,753 |
0,125312 |
для программы вычисления функции экспоненты
Количество элементов |
CPU Intel i7 |
GPU NVIDIA Quadro |
CPU Intel Xeon |
GPU Tesla |
10 |
0,00241487 |
0,213664 |
0,3 |
0,056704 |
1 000 |
0,0187152 |
0,211488 |
0,388 |
0,087232 |
10 000 |
0,330535 |
0,214656 |
3,309 |
0,09712 |
100 000 |
26,9412 |
0,265152 |
5,868 |
0,063424 |
1 000 000 |
59,4936 |
0,789152 |
33,24 |
0,139232 |
6. Выводы
Технология CUDA — это программно–аппаратная архитектура, которая позволяет производить вычисления с использованием графических процессоров NVIDIA. Данная технология основана на расширении языка С и дает возможность организовывать доступ к набору инструкций графического ускорителя и управлять его памятью, а также разработать на нем сложные параллельные вычисления.
Информация о работе Программирование графических процессоров