我正在进行GPU编程以完成一些模拟工作,我一直在学习本教程:
http://www.drdobbs.com/parallel/cuda-supercomputing-for-the-masses-part/208401741
但是,我的术语很混乱,访问nVidia的文档让我更加困惑.
这些术语:流式多处理器,线程,warp,块,网格,占用,着色器
我压倒了一点点.
这是我非常粗略的理解:
GPU被分成多处理器(可能就像其中的2个).每个多处理器都被分成warp,warp被分成块,这些块被分成线程.我不知道......我希望我有一张图.有人可以帮帮我吗?
编辑:让我解释为什么我问这个.假设我试图找出"扭曲"是什么.我谷歌"CUDA扭曲".首先出现的是http://developer.download.nvidia.com/CUDA/training/cuda_webinars_WarpsAndOccupancy.pdf.所以我向下滚动它说:
网格由完全独立的块组成
好的,我明白了.
块由可以在它们自己的块内通信的线程组成
好的...
32个线程形成一个扭曲
现在我迷路了.32个线程形成扭曲?所有线程都必须在同一个块中吗?为什么我们任意将32个线程标记为"warp"?我可以将12个线程称为"书包"吗?因此,如果一个块可以容纳20个线程,这是否意味着我需要2个块来包含warp?你可以看到我的困惑来自哪里.我查看的所有内容都取决于了解其他术语,所以有点像通过阅读字典来学习一门语言 - 这都是循环的.
我想运行一个cuda程序,但我是初学者.我必须为直方图编写一个程序.但是用水桶.根据maxValue(示例中为40),该数字将添加到相应的存储桶中.如果我们有4个桶:
histo:| 1 | 10 | 30 | 39 | 32 | 2 | 4 | 5 | 1 |
0-9(第1桶)
10-19(第2桶)
20-29(第3桶)
30-39(第4桶)
我的GPU具有计算能力1.1.
我试图做一个像块一样的临时temp [],每个线程都在他的临时表上添加他的值:
__global__ void histo_kernel_optimized5( unsigned char *buffer, long size,
unsigned int *histo )
{
extern __shared__ unsigned int temp[];
temp[threadIdx.x] = 0;
__syncthreads();
int i = threadIdx.x + blockIdx.x * blockDim.x;
int offset = blockDim.x * gridDim.x;
int bucketID;
while (i < size)
{
bucketID = array[i]/Bwidth;
atomicAdd( &temp[bucketID], 1);
i += offset; …Run Code Online (Sandbox Code Playgroud) 我正在做一些测试,我意识到在编译时使用-G参数会给我一个糟糕的表现,而不是没有它.
我查看了Nvidia的文档:
--device-debug (-G)
Generate debug information for device code.
Run Code Online (Sandbox Code Playgroud)
但它并没有帮助我知道为什么给我这么糟糕的表现.它在哪里产生这个调试信息?何时?这可能是造成这种糟糕表现的原因?
换句话说,是否有任何GPU不支持OpenGL,而是支持其他图形渲染库,如DirectX,OpenCl.
我希望计算我的cuda代码的两个不同部分的执行时间。为了做到这一点,我试图用CudaEvent_t启动,停止。 我的问题是,是否可以在其他部分中使用相同的两个事件“开始”和“停止”来计算执行时间?
例如:
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
// SECTION 1
cudaEventRecord(start, 0);
cudaMemcpy(..., ..., ..., cudaMemcpyHostToDevice);
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&executionTime, start, stop);
printf("SECTION 1 executionTime: %f", executionTime);
// SECTION 1
// SECTION 2
cudaEventRecord(start, 0); // Reusing start event
cudaMemcpy(..., ..., ..., cudaMemcpyDeviceToHost);
cudaEventRecord(stop, 0); // Reusing stop event
cudaEventSynchronize(stop);
cudaEventElapsedTime(&executionTime, start, stop);
printf("SECTION 2 executionTime: %f", executionTime);
// SECTION 2
Run Code Online (Sandbox Code Playgroud)
由于我正在尝试重新启动cudaEvent_t start,也为第2部分停止,因此这段代码会为第1部分和第2部分的执行时间给出准确的估计吗?还是我需要为第二部分创建两个附加事件start1和stop1?
我必须在GPU中实现以下算法
for(int I = 0; I < 1000; I++){
VAR1[I+1] = VAR1[I] + VAR2[2*K+(I-1)];//K is a constant
}
Run Code Online (Sandbox Code Playgroud)
每次迭代都依赖于先前的,因此并行化很困难.我不确定原子操作在这里是否有效.我能做什么?
编辑:
的VAR1和VAR2都是一维数组.
VAR1[0] = 1
Run Code Online (Sandbox Code Playgroud) 我使用了CUDA Binary Utilities之一cuobjdump来生成SASS代码,示例结果如下。这些代码尝试从全局内存加载。
/*0028*/ IMAD R6.CC, R3, R5, c[0x0][0x20];
/*0030*/ IMAD.HI.X R7, R3, R5, c[0x0][0x24];
/*0040*/ LD.E R2, [R6]; //load
Run Code Online (Sandbox Code Playgroud)
我在哪里可以获得解释每个指令含义的SASS代码的完整手册。在“ cuda二进制实用程序”中,它仅提供指令含义的一般说明。例如,它没有解释“ R1.cc”,“ IMAD.HI.X”和LD.e的含义。
第二条指令的含义是什么。我猜第一个是计算每个线程应该加载的内存地址,而第三个指令是将全局内存加载到寄存器中。我对第二条指令的含义一无所知。
我猜cuda将一些参数信息(例如网格大小,块大小和数组基地址)保存到常量内存中。在这种情况下,c [0x0] [0x20]是数组的基地址。我的问题是我如何获得这些信息。
我需要计算复数的两个向量(Hadamard乘积)的元素明智乘法与NVidia CUBLAS.不幸的是,CUBLAS中没有HAD操作.显然,您可以使用SBMV操作执行此操作,但它不适用于CUBLAS中的复数.我无法相信没有办法用CUBLAS实现这一目标.对于复杂的数字,有没有其他方法可以实现CUBLAS?
我不能编写自己的内核,我必须使用CUBLAS(或其他标准的NVIDIA库,如果CUBLAS真的不可能).
我正在使用https://github.com/chiphuyen/stanford-tensorflow-tutorials/blob/master/examples/04_word2vec_no_frills.py中的代码试验word2vec
但是,它很容易耗尽我所有的GPU内存,不知道为什么?
with tf.name_scope('data'):
center_words = tf.placeholder(tf.int32, shape=[BATCH_SIZE], name='center_words')
target_words = tf.placeholder(tf.int32, shape=[BATCH_SIZE, 1], name='target_words')
with tf.name_scope("embedding_matrix"):
embed_matrix = tf.Variable(tf.random_uniform([VOCAB_SIZE, EMBED_SIZE], -1.0, 1.0), name="embed_matrix")
with tf.name_scope("loss"):
embed = tf.nn.embedding_lookup(embed_matrix, center_words, name="embed")
nce_weight = tf.Variable(tf.truncated_normal([VOCAB_SIZE, EMBED_SIZE], stddev=1.0/(EMBED_SIZE ** 0.5)), name="nce_weight")
nce_bias = tf.Variable(tf.zeros([VOCAB_SIZE]), name="nce_bias")
loss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weight, biases=nce_bias, labels=target_words, inputs=embed, num_sampled=NUM_SAMPLED, num_classes=VOCAB_SIZE), name="loss")
optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(loss)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
total_loss = 0.0 # we use this to calculate the average loss in the last SKIP_STEP steps
writer …Run Code Online (Sandbox Code Playgroud) 在读取GPU的存储层次时,我会看到一些类似的术语,并且由于在过去的版本中进行了一些体系结构修改,因此我不知道它们可以一起使用还是具有不同的含义。设备是M2000,计算兼容性为5.2。
顶层(最接近管道)是统一的L1 /纹理缓存,每个SM为24KB。难道是统一的指令和数据呢?
在此之下,是L2缓存,也称为共享内存,由所有SM共享。根据./deviceQuery,L2大小为768KB。如果这是合计值,则每个SM具有768KB / 6 = 128KB。但是,根据编程指南,共享内存为96KB。
那么什么是恒定内存,它驻留在哪里?在deviceQuery和nvprof指标中都没有有关其大小的信息。编程指南说:
所有线程还可以访问两个附加的只读存储空间:常量存储空间和纹理存储空间。全局,常量和纹理内存空间针对不同的内存使用进行了优化(请参阅设备内存访问)。纹理存储器还为某些特定的数据格式提供了不同的寻址模式以及数据过滤(请参见纹理和表面存储器)。
全局,常量和纹理存储空间在同一应用程序的内核启动之间是持久的。
L2下面是全局内存,称为设备内存,可以是2GB,4GB和...