CUDA By Example (1)
9148 단어 example
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include<conio.h>
#include <stdio.h>
__global__ void add(int a,int b,int *c){ //
*c=a+b;
}
int main(){
int c;
int *dev_c;
cudaMalloc((void**)&dev_c,sizeof(int)); // dev_c
add<<<1,1>>>(2,7,dev_c); // grid block, block thread kernel
cudaMemcpy(&c,dev_c,sizeof(int),cudaMemcpyDeviceToHost); // dev_c c
printf("2+7=%d",c);
cudaFree(dev_c); // dev_c
getche();
return 0;
}
뾰족괄호에는 두 개의 파라미터가 있는데, 첫 번째 파라미터는 장치가 핵 함수를 실행할 때 사용하는 병렬 블록 블록의 수량을 가리킨다.kernel <<<256,1>>>은 이 kernel을 실행하기 위해 Grid에 256개의 스레드 블록이 있다는 것을 의미합니다.BlockIdx를 사용할 수 있습니다.x로 라인 블록의 인덱스를 가져옵니다.CUDA는 2차원 스레드 블록 배열을 지원하여 행렬을 처리할 때나 도형을 처리할 때 매우 편리하다.스레드 블록 그룹을 시작할 때, 그룹의 매 비트는 65335를 초과할 수 없습니다.두 번째 파라미터는 모든 스레드 블록에서 실행되는 스레드의 수량을 표시합니다.스레드 블록의 병렬 스레드는 병렬 스레드 블록(block)이 할 수 없는 작업을 완성할 수 있습니다.스레드 블록의 스레드는threadIdx를 사용할 수 있습니다.색인
#ifndef _use_h
#define _use_h
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <conio.h>
#include <stdio.h>
#define N 100
__global__ void add(int *a,int *b,int *c);
#endif
#include "use.h"
__global__ void add(int *a,int *b,int *c){
//int tid=blockIdx.x; //tid i block
int tid=threadIdx.x; //tid i thread
if(tid<N)
c[tid]=a[tid]+b[tid];
}
#include "use.h"
int main(){
int a[N],b[N],c[N];
int *dev_a,*dev_b,*dev_c;
cudaMalloc((void**)&dev_a,N*sizeof(int));
cudaMalloc((void**)&dev_b,N*sizeof(int));
cudaMalloc((void**)&dev_c,N*sizeof(int));
//CPU a,b
for(int i=0;i<N;i++){
a[i]=-i;
b[i]=i*i;
}
// a,b GPU
cudaMemcpy(dev_a,a,N*sizeof(int),cudaMemcpyHostToDevice);
cudaMemcpy(dev_b,b,N*sizeof(int),cudaMemcpyHostToDevice);
//add<<<N,1>>>(dev_a,dev_b,dev_c); //N block, block add
add<<<1,N>>>(dev_a,dev_b,dev_c); //1 block, block N add
// c GPU CPU
cudaMemcpy(c,dev_c,N*sizeof(int),cudaMemcpyDeviceToHost);
for(int i=0;i<N;i++){
printf("%d+%d=%d
",a[i],b[i],c[i]);
}
// GPU
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
getche();
}
gridDim을 사용할 수 있습니다.x는 grid당 몇 개의 Block을 가져옵니다. BlockDim을 사용하십시오.Block마다 thread가 얼마나 있는지 가져오십시오.이 두 수는 라인 포지셔닝에 매우 유용하다.상기 벡터를 더하면 스레드 수량과 하드웨어의 일부 제한을 고려하지 않았다. 예를 들어 스레드 칸은 한 명당 65535를 초과하지 않는다.다음과 같이 향상되었습니다.
#include "use.h"
__global__ void add(int *a,int *b,int *c){
int tid=blockIdx.x*blockDim.x+threadIdx.x; // i block i*blockDim ,tid
while(tid<N){
c[tid]=a[tid]+b[tid];
tid+=blockDim.x*gridDim.x; // N , i (i+k* )
}
}
#include "use.h"
int main(){
int a[N],b[N],c[N];
int *dev_a,*dev_b,*dev_c;
//GPU
cudaMalloc((void**)&dev_a,N*sizeof(int));
cudaMalloc((void**)&dev_b,N*sizeof(int));
cudaMalloc((void**)&dev_c,N*sizeof(int));
//CPU a,b
for(int i=0;i<N;i++){
a[i]=i;
b[i]=i*i;
}
// a,b GPU
cudaMemcpy(dev_a,a,N*sizeof(int),cudaMemcpyHostToDevice);
cudaMemcpy(dev_b,b,N*sizeof(int),cudaMemcpyHostToDevice);
add<<<128,128>>>(dev_a,dev_b,dev_c); //128 block, block 128 add, 16384, N 1/3
// c GPU CPU
cudaMemcpy(c,dev_c,N*sizeof(int),cudaMemcpyDeviceToHost);
int success=1;
for(int i=0;i<N;i++){
//printf("%d+%d=%d
",a[i],b[i],c[i]);
if(a[i]+b[i]!=c[i])
{success=0;break;}
}
if(success==1)
printf("sucess
");
else
printf("failure
");
// GPU
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
getche();
}
키워드share__변수 성명에 사용되며 공유 메모리에 변수를 주재할 수 있습니다.CUDA C는 공유 변수를 일반 변수와 다르게 처리합니다.공유 메모리의 변수에 대해 컴파일러는 그 부본을 만들 것입니다. 이 Block의 모든thread는 이 부본을 공유합니다. (다른 Block의 루트는 접근할 수 없습니다.) 공유 메모리 버퍼가 물리적 GPU에 주재하도록 합니다.공유 메모리에 접근하는 지연은 일반 버퍼에 접근하는 지연보다 훨씬 낮다.그러나 라인 간의 통신은 동기화 메커니즘을 실현해야 한다.
동기화 메커니즘용syncthreads () 로 실행합니다.코드에서 만약 이 함수를 사용한다면, 모든 라인이 이 함수를 실행한 후에야 나머지 부분을 더 실행할 수 있다.
다음 예는 두 벡터의 내적을 계산하는 것입니다.
#ifndef _use_h
#define _use_h
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "device_functions.h"
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#define imin(a,b) (a<b?a:b)
const int N=33*1024;
const int threadPerBlock=256;
const int blockPerGrid=imin(32,(N+threadPerBlock-1) / threadPerBlock);
__global__ void dot(float *a,float *b,float *c);
#endif
#include "use.h"
__global__ void dot(float *a,float *b,float *c){
__shared__ float cache[threadPerBlock]; // , a[i]*b[i] , block
int tid=threadIdx.x+blockIdx.x*blockDim.x; // grid
int cacheIndex=threadIdx.x; //block
float temp=0;
while(tid<N){
temp+=a[tid]*b[tid]; //
tid+=blockDim.x*gridDim.x; //tid
}
cache[cacheIndex]=temp; // block chace
__syncthreads(); // ,
int i=blockDim.x/2;
while(i!=0){
if(cacheIndex<i)
cache[cacheIndex]+=cache[cacheIndex+i];
__syncthreads(); //cache[0] cache[i]
i=i/2;
}
if(cacheIndex==0)
c[blockIdx.x]=cache[0];
}
#include "use.h"
int main(){
float *a,*b,c,*partial_c; //a,b ,c ,partial_c grid block ,
//partial_c[i] i block
float *dev_a,*dev_b,*dev_partial_c;
// CPU
a=(float*)malloc(N*sizeof(float));
b=(float*)malloc(N*sizeof(float));
partial_c=(float*)malloc(blockPerGrid*sizeof(float));
// GPU
cudaMalloc((void**)&dev_a,N*sizeof(float));
cudaMalloc((void**)&dev_b,N*sizeof(float));
cudaMalloc((void**)&dev_partial_c,blockPerGrid*sizeof(float));
//
for(int i=0;i<N;i++){
a[i]=i;
b[i]=i*2;
}
// a,b GPU
cudaMemcpy(dev_a,a,N*sizeof(float),cudaMemcpyHostToDevice);
cudaMemcpy(dev_b,b,N*sizeof(float),cudaMemcpyHostToDevice);
dot<<<blockPerGrid,threadPerBlock>>>(dev_a,dev_b,dev_partial_c);
// partial_c HOST , HOST
cudaMemcpy(partial_c,dev_partial_c,blockPerGrid*sizeof(float),cudaMemcpyDeviceToHost);
c=0;
for(int i=0;i<blockPerGrid;i++){
c+=partial_c[i];
}
#define sum_squares(x) (x*(x+1)*(2*x+1)/6)
printf("Does GPU value %.6g=%.6g?
",c,2*sum_squares((float)(N-1)));
// GPU
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_partial_c);
free(a);
free(b);
free(partial_c);
getche();
}
이 구내적 과정 중 추상적으로는 하나의 입력 수조에 대해 어떤 계산을 한 다음에 더욱 작은 결과 수조를 생성하고 이 과정도 귀약(reduction)이 된다.귀약을 실현하는 가장 간단한 방법은 공유 메모리에서 하나의 라인을 교체하여 총화 값을 계산하는 것이다.
코드 중;
int i=blockDim.x/2;
while(i!=0){
if(cacheIndex<i)
cache[cacheIndex]+=cache[cacheIndex+i];
__syncthreads();
i=i/2;
}
여기서는 일부 스레드만 작동하고 나머지 스레드는 항상syncthreads 기다림은 다음과 같은 최적화가 있을 수 있습니다. 즉, 일을 하지 않는 라인을 기다림이 아니라 끝까지 계속 실행하도록 하는 것입니다. 그러면 효율이 좀 높을 수도 있습니다.int i=blockDim.x/2;
while(i!=0){
if(cacheIndex<i){
cache[cacheIndex]+=cache[cacheIndex+i];
__syncthreads();
}
i=i/2;
}
하지만, 이것은 일할 수 없습니다. 왜냐하면syncthreads는 모든 스레드가 여기까지 실행되어야만 스레드가 다음 작업을 진행할 수 있지만, 일부 스레드는 영원히 실행되지 않습니다syncthreads (), 이렇게 하면 프로그램이 끝없이 기다릴 수 있습니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
간단한 Golang HTTP 서버 예제Go에서 HTTP 서버를 만드는 것은 다음과 같이 간단합니다. http.ListenAndServe(":8222", nil) 여기서 우리는 머신의 8222 포트에서 요청을 수신하는 간단한 서버를 만들었습니다. 이것은 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.