So, let's take a closer look at the code, line by line,
so we can all be sure we know what each call does.
We're going to walk through the CPU code first.
The first thing we're going to do is declare the size of the array and determine how many bytes it uses.
We then fill it up in this loop with floating point numbers,
where array element i is simply set to i.
All of this is standard C, nothing GPU-specific so far.
One thing to note, though, is a common Cuda convention.
Data on the CPU, the host, starts with h underscore. Data on the GPU, the device, starts with d underscore.
This is just a convention. You can name your variables anything you want.
But naming variables in this way helps you avoid the single most common beginner
error in Cuda, where you try to access a piece of data on the CPU from the GPU, or vice versa.
If you're accessing data through a pointer on the CPU,
your pointer better point to something in CPU memory, or you're going to have a bad time.
Same thing for the GPU. You'll find lots of Cuda code that you see uses this convention.
So, let's scroll up just a little bit.
And the first interesting thing that you see is how to declare a pointer on the GPU.
It looks just like a pointer declared on the CPU. It's just a float star.
Now to tell Cuda that your data is actually on the GPU, not the CPU, look at the next 2 lines.
We're using cudaMalloc with 2 arguments, the pointer and the number of bytes to allocate.
CudaMalloc means allocate the data on the GPU,
whereas a plain Malloc would mean allocate the data on the CPU.
The next thing we do is actually copy the data from the CPU,
the array h underscore in on to the GPU, the array d underscore in.
This call is cudamMemcpy--it's just like a regular Memcpy, but it takes
4 arguments instead of 3. The first 3 arguments are the same as
regular C Memcpy, the destination, the source, and the number of bytes.
The fourth argument says the direction of the transfer.
The 3 choices are Cuda memory host to device, Cuda memory device to host,
and Cuda memory device to device.
Теперь детально рассмотри код, строку за строкой,
чтобы уверенно знать, что делает каждый вызов.
Сперва пройдемся по CPU коду.
И первое, мы делаем это объявляем размер массива и определяем как много байтов он использует.
Затем заполняем его в этом цикле числами с плавающей запятой,
просто задавая i-й элемент массива как i.
Все это стандартный C, ничего специфичного для GPU нет.
Хотя отметим одну вещь, это общая договоренность в CUDA.
Данные CPU, host'а, начинаются с "h_". Данные GPU - с "d_".
Это просто договоренность. Вы можете именовать свои переменные как хотете.
Но именование переменных таким образом, помогает избежать самой распространенной ошибки новичков
в CUDA, когда вы попытаетесь доступиться до данных на CPU из GPU или наоборот.
Если вы доступитесь в данным через указатель на CPU,
ваш указатель будет указывать на что-то в CPU, или получите ошибку.
Тоже самое на GPU. Вы найдете много кода который использует эту договоренность.
Прокрутим немного выше.
И первая интересная вещь, что вы видите это как объявляется указатель на GPU.
Он выглядит также как указатель на CPU. Это просто flaot*.
Теперь говорим CUDA что ваши данные на самом деле на GPU не на CPU, посмотрите на следующие две линии.
Мы используем cudaMalloc с двумя аргументами, указателем и количеством байт для аллоцирования.
cudaMalloc означает аллоцирование данных на GPU,
тогда как просто malloc означает аллоцирование памяти на CPU.
Следующее что происходит это копирование данных с CPU,
массива с "h_", на GPU в массив с "d_".
Это cudaMemcpy - как стандартная memcpy, но она принимает
4 аргумента вместо 3. Первые два аргумента такие же как в
стандартном memcpy: назначение, источник и кол-во байт.
Четвертый аргумент задает напавление передачи.
Есть 3 варианта c host'а на device, с devic'а на host
и с devic'а на device.
让我们一行一行地仔细看一下代码,
所以我们能肯定我们知道每个调用的作用。
我们首先看一遍CPU代码。
我们要做的第一件事是声明数组大小,决定它用多少字节。
然后我们用浮点数填充这个循环,
其中数组元素 i 简单地设为 i。
所有这些都是标准的C语言,目前还没有GPU特定的内容。
不过,值得注意的一点是一个常用的CUDA约定。
主机CPU上的数据以h_ 开头,
设备GPU上的数据以d _ 开头。
这只是一个约定,你可以对你的变量任意命名。
但以这个方式对变量进行命名有助于
避免CUDA中初学者最常犯的错误,
在其中你试图从GPU访问CPU上的数据,反之亦然。
如果你通过CPU上的指针访问数据,
你的指针最好指向CPU内存中某位置,不然你将遇到困难。
对GPU也是如此。你会发现你看到的很多CUDA代码都用这约定。
让我们向上滚动一点。
你看到的第一样有趣的东西是如何在GPU声明指针。
这看起来就像在CPU上声明指针,就是一个float *。
现在要告诉CUDA你的数据实际在GPU上,
而不在CPU上,看下面两行。
我们用带两个参数的cudaMalloc,指针和分配的字节数。
CudaMalloc意思是分配GPU上的数据,
而普通的Malloc意思是分配CPU上的数据。
我们接下来做的是从CPU数组h_in
复制数据到GPU的数组d_in。
这个调用是cudaMemcpy,它就像普通的Memcpy,
但它有四个参数,而不是3个。前3个参数与
普通C Memcpy一样,目标地址、源地址和字节。
第4个参数是转移方向。
3个选项是CUDA内存主机到设备、CUDA内存设备到主机以及
CUDA内存设备到设备。