Параллельное программирование<br />На современных видеокартах(GPGPU)<br />Алексей Тутубалинwww.gpgpu.rulexa@lexa.ru<br />
План встречи<br />
Параллельные вычисления: зачем?<br /><ul><li>Производительности всегда не хватает
Рост производительности CPU сильно замедлился</li></li></ul><li>The Landscape of Parallel Computer Research:  A View from ...
Параллельные вычисления<br />Как?<br />Одновременное исполнение независимых вычислений на разных процессорах с последующей...
Параллельные системы<br />
Высокая производительность: объективные проблемы<br />Задержки (Latency)<br />Часто определяют производительностьПример: У...
Вычисления на GPU: предпосылки<br />
«Старые видеокарты» (2003-2006)<br />Специализация под 3D-графику (отрисовка2D-проекции сцены)<br />Фиксированные стадии о...
2001-2006: «Многообещающие результаты»<br />~3000 научных публикацийС общим смыслом «вот на следующих поколениях оборудова...
Проблемы начального этапа<br />Неудобная парадигма «Потоковых вычислений» (Stream Computing):<br />«микропрограммы» (шейде...
2006: NVidia CUDA и G80 Compute Unified Device Architecture<br />Принципиально новая (для GPU) архитектура<br />Взаимодейс...
2006: интерес других производителей<br />ATI (AMD):<br />Инициатива Close-To-Metal: публикация спецификаций кода, надежда ...
2007-2008: быстрое взросление<br />>2000 публикаций про использование CUDA<br />Топовые конференции (Supercomputing)<br />...
Ускорение приложений на CUDA<br />2008 г.: NVidia 8800GTX в сравнении с AMD Opteron 248 (2.2GHz, 2 ядра)<br />
Современный этап: оборудование<br />Видеокарты:<br />ATI R800<br />2.7TFLOP/s single, 500 GFLOP/s double<br />Поддержка Op...
Современный этап: программы<br />Стандарт  OpenCL (лето-осень 2009): переносимые GPU-программы<br />Для пользователяускоре...
Современный этап: производительность<br />
Наглядная агитация<br />4xTesla  == Cray XT4  на задачах молекулярной биологии (AMBER11)(слайд с NVidia GPU Technology con...
NVidia CUDACompute Unified Device Architecture<br />Общий обзор «сверху вниз»<br />Как устроено оборудование<br />И как эт...
Общая схема исполнения программ<br />Все стадии независимы, одновременно можно:<br />Передавать в видеопамять<br />Считать...
Архитектура G80<br />До 16 одинаковых мультипроцессоровна чипе<br />Общая глобальная память (R/W): медленная и много (до 1...
2 специальных процессора (SFU) для сложных функций: 32 потока за 16 тактов, SIMD
Один диспетчер команд
до 768 потоков на одном SM в «одновременном» режиме
 потоки объединяются в пачки по 32 потока (warp), которые исполняются SIMD
 16 kb разделяемой памяти (shared memory)
 8192 32-битных регистра</li></ul>На 2 SM – один блок обработки текстур с текстурным кэшем и блоком аппаратной интерполяци...
Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Host<...
Логическая организация программ<br />Десятки тысяч – миллионы независимых потоков в программе<br />Поток – обрабатывает ча...
Логическая организация (2)<br />Блок исполняется на одном мультипроцессоре<br />Разные блоки – на разных<br />Порядок не о...
Иерархия памяти<br />
Параметры SM – не догма<br />G92:<br />16384регистров, до 1024 потоков  на SM<br />GF100 (Fermi)<br />32768 регистров и 32...
Пример: cложение двух векторов<br />Код GPU: складываем два элемента:<br />__global__ void VecAdd(float* A,float* B, float...
код на CPU<br />// аллоцируем память на GPU<br />size_t size = N * sizeof(float);<br />cudaMalloc((void**)&d_A, size);<br ...
CUDA:С/C++ с небольшими изменениями<br />Спецификаторы типа функции:<br />__global__- GPU, может быть вызвана с CPU (с пар...
Типы данных и переменные<br />Скалярные:char, short, int, long,longlong, float, double (и беззнаковые для целых)<br />Вект...
Двумерные блоки например, для двумерных моделей<br />На CPU:<br />dim3 blockSize(16, 16);<br />// некратным размером сетки...
Синхронизация, атомарные операции<br />Глобальная синхронизация всех блоков – завершение kernel<br />__syncthreads() – син...
Скалярное произведение<br />Накапливаем частные произведенияпо потокам:<br />__global__ result;<br />shared__ float psum[N...
Тонкости<br />Оптимальный доступ к глобальной памяти<br />Особенности доступа к shared memory<br />Условные операции<br />...
Доступ к глобальной памяти<br />Сложение векторов, 16 сложений на thread:<br />___________________________________________...
Доступ к глобальной памяти - 2<br />Прямые рекомендации из Programming Guide:<br />Оптимально, когда все потоки одного (по...
Разделяемая память<br />Разделена на банки <br />16 банков на G80-G200, 32 на GF100<br />Interleave 4 байта<br />Два поток...
Нет конфликта банков<br />Bank 0<br />Thread 0<br />Bank 0<br />Thread 0<br />Bank 1<br />Thread 1<br />Bank 1<br />Thread...
Конфликт банков<br />Bank 0<br />Bank 1<br />Thread 0<br />Bank 2<br />Thread 1<br />Bank 3<br />Thread 2<br />Bank 4<br /...
Условные операции<br />SIMD <br />поэтому если в одном warp разные ветки if, их исполнение будет последовательным:<br />if...
Распределение блоков по SM<br />Не меньше одного блока т.е. блок должен пролезать по ресурсам:<br />Общее число потоковв б...
Загрузка SM (occupancy)<br />Отношение числа работающих warps к из возможному количеству<br />В общем случае, к 100% надо ...
Разное<br />Целая арифметика:<br />G80-G200: 24-бита – быстрая, 32 бита – медленная<br />GF100 – 32 бита – быстрая, 24 бит...
Продолжение.....<br />Документация NvidiaОчень хорошая!http://developer.nvidia.com/object/cuda_download.html<br />CUDA Pro...
Программные средства<br />CUDA Toolkit – компилятор + библиотеки<br />Интегрируется с Visual C++ (добавление правил компил...
Подробности компиляции<br />float4 me = gx[gtid];<br />me.x += me.y * me.z;<br />C/C++ CUDA<br />Application<br />CPU-code...
Компиляция в внешний .cubin-файл и загрузка на runtime</li></ul>Финальную компиляцию  реальные коды делает драйвер видеока...
Два API<br />CUDA C API: <br />реализуется внешней библиотекой cudart<br />Высокоуровневое, более удобное<br />удобная под...
Альтернативы CUDA<br />OpenCL<br />CAL/IL (Compute Abstraction Layer/Intermediate Language)<br />Только видеокарты ATI<br ...
OpenCL<br />Многоплатформенный стандарт<br />Необычайно похож на CUDA Driver API<br />Детали:<br />Язык C для kernels, дру...
Сложение векторов<br />Код GPU:<br />__kernel void VectorAdd(__global const float* a,__global const float* b,__global floa...
Код CPU<br />// Создаем контекст GPU (до того был поиск устройств...)<br />Context = clCreateContext(0, 1, &cdDevice, NULL...
CUDA  OpenCL<br />AMD: Porting CUDA to OpenCLhttp://developer.amd.com/zones/OpenCLZone/Pages/portingcudatoopencl.aspx<br />
Переносимость и производительность<br />Переносимыйкод (NVidia, ATI,x86, Cell)<br />Производительность не переносится:<br ...
OpenCL и видеокарты ATI<br />Человеческий интерфейс (в отличие от CAL/IL)<br />HD5870 – производительность примеров SDK - ...
Почему GPU НАСТОЛЬКО быстрее?<br /><ul><li>Линейная алгебра: 5-8раз
Обработка сигналов, обработка изображений: десятки раз
Некоторые задачи (молекулярная динамика, N-body): бывают сотни раз</li></li></ul><li>Вот почему:<br />Другой аппаратный ди...
Upcoming SlideShare
Loading in …5
×

Параллельное программирование на современных видеокартах

26,523 views

Published on

Слайды со встречи на физфаке МГУ, 29 сентября 2010

Published in: Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
26,523
On SlideShare
0
From Embeds
0
Number of Embeds
16,429
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Параллельное программирование на современных видеокартах

  1. 1. Параллельное программирование<br />На современных видеокартах(GPGPU)<br />Алексей Тутубалинwww.gpgpu.rulexa@lexa.ru<br />
  2. 2. План встречи<br />
  3. 3. Параллельные вычисления: зачем?<br /><ul><li>Производительности всегда не хватает
  4. 4. Рост производительности CPU сильно замедлился</li></li></ul><li>The Landscape of Parallel Computer Research: A View from Berkeley (2006)<br />http://www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-183.pdf<br /> - старые парадигмы во многом устарели, параллельность – единственный (на сегодня) путь<br />Ответ индустрии оборудования: многоядерностьCPU<br /><ul><li>а до того – многопроцессорные машины с общей памятью (SMP) и векторные инструкции</li></ul>Программистам от параллельности деваться некуда<br />
  5. 5. Параллельные вычисления<br />Как?<br />Одновременное исполнение независимых вычислений на разных процессорах с последующей синхронизацией<br />Проблемы:<br />Правило Амдала: ускорение=P – доля программы, которую можно распараллелить, N – число потоков исполнения<br />Слишком маленькие независимые блоки много затрат на синхронизацию<br />Сложно программировать (много объектов, синхронизация, критические секции)<br />
  6. 6. Параллельные системы<br />
  7. 7. Высокая производительность: объективные проблемы<br />Задержки (Latency)<br />Часто определяют производительностьПример: Умножение матриц наивным способом - медленный доступ «по столбцам»: особенности памяти (и кэшей, если не повезло)<br />Синхронизация: всегда непроизводительное ожидание<br />Скорость чтения/записи в память (Bandwidth)<br />Часто определяет производительностьSSE на Core i7: две векторные (16 байт) операции на такт(96 байт/такт), скорость доступа к памяти порядка 6 байт/такт (или 1-1.5 байта на ядро)<br />Нужна быстрая память, кэши частично спасают<br />Нужно повышение сложности: больше операций над данными в регистрах.<br />Распределенные системы: линейный рост bandwidth<br />Арифметическая интенсивность (операций/единица данных)<br />a = b+c: 1 операция, 2 чтения, 1 запись<br />Распараллеливание может стать бессмысленным, весь выигрыш будет съеден пересылками<br />Чтобы был выигрыш от параллельности, алгоритмы должны быть либо сложнее O(n),либо для O(n) – константапри O – большая.<br />
  8. 8. Вычисления на GPU: предпосылки<br />
  9. 9. «Старые видеокарты» (2003-2006)<br />Специализация под 3D-графику (отрисовка2D-проекции сцены)<br />Фиксированные стадии обработки (вершины-геометрия-пиксели)<br />С 2001 – программируемые шейдеры (GeForce3, OpenGL 1.5)<br />Высокая производительность за счет:<br />Архитектуры, сделанной ровно под одну задачу<br />Высокой скорости линейного чтения памяти<br />Отсутствия синхронизации внутри стадии обработки<br />
  10. 10. 2001-2006: «Многообещающие результаты»<br />~3000 научных публикацийС общим смыслом «вот на следующих поколениях оборудования все будет хорошо...»<br />Первые средства разработки для не-графики: Brook, Sh<br />Результаты:<br />Ускорение линейной алгебры в разы (относительно CPU), но single precision<br />Сортировка: ускорение в разы, GPUTeraSortвыиграла Sort Benchmark 2006г<br />Промышленное использование:<br />Обработка сигналов<br />Обработка цифрового кино (поток 200-500Mb/sec)<br />
  11. 11. Проблемы начального этапа<br />Неудобная парадигма «Потоковых вычислений» (Stream Computing):<br />«микропрограммы» (шейдеры) – обработка одного элемента входного потока<br />Никакого взаимодействия между потоками<br />Многие задачи очень неудобно программировать<br />Только одинарная точность вычислений<br />Неудобство средств разработки<br />
  12. 12. 2006: NVidia CUDA и G80 Compute Unified Device Architecture<br />Принципиально новая (для GPU) архитектура<br />Взаимодействие между потоками вычислений<br />Произвольный код вместо шейдеров<br />Иерархическая структура памяти<br />345 GFLOP/s (single), 87Gb/sec memory bandwidth<br />Средства программирования общего назначения (CUDA):<br />Вычислительный код на языке «С»<br />Компактная архитектура запуска вычислителей<br />Много готовых вычислительных примеров<br />Готовые библиотеки BLAS и FFT в поставке<br />Прекрасная поддержка разработчиков и университетов<br />2007: NVidia Tesla – «Supercomputer on Desktop» - «видеокарты без видеовыхода», только вычисления<br />
  13. 13. 2006: интерес других производителей<br />ATI (AMD):<br />Инициатива Close-To-Metal: публикация спецификаций кода, надежда на отказ от OpenGL и появление нормальных компиляторов<br />FireStream – первый ускоритель для вычислений а не видеокарта<br />Остаются в парадигме потоковых вычислений<br />Cell (IBM-Sony-Toshiba)<br />8 ядер с локальной памятью (256кб на ядро)<br />Быстрая внешняя шина (25Gb/sec)<br />230 GFLOP/s single, 15-20GFLOP/s double<br />PlayStation 3 и плата в серверы<br />
  14. 14. 2007-2008: быстрое взросление<br />>2000 публикаций про использование CUDA<br />Топовые конференции (Supercomputing)<br />Хорошие готовые библиотеки<br />Новое оборудование:<br />Поддержка двойной точности у всех<br />NVidia: G200 – 800 GFLOP/s single, 100 – double, <br />ATI HD4870: 1000/240 GFLOP/s single/double, но все еще потоковое программирование<br />IBM PowerXCell: ~200/100 GFLOP/s<br />
  15. 15. Ускорение приложений на CUDA<br />2008 г.: NVidia 8800GTX в сравнении с AMD Opteron 248 (2.2GHz, 2 ядра)<br />
  16. 16. Современный этап: оборудование<br />Видеокарты:<br />ATI R800<br />2.7TFLOP/s single, 500 GFLOP/s double<br />Поддержка OpenCL (не только потоковые вычисления)<br />NVidia GF100 (Fermi):<br />Tesla 1.2 TFLOP/s single, 600 GFLOP/s double<br />Geforce GTX 480: 1.3 TFLOP/s single, ~180 GFLOP/s double<br />Для сравнения, топовые x86 CPU: 80-110GFLOP/s (double)<br />GPU-кластеры<br />Промышленные решения (Cray, IBM, Т-платформы)<br />Суперкомпьютеры: Nebulae - №2 в Supercomputer Top500 по реальной производительности, №1 по пиковой.<br />
  17. 17. Современный этап: программы<br />Стандарт OpenCL (лето-осень 2009): переносимые GPU-программы<br />Для пользователяускорение multimedia, обработка изображений и видео, 3D-моделирование, инженерные программы...<br />Для программиста<br />много готовых библиотек: линейная алгебра, обработка сигналов, computer vision<br />Для ученого: поддержка в расчетных программах<br />Общего назначения: Matlab, Mathematica<br />Специализированные пакеты: проектирование, компьютерная химия, компьютерная биология, молекулярная динамика<br />
  18. 18. Современный этап: производительность<br />
  19. 19. Наглядная агитация<br />4xTesla == Cray XT4 на задачах молекулярной биологии (AMBER11)(слайд с NVidia GPU Technology conference, 22 сентября 2010)<br />
  20. 20. NVidia CUDACompute Unified Device Architecture<br />Общий обзор «сверху вниз»<br />Как устроено оборудование<br />И как это отражается в логической структуре программ<br />Минимальные примеры программ<br />Некоторые тонкие моменты<br />Обзор средств программиста и дополнительных библиотек<br />Нет задачи и возможности заменить чтение документации и самостоятельные упражнения<br />
  21. 21. Общая схема исполнения программ<br />Все стадии независимы, одновременно можно:<br />Передавать в видеопамять<br />Считать (другие данные)<br />Передавать из видеопамяти<br />
  22. 22. Архитектура G80<br />До 16 одинаковых мультипроцессоровна чипе<br />Общая глобальная память (R/W): медленная и много (до 1.5Gb)<br />Общая константная память (RO): быстрая и мало<br />Общий планировщик потоков (блоками)<br />Общий исполняемый код на вечь чип<br />G80Streaming Multiprocessor (SM)<br /><ul><li> 8 простых процессоров (SP): исполняют 32 потока за 4 такта в SIMD-режиме
  23. 23. 2 специальных процессора (SFU) для сложных функций: 32 потока за 16 тактов, SIMD
  24. 24. Один диспетчер команд
  25. 25. до 768 потоков на одном SM в «одновременном» режиме
  26. 26. потоки объединяются в пачки по 32 потока (warp), которые исполняются SIMD
  27. 27. 16 kb разделяемой памяти (shared memory)
  28. 28. 8192 32-битных регистра</li></ul>На 2 SM – один блок обработки текстур с текстурным кэшем и блоком аппаратной интерполяции<br />…<br />TPC<br />TPC<br />TPC<br />TPC<br />TPC<br />TPC<br />Streaming Multiprocessor<br />Texture Processor Cluster<br />Instruction L1<br />Data L1<br />Instruction Fetch/Dispatch<br />SM<br />Shared Memory<br />TEX<br />SP<br />SP<br />SP<br />SP<br />SM<br />SFU<br />SFU<br />SP<br />SP<br />SP<br />SP<br />
  29. 29. Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Texture<br />Host<br />Input Assembler<br />Thread Execution Manager<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Parallel DataCache<br />Load/store<br />Load/store<br />Load/store<br />Load/store<br />Load/store<br />Load/store<br />Global Memory<br />G80: общая схема<br />
  30. 30. Логическая организация программ<br />Десятки тысяч – миллионы независимых потоков в программе<br />Поток – обрабатывает часть входных данных<br />Потоки объединены в блоки<br />Общая shared memory<br />Синхронизация<br />Блоки объединены в grid<br />Синхронизации нет<br />Grid of Thread Blocks<br />
  31. 31. Логическая организация (2)<br />Блок исполняется на одном мультипроцессоре<br />Разные блоки – на разных<br />Порядок не определен<br />Может быть несколько блоков на SM одновременно<br />Нумерация потоков в блоке: 1D, 2D или 3D<br />Нумерация блоков: 1D,2D<br />Каждый поток знает свое положение в сетке и блоке<br />
  32. 32. Иерархия памяти<br />
  33. 33. Параметры SM – не догма<br />G92:<br />16384регистров, до 1024 потоков на SM<br />GF100 (Fermi)<br />32768 регистров и 32/48 процессоров на SM <br />1536 потоков (48 warp) на SM<br />64kb shared memory+L1-cache (16/48 или 48/16 shared/cache)<br />Другие параметры другой оптимальный код<br />Другие улучшения<br />Атомарные операции (G86, G92)<br />Поддержка двойной точности (G200, GF100)<br />
  34. 34. Пример: cложение двух векторов<br />Код GPU: складываем два элемента:<br />__global__ void VecAdd(float* A,float* B, float* C, int N)<br />{<br /> int i = blockDim.x * blockIdx.x + threadIdx.x;<br /> if (i < N)<br /> C[i] = A[i]+B[i];<br />}<br />threadIdx – предопределенная переменная (3-компонентный вектор) – номер потока в блоке<br />blockDim – размерность одного блока (3D)<br />blockIdx – номер блока в сетке (2D)<br />
  35. 35. код на CPU<br />// аллоцируем память на GPU<br />size_t size = N * sizeof(float);<br />cudaMalloc((void**)&d_A, size);<br />cudaMalloc((void**)&d_B, size);<br />cudaMalloc((void**)&d_C, size);<br />// копируем данные на GPU<br />cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice); <br />cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);<br />// запускаем kernel на GPU (1D сетка и блок):<br />int Nthreads = 256;<br />int Nblocks = (N+Nthreads-1)/Nthreads;<br />VecAdd<<<Nblocks,Nthreads>>>(d_A, d_B, d_C, N);<br />// получаем результаты с GPU<br />cudaMemcpy(h_C, d_C, size, cudaMemcpyDeviceToHost);<br />
  36. 36. CUDA:С/C++ с небольшими изменениями<br />Спецификаторы типа функции:<br />__global__- GPU, может быть вызвана с CPU (с параметрами)<br />__device__ - GPU, вызывается из __global__<br />__host__ - CPUРекурсия и указатели на функции: только Fermi (GF100) <br />Спецификаторы местоположения переменной<br />__device__ - глобальная память, R/W<br />__constant__ - константная память, R/O<br />__shared__ - shared memory, R/W, локальна в блоке<br />Автоматические переменные – могут быть в регистрах, если известен размер и регистров достаточно. Иначе – local memory, т.е. живут в медленной глобальной памяти<br />
  37. 37. Типы данных и переменные<br />Скалярные:char, short, int, long,longlong, float, double (и беззнаковые для целых)<br />Векторные: <br /><=32 бит/компонент – до 4 элементов (uchar2,float4)<br />64 бита – 2 элемента (double2, longlong2)<br />Векторных операций НЕТ: c.x=a.x+b.x работает, c=a+b - нет<br />dim3 – тип для задания размера сетки блоков<br />Встроенные переменные:<br />gridDim, blockDim– размер сетки и блока (dim3)<br />blockIdx, threadIdx– номер блока и потока (dim3)<br />warpSize – ширина SIMD (пока всегда 32)<br />
  38. 38. Двумерные блоки например, для двумерных моделей<br />На CPU:<br />dim3 blockSize(16, 16);<br />// некратным размером сетки пренебрегаем... <br />dim3 gridSize(width/blockSize.x, height/blockSize.y);<br />myKernel<<<gridSize,blockSize>>>(…..)<br />На GPU<br />uint x = blockIdx.x*blockDim.x+threadIdx.x;<br />uint y = blockIdx.y*blockDim.y +threadIdx.y;<br />
  39. 39. Синхронизация, атомарные операции<br />Глобальная синхронизация всех блоков – завершение kernel<br />__syncthreads() – синхронизация потоков блока<br />Атомарные сложения, вычитания и т.п. (atomicAdd() и т.д.) - G86+<br />Shared или Global memory (G86 – только global)<br />Атомарное исполнение<br />Медленные<br />
  40. 40. Скалярное произведение<br />Накапливаем частные произведенияпо потокам:<br />__global__ result;<br />shared__ float psum[NTHREADS];<br />psum[threadIdx.x] = 0;<br />for(j=0;j<K*NTHREADS;j+=NTHREADS)<br />psum[threadIdx.x] += A[base+j]*B[base+j];<br />__syncthreads();<br />// Складываем для блока<br />if(threadIdx.x == 0)<br />{<br /> for(j=1;j<blockDim.x;j++)<br />psum[0]+=psum[j];<br /> // синхронизации не надо!! 0-йthread<br />atomicAdd(&result,psum[0]);<br />}<br />
  41. 41. Тонкости<br />Оптимальный доступ к глобальной памяти<br />Особенности доступа к shared memory<br />Условные операции<br />Распределение блоков по процессорам<br />
  42. 42. Доступ к глобальной памяти<br />Сложение векторов, 16 сложений на thread:<br />___________________________________________________<br />int j,base = (blockDim.x*blockIdx.x+threadIdx.x)*16;<br />for(j=0;j<16;j++)<br />C[base+j] = A[base+j] + B[base+j]<br />Thread0: A[0], A[1]<br />Thread1: A[16], A[17]<br />Весь Warp обращается c «размахом» в 512 слов<br />______________________________________________________<br />int j,base = (blockDim.x*blockIdx.x)*16+threadIdx.x;<br />for(j=0;j<blockDim.x*16;j+=blockDim.x)<br />C[base+j] = A[base+j] + B[base+j]<br />Thread0: A[0], A[blockDim.x]...<br />Thread1: A[1], A[blockDim.x+1]....<br />Весь Warp обращается к соседним словам<br />Второй вариант – coalesced access: доступ к соседним адресам <br />
  43. 43. Доступ к глобальной памяти - 2<br />Прямые рекомендации из Programming Guide:<br />Оптимально, когда все потоки одного (полу)-warp*обращаются к одному 128-байтному сегменту<br />Для 16-байтных элементов (вектор) – два подряд 128-байтных сегмента.<br />В правильном порядке – k-йthread к k-му элементу в сегменте.<br />Идеальная ситуация: Array[base + treadIdx.x]Array[base] – выровнен на 128 байт<br />
  44. 44. Разделяемая память<br />Разделена на банки <br />16 банков на G80-G200, 32 на GF100<br />Interleave 4 байта<br />Два потока в 1 банк =>конфликт, каждый конфликт – 4 такта ожидания<br />Оптимальный доступ array[threadIdx]<br />
  45. 45. Нет конфликта банков<br />Bank 0<br />Thread 0<br />Bank 0<br />Thread 0<br />Bank 1<br />Thread 1<br />Bank 1<br />Thread 1<br />Bank 2<br />Thread 2<br />Bank 2<br />Thread 2<br />Bank 3<br />Thread 3<br />Bank 3<br />Thread 3<br />Bank 4<br />Thread 4<br />Bank 4<br />Thread 4<br />Bank 5<br />Thread 5<br />Bank 5<br />Thread 5<br />Bank 6<br />Thread 6<br />Bank 6<br />Thread 6<br />Bank 7<br />Thread 7<br />Bank 7<br />Thread 7<br />Bank 15<br />Thread 15<br />Bank 15<br />Thread 15<br />
  46. 46. Конфликт банков<br />Bank 0<br />Bank 1<br />Thread 0<br />Bank 2<br />Thread 1<br />Bank 3<br />Thread 2<br />Bank 4<br />Thread 3<br />Bank 5<br />Thread 4<br />Bank 6<br />Bank 7<br />Thread 8<br />Thread 9<br />Bank 15<br />Thread 10<br />Thread 11<br />GF100: несколько чтений разных потоков по одному адресу (не банку) – не приводят к конфликту (broadcast данных)<br />
  47. 47. Условные операции<br />SIMD <br />поэтому если в одном warp разные ветки if, их исполнение будет последовательным:<br />if (threadIdx.x %2)<br /> { четные ветки стоят, нечетные работают}<br />else<br /> { четные работают, нечетные стоят }<br />
  48. 48. Распределение блоков по SM<br />Не меньше одного блока т.е. блок должен пролезать по ресурсам:<br />Общее число потоковв блоке < лимита оборудования<br />Требуемое количество shared memory< лимита<br />Общее количество регистров (регистров на поток * число потоков) < лимита <br />Несколько блоков на SM – если достаточно ресурсов (регистров, shared memory, потоков)<br />G80-G200 – передача параметров в shared mem, 2 X 8192 – не влезет в 16 килобайт<br />
  49. 49. Загрузка SM (occupancy)<br />Отношение числа работающих warps к из возможному количеству<br />В общем случае, к 100% надо стремиться:<br />Прячется латентность доступа к памяти<br />Но мало регистров (G92 – 16 регистров/thread)<br />Альтернативный подход:<br />Мало потоков (128-192-256 на SM)<br />Зато много регистров на поток<br />Полезно для блочных алгоритмов<br />Подробнее: Volkov, V. 2010. Use registers and multiple outputs per thread on GPUhttp://www.cs.berkeley.edu/~volkov/volkov10-PMAA.pdf<br />
  50. 50. Разное<br />Целая арифметика:<br />G80-G200: 24-бита – быстрая, 32 бита – медленная<br />GF100 – 32 бита – быстрая, 24 бита - медленная<br />Текстуры: 1-2-3D-массивы<br />Кэшируются, кэш локален по координатам (эффективное кэширование по столбцам, при последовательном доступе – медленнее global memory)<br />Аппаратная интерполяция<br />
  51. 51. Продолжение.....<br />Документация NvidiaОчень хорошая!http://developer.nvidia.com/object/cuda_download.html<br />CUDA Programming Guide<br />CUDA Reference Guide<br />CUDA Best Practices Guide<br />Примеры SDK и документация к нимhttp://developer.download.nvidia.com/compute/cuda/sdk/website/samples.html<br />Форумы Nvidiahttp://forums.nvidia.com/index.php?showforum=62<br />
  52. 52. Программные средства<br />CUDA Toolkit – компилятор + библиотеки<br />Интегрируется с Visual C++ (добавление правил компиляции для .cu)<br />Отладчик – gdb (командная строка)<br />Visual Profiler – не на уровне отдельных строк кода<br />Parallel Nsight<br />Пошаговая отладка<br />Глобальный профайлинг<br />Standard (бесплатная) и Professional (бесплатная для ВУЗов) версии<br />CUDA-x86<br />Был эмулятор, но в Cuda 3.x удален<br />PGI обещает компилятор<br />
  53. 53. Подробности компиляции<br />float4 me = gx[gtid];<br />me.x += me.y * me.z;<br />C/C++ CUDA<br />Application<br />CPU-code компилируется родным компилятором<br />PTX – неоптимизированный ассемблер, дальнейшие варианты:<br /><ul><li> Компиляция в один executable
  54. 54. Компиляция в внешний .cubin-файл и загрузка на runtime</li></ul>Финальную компиляцию реальные коды делает драйвер видеокарты<br />NVCC<br />CPU Code<br />PTX Code<br />Virtual<br />Physical<br />PTX to Target<br />Compiler<br /> G80<br /> …<br /> GPU <br />Target code<br />
  55. 55. Два API<br />CUDA C API: <br />реализуется внешней библиотекой cudart<br />Высокоуровневое, более удобное<br />удобная поддержка нескольких контекстов (например для использования в многопоточных программах)<br />CUDA Driver API: <br />Аналогично по возможностям<br />Не требует дополнительных библиотек<br />Больше работы программисту<br />
  56. 56. Альтернативы CUDA<br />OpenCL<br />CAL/IL (Compute Abstraction Layer/Intermediate Language)<br />Только видеокарты ATI<br />Потоковое программирование<br />Плохо поддерживается<br />DirectX 11 (DirectCompute)<br />Только Windows <br />
  57. 57. OpenCL<br />Многоплатформенный стандарт<br />Необычайно похож на CUDA Driver API<br />Детали:<br />Язык C для kernels, другие ключевые слова<br />Компиляция из исходных текстов на ходу («в драйвере»)<br />Уже две версии (1.0 и 1.1)<br />Нестандартная конфигурация поддерживается через «расширения»<br />
  58. 58. Сложение векторов<br />Код GPU:<br />__kernel void VectorAdd(__global const float* a,__global const float* b,__global float* c, int N)<br />{<br /> int iGID = get_global_id(0);<br /> if (iGID < N)<br /> c[iGID] = a[iGID] + b[iGID];<br />}<br />
  59. 59. Код CPU<br />// Создаем контекст GPU (до того был поиск устройств...)<br />Context = clCreateContext(0, 1, &cdDevice, NULL, NULL, &ciErr1);<br />// и очередь команд<br />CommandQueue = clCreateCommandQueue(Context, cdDevice, 0, &ciErr1);<br />// Аллоцируем массив(ы) на GPU<br />cmDevSrcA = clCreateBuffer(Context, CL_MEM_READ_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &ciErr1);<br />…. И еще два аллоцирования ....<br />// Создаем (компилируем) программу из исходных текстов<br />cpProgram = clCreateProgramWithSource(Context, 1, (const char **)&cSourceCL, &szKernelLength, &ciErr1);<br />// создаем из нее kernel<br />ckKernel = clCreateKernel(cpProgram, "VectorAdd", &ciErr1);<br />// задаем ему аргумент(ы)<br />clSetKernelArg(ckKernel, 0, sizeof(cl_mem), (void*)&cmDevSrcA);<br />.... И еще три аргумента ......<br />// В очередь команд помещаем копирование данных и запуск kernel, все асинхронно<br />clEnqueueWriteBuffer(CommandQueue, cmDevSrcA, CL_FALSE, 0, sizeof(cl_float) * szGlobalWorkSize, srcA, 0, NULL, NULL);<br />.... И еще одно копирование....<br />clEnqueueNDRangeKernel(CommandQueue, ckKernel, 1, NULL, &szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL);<br />// В очередь команд помещаем синхронное чтение результата<br />clEnqueueReadBuffer(CommandQueue, cmDevDst, CL_TRUE, 0, sizeof(cl_float) * szGlobalWorkSize, dst, 0, NULL, NULL);<br />
  60. 60. CUDA  OpenCL<br />AMD: Porting CUDA to OpenCLhttp://developer.amd.com/zones/OpenCLZone/Pages/portingcudatoopencl.aspx<br />
  61. 61. Переносимость и производительность<br />Переносимыйкод (NVidia, ATI,x86, Cell)<br />Производительность не переносится:<br />Либо используем векторные типы на векторных архитектурах (ATI, Cell) и получаем непереносимый код<br />Либо код получается переносимый и в разы медленнее<br />Перенос CUDA  OpenCL – потеря 20-30%. Компилятор??<br />CUDA всегда будет впереди т.к. нет этапа согласований с рабочей группой<br />
  62. 62. OpenCL и видеокарты ATI<br />Человеческий интерфейс (в отличие от CAL/IL)<br />HD5870 – производительность примеров SDK - на уровне GTX280 (в разы ниже ожидаемого)<br />HD4xxx – производительность плохая т.к. нет shared memory (эмуляция через глобальную)<br />Плохая документация (в сравнении с...)<br />Но что делать, если попалось такое оборудование и не хочется ассемблера.....<br />
  63. 63. Почему GPU НАСТОЛЬКО быстрее?<br /><ul><li>Линейная алгебра: 5-8раз
  64. 64. Обработка сигналов, обработка изображений: десятки раз
  65. 65. Некоторые задачи (молекулярная динамика, N-body): бывают сотни раз</li></li></ul><li>Вот почему:<br />Другой аппаратный дизайн:<br />CPU – оптимизация под любые задачи (включая очень плохой код) и низкую латентность. <br />GPU – оптимизация под общую производительность и только высокопараллельные задачи.<br />Быстрая память:<br />В разы выше bandwidth видеопамяти<br />Больше очень быстрой памяти(2-3Mbпротив 32-256Kb L1 cache CPU)<br />Аппаратная поддержка ряда функций (exp, sin, cos, pow, log….): разница с CPU в десятки и даже сотни (!) раз<br />Часто сравнивают с неоптимизированным кодом (а другого и нет, писать руками SSE-инструкции скучно)<br />
  66. 66. На каких задачах GPU медленнее?<br />Задачи, которые не распараллеливаются на тысячи независимых потоков<br />State machine, операции со строками<br />Обход (одного большого) графа<br />Неподходящий размер working set:<br />На GPU 1-3 Mbочень быстрой памяти<br />На CPU 4-8-12-64Mb L2 cache<br />Случайный доступ к большому массиву<br />Видеопамять медленнее при случайном доступе<br />Низкая арифметическая интенсивность<br />
  67. 67. Как с этим жить?<br />Дешевый способ увеличить производительность в 5-10-100 раз, в зависимости от задачи.<br />Рекомендации по самостоятельному использованию:<br />Учиться на CUDA<br />Использовать OpenCL <br />если действительно нужна переносимость<br />Если нет GPU, а попробовать хочется<br />Использовать ATI и CAL/IL если нужна максимальная производительность на потоковых операциях<br />Используйте mixed-precision схемы (на CPU тоже очень полезно!)<br />
  68. 68. Как с этим жить - 2<br />Используйте библиотеки:<br />CUBLAS, CUFFT, CUSPARSE – входят в CUDA SDK<br />CUDPP, MAGMA, GATLAS, OpenCV – 3rd party и бесплатны<br />ACML-GPU для ATI<br />.... библиотек уже много....<br />Расширения для Matlab<br />Parallel Computing Toolbox (R2010b)<br />Jacket<br />GPUmat, ViennaCL<br />
  69. 69. CUDA: Университетские курсы<br />University of Urbana самый первыйдоступный курс курс: http://courses.engr.illinois.edu/ece498/al/Syllabus.html (доступны слайды и запись голоса).<br />Курс по CUDA, читаемый на ВМКЗаписи 2009 года: http://esyr.org/lections/audio/cuda_2009_summer/ и http://esyr.org/video/cuda/Записи 2010 года: ftp://geophyslab.srcc.msu.ru/Events/CUDA2010/Google-группа к этому курсу: http://groups.google.ru/group/cudacsmsusu/<br />
  70. 70. CUDA: книги<br />На русском<br />А. В. Боресков, А. А. Харламов Основы работы с технологией CUDA (+ CD-ROM)http://www.ozon.ru/context/detail/id/5080841/<br />На английском<br />Programming Massively Parallel Processors: A Hands-on Approach, David B. Kirk, Wen-mei W. Hwuhttp://www.amazon.com/Programming-Massively-Parallel-Processors-Hands/dp/0123814723/ref=sr_1_1?ie=UTF8&s=books&qid=1284301217&sr=8-1<br /> CUDA by Example: An Introduction to General-Purpose GPU Programming by Jason Sanders and Edward Kandrothttp://www.amazon.com/CUDA-Example-Introduction-General-Purpose-Programming/dp/0131387685/ref=sr_1_4?ie=UTF8&s=books&qid=1284301217&sr=8-4<br />
  71. 71. Литература OpenCL<br />Сайт с описанием стандарта: http://www.khronos.org/opencl/далее по ссылкам.<br />Обзор «OpenCL: A Parallel Programming Standard for Heterogeneous Computing Systems» http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=5457293<br />Документы AMD по миграции с CUDA на OpenCL: <br />http://developer.amd.com/documentation/articles/pages/OpenCL-and-the-ATI-Stream-v2.0-Beta.aspx#four<br />http://developer.amd.com/gpu/ATIStreamSDK/pages/TutorialOpenCL.aspx<br />Документы NVIdia по программированию OpenCL:<br />Programming Guide: http://developer.download.nvidia.com/compute/cuda/3_1/toolkit/docs/NVIDIA_OpenCL_ProgrammingGuide.pdf<br />Best Practices Guide: http://developer.download.nvidia.com/compute/cuda/3_1/toolkit/docs/NVIDIA_OpenCL_BestPracticesGuide.pdf<br />Code Samples: http://developer.download.nvidia.com/compute/opencl/sdk/website/samples.html<br />Книги:<br />The OpenCL Programming Book http://www.fixstars.com/en/company/books/opencl/<br />
  72. 72. Литература: Разное<br />Debunking the 100X GPU vs CPU Myth: an Evaluation of Throughput Computing on CPU and GPUhttp://www.hwsw.hu/kepek/hirek/2010/06/p451-lee.pdf<br />Относиться с осторожностью, авторам статьи (инженерам Intel) обидно за свои процессоры и они тянут одеяло в свою сторону<br />
  73. 73. Спасибо за внимание!<br />Задавайте вопросы<br />

×