nvidia cuda 软件和 gpu 并行计算架构 -...
TRANSCRIPT
NVIDIA CUDA 软件和 GPU 并行计算架构
David B. Kirk, Chief Scientist
© NVIDIA Corporation 2006-2008
2
提纲
GPU 计算的应用
CUDA 编程模型介绍
用CUDA 编程 – 基础
如何开始!
练习 / 实例家庭作业
© NVIDIA Corporation 2006-2008
3
未来科学和工程突破的关键在于计算
计算
建模
计算
化学
计算
医学
计算
物理学
计算
生物学
计算
金融
计算
地球科学
计算
图像处理
© NVIDIA Corporation 2006-2008
4
快不仅仅是 “快”
2-3X 快只是“快”
做多一些, 等待少一些
不会改变你如何工作
5-10x 快是 “重大的”
值得升级
值得重写应用软件(部分)
100x+ 快是 “根本不同”
值得考虑新的平台
值得重新构架应用软件
使新的应用软件成为可能
驱动 “time to discovery” 并且在科学中创造基本的变化
© NVIDIA Corporation 2006-2008
5
GPU 是一个新的计算引擎
相对浮点性能
Eraof Shaders
Fully Programmable
0
10
20
30
40
50
60
70
80
2002 2003 2004 2005 2006
G80
1
© NVIDIA Corporation 2006-2008
6
CPU-GPU 紧密耦合
Operation 1 Operation 2 Operation 3
Init
Alloc
Function Lib Lib Function Function
CPU
GPU
集成的编程模型
高速数据传输 – 高达 3.2 GB/s
异步操作
大 GPU 内存系统
© NVIDIA Corporation 2006-2008
7
数百万基于CUDA GPUs
Total GPUs(millions)
25
50
2006 2007
专注于计算
GPU上的C语言
服务器到笔记本PC
© NVIDIA Corporation 2006-2008
8
TeslaTM
高性能计算
Quadro®
设计和创作
GeForce®
娱乐
© NVIDIA Corporation 2006-2008
9
VMD/NAMD 分子动力学
http://www.ks.uiuc.edu/Research/vmd/projects/ece498/lecture/
240X 加速
计算生物学
© NVIDIA Corporation 2006-2008
10
生物进化机
130X 的加速
模拟脑电波
感观计算: 视觉,嗅觉
EvolvedMachines
© NVIDIA Corporation 2006-2008
11
Hanweck合作伙伴
VOLERA、实时期权隐含波动引擎
单精度的准确结果
在不到1秒钟的时间内,评估所有美国上市的股票期权
www.hanweckassoc.com
© NVIDIA Corporation 2006-2008
12
LIBOR应用:Mike Giles和Su Xiaoke
牛津大学计算实验室
带有互换期权投资组合的LIBOR模型
80个初始期货汇率和距离到期日的40时间步长
用伴随方法计算80Delta
No Greeks Greeks
Intel Xeon 18.1s - 26.9s -
ClearSpeed Advance
2 CSX600
2.9s 6x 6.4s 4x
NVIDIA 8800 GTX 0.045s 400x 0.18s 149x
可在此处获得源代码和论文:
http://web.comlab.ox.ac.uk/oucl/work/mike.giles/hpc
“CUDA代码性能非凡”
-Mike Giles
© NVIDIA Corporation 2006-2008
13
Manifold 8地理信息
从Manifold 8特色列表中:…过去要达完成CUDA要求的应用程序往往需要数十秒甚至几分钟的时间,而现在只需短短百分之几秒的时间就能完成. … CUDA将会开启几乎所有GIS计算的未来
从用户手册中:“NVIDIA CUDA …是于微处理器的发明之后很有可能成为计算机领域一大革命性的事件。”
© NVIDIA Corporation 2006-2008
14
N体天体物理学
http://progrape.jp/cs/
天体物理学研究
在标准PC上实现1 GF
在GeForce 8800GTX上300+ GF
比GRAPE-6Af 定制的仿真计算机更快
视频演示
© NVIDIA Corporation 2006-2008
15
17X with MATLAB CPU+GPU
Pseudo-spectral simulation of 2D Isotropic turbulence
Matlab: 科学的语言
http://www.amath.washington.edu/courses/571-winter-2006/matlab/FS_2Dturb.m
http://developer.nvidia.com/object/matlab_cuda.html
CUDA 编程模型介绍
© NVIDIA Corporation 2006-2008
17
GPU 计算
GPU 是大规模并行计算NVIDIA G80: 128 个处理器
支持成千上万个活动线程度 (12,288 on G80)
GPU 计算需要一个编程模型, 能有效地表达这种并行最重要, 数据并行
CUDA 实现了这样一个编程模型
© NVIDIA Corporation 2006-2008
18
CUDA 内核和线程
程序的并行部分在设备上执行, 这称为内核一次执行一个内核
许多线程执同一内核
CUDA 和 CPU 线程的区别CUDA 线程是超轻量级
非常小的创建开销
立即切换
CUDA 使用 1000 线程来获得效率多核CPU 只使用很少
定义:
设备 = GPU; 主机 = CPU
内核 = 运行在设备上的的函数
© NVIDIA Corporation 2006-2008
19
并行线程阵列
一组线程阵列执行同一CUDA 内核所有线程运行相同的代码
每个线程都有自己的ID, 用来计算内存地址和做控制决策
0 1 2 3 4 5 6 7
…
float x = input[threadID];
float y = func(x);
output[threadID] = y;
…
threadID
© NVIDIA Corporation 2006-2008
20
线程协作
不可缺少: 线程可能需要协作
线程协作是是有价值的共享结果节省计算
同步
共享内存访问
带宽的急剧降低
线程协作是CUDA的强大性能之一
© NVIDIA Corporation 2006-2008
21
…
float x = input[threadID];
float y = func(x);
output[threadID] = y;
…
threadID
Thread Block 0
……
float x = input[threadID];
float y = func(x);
output[threadID] = y;
…
Thread Block 0
…
float x = input[threadID];
float y = func(x);
output[threadID] = y;
…
Thread Block N - 1
线程块:可伸缩的协作
把整个线程阵列分成许多块(Block)
块中的线程通过共享 内存
不同块中的线程不能协作
使得程序可以在任意数目的处理器上透明伸缩!
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
© NVIDIA Corporation 2006-2008
22
透明伸缩
任何时候硬件都可以自由地在处理器上调度线程块
内核的伸缩可以跨任何数目的并行处理器
Device
Block 0 Block 1
Block 2 Block 3
Block 4 Block 5
Block 6 Block 7
Kernel grid
Block 0 Block 1
Block 2 Block 3
Block 4 Block 5
Block 6 Block 7
Device
Block 0 Block 1 Block 2 Block 3
Block 4 Block 5 Block 6 Block 7
© NVIDIA Corporation 2006-2008
23
CUDA 编程模型
内核被一个 grid 的线程块执行(thread block)
线程块(thread block)是可以相互协作的线程的批处理,通过:
通过共享内存共享数据
同步它们的运行
不同块的线程不能协作
Host
Kernel
1
Kernel
2
Device
Grid 1
Block
(0, 0)
Block
(1, 0)
Block
(2, 0)
Block
(0, 1)
Block
(1, 1)
Block
(2, 1)
Grid 2
Block (1, 1)
Thread
(0, 1)
Thread
(1, 1)
Thread
(2, 1)
Thread
(3, 1)
Thread
(4, 1)
Thread
(0, 2)
Thread
(1, 2)
Thread
(2, 2)
Thread
(3, 2)
Thread
(4, 2)
Thread
(0, 0)
Thread
(1, 0)
Thread
(2, 0)
Thread
(3, 0)
Thread
(4, 0)
© NVIDIA Corporation 2006-2008
24
处理器 执行计算线程
线程执行管理器发送线程
128 线程处理器分成16组多处理器(SM)
并行数据缓存 (共享内存) 使线程协作
G80 设备
Thread Execution Manager
Input Assembler
Host
Parallel
Data
Cache
Global Memory
Load/store
Parallel
Data
Cache
Thread Processors
Parallel
Data
Cache
Parallel
Data
Cache
Thread Processors
Parallel
Data
Cache
Parallel
Data
Cache
Thread Processors
Parallel
Data
Cache
Parallel
Data
Cache
Thread Processors
Parallel
Data
Cache
Parallel
Data
Cache
Thread Processors
Parallel
Data
Cache
Parallel
Data
Cache
Thread Processors
Parallel
Data
Cache
Parallel
Data
Cache
Thread Processors
Parallel
Data
Cache
Parallel
Data
Cache
Thread Processors
© NVIDIA Corporation 2006-2008
25
线程和块 ID
线程和 Block 都有 ID每个线程能决定什么数据执行
Block ID: 1D or 2D
Thread ID: 1D, 2D, or 3D
简化内存寻址,当处理多维数据时
图像处理
偏微分方程
Device
Grid 1
Block
(0, 0)
Block
(1, 0)
Block
(2, 0)
Block
(0, 1)
Block
(1, 1)
Block
(2, 1)
Block (1, 1)
Thread
(0, 1)
Thread
(1, 1)
Thread
(2, 1)
Thread
(3, 1)
Thread
(4, 1)
Thread
(0, 2)
Thread
(1, 2)
Thread
(2, 2)
Thread
(3, 2)
Thread
(4, 2)
Thread
(0, 0)
Thread
(1, 0)
Thread
(2, 0)
Thread
(3, 0)
Thread
(4, 0)
© NVIDIA Corporation 2006-2008
26
内核内存访问
寄存器(Register)
全局内存 (external DRAM)内核的输入输出数据存放在这里片下,较大非高速缓存
共享内存 (Parallel Data Cache)被同一块内的线程共享片上,较小与寄存器同样快
Grid
Global
Memory
Block (0, 0)
Shared Memory
Thread (0, 0)
Registers
Thread (1, 0)
Registers
Block (1, 0)
Shared Memory
Thread (0, 0)
Registers
Thread (1, 0)
Registers
Host
主机可以读写全局内存但不能读写共享内存
© NVIDIA Corporation 2006-2008
27
执行模型
内核以Grid执行一个内核一次执行
一个Block 执行在一个流式多处理器上 (SM)
不需要移动
多个Block 可以同时驻留在一个 SM 上控制限制(G8X/G9X GPUs):
每个SM最多 8 并发 Block
每个SM最多 768 并发线程
数目进一步受到SM资源的限制寄存器文件在所有的驻留线程中分配
共享内存在所有的驻留线程块中分配
© NVIDIA Corporation 2006-2008
28
CUDA 相对传统 GPGPU的优势(传统GPGPU是通过图形API编程GPU)
随机访问字节内存线程可访问内存任何地方
无限制访问内存线程可根据需要读写多个内存位置
共享内存 (Block) 和线程同步线程可以协作把数据装入共享内存
然后任何线程可以访问共享内存的任何位置
较低的学习曲线只是对C的一些扩展
不需要图形的知识
没有图形API的额外开销
© NVIDIA Corporation 2006-2008
29
CUDA 模型总结
成千上万的并发轻量级线程没有转换开销
隐藏指令和内存延迟
共享内存用户可管理的L1缓存
块内线程可通讯和协作
随机访问全局内存任何线程可读写任何位置
最新一代的硬件:多达128个流式处理器
Memory Location Cached Access Scope (“Who?”)
Shared On-chip N/A Read/write All threads in a block
Global Off-chip No Read/write All threads + host
CUDA编程
基础篇
© NVIDIA Corporation 2006-2008
31
CUDA 基础篇纲要
建立和执行GPU代码:
GPU 内存管理
GPU 内核的执行
GPU代码的一些细节
一些其他的特性:
向量类型
管理多个GPU,多个CPU线程
检查CUDA错误
CUDA 事件 API
编译路径
注意:只覆盖基本特性更多的API函数参考编程指南
© NVIDIA Corporation 2006-2008
32
管理内存
主机 (CPU) 管理设备 (GPU) 内存:
分配 / 释放
拷贝数据
对设备内存使用 global 和 constant
共享内存 (片上) 静态分配
主机管理纹理数据:
存储在 GPU 上
利用纹理缓存、过滤和钳位的优势( texture caching /
filtering / clamping)
主机管理固定CPU内存 (不可页交换) :
分配 / 释放
© NVIDIA Corporation 2006-2008
33
GPU 内存分配 / 释放
cudaMalloc(void ** pointer, size_t nbytes)
cudaMemset(void * pointer, int value, size_t count)
cudaFree(void* pointer)
int n = 1024;
int nbytes = 1024*sizeof(int);
int *d_a = 0;
cudaMalloc( (void**)&d_a, nbytes );
cudaMemset( d_a, 0, nbytes);
cudaFree(d_a);
© NVIDIA Corporation 2006-2008
34
数据拷贝
cudaMemcpy (void *dst, void *src, size_t nbytes, enum cudaMemcpyKind direction);
direction描述数据拷贝方向
阻塞CPU线程: 拷贝完成后返回
不开始拷贝直到前一个CUDA调用完成
cudaMemcpyAsync(..., cudaStream_t streamId)
主机内存必须固定 (用 cudaMallocHost 分配)
立即返回
不开始拷贝直到前一个CUDA用streamId调用完成或0完成
enum cudaMemcpyKindcudaMemcpyHostToDevice
cudaMemcpyDeviceToHost
cudaMemcpyDeviceToDevice
© NVIDIA Corporation 2006-2008
35
练习 1
我们开始进入CUDA编程
在练习 1 你将学习使用 cudaMalloc 和 cudaMemcpy
© NVIDIA Corporation 2006-2008
36
在GPU执行代码
C 函数的限制只能访问GPU内存没有参数的变量数目 (“varargs”)
没有静态变量
必须用限定词声明__global__ : 在主机(CPU)代码中调用,
不能从设备(GPU)代码中调用必须返回空 void
__device__ :在其他GPU代码中调用,
不能从主机CPU代码中调用
__host__ : 只能被CPU执行,从主机调用
__host__ 和 __device__ 联合使用
例如:过载操作符编译器将产生 CPU 和 GPU 代码
© NVIDIA Corporation 2006-2008
37
发射GPU上的内核
修改的C函数调用语法:kernel<<<dim3 grid, dim3 block, int smem, int stream>>>(…)
执行配置 (“<<< >>>”):
grid 维数: x 和 y
线程块维数: x, y, 和 z
共享内存: 每个块的外部声明的无大小的smem变量的字节数
可选,缺省0
stream ID
可选,缺省0
dim3 grid(16, 16);
dim3 block(16,16);
kernel<<<grid, block, 0, 0>>>(...);
kernel<<<32, 512>>>(...);
© NVIDIA Corporation 2006-2008
38
CUDA 内置的设备变量
所有 __global__ 和 __device__ 函数可以访问这些自动定义的变量
dim3 gridDim;
Grid 的块维数 (gridDim.z不使用)
dim3 blockDim;
Block的线程维数
dim3 blockIdx;
Grid 中的Block 索引
dim3 threadIdx;
Block 中的线程索引
© NVIDIA Corporation 2006-2008
39
最小的 Kernel
__global__ void minimal( int* d_a)
{
*d_a = 13;
}
__global__ void assign( int* d_a, int value)
{
int idx = blockDim.x * blockIdx.x + threadIdx.x;
d_a[idx] = value;
} Common Pattern!
© NVIDIA Corporation 2006-2008
40
2D数据的最小 Kernel
__global__ void assign2D(int* d_a, int w, int h, int value)
{
int iy = blockDim.y * blockIdx.y + threadIdx.y;
int ix = blockDim.x * blockIdx.x + threadIdx.x;
int idx = iy * w + ix;
d_a[idx] = value;
}
...
assign2D<<<dim3(64, 64), dim3(16, 16)>>>(...);
© NVIDIA Corporation 2006-2008
41
练习 2: 你的第一个 CUDA kernel
在这个练习中,你要写并执行一个简单的 CUDA kernel
© NVIDIA Corporation 2006-2008
42
主机同步
所有 kernel 发射都是异步的控制立即返回到CPU
在以前所有CUDA调用完成后,kernel 才执行
cudaMemcpy 是异步的拷贝完成后控制立即返回到CPU
在以前所有CUDA调用完成后, 拷贝开始
cudaThreadSynchronize()
在以前所有CUDA调用完成后, 开始阻塞
异步 API 提供:
GPU CUDA-call streams
non-blocking cudaMemcpyAsync
© NVIDIA Corporation 2006-2008
43
实例:数组元素增量
CPU program CUDA program
void increment_cpu(float *a, float b, int N)
{
for (int idx = 0; idx<N; idx++)
a[idx] = a[idx] + b;
}
void main()
{
.....
increment_cpu(a, b, N);
}
__global__ void increment_gpu(float *a, float b, int N)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N)
a[idx] = a[idx] + b;
}
void main()
{
…..
dim3 dimBlock (blocksize);
dim3 dimGrid( ceil( N / (float)blocksize) );
increment_gpu<<<dimGrid, dimBlock>>>(a, b, N);
}
© NVIDIA Corporation 2006-2008
44
实例: 数组元素增量
Increment N-element vector a by scalar b
Let’s assume N=16, blockDim=4 -> 4 blocks
blockIdx.x=0
blockDim.x=4
threadIdx.x=0,1,2,3
idx=0,1,2,3
blockIdx.x=1
blockDim.x=4
threadIdx.x=0,1,2,3
idx=4,5,6,7
blockIdx.x=2
blockDim.x=4
threadIdx.x=0,1,2,3
idx=8,9,10,11
blockIdx.x=3
blockDim.x=4
threadIdx.x=0,1,2,3
idx=12,13,14,15
int idx = blockDim.x * blockId.x + threadIdx.x;
will map from local index threadIdx to global index
NB: blockDim should be >= 32 in real code, this is just an example
© NVIDIA Corporation 2006-2008
45
实例: 主机// allocate host memory
unsigned int numBytes = N * sizeof(float)
float* h_A = (float*) malloc(numBytes);
// allocate device memory
float* d_A = 0;
cudaMalloc((void**)&d_A, numbytes);
// copy data from host to device
cudaMemcpy(d_A, h_A, numBytes, cudaMemcpyHostToDevice);
// execute the kernel
increment_gpu<<< N/blockSize, blockSize>>>(d_A, b);
// copy data from device back to host
cudaMemcpy(h_A, d_A, numBytes, cudaMemcpyDeviceToHost);
// free device memory
cudaFree(d_A);
© NVIDIA Corporation 2006-2008
46
变量限定符 (GPU 代码)
__device__存储在设备内存中 (大, 高延迟, 非缓存)
用cudaMalloc分配(暗指__device__ 限定符)
可被所有线程访问寿命: 整个应用程序
__constant__与 __device__ 相同, 但被缓存并GPU只读通过 cudaMemcpyToSymbol(...) 调用被CPU写寿命: 整个应用程序
__shared__存储在片上共享内存中 (延迟非常低)
可被相同线程块内的所有线程访问寿命: Kernel
无限制的变量:存储在寄存器中的标量和内置的向量类型超过4个元素的数组存储在设备内存中
© NVIDIA Corporation 2006-2008
47
CUDA 内存空间
每个线程可以:
读/写每个thread registers
读/写每个thread local memory
读/写每个block shared memory
读/写每个grid global memory
只读每个grid constant memory
只读每个grid texture memory
Grid
Constant
Memory
Texture
Memory
Global
Memory
Block (0, 0)
Shared Memory
Local
Memory
Thread (0, 0)
Registers
Local
Memory
Thread (1, 0)
Registers
Block (1, 0)
Shared Memory
Local
Memory
Thread (0, 0)
Registers
Local
Memory
Thread (1, 0)
Registers
Host主机可以读写全局,常数和纹理内存(存储在DRAM中)
© NVIDIA Corporation 2006-2008
48
CUDA 内存空间之前介绍了全局和共享内存
最重要,最常用
Local , Constant和Texture是为了方便和性能Local: 编译器自动分配的数组变量
Constant: 用于均匀访问的只读数据
被缓存 (参见编程指南)
Texture: 用于空间连续的随机访问的只读数据
被缓存 (参见编程指南)
提供地址clamping 和wrapping
Memory Location Cached Access Scope (“Who?”)
Local Off-chip No Read/write One thread
Shared On-chip N/A Read/write All threads in a block
Global Off-chip No Read/write All threads + host
Constant Off-chip Yes Read All threads + host
Texture Off-chip Yes Read All threads + host
© NVIDIA Corporation 2006-2008
49
内置的向量类型
可以在GPU和CPU代码中使用
[u]char[1..4], [u]short[1..4], [u]int[1..4],
[u]long[1..4], float[1..4]
x, y, z, w 域的结构:
uint4 param;
int y = param.y;
dim3
基于 uint3
用来描述维数
缺省值 (1,1,1)
© NVIDIA Corporation 2006-2008
50
线程同步函数
void __syncthreads();
同步块中的所有线程产生壁垒( barrier)同步指令
没有线程可以通过这个壁垒( barrier )直到块中的所有线程到达它
当访问共享内存时,用来避免 RAW / WAR / WAW 危险
允许在条件代码中,并只有这个条件在整个线程块中时统一的
© NVIDIA Corporation 2006-2008
51
GPU 原子整数操作
在全局内存中对整数的原子操作:
Associative operations on signed/unsigned ints
add, sub, min, max, ...
and, or, xor
Increment, decrement
Exchange, compare and swap
需要计算能力1.1的硬件
© NVIDIA Corporation 2006-2008
52
设备管理
CPU 可以查询和选择GPU设备cudaGetDeviceCount( int *count )
cudaSetDevice( int device )
cudaGetDevice( int *current_device )
cudaGetDeviceProperties( cudaDeviceProp* prop,
int device )
cudaChooseDevice( int *device, cudaDeviceProp* prop )
多GPU的设置:
缺省使用设备0
一个CPU线程只能控制一个GPU
多CPU线程可以控制相同的GPU
– 驱动串行执行调用
© NVIDIA Corporation 2006-2008
53
多CPU线程和 CUDA
一个CPU线程分配的CUDA 资源只被相同CPU线程中的CUDA调用所利用
例外:
CPU thread 2 分配GPU内存,存储在 p
thread 3 发出一个访问p CUDA调用
© NVIDIA Corporation 2006-2008
54
CUDA 错误报告给 CPU
所有CUDA返回错误代码:
kernel 发射例外
cudaError_t 类型
cudaError_t cudaGetLastError(void)
返回最后的错误代码 (no error has a code)
char* cudaGetErrorString(cudaError_t code)
返回一个非空的字符串描述错误
printf(“%s\n”, cudaGetErrorString( cudaGetLastError() ) );
© NVIDIA Corporation 2006-2008
55
CUDA 事件 API
事件插入进CUDA调用流中
使用脚本:测量CUDA调用的时间 (clock cycle precision)
查询异步CUDA调用的状态
阻塞CPU直到事件以前的CUDA调用完成
在CUDA SDK 中有异步API 的实例
cudaEvent_t start, stop;
cudaEventCreate(&start); cudaEventCreate(&stop);
cudaEventRecord(start, 0);
kernel<<<grid, block>>>(...);
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
float et;
cudaEventElapsedTime(&et, start, stop);
cudaEventDestroy(start); cudaEventDestroy(stop);
© NVIDIA Corporation 2006-2008
56
编译 CUDA
NVCC
C/C++ CUDA
Application
PTX to Target
Compiler
G80 … GPU
Target code
PTX Code Virtual
Physical
CPU Code
© NVIDIA Corporation 2006-2008
57
NVCC & PTX 虚拟机
EDG
区别GPU和CPU代码
Open64
产生 GPU PTX 汇编
Parallel Thread eXecution (PTX)
虚拟机和 ISA
编程模型
执行资源和状态
EDG
C/C++ CUDA
Application
CPU Code
Open64
PTX Code
ld.global.v4.f32 {$f1,$f3,$f5,$f7}, [$r9+0];mad.f32 $f1, $f5, $f3, $f1;
float4 me = gx[gtid];me.x += me.y * me.z;
© NVIDIA Corporation 2006-2008
58
编译
任何包含CUDA语言扩展的源文件都必须用nvcc编译
NVCC 是一个 编译器驱动程序调用所有必要的工具和编译器,如 cudacc, g++, cl, ...
NVCC 可以输出:
C 代码 (CPU代码)
然后必须用另一个工具编译程序的剩余部分
或 PTX 目标代码
CUDA代码的可执行文件需要:CUDA 核心库 (cuda)
CUDA 运行库 (cudart)
如果使用运行(runtime )API
装载 cuda 库
© NVIDIA Corporation 2006-2008
59
练习 3: 反转一个小数组
给定一个输入数组,反转它
在这部分, 你将反转一个小数组单个线程块的大小
© NVIDIA Corporation 2006-2008
60
练习 3: 反转一个大数组
给定一个大输入数组,反转它
这需要发射许多线程块
让我们开始
© NVIDIA Corporation 2006-2008
62
获得CUDA
CUDA Zone: http://nvidia.com/cuda
编程指南和其他文档
工具包和SDK::
Windows
Linux
MacOS
库
插件
论坛
代码范例
© NVIDIA Corporation 2006-2008
63
来参加课程!
UIUC ECE498AL – 大规模并行处理器编程(http://courses.ece.uiuc.edu/ece498/al/)
David Kirk (NVIDIA) 和 Wen-mei Hwu (UIUC) 共同讲授
CUDA 编程, GPU 计算, 实验练习和项目
讲稿和录音
© NVIDIA Corporation 2006-2008
64
问题?