【问题标题】:Cuda hello world exampleCuda hello world 示例
【发布时间】:2016-01-12 17:02:54
【问题描述】:

我试图理解 hello world CUDA 示例中的一个简单添加。 我有两个数组:

char a[N] = "Hello \0\0\0\0\0\0";
int b[N] = {15, 10, 6, 0, -11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

网格和块的维度是 1 和 16。 当您执行此操作时,我真的不明白:

a[threadIdx.x] += b[threadIdx.x];

你会得到“Hello World!”。 这是 CUDA 中的经典介绍性示例,并行性背后的逻辑很容易理解,但是这个总和......我真的不明白。 获取完整源代码

#include <stdio.h>

const int N = 16; 
const int blocksize = 16; 

__global__ 
void hello(char *a, int *b) 
{
    a[threadIdx.x] += b[threadIdx.x];
}

int main()
{
    char a[N] = "Hello \0\0\0\0\0\0";
    int b[N] = {15, 10, 6, 0, -11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

    char *ad;
    int *bd;
    const int csize = N*sizeof(char);
    const int isize = N*sizeof(int);

    printf("%s", a);

    cudaMalloc( (void**)&ad, csize ); 
    cudaMalloc( (void**)&bd, isize ); 
    cudaMemcpy( ad, a, csize, cudaMemcpyHostToDevice ); 
    cudaMemcpy( bd, b, isize, cudaMemcpyHostToDevice ); 

    dim3 dimBlock( blocksize, 1 );
    dim3 dimGrid( 1, 1 );
    hello<<<dimGrid, dimBlock>>>(ad, bd);
    cudaMemcpy( a, ad, csize, cudaMemcpyDeviceToHost ); 
    cudaFree( ad );
    cudaFree( bd );

    printf("%s\n", a);
    sleep(1);
    return EXIT_SUCCESS;
}

【问题讨论】:

  • 我已经添加了完整的代码。不鼓励链接到代码,因为链接往往会中断,一旦发生这种情况,问题(和答案)对很多人来说就毫无用处了
  • 你是对的。谢谢。
  • 只是好奇,但在标准 C 中,您可以省略两个数组(ab)末尾的 0'\0' 值,因为 a 的其余元素默认情况下,堆栈数组将初始化为 0。看起来该示例有意手动初始化所​​有索引。这是因为 CUDA C 完全符合标准,还是只是为了明确两个数组的大小相等或其他原因
  • 我不确定,因为 NVIDIA C 编译器然后将代码拆分为使用常规 c 编译器编译的主机代码(CPU)和使用 NVIDIA 汇编器等的设备代码。但是由于这段代码将要使用 c 标准编译器,我想说这只是为了说清楚。对不起,如果我不能更好地帮助你。

标签: c cuda parallel-processing


【解决方案1】:

再看一遍示例代码:

printf("%s", a);

这将打印 "Hello ",这是您在粘贴的行中分配给 a 的值。然后,代码迭代两个数组并使用b 值递增每个a 值(char 是一种算术类型)。所以你得到的是:

'H' + 15 = W
'e' + 10 = o
'l' + 6  = r
'l' + 0  = l
'0' - 11 = d
' ' + 1  = !

在所有的 cuda 东西之后,有这个简单的声明:

printf("%s\n", a);

a 现在更改的值打印到标准输出:“World!”。将两者放在一起,您会得到“Hello World!”

至于threadIdx的使用,就是保存线程ID的变量more details here

包含您不确定的增量语句的函数是这样调用的:

hello<<<dimGrid, dimBlock>>>(ad, bd);

使用dim3 dimGrid( 1, 1 );dim3 dimBlock( blocksize, 1 );blocksizeconst int blocksize = 16(与 N 的值相同。

简而言之,您基本上是在 16 个不同的线程上调用 hello 16 次,并且每个线程都使用其 唯一 id 作为偏移量。因为块大小等于数组大小,所以您永远不会访问越界内存。

当然,这是假设您使用的是 ASCII,在这种情况下,您可以使用 b 的值来形成您喜欢的任何单词:

字符 十二月 十月 十六进制 |字符 十二月 十月 十六进制 |字符 十二月 十月 十六进制 |字符 十二月 十月 十六进制 -------------------------------------------------- ---------------------------------- (无) 0 0000 0x00 | (sp) 32 0040 0x20 | @ 64 0100 0x40 | ` 96 0140 0x60 (苏)1 0001 0x01 | ! 33 0041 0x21 | 65 0101 0x41 | 97 0141 0x61 (stx) 2 0002 0x02 | " 34 0042 0x22 | B 66 0102 0x42 | b 98 0142 0x62 (etx) 3 0003 0x03 | # 35 0043 0x23 | C 67 0103 0x43 | c 99 0143 0x63 (eot) 4 0004 0x04 | $ 36 0044 0x24 | D 68 0104 0x44 | d 100 0144 0x64 (enq) 5 0005 0x05 | % 37 0045 0x25 | E 69 0105 0x45 | e 101 0145 0x65 (确认)6 0006 0x06 | & 38 0046 0x26 | F 70 0106 0x46 | f 102 0146 0x66 (贝尔)7 0007 0x07 | ' 39 0047 0x27 | G 71 0107 0x47 | g 103 0147 0x67 (bs) 8 0010 0x08 | ( 40 0050 0x28 | H 72 0110 0x48 | H 104 0150 0x68 (ht) 9 0011 0x09 | ) 41 0051 0x29 |我 73 0111 0x49 |我 105 0151 0x69 (nl) 10 0012 0x0a | * 42 0052 0x2a | J 74 0112 0x4a | j 106 0152 0x6a (vt) 11 0013 0x0b | + 43 0053 0x2b | K 75 0113 0x4b | k 107 0153 0x6b (np) 12 0014 0x0c | , 44 0054 0x2c | L 76 0114 0x4c | l 108 0154 0x6c (cr) 13 0015 0x0d | - 45 0055 0x2d | M 77 0115 0x4d |米 109 0155 0x6d (所以)14 0016 0x0e | . 46 0056 0x2e | N 78 0116 0x4e | n 110 0156 0x6e (si) 15 0017 0x0f | / 47 0057 0x2f | O 79 0117 0x4f | o 111 0157 0x6f (空)16 0020 0x10 | 0 48 0060 0x30 | P 80 0120 0x50 |电话 112 0160 0x70 (dc1) 17 0021 0x11 | 1 49 0061 0x31 | Q 81 0121 0x51 | q 113 0161 0x71 (dc2) 18 0022 0x12 | 2 50 0062 0x32 | R 82 0122 0x52 | r 114 0162 0x72 (dc3) 19 0023 0x13 | 3 51 0063 0x33 | S 83 0123 0x53 | 115 0163 0x73 (dc4) 20 0024 0x14 | 4 52 0064 0x34 |电话 84 0124 0x54 | t 116 0164 0x74 (nak) 21 0025 0x15 | 5 53 0065 0x35 | U 85 0125 0x55 |你 117 0165 0x75 (同步)22 0026 0x16 | 6 54 0066 0x36 | V 86 0126 0x56 | v 118 0166 0x76 (等)23 0027 0x17 | 7 55 0067 0x37 | W 87 0127 0x57 | w 119 0167 0x77 (罐头)24 0030 0x18 | 8 56 0070 0x38 | X 88 0130 0x58 | x 120 0170 0x78 (em) 25 0031 0x19 | 9 57 0071 0x39 |是的 89 0131 0x59 |是 121 0171 0x79 (子)26 0032 0x1a | : 58 0072 0x3a | Z 90 0132 0x5a | z 122 0172 0x7a (esc) 27 0033 0x1b | ; 59 0073 0x3b | [ 91 0133 0x5b | { 123 0173 0x7b (fs) 28 0034 0x1c | 62 0076 0x3e | ^ 94 0136 0x5e | ~ 126 0176 0x7e (我们) 31 0037 0x1f | ? 63 0077 0x3f | _ 95 0137 0x5f | (删除)127 0177 0x7f

如果您使用的是 EBCDIC 字符编码,请查找您正在处理的任何变体的等效表并从那里获取。

【讨论】:

  • 你好>>(ad, bd); 这个是不是超载了?
  • 是的,这就是我的猜测,但我问的是“H”加 15 为何是“W”。我的意思是,如果您将“H”相加并在 abecedary 中前进 15 位,您将得到 W。但我的问题是这个加法的类型是什么,或者计算机如何在内部对此求和。例如,这是 ASCII 吗?对不起,如果我远离正确,或者到底发生了什么?感谢您的回答。
  • @2501:这是一个语言扩展,also documented here。我也在答案中添加了一些有关该位的基本信息
猜你喜欢
  • 2012-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2013-07-31
  • 1970-01-01
相关资源
最近更新 更多