Archive for the ‘GPU関連’
Published
10月 19th, 2007
in
学会関連, GPU関連 |
コメント(0) »
〆切は来週です.まだ全然書き終わってません.
いつもどおりの6P論文のつもりで書いていたら,実は参加するセッションが4P程度のShortPaperを要求していることに気がついた件について.
直前じゃなくて良かった.頑張って書き上げるぞ.
……研究室で寝てから.今週末は必死だな.
Published
9月 11th, 2007
in
GPU関連 |
コメント(0) »
東大小柴ホールを満席にして(むしろ溢れてる)講演中。
tgbtの人は英語を聞き取る能力がカスですが、前提知識があるのでなんとかって感じ? っつーか新しいことはあまり言ってないしな。
あどえすのカメラ機能はズームがへたれなので氏の写真を貼れない。デジカメとつなげる環境を構築しておくか……。
Published
9月 8th, 2007
in
GPU関連 |
コメント(0) »
CUDA:
__device__ int flags[2]={0,0};
こういう書き方が出来るのはわかっている。
ここで、配列の長さに#defineした値なんかを使っていると困る。具体的には
なんて場合。
というわけで、とりあえず__device__メモリの確保と初期化について少しコードを書いてみた。
CODE:
// 値の設定方法
// 1:cudaMemcpyを利用する
// 2:cudaMemsetを利用する
#define TESTVERSION 1
#define N 128
// __device__変数のポインタををextern宣言しておく。
// __global__関数経由で実体(Mallocされたメモリ)と関連付ける。
// この方法で__global__関数以外の関数(__device__関数)からも
// bufを利用することが可能になる。
extern __device__ int* buf;
__global__ void gpu
(int *mem0, int *_buf)
{
int i;
buf = _buf;
for(i=0; i<N; i++){
mem0[i] = buf[i];
}
}
void
runTest(int argc, char** argv)
{
CUT_DEVICE_INIT();
// メモリ確保
int* h_mem0;
int* d_mem0;
h_mem0 = (int*)malloc(sizeof(int)*N);
CUDA_SAFE_CALL(cudaMalloc((void**)&d_mem0, sizeof(int)*N));
// 値を入れる必要性が無いのでコメントアウト
//CUDA_SAFE_CALL(cudaMemcpy(d_mem0, h_mem0, sizeof(int)*N, cudaMemcpyHostToDevice) );
// __device__メモリ(buf)の確保と初期化
int* h_buf=NULL;
int* d_buf=NULL;
// その1:cudaMemcpyを利用する
#if TESTVERSION == 1
CUDA_SAFE_CALL(cudaMallocHost((void**)&h_buf, sizeof(int)*N)); // 普通にmallocしてもOK
CUDA_SAFE_CALL(cudaMalloc((void**)&d_buf, sizeof(int)*N));
// 値のセット
int n;
for(n=0; n<N; n++){
h_buf[n] = n;
}
// データのセット
CUDA_SAFE_CALL(cudaMemcpy(d_buf, h_buf, sizeof(int)*N, cudaMemcpyHostToDevice) );
#endif
// その2:cudaMemsetを利用する
#if TESTVERSION == 2
CUDA_SAFE_CALL(cudaMalloc((void**)&d_buf, sizeof(int)*N));
CUDA_SAFE_CALL(cudaMemset(d_buf,0,sizeof(int)*N));
#endif
dim3 grid(1,1,1);
dim3 threads(1,1,1);
gpu<<<grid, threads>>>(d_mem0, d_buf);
CUDA_SAFE_CALL( cudaThreadSynchronize() );
CUT_CHECK_ERROR("Kernel execution failed");
CUDA_SAFE_CALL(cudaMemcpy(h_mem0, d_mem0, sizeof(int)*N, cudaMemcpyDeviceToHost) );
CUDA_SAFE_CALL(cudaFree(d_mem0));
CUDA_SAFE_CALL(cudaFree(d_buf));
if(h_buf){CUDA_SAFE_CALL(cudaFreeHost(h_buf));}
int i;
printf("mem0:");
for(i=0; i<N; i++){
printf(" %d", h_mem0[i]);
}
printf("\n");
free(h_mem0);
}
まぁこんな感じ。
といいたいところだが、実は後者(#define TESTVERSION 2 の場合)に、cudaMemsetの第二引数を0じゃなくすると出力結果が無茶苦茶になってしまう。イージーミスか、バグか、仕様か、はてさて……???
Published
9月 5th, 2007
in
GPU関連 |
コメント(2) »
今度はバリア同期っぽく。
global memory spaceにバリア同期ポイント到着フラグ(配列)を用意しておいて、全てのフラグが埋まるのを待つという単純な実装。
CUDA:
// -*- C++ -*-
/*
block制御のテスト
バリア同期のようなものを作成し、待ち合わせを行う
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <cutil.h>
#define N 4
#define USE_BARRIER
__device__ int flags[N]={0,0,0,0}; // 待ち合わせのためのフラグ
__device__ int tmp[N]={0,0,0,0}; // 計算途中のデータ
__global__ void gpu
(int* answer)
{
int id = blockIdx.x;
int id2;
id2 = 4 - (id+1);
tmp[id] = id+1;
// tmp[] = {1,2,3,4}
// blockによって実行時間にばらつきを出すためのダミー演算
// id=0およびid=1のtmpは二倍になります
if(id<2){
int n = 1;
n *= 2;
n *= (id+1);
if(id==1){
n /= 2;
}
tmp[id] *= n;
}
// tmp[] = {2,4,3,4}
// 擬似バリア同期
// 全てのフラグが埋まるのを待つことで、バリア同期のような感じに
#ifdef USE_BARRIER
int sum = 0;
flags[id] = 1;
while(sum <4){
__syncthreads();
sum = flags[0]+flags[1]+flags[2]+flags[3];
}
#endif
answer[id] = tmp[id2] * (id+2);
// answer[] =
// 同期ミス = 8,9, 8, 5 (16と10の片方のみ狂う可能性もあり)
// 同期成功 = 8,9,16,10
}
void
runTest(int argc, char** argv)
{
CUT_DEVICE_INIT();
int answer[N];
int i;
for(i=0; i<N; i++){
answer[i] = 0;
}
int* d_a;
CUDA_SAFE_CALL(cudaMalloc((void**)&d_a, sizeof(int)*N));
CUDA_SAFE_CALL(cudaMemcpy(d_a, &answer, sizeof(int)*N, cudaMemcpyHostToDevice) );
dim3 grid(N,1,1);
dim3 threads(1,1,1);
gpu<<<grid, threads>>>(d_a);
CUDA_SAFE_CALL( cudaThreadSynchronize() );
CUT_CHECK_ERROR("Kernel execution failed");
CUDA_SAFE_CALL(cudaMemcpy(&answer, d_a, sizeof(int)*N, cudaMemcpyDeviceToHost) );
CUDA_SAFE_CALL(cudaFree(d_a));
for(i=0; i<N; i++){
printf(" %d\n", answer[i]);
}
printf("\n");
}
int
main(int argc, char** argv)
{
runTest(argc, argv);
CUT_EXIT(argc, argv);
}
それっぽく動いた。
へー。
Published
9月 5th, 2007
in
GPU関連 |
コメント(0) »
CUDAプログラミングガイドより意訳:block間での同期は取れないよ
流石に困るので、なんとかして同期っぽいことができないか試してみた。
考え方は以下:
global memory space内の変数をフラグとして利用する。以上。
適当に実装してみたが、とりあえずそれっぽく動いてくれた。
まぁ同期とはちょっと違うんだけど。
CUDA:
// -*- C++ -*-
/*
block制御のテスト
同期のようなものを作成して逐次処理を行う
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <cutil.h>
#define N 4
__device__ int counter=0; // 逐次処理のためのカウンタ
__global__ void gpu
(int* answer)
{
int id = blockIdx.x;
// カウンタを監視して自分の順番を待つ
while(counter != id){
__syncthreads();
}
*answer = (*answer*id) + (id+1);
counter += 1;
}
void
runTest(int argc, char** argv)
{
CUT_DEVICE_INIT();
int answer=0;
int* d_a;
CUDA_SAFE_CALL(cudaMalloc((void**)&d_a, sizeof(int)));
CUDA_SAFE_CALL(cudaMemcpy(d_a, &answer, sizeof(int), cudaMemcpyHostToDevice) );
dim3 grid(N,1,1);
dim3 threads(1,1,1);
gpu<<<grid, threads>>>(d_a);
CUDA_SAFE_CALL( cudaThreadSynchronize() );
CUT_CHECK_ERROR("Kernel execution failed");
CUDA_SAFE_CALL(cudaMemcpy(&answer, d_a, sizeof(int), cudaMemcpyDeviceToHost) );
CUDA_SAFE_CALL(cudaFree(d_a));
printf("answer %d\n", answer);
}
int
main(int argc, char** argv)
{
runTest(argc, argv);
CUT_EXIT(argc, argv);
}
カウンタを監視して自分の順番を待つ、ってところがあるおかげで正答である31が得られる。これがないと変な値が得られてしまう。
次はバリア同期を実装だな。
Published
9月 5th, 2007
in
GPU関連 |
コメント(0) »
ifでもswitchでも同じ感じ。
CUDA:
// -*- C++ -*-
/*
block制御のテスト
if実験
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <cutil.h>
#define N 4
int a[N];
int b[N];
#define PATTERN 0
/*
0 : id => OK
1 : 即値 => NG
2 : table[id] => OK
3 : table[即値] => NG
*/
__constant__ int table[4] = {0,1,2,3};
__global__ void gpu
(int* d_a, int* d_b)
{
int id = blockIdx.x;
#if PATTERN == 0
if(id==0){
d_b[id] = 1;
}else if(id==1){
d_b[id] = 2;
}else if(id==2){
d_b[id] = 3;
}else if(id==3){
d_b[id] = 4;
}
#endif
#if PATTERN == 1
if(id==0){
d_b[0] = 1;
}else if(id==1){
d_b[1] = 2;
}else if(id==2){
d_b[2] = 3;
}else if(id==3){
d_b[3] = 4;
}
#endif
#if PATTERN == 2
if(id==0){
d_b[table[id]] = 1;
}else if(id==1){
d_b[table[id]] = 2;
}else if(id==2){
d_b[table[id]] = 3;
}else if(id==3){
d_b[table[id]] = 4;
}
#endif
#if PATTERN == 3
if(id==0){
d_b[table[0]] = 1;
}else if(id==1){
d_b[table[1]] = 2;
}else if(id==2){
d_b[table[2]] = 3;
}else if(id==3){
d_b[table[3]] = 4;
}
#endif
}
void
runTest(int argc, char** argv)
{
int i, n;
n = N;
for( i = 0 ; i <n ; i++ ){
a[i] = 0;
b[i] = 0;
}
CUT_DEVICE_INIT();
int* d_a;
CUDA_SAFE_CALL(cudaMalloc((void**)&d_a, sizeof(int)*n));
CUDA_SAFE_CALL(cudaMemcpy(d_a, a, sizeof(int)*n, cudaMemcpyHostToDevice) );
int* d_b;
CUDA_SAFE_CALL(cudaMalloc((void**)&d_b, sizeof(int)*n));
CUDA_SAFE_CALL(cudaMemcpy(d_b, b, sizeof(int)*n, cudaMemcpyHostToDevice) );
dim3 grid(n,1,1);
dim3 threads(1,1,1);
gpu<<<grid, threads>>>(d_a, d_b);
CUDA_SAFE_CALL( cudaThreadSynchronize() );
CUT_CHECK_ERROR("Kernel execution failed");
CUDA_SAFE_CALL(cudaMemcpy(b, d_b, sizeof(int)*n, cudaMemcpyDeviceToHost) );
CUDA_SAFE_CALL(cudaFree(d_a));
CUDA_SAFE_CALL(cudaFree(d_b));
for( i = 0 ; i <n ; i++ ){
printf(" %d", b[i]);
}
printf("\n");
}
int
main(int argc, char** argv)
{
runTest(argc, argv);
CUT_EXIT(argc, argv);
}
CUDA:
// -*- C++ -*-
/*
block制御のテスト
switch実験
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <cutil.h>