2016-12-02 15 views
0

私はここ数週間、c/C++ OpenCLソリューションを開発しています。私の解決策として、CPU(ホスト)からGPU(デバイス)にクラスを渡す必要があります。クラスを引数として渡そうとすると、 "Unknown Type-Identifier Class"というエラーが返されます。私が疑問に思うのは、インテルPlatform上のOpenCLがクラスをカーネルに渡すことを許可するのか、それとも回避することができるのかという疑問です。 CUDAでは、いくつかの例を見てきましたが、プラットフォームにとっては問題なく動作します。しかし、OpenCLに関しては、私はこの照会に関連する参考文献も例も見つけられません。この問題に関して私は本当に感謝しています。私はIntelのWebサイトに同じ質問を掲載しましたが、無駄です。誰かが私がどこに間違っているのか、これをどのように進めるべきかを理解する助けになるほど親切であれば、本当に感謝しています。Intel Openclのカーネルにクラスを渡す

// HOST側のコード

#include<stdio.h> 
#include<iostream> 
#include"CL/cl.h" 


class test 
{ 
public: 
    cl_int a; 
    cl_char b; 
}; 

int main() 
{ 
    test *tempstruct = new test; 

    cl_platform_id platfrom_id; 
    cl_device_id device_id; // compute device id 
    cl_context context; // compute context 
    cl_command_queue commands; // compute command queue 
    cl_program program; // compute program 
    cl_kernel kernel; // compute kernel 

    int err; 

    err = clGetPlatformIDs(1, &platfrom_id, NULL); 
    if (err != CL_SUCCESS) 
    { 
     printf("Error: Failed to create a platfrom group!\n"); 
     return -1; 
    } 

    err = clGetDeviceIDs(platfrom_id, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL); 

    if (err != CL_SUCCESS) 
    { 
     printf("Error: Failed to create a device group!\n"); 
     return -1; 
    } 

    context = clCreateContext(0, 1, &device_id, NULL, NULL, NULL); 

    if (!context) 
    { 
     printf("Error: Failed to create a compute context!\n"); 
     return -1; 
    } 

    commands = clCreateCommandQueue(context, device_id, 0, NULL); 

    if (!commands) 
    { 
     printf("Error: Failed to create a command commands!\n"); 
     return -1; 
    } 

    #define MAX_SOURCE_SIZE (0x100000) 
    FILE *fp, *fp1; 
    char filename[] = "Template.cl"; 
    fp = fopen(filename, "r"); 
    if (fp == NULL) 
    { 
     printf("\n file not found \n"); 
     return -1; 
    } 
    char * source_str = (char*)malloc(MAX_SOURCE_SIZE); 
    size_t size = fread(source_str, 1, MAX_SOURCE_SIZE, fp); 
    fclose(fp); 

    cl_mem classobj = clCreateBuffer(context, CL_MEM_USE_HOST_PTR, sizeof(tempstruct), &tempstruct, &err); 

    if (err != CL_SUCCESS) 
    { 
     printf("Error: Failed to allocate device memory!\n"); 
     return -1; 
    } 

    program = clCreateProgramWithSource(context, 1, (const char **)& source_str, (const size_t *)&size, &err); 

    if (!program) 
    { 
     printf("Error: Failed to create program with source!\n"); 
     return -1; 
    } 

    err = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); 

    if (err != CL_SUCCESS) 
    { 
     printf("Error: Failed to build program executable!\n"); 
     return -1; 
    } 


    test *resptr = (test *)clEnqueueMapBuffer(commands, classobj, CL_TRUE, CL_MAP_WRITE, NULL, sizeof(test), NULL, NULL, NULL, &err); 
    // INITIALISATION OF CLASS 

    tempstruct->a = 10; 
    if (!resptr) 
    { 
     printf("Error: Failed to create enqueuemapbuffer!\n"); 
     return -1; 
    } 

    err = clEnqueueUnmapMemObject(commands, classobj, resptr, 0, NULL, NULL); 

    if (err != CL_SUCCESS) 
    { 
     printf("Error: Failed to write to source array!\n"); 
     return -1; 
    } 

    kernel = clCreateKernel(program, "CLASS", &err); 
    if (err != CL_SUCCESS) 
    { 
     printf("Error: Failed to create compute kernel!\n"); 
     return -1; 
    } 

    err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &classobj); 

    if (err != CL_SUCCESS) 
    { 
     printf("Error: Failed to set kernel arguments! %d\n", err); 
     return -1; 
    } 

    size_t globalsize = 1; 
    size_t local = 1; 

    err = clEnqueueNDRangeKernel(commands, kernel, 1, NULL, &globalsize, &local, 0, NULL, NULL); 
    if (err) 
    { 
     printf("Error: Failed to execute nd range!\n"); 
     return -1; 
    } 

    test *resptr1 = (test *)clEnqueueMapBuffer(commands, classobj, CL_TRUE, CL_MAP_READ, NULL, sizeof(test), NULL, NULL, NULL, &err); 

    err = clEnqueueUnmapMemObject(commands, classobj, resptr1, 0, NULL, NULL); 
    if (err != CL_SUCCESS) 
    { 
     printf("Error: Failed to read output array! %d\n", err); 
     return -1; 
    } 

    // again i am printing the class value 

    printf("\n in cpu side = %d\n", tempstruct->a); 

} 


//HOST END 


//DEVICE SIDE(KERNEL CODE) 

// filename : Template.cl 

class test 
{ 
public: 
    cl_int a; 
    cl_char b; 
}; 

__kernel void CLASS(__global test *inclass) 
{ 
    inclass->a = 10; 
    printf("\n in kernel side = %d \n",inclass->a); 
} 

// KERNEL END

エラー:

私はこれらすべてのエラーカーネル側でのみ

1)エラーTempalte.CLに直面しています不明なタイプ名 'test'
2)Tempalte.CLのエラー ';'トップレベルの宣言子の後
3)エラーTempalte.CLプログラムスコープ変数は、一定のアドレス空間内で宣言される必要がある
4)エラーTempalte.CL未知のタイプ名 'クラスの

QUERY:

Q)私の主な質問は、クラスをIntelアーキテクチャのカーネルに渡す方法です。
*私は、AMDのクラスにクラスを正常に渡しました。 Intel側で同じコードを試すたびに、上記の4つのエラーが表示されます。
*インテルのカーネルにクラスを渡す方法はありますか?また、インテルのアーキテクチャでクラスをカーネルに渡すことも可能ですか?

+2

これにはsyclが必要です。ほぼ純粋にC++を使用できます。エラーを起こすコードを投稿できますか?あなたはどのバージョンのopenclを使用していますか? –

+2

@huseyin tugrul buyukisik、私はあなたの要求ごとにコードを追加しました。あなたがそれから見つけることができるものを教えてください。前もって感謝します。 – Harrisson

答えて

4

OpenCLはC99を使用します。したがって、クラスではなく構造体をカーネルに渡すことができます。

huseyin tugrul buyukisikによれば、C++ 14(またはその周辺)をサポートするSYCLを使用できます。

また、NVIDIA®CUDA™とOpenCLの両方をサポートしたい場合は、NVIDIA®CUDA™でのみ書き込んでから、https://github.com/hughperkins/cuda-on-clを使用してOpenCL 1.2 GPUデバイスでNVIDIA®CUDA™コードを実行してください。完全な開示:私はcuda-on-clの著者であり、現在は少し進歩しています。それはいくつかの注意点/制限と共に、動作します。それは、例えば、本格的なC++ 11、テンプレート、クラスなどを扱うことができ、それはsycl(とヒュー・パーキンスの素敵なソリューション)場合はOpenCLの上1.2のGPU https://bitbucket.org/hughperkins/eigen/src/eigen-cl/unsupported/test/cuda-on-cl/?at=eigen-cl

+3

ありがとうございます。今私はそのコンセプトを理解していると思う。 – Harrisson

+3

intelは十分ではありませんAMD – Harrisson

+3

あなたはNVIDIA®を意味すると思います。彼らはそれぞれニッチを持っています。インテルは、統合されたGPUに強く、最近の多くのコンピュータで一般的にインテルCPUを使用しています。 NVIDIAはCUDAを発明し、私の知る限り、GPUを数学プロセッサとして販売する最初の会社でした。情報をお寄せいただきありがとうございます。 –

2

を固有のコンパイルおよび実行するために使用することができますオプションではありません

typedef struct Warrior_tag 
{ 
    int id; 
    float hp; 
    int strength; 
    int dexterity; 
    int constitution; 
} Warrior; 

typedef struct Mage_tag 
{ 
    int id; 
    Warrior summoned_warriors[90]; 
} Mage; 
// should be more than 32*90 + 32*90 => 5760(2.8k *2) => 8192(4k*2) bytes 
// because id + padding = 90 warriors or it doesn't work in runtime 
// reversing order of fields should make it 4k + 4 bytes 


__kernel void test0(__global Warrior * warriors) 
{ 
    int id=get_global_id(0); 
    Warrior battal_gazi = warriors[0]; 
    Warrior achilles = warriors[1]; 
    Warrior aramis = warriors[2]; 
    Warrior hattori_hanzo = warriors[3]; 
    Warrior ip_man = warriors[4]; 

    Mage nakano = (Mage){0,{battal_gazi, achilles}}; 
    Mage gul_dan = (Mage){0,{aramis , hattori_hanzo,ip_man }}; 
} 

、その後、あなたは、アライメントや構造体のサイズの取り扱いを担当している:あなたとあなたのクラスには、任意のメソッドを持っていない場合、あなたは(デバイスにコピーする際にバイト配列にシリアライズ)の代わりに構造体を使用することができますため 。たとえば、Warrior構造体のフィールドは全部で20バイトですが、デバイス側では32バイトである可能性があります(メモリ内で2のべき乗を強制するルールがいくつかあるため)。ホスト側から認識して、データを配置に合わせて配置してください可変サイズ。 "一度書いて、どこでも走る"ために扱う苦痛であるエンディアンも言及していません。だから、最適化されたコンピュータでのみ実行するべきです。

構造体の上部に最大のフィールドを配置し、下部に小さいフィールドを追加します。構造体の整列を2のべき乗として計算してください。 float3、int3、およびこれと同様に文書化されていない同様の実装については、float4、int4をバックグラウンドで使用する場合と使用しない場合があるので注意してください。グローバルメモリアクセスのパフォーマンスが重要でない場合は、シンプルさのために、それより小さいすべての構造体でNのような大きな番号を選択し、相対バイトアドレス指定を構造体の先頭バイトに置きます。 Warrior構造体の先頭のバイトアドレス(hpのバイトアドレスなど)(パックされた4バイトを単一のintにしたもの)。次にデバイス側では、どのバイトにフィールド開始があるかを問い合わせることができます。

  • は、コンストラクタカーネルにフィールドの配列を送信する:ホスト側の構造体フィールドのアライメントができない場合は

    を(エンディアンが、それはよりトリッキーすることができますので、純粋な構造体のためbuffercopiesを使用しないでください) (float配列 - > HP、int配列 - > ID)

  • カーネル(Warriorは、HPの配列からIDを構築している唯一のデバイス側のバッファ、...)
  • を使用して、デバイスでのコンストラクトはいじるませんアラインメントやサイズを使用しなくても、内部のすべての構造体に適合するようにバッファを大きくするだけです。 32 *数の戦士バイトを選ぶことは、戦士配列にとって十分であるはずです。
  • 他のカーネルを使用してデバイス側の配列に構造体を展開した後、結果が配列として再びホスト側に返されます。
関連する問題