thrust快速入门指南
Introduction
Thrust是基于标准模板库(STL)的并行平台的C ++模板库。Thrust允许您通过高级接口以最少的编程工作实现高性能并行应用程序,该接口可与C ++,CUDA,OpenMP和TBB等技术完全互操作。
Thrust提供了丰富的数据并行原语集合,例如扫描,排序和缩减,它们可以组合在一起,通过简洁易读的源代码实现复杂的算法。通过根据这些高级抽象描述您的计算,您可以为Thrust提供自动选择最有效实现的自由。因此,Thrust可用于CUDA应用程序的快速原型设计,其中程序员生产力最重要,而且在生产中,稳健性和绝对性能至关重要。
本文档描述了如何使用Thrust开发并行应用程序。即使您具有有限的C ++或并行编程经验,也可以访问本教程。
Prerequisites
Thrust v1.6.0与CUDA 4.1(首选)和CUDA 4.0兼容。您可以通过nvcc --version在命令行上运行来确认已安装CUDA 。例如,在Linux系统上,
$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2011 NVIDIA Corporation
Built on Thu_Jan_12_14:41:45_PST_2012
Cuda compilation tools, release 4.1, V0.2.1221
如果您使用的是CUDA 4.0或更高版本,那么您的系统上已经安装了Thrust,您可以安全地跳到下一部分。
由于Thrust是一个C ++模板库,因此无需“构建”。只需从下载部分下载最新版本,然后将zip文件的内容解压缩到一个目录中。我们建议将Thrust安装到CUDA include目录中,这通常是
/usr/local/cuda/include/ 在Linux和Mac OSX上
C:\CUDA\include\ 在Windows系统上
如果您无法将Thrust安装到CUDA include目录,那么您可以将Thrust放在主目录中的某个位置,例如:/home/nathan/libraries/。
警告:不要将Thrust安装到标准包含路径之类的/usr/local/include/。似乎nvcc对这些路径的处理方式不同于上面的建议,这会导致错误error: expected primary-expression before ‘<’ token.
Simple Example
让我们用Thrust编译一个简单的程序,以确保满足所有先决条件。将以下源代码保存到名为的文件中version.cu。
#include <thrust/version.h>
#include <iostream>
int main(void)
{
int major = THRUST_MAJOR_VERSION;
int minor = THRUST_MINOR_VERSION;
std::cout << "Thrust v" << major << "." << minor << std::endl;
return 0;
}
现在编译version.cu带nvcc。如果将Thrust安装到CUDA include目录,那么以下命令应该可以正常工作。
$ ls
thrust version.cu
$ nvcc version.cu -o version
$ ls
thrust version version.cu
$ ./version
Thrust v1.6
如果Thrust 目录放在其他地方,请使用该-I选项告知nvcc要查看的位置。例如,如果放入推力,/home/nathan/libraries/则应使用以下命令。
$ nvcc version.cu -o version -I /home/nathan/libraries/
Vectors
Thrust提供两个矢量容器,host_vector和device_vector。顾名思义,host_vector存储在CPU的系统或“主机”内存中,同时device_vector存在于GPU的“设备”内存中。Thrust的向量容器就像std::vector在C ++标准库中一样。喜欢std::vector,host_vector并且device_vector是可以动态调整大小的通用容器(能够存储任何数据类型)。以下源代码说明了Thrust的向量容器的使用。
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <iostream>
int main(void)
{
// H has storage for 4 integers
thrust::host_vector<int> H(4);
// initialize individual elements
H[0] = 14;
H[1] = 20;
H[2] = 38;
H[3] = 46;
// H.size() returns the size of vector H
std::cout << "H has size " << H.size() << std::endl;
// print contents of H
for(int i = 0; i < H.size(); i++)
{
std::cout << "H[" << i << "] = " << H[i] << std::endl;
}
// resize H
H.resize(2);
std::cout << "H now has size " << H.size() << std::endl;
// Copy host_vector H to device_vector D
thrust::device_vector<int> D = H;
// elements of D can be modified
D[0] = 99;
D[1] = 88;
// print contents of D
for(int i = 0; i < D.size(); i++)
{
std::cout << "D[" << i << "] = " << D[i] << std::endl;
}
// H and D are automatically destroyed when the function returns
return 0;
}
如此示例所示,=操作员可用于将a复制host_vector到a device_vector(反之亦然)。该=运营商还可以用来复制host_vector到host_vector或device_vector到device_vector。另请注意,device_vector可以使用标准括号表示法访问a的各个元素。但是,因为这些访问中的每一个都需要调用cudaMemcpy,所以应该谨慎使用它们。稍后我们将介绍一些更有效的技术。
将向量的所有元素初始化为特定值或仅将一组值从一个向量复制到另一个向量通常很有用。Thrust提供了一些方法来执行这些操作。
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <thrust/fill.h>
#include <thrust/sequence.h>
#include <iostream>
int main(void)
{
// initialize all ten integers of a device_vector to 1
thrust::device_vector<int> D(10, 1);
// set the first seven elements of a vector to 9
thrust::fill(D.begin(), D.begin() + 7, 9);
// initialize a host_vector with the first five elements of D
thrust::host_vector<int> H(D.begin(), D.begin() + 5);
// set the elements of H to 0, 1, 2, 3, ...
thrust::sequence(H.begin(), H.end());
// copy all of H back to the beginning of D
thrust::copy(H.begin(), H.end(), D.begin());
// print D
for(int i =